Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync to 5.0.0-alpha.1.20073.3 #1234

Merged
merged 7 commits into from
Feb 1, 2020
Merged

Sync to 5.0.0-alpha.1.20073.3 #1234

merged 7 commits into from
Feb 1, 2020

Conversation

roji
Copy link
Member

@roji roji commented Jan 28, 2020

No description provided.

@roji roji force-pushed the 5.0-sync branch 6 times, most recently from d37adcf to f95a1ec Compare January 28, 2020 16:53
@roji roji mentioned this pull request Jan 28, 2020
Copy link
Contributor

@YohDeadfall YohDeadfall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partly reviewed the PR and will continue tomorrow.

@@ -66,16 +98,39 @@ public static class NpgsqlDbContextOptionsExtensions
var extension = (NpgsqlOptionsExtension)GetOrCreateExtension(optionsBuilder).WithConnection(connection);
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);

ConfigureWarnings(optionsBuilder);

npgsqlOptionsAction?.Invoke(new NpgsqlDbContextOptionsBuilder(optionsBuilder));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These lines are repeated multiple times, so it's worth to make a private method for them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. But since this class is basically a copy-paste from EF Core, I prefer to just leave things like they are upstream... And there's not huge value here in the private method.

src/EFCore.PG/Internal/NpgsqlLoggerExtensions.cs Outdated Show resolved Hide resolved
src/EFCore.PG/Internal/NpgsqlLoggerExtensions.cs Outdated Show resolved Hide resolved
src/EFCore.PG/Internal/NpgsqlLoggerExtensions.cs Outdated Show resolved Hide resolved
.Append(" INCLUDE (")
.Append(ColumnList(includeColumns))
.Append(")");
if (operation[NpgsqlAnnotationNames.IndexInclude] is string[] includeColumns &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nested condition can be safely merged with the outer since there are no returns on else blocks.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Note that I wasn't totally sure here about something - would be good to have your opinion (also @bricelam's).

In most cases, if something isn't supported, I prefer throwing an exception to make it clear to the user. In the case of index-included properties, for old versions which don't support this, for now I've decided to simply ignore - creating the index without the included properties. This is because included properties are an optional feature which only improves perf, and this makes the same model usable on any version of PG: with newer versions we get the speedup, with older versions we don't.

Does this make sense? Or is it better to throw on older versions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing or ignoring both seem fine to me. Did you consider logging a warning?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep forgetting those :) Ignoring and logging does sound like the way to go.

{
[DebuggerStepThrough]
public static T GetValueOrDefault<T>([NotNull] this DbDataReader reader, [NotNull] string name)
[return: MaybeNull]
internal static T GetValueOrDefault<T>(this DbDataReader reader, string name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case a reader is not NpgsqlDataReader?

Copy link
Member Author

@roji roji Jan 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our code I think it's always NpgsqlDataReader - but it doesn't really make a difference.. Any reason to change it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since NpgsqlDataReader is a final class the JIT could inline calls if they meet requirements. Another reason is that it's an internal extension method which is for Npgsql only, no need in an additional abstraction.

@@ -215,15 +207,16 @@ public override DatabaseModel Create(DbConnection dbConnection, DatabaseModelFac
{
while (reader.Read())
{
var table = new DatabaseTable
var schema = reader.GetValueOrDefault<string>("nspname");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you're using extensions here. I have fixed all methods on the command to return an NpgsqlDataReader.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Any reason to do any change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

See dotnet/efcore#16200
Follows 690ebc4540334c1d0938660a5960a25d4338acd4 in EF Core
@roji
Copy link
Member Author

roji commented Jan 29, 2020

Partly reviewed the PR and will continue tomorrow.

No problem and thanks! Have addressed the comments you've already made.

Copy link
Contributor

@YohDeadfall YohDeadfall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hope reviewed it carefully...

@@ -1083,6 +1033,7 @@ static SequenceInfo ReadSequenceInfo(DbDataRecord record, Version postgresVersio

class SequenceInfo
{
public SequenceInfo(string storeType) => StoreType = storeType;
public string StoreType { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove setter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving it since everything else has a setter... It's just a temporarily values holder...

// {
// DiffSnapshot(new BloggingContextModelSnapshot22(), context);
// }
//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it commented?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was this way before too - I don't remember really. One day someone will look at it :)

AssertSql(
@"ALTER TABLE ""People"" ALTER COLUMN ""FirstName"" TYPE text;
ALTER TABLE ""People"" ALTER COLUMN ""FirstName"" SET NOT NULL;
ALTER TABLE ""People"" ALTER COLUMN ""FirstName"" DROP DEFAULT;");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this style of assertion used in some places, but in others you put different commands in multiple strings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm mistaken, when you see multiple strings with a comment separating them, this means the migrations generator is generating multiple ADO commands. In other cases (like here), multiple statements are batched in the same command. In general it doesn't make much of a difference (we don't care about network roundtrips in migrations), but it could be an issue where we need to suppress transactions, since that holds for the entire command.

AssertSql(
@"ALTER TABLE ""People"" DROP COLUMN ""Sum"";",
//
@"ALTER TABLE ""People"" ADD ""Sum"" integer GENERATED ALWAYS AS (""X"" + ""Y"") STORED;");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, there are two strings.


#region Helpers
protected override void ClearLog()
=> Fixture.TestSqlLoggerFactory.Clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does EF implement this method as no op?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because TestSqlLoggerFactory is a relational-only thing (SQL), but the test base class isn't relational - it is used also for non-relational databases. So you can think about ClearLog as a general, "clear all logs" that isn't SQL specific, which providers must then override to clear the log in their particular way (for relational databases that means clearing SQL).

For test base classes which are relational only this can and should be implemented at the base class.

protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
base.OnModelCreating(modelBuilder, context);

modelBuilder.HasPostgresExtension("postgis");
}

//protected override bool CanExecuteQueryString => true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we haven't implemented this yet, see #1232

{
public static NpgsqlDbContextOptionsBuilder ApplyConfiguration(this NpgsqlDbContextOptionsBuilder optionsBuilder)
{
//optionsBuilder.ExecutionStrategy(d => new TestNpgsqlRetryingExecutionStrategy(d));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why commented?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this introduces a lot of test breakage which I didn't want to deal with at this point. We should do this at some point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #1244 to track this.

.Generate(operation, modelBuilder.Model);

Sql = string.Join(
"GO" + EOL + EOL,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is see an SQL Server directive!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a "delimiter" introduced in the tests to indicate a batch boundary (I've added a comment) - yes it's "inspired" by SQL Server :) Don't forget that these are just unit tests on the produced migrations DDL - nothing is executed on the database. Also note that this base class is copied as-is from EF Core, since there's no nuget package for the non-functional tests.

@roji
Copy link
Member Author

roji commented Feb 1, 2020

Thanks for the review @YohDeadfall! Have answered all the comments above, if there's something you want more info on let me know.

@roji roji merged commit 1fe05c6 into npgsql:dev Feb 1, 2020
@roji roji deleted the 5.0-sync branch February 1, 2020 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants