Skip to content

Commit

Permalink
Add support for index sort options
Browse files Browse the repository at this point in the history
  • Loading branch information
khellang committed Nov 15, 2018
1 parent d014f51 commit 48676c0
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ public override MethodCallCodeFragment GenerateFluentApi(IIndex index, IAnnotati
return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlHasMethod), annotation.Value);
if (annotation.Name == NpgsqlAnnotationNames.IndexOperators)
return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlHasOperators), annotation.Value);
if (annotation.Name == NpgsqlAnnotationNames.IndexSortOptions)
return new MethodCallCodeFragment(nameof(NpgsqlIndexBuilderExtensions.ForNpgsqlHasSortOptions), annotation.Value);

return null;
}
Expand Down
19 changes: 19 additions & 0 deletions src/EFCore.PG/Extensions/NpgsqlIndexBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,24 @@ public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder ind

return indexBuilder;
}

/// <summary>
/// The PostgreSQL index sort options to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
/// <param name="indexBuilder"> The builder for the index being configured. </param>
/// <param name="sortOptions"> The sort options to use for each column. </param>
/// <returns> A builder to further configure the index. </returns>
public static IndexBuilder ForNpgsqlHasSortOptions([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] sortOptions)
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(sortOptions, nameof(sortOptions));

indexBuilder.Metadata.Npgsql().SortOptions = sortOptions;

return indexBuilder;
}
}
}
8 changes: 8 additions & 0 deletions src/EFCore.PG/Metadata/INpgsqlIndexAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,13 @@ public interface INpgsqlIndexAnnotations : IRelationalIndexAnnotations
/// https://www.postgresql.org/docs/current/static/indexes-opclass.html
/// </remarks>
IReadOnlyList<string> Operators { get; }

/// <summary>
/// The PostgreSQL index sort options to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
IReadOnlyList<string> SortOptions { get; }
}
}
1 change: 1 addition & 0 deletions src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class NpgsqlAnnotationNames
public const string HiLoSequenceSchema = Prefix + "HiLoSequenceSchema";
public const string IndexMethod = Prefix + "IndexMethod";
public const string IndexOperators = Prefix + "IndexOperators";
public const string IndexSortOptions = Prefix + "IndexSortOptions";
public const string PostgresExtensionPrefix = Prefix + "PostgresExtension:";
public const string EnumPrefix = Prefix + "Enum:";
public const string RangePrefix = Prefix + "Range:";
Expand Down
17 changes: 17 additions & 0 deletions src/EFCore.PG/Metadata/NpgsqlIndexAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,27 @@ public string[] Operators

IReadOnlyList<string> INpgsqlIndexAnnotations.Operators => Operators;

/// <summary>
/// The PostgreSQL index sort options to be used.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public string[] SortOptions
{
get => (string[])Annotations.Metadata[NpgsqlAnnotationNames.IndexSortOptions];
set => SetSortOptions(value);
}

IReadOnlyList<string> INpgsqlIndexAnnotations.SortOptions => SortOptions;

protected virtual bool SetMethod(string value)
=> Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexMethod, value);

protected virtual bool SetOperators(string[] value)
=> Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexOperators, value);

protected virtual bool SetSortOptions(string[] value)
=> Annotations.SetAnnotation(NpgsqlAnnotationNames.IndexSortOptions, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public override IEnumerable<IAnnotation> For(IIndex index)
yield return new Annotation(NpgsqlAnnotationNames.IndexMethod, index.Npgsql().Method);
if (index.Npgsql().Operators != null)
yield return new Annotation(NpgsqlAnnotationNames.IndexOperators, index.Npgsql().Operators);
if (index.Npgsql().SortOptions != null)
yield return new Annotation(NpgsqlAnnotationNames.IndexSortOptions, index.Npgsql().SortOptions);
}

public override IEnumerable<IAnnotation> For(IModel model)
Expand Down
50 changes: 34 additions & 16 deletions src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ protected override void Generate(

var method = (string)operation[NpgsqlAnnotationNames.IndexMethod];
var operators = (string[])operation[NpgsqlAnnotationNames.IndexOperators];
var sortOptions = (string[])operation[NpgsqlAnnotationNames.IndexSortOptions];

builder.Append("CREATE ");

Expand All @@ -560,7 +561,7 @@ protected override void Generate(

builder
.Append(" (")
.Append(IndexColumnList(operation.Columns, operators))
.Append(IndexColumnList(operation.Columns, operators, sortOptions))
.Append(")");

if (!string.IsNullOrEmpty(operation.Filter))
Expand Down Expand Up @@ -1134,29 +1135,46 @@ static string GetSchemaOrDefault([CanBeNull] string schema, [CanBeNull] IAnnotat
bool VersionAtLeast(int major, int minor)
=> _postgresVersion is null || new Version(major, minor) <= _postgresVersion;

string IndexColumnList(string[] columns, string[] operators)
string IndexColumnList(string[] columns, string[] operators, string[] sortOptions)
{
if (operators == null || operators.Length == 0)
return ColumnList(columns);
var isFirst = true;
var builder = new StringBuilder();

return string.Join(", ", columns.Select((v, i) =>
for (int i = 0; i < columns.Length; i++)
{
var identifier = Dependencies.SqlGenerationHelper.DelimitIdentifier(v);
if (!isFirst)
builder.Append(", ");

if (i >= operators.Length)
return identifier;
builder.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(columns[i]));

var @operator = operators[i];
if (operators != null && i < operators.Length)
{
var @operator = operators[i];

if (string.IsNullOrEmpty(@operator))
return identifier;
if (!string.IsNullOrEmpty(@operator))
{
var delimitedOperator = TryParseSchema(@operator, out var name, out var schema)
? Dependencies.SqlGenerationHelper.DelimitIdentifier(name, schema)
: Dependencies.SqlGenerationHelper.DelimitIdentifier(@operator);

var delimitedOperator = TryParseSchema(@operator, out var name, out var schema)
? Dependencies.SqlGenerationHelper.DelimitIdentifier(name, schema)
: Dependencies.SqlGenerationHelper.DelimitIdentifier(@operator);
builder.Append(" ").Append(delimitedOperator);
}
}

if (sortOptions != null && i < sortOptions.Length)
{
var sortOption = sortOptions[i];

if (!string.IsNullOrEmpty(sortOption))
{
builder.Append(" ").Append(sortOption);
}
}

isFirst = false;
}

return string.Concat(identifier, " ", delimitedOperator);
}));
return builder.ToString();
}

static bool TryParseSchema(string identifier, out string name, out string schema)
Expand Down
35 changes: 35 additions & 0 deletions test/EFCore.PG.FunctionalTests/NpgsqlMigrationSqlGeneratorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,41 @@ public void CreateIndexOperation_schema_qualified_operations()
Sql);
}

[Fact]
public void CreateIndexOperation_sort_options()
{
Generate(new CreateIndexOperation
{
Name = "IX_People_Name",
Table = "People",
Schema = "dbo",
Columns = new[] { "FirstName", "LastName" },
[NpgsqlAnnotationNames.IndexSortOptions] = new[] { "ASC NULLS FIRST", "DESC" }
});

Assert.Equal(
"CREATE INDEX \"IX_People_Name\" ON dbo.\"People\" (\"FirstName\" ASC NULLS FIRST, \"LastName\" DESC);" + EOL,
Sql);
}

[Fact]
public void CreateIndexOperation_operations_and_sort_options()
{
Generate(new CreateIndexOperation
{
Name = "IX_People_Name",
Table = "People",
Schema = "dbo",
Columns = new[] { "FirstName", "LastName" },
[NpgsqlAnnotationNames.IndexOperators] = new[] { "text_pattern_ops" },
[NpgsqlAnnotationNames.IndexSortOptions] = new[] { "ASC NULLS FIRST", "DESC" }
});

Assert.Equal(
"CREATE INDEX \"IX_People_Name\" ON dbo.\"People\" (\"FirstName\" text_pattern_ops ASC NULLS FIRST, \"LastName\" DESC);" + EOL,
Sql);
}

[Fact]
public void RenameIndexOperation()
{
Expand Down

0 comments on commit 48676c0

Please sign in to comment.