提交 08d8cc55 编写于 作者: S Shay Rojansky

Support new EF Core way for specifying descending indexes

Closes #2267
上级 a6017db2
......@@ -369,99 +369,6 @@ public static class NpgsqlIndexBuilderExtensions
#endregion Collation
#region Sort order
/// <summary>
/// The PostgreSQL index sort ordering 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="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public static IndexBuilder HasSortOrder(
this IndexBuilder indexBuilder,
params SortOrder[]? values)
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(values, nameof(values));
if (!SortOrderHelper.IsDefaultSortOrder(values))
{
indexBuilder.Metadata.SetSortOrder(values);
}
return indexBuilder;
}
/// <summary>
/// The PostgreSQL index sort ordering 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="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public static IndexBuilder<TEntity> HasSortOrder<TEntity>(
this IndexBuilder<TEntity> indexBuilder,
params SortOrder[]? values)
=> (IndexBuilder<TEntity>)HasSortOrder((IndexBuilder)indexBuilder, values);
/// <summary>
/// The PostgreSQL index sort ordering 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="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
public static IConventionIndexBuilder? HasSortOrder(
this IConventionIndexBuilder indexBuilder,
IReadOnlyList<SortOrder>? values,
bool fromDataAnnotation)
{
if (indexBuilder.CanSetSortOrder(values, fromDataAnnotation))
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(values, nameof(values));
if (!SortOrderHelper.IsDefaultSortOrder(values))
{
indexBuilder.Metadata.SetSortOrder(values, fromDataAnnotation);
}
return indexBuilder;
}
return null;
}
/// <summary>
/// Returns a value indicating whether the PostgreSQL index sort ordering can be set.
/// </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="values">The sort order to use for each column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>A builder to further configure the index.</returns>
public static bool CanSetSortOrder(
this IConventionIndexBuilder indexBuilder,
IReadOnlyList<SortOrder>? values,
bool fromDataAnnotation)
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
return indexBuilder.CanSetAnnotation(NpgsqlAnnotationNames.IndexSortOrder, values, fromDataAnnotation);
}
#endregion Sort order
#region Null sort order
/// <summary>
......@@ -480,9 +387,7 @@ public static class NpgsqlIndexBuilderExtensions
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(values, nameof(values));
var sortOrders = indexBuilder.Metadata.GetSortOrder();
if (!SortOrderHelper.IsDefaultNullSortOrder(values, sortOrders))
if (!SortOrderHelper.IsDefaultNullSortOrder(values, indexBuilder.Metadata.IsDescending))
{
indexBuilder.Metadata.SetNullSortOrder(values);
}
......@@ -521,9 +426,7 @@ public static class NpgsqlIndexBuilderExtensions
{
if (indexBuilder.CanSetNullSortOrder(values, fromDataAnnotation))
{
var sortOrders = indexBuilder.Metadata.GetSortOrder();
if (!SortOrderHelper.IsDefaultNullSortOrder(values, sortOrders))
if (!SortOrderHelper.IsDefaultNullSortOrder(values, indexBuilder.Metadata.IsDescending))
{
indexBuilder.Metadata.SetNullSortOrder(values, fromDataAnnotation);
}
......@@ -763,6 +666,111 @@ public static IndexBuilder<TEntity> IsCreatedConcurrently<TEntity>(this IndexBui
#endregion Created concurrently
#region Sort order (legacy)
/// <summary>
/// The PostgreSQL index sort ordering 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="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[Obsolete("Use IsDescending instead")]
public static IndexBuilder HasSortOrder(
this IndexBuilder indexBuilder,
params SortOrder[]? values)
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(values, nameof(values));
var isDescending = new bool[indexBuilder.Metadata.Properties.Count];
for (var i = 0; i < isDescending.Length; i++)
{
isDescending[i] = values?.Length > i && values[i] == SortOrder.Descending;
}
indexBuilder.IsDescending(isDescending);
return indexBuilder;
}
/// <summary>
/// The PostgreSQL index sort ordering 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="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[Obsolete("Use IsDescending instead")]
public static IndexBuilder<TEntity> HasSortOrder<TEntity>(
this IndexBuilder<TEntity> indexBuilder,
params SortOrder[]? values)
=> (IndexBuilder<TEntity>)HasSortOrder((IndexBuilder)indexBuilder, values);
/// <summary>
/// The PostgreSQL index sort ordering 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="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <param name="values">The sort order to use for each column.</param>
/// <returns>A builder to further configure the index.</returns>
[Obsolete("Use IsDescending instead")]
public static IConventionIndexBuilder? HasSortOrder(
this IConventionIndexBuilder indexBuilder,
IReadOnlyList<SortOrder>? values,
bool fromDataAnnotation)
{
if (indexBuilder.CanSetSortOrder(values, fromDataAnnotation))
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
Check.NullButNotEmpty(values, nameof(values));
var isDescending = new bool[indexBuilder.Metadata.Properties.Count];
for (var i = 0; i < isDescending.Length; i++)
{
isDescending[i] = values?.Count > i && values[i] == SortOrder.Descending;
}
indexBuilder.IsDescending(isDescending);
return indexBuilder;
}
return null;
}
/// <summary>
/// Returns a value indicating whether the PostgreSQL index sort ordering can be set.
/// </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="values">The sort order to use for each column.</param>
/// <param name="fromDataAnnotation">Indicates whether the configuration was specified using a data annotation.</param>
/// <returns>A builder to further configure the index.</returns>
[Obsolete("Use IsDescending instead")]
public static bool CanSetSortOrder(
this IConventionIndexBuilder indexBuilder,
IReadOnlyList<SortOrder>? values,
bool fromDataAnnotation)
{
Check.NotNull(indexBuilder, nameof(indexBuilder));
return indexBuilder.CanSetAnnotation(NpgsqlAnnotationNames.IndexSortOrder, values, fromDataAnnotation);
}
#endregion Sort order (obsolete)
#region Obsolete
/// <summary>
......
......@@ -159,54 +159,6 @@ public static void SetCollation(this IMutableIndex index, IReadOnlyList<string>?
#endregion Collation
#region Sort order
/// <summary>
/// Returns the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public static IReadOnlyList<SortOrder>? GetSortOrder(this IReadOnlyIndex index)
=> (IReadOnlyList<SortOrder>?)index[NpgsqlAnnotationNames.IndexSortOrder];
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public static void SetSortOrder(this IMutableIndex index, IReadOnlyList<SortOrder>? sortOrder)
=> index.SetOrRemoveAnnotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder);
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
public static IReadOnlyList<SortOrder>? SetSortOrder(
this IConventionIndex index,
IReadOnlyList<SortOrder>? sortOrder,
bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(sortOrder, nameof(sortOrder));
index.SetOrRemoveAnnotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder, fromDataAnnotation);
return sortOrder;
}
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the index sort orders.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the index sort orders.</returns>
public static ConfigurationSource? GetSortOrderConfigurationSource(this IConventionIndex index)
=> index.FindAnnotation(NpgsqlAnnotationNames.IndexSortOrder)?.GetConfigurationSource();
#endregion Sort order
#region Null sort order
/// <summary>
......@@ -419,4 +371,56 @@ public static void SetTsVectorConfig(this IMutableIndex index, string? config)
=> index.FindAnnotation(NpgsqlAnnotationNames.TsVectorConfig)?.GetConfigurationSource();
#endregion ToTsVector
#region Sort order (legacy)
/// <summary>
/// Returns the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[Obsolete("Use IsDescending instead")]
public static IReadOnlyList<SortOrder>? GetSortOrder(this IReadOnlyIndex index)
=> (IReadOnlyList<SortOrder>?)index[NpgsqlAnnotationNames.IndexSortOrder];
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[Obsolete("Use IsDescending instead")]
public static void SetSortOrder(this IMutableIndex index, IReadOnlyList<SortOrder>? sortOrder)
=> index.SetOrRemoveAnnotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder);
/// <summary>
/// Sets the column sort orders to be used, or <c>null</c> if they have not been specified.
/// </summary>
/// <remarks>
/// https://www.postgresql.org/docs/current/static/indexes-ordering.html
/// </remarks>
[Obsolete("Use IsDescending instead")]
public static IReadOnlyList<SortOrder>? SetSortOrder(
this IConventionIndex index,
IReadOnlyList<SortOrder>? sortOrder,
bool fromDataAnnotation = false)
{
Check.NullButNotEmpty(sortOrder, nameof(sortOrder));
index.SetOrRemoveAnnotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder, fromDataAnnotation);
return sortOrder;
}
/// <summary>
/// Returns the <see cref="ConfigurationSource" /> for the index sort orders.
/// </summary>
/// <param name="index">The index.</param>
/// <returns>The <see cref="ConfigurationSource" /> for the index sort orders.</returns>
[Obsolete("Use IsDescending instead")]
public static ConfigurationSource? GetSortOrderConfigurationSource(this IConventionIndex index)
=> index.FindAnnotation(NpgsqlAnnotationNames.IndexSortOrder)?.GetConfigurationSource();
#endregion Sort order (legacy)
}
\ No newline at end of file
......@@ -13,7 +13,6 @@ public static class NpgsqlAnnotationNames
public const string IdentityOptions = Prefix + "IdentitySequenceOptions";
public const string IndexMethod = Prefix + "IndexMethod";
public const string IndexOperators = Prefix + "IndexOperators";
public const string IndexSortOrder = Prefix + "IndexSortOrder";
public const string IndexNullSortOrder = Prefix + "IndexNullSortOrder";
public const string IndexInclude = Prefix + "IndexInclude";
public const string Tablespace = Prefix + "Tablespace";
......@@ -55,4 +54,7 @@ public static class NpgsqlAnnotationNames
[Obsolete("Replaced by RelationalAnnotationNames.Collation")]
public const string IndexCollation = Prefix + "IndexCollation";
// Replaced by IsDescending in EF Core 7.0
public const string IndexSortOrder = Prefix + "IndexSortOrder";
}
\ No newline at end of file
......@@ -133,11 +133,6 @@ public override IEnumerable<IAnnotation> For(ITableIndex index, bool designTime)
yield return new Annotation(NpgsqlAnnotationNames.IndexOperators, operators);
}
if (modelIndex.GetSortOrder() is { } sortOrder)
{
yield return new Annotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder);
}
if (modelIndex.GetNullSortOrder() is { } nullSortOrder)
{
yield return new Annotation(NpgsqlAnnotationNames.IndexNullSortOrder, nullSortOrder);
......@@ -166,6 +161,12 @@ public override IEnumerable<IAnnotation> For(ITableIndex index, bool designTime)
NpgsqlAnnotationNames.CreatedConcurrently,
isCreatedConcurrently.Value);
}
// Support legacy annotation for index ordering
if (modelIndex[NpgsqlAnnotationNames.IndexSortOrder] is IReadOnlyList<SortOrder> legacySortOrder)
{
yield return new Annotation(NpgsqlAnnotationNames.IndexSortOrder, legacySortOrder);
}
}
public override IEnumerable<IAnnotation> For(IRelationalModel model, bool designTime)
......
......@@ -1940,7 +1940,7 @@ private string IndexColumnList(IndexColumn[] columns, string? method)
// sorting, thus we only want to emit sort options for btree indexes.
if (method is null || method == "btree")
{
if (column.SortOrder == SortOrder.Descending)
if (column.IsDescending)
{
builder.Append(" DESC");
}
......@@ -2006,7 +2006,11 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
var collations = operation[RelationalAnnotationNames.Collation] as string[];
var operators = operation[NpgsqlAnnotationNames.IndexOperators] as string[];
var sortOrders = operation[NpgsqlAnnotationNames.IndexSortOrder] as SortOrder[];
// We used to have our own annotation-based descending index mechanism, this got replaced with IsDescending in EF Core 7.0.
var isDescendingValues = operation.IsDescending;
var legacySortOrders = operation[NpgsqlAnnotationNames.IndexSortOrder] as SortOrder[];
var nullSortOrders = operation[NpgsqlAnnotationNames.IndexNullSortOrder] as NullSortOrder[];
var columns = new IndexColumn[operation.Columns.Length];
......@@ -2016,10 +2020,12 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
var name = operation.Columns[i];
var @operator = i < operators?.Length ? operators[i] : null;
var collation = i < collations?.Length ? collations[i] : null;
var sortOrder = i < sortOrders?.Length ? sortOrders[i] : SortOrder.Ascending;
var isColumnDescending = isDescendingValues is not null
? isDescendingValues[i]
: i < legacySortOrders?.Length && legacySortOrders[i] == SortOrder.Descending;
var nullSortOrder = i < nullSortOrders?.Length ? nullSortOrders[i] : NullSortOrder.Unspecified;
columns[i] = new IndexColumn(name, @operator, collation, sortOrder, nullSortOrder);
columns[i] = new IndexColumn(name, @operator, collation, isColumnDescending, nullSortOrder);
}
return columns;
......@@ -2027,19 +2033,19 @@ private static IndexColumn[] GetIndexColumns(CreateIndexOperation operation)
private readonly struct IndexColumn
{
public IndexColumn(string name, string? @operator, string? collation, SortOrder sortOrder, NullSortOrder nullSortOrder)
public IndexColumn(string name, string? @operator, string? collation, bool isDescending, NullSortOrder nullSortOrder)
{
Name = name;
Operator = @operator;
Collation = collation;
SortOrder = sortOrder;
IsDescending = isDescending;
NullSortOrder = nullSortOrder;
}
public string Name { get; }
public string? Operator { get; }
public string? Collation { get; }
public SortOrder SortOrder { get; }
public bool IsDescending { get; }
public NullSortOrder NullSortOrder { get; }
}
......
......@@ -710,26 +710,16 @@ deptype IN ('e', 'x')
{
var options = record.GetFieldValue<ushort[]>("indoption");
// The first bit specifies whether values are sorted in descending order.
const ushort indoptionDescFlag = 0x0001;
var sortOrders = options
.Select(val => (val & indoptionDescFlag) != 0 ? SortOrder.Descending : SortOrder.Ascending)
.ToArray();
if (!SortOrderHelper.IsDefaultSortOrder(sortOrders))
{
index[NpgsqlAnnotationNames.IndexSortOrder] = sortOrders;
}
// The second bit specifies whether NULLs are sorted first instead of last.
const ushort indoptionNullsFirstFlag = 0x0002;
// The first bit in indoption specifies whether values are sorted in descending order, the second whether
// NULLs are sorted first instead of last.
var isDescending = options.Select(val => (val & 0x0001) != 0).ToList();
var nullSortOrders = options
.Select(val => (val & indoptionNullsFirstFlag) != 0 ? NullSortOrder.NullsFirst : NullSortOrder.NullsLast)
.Select(val => (val & 0x0002) != 0 ? NullSortOrder.NullsFirst : NullSortOrder.NullsLast)
.ToArray();
if (!SortOrderHelper.IsDefaultNullSortOrder(nullSortOrders, sortOrders))
index.IsDescending = isDescending;
if (!SortOrderHelper.IsDefaultNullSortOrder(nullSortOrders, isDescending))
{
index[NpgsqlAnnotationNames.IndexNullSortOrder] = nullSortOrders;
}
......
......@@ -4,12 +4,9 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Utilities;
internal static class SortOrderHelper
{
public static bool IsDefaultSortOrder(IReadOnlyList<SortOrder>? sortOrders)
=> sortOrders?.All(sortOrder => sortOrder == SortOrder.Ascending) ?? true;
public static bool IsDefaultNullSortOrder(
IReadOnlyList<NullSortOrder>? nullSortOrders,
IReadOnlyList<SortOrder>? sortOrders)
IReadOnlyList<bool>? isDescendingValues)
{
if (nullSortOrders is null)
{
......@@ -21,9 +18,7 @@ public static bool IsDefaultSortOrder(IReadOnlyList<SortOrder>? sortOrders)
var nullSortOrder = nullSortOrders[i];
// We need to consider the ASC/DESC sort order to determine the default NULLS FIRST/LAST sort order.
var sortOrder = i < sortOrders?.Count ? sortOrders[i] : SortOrder.Ascending;
if (sortOrder == SortOrder.Descending)
if (isDescendingValues is not null && isDescendingValues[i])
{
// NULLS FIRST is the default when DESC is specified.
if (nullSortOrder != NullSortOrder.NullsFirst)
......
......@@ -1817,13 +1817,77 @@ public override async Task Create_index_unique()
@"CREATE UNIQUE INDEX ""IX_People_FirstName_LastName"" ON ""People"" (""FirstName"", ""LastName"");");
}
[ConditionalFact(Skip = "https://github.com/npgsql/efcore.pg/issues/2267")]
public override Task Create_index_descending()
=> Task.CompletedTask;
public override async Task Create_index_descending()
{
await base.Create_index_descending();
AssertSql(
@"CREATE INDEX ""IX_People_X"" ON ""People"" (""X"" DESC);");
}
public override async Task Create_index_descending_mixed()
{
await base.Create_index_descending_mixed();
AssertSql(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");");
}
#pragma warning disable CS0618 // HasSortOrder is obsolete
[Fact]
public virtual async Task Create_index_descending_mixed_legacy_api()
{
await Test(
builder => builder.Entity(
"People", e =>
{
e.Property<int>("Id");
e.Property<int>("X");
e.Property<int>("Y");
e.Property<int>("Z");
}),
builder => { },
builder => builder.Entity("People")
.HasIndex("X", "Y", "Z")
.HasSortOrder(SortOrder.Ascending, SortOrder.Descending),
model =>
{
var table = Assert.Single(model.Tables);
var index = Assert.Single(table.Indexes);
Assert.Collection(index.IsDescending, Assert.False, Assert.True, Assert.False);
});
AssertSql(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");");
}
#pragma warning restore CS0618
[Fact]
public virtual async Task Create_index_descending_mixed_legacy_annotation()
{
await Test(
builder => builder.Entity(
"People", e =>
{
e.Property<int>("Id");
e.Property<int>("X");
e.Property<int>("Y");
e.Property<int>("Z");
}),
builder => { },
builder => builder.Entity("People")
.HasIndex("X", "Y", "Z")
.HasAnnotation(NpgsqlAnnotationNames.IndexSortOrder, new[] { SortOrder.Ascending, SortOrder.Descending }),
model =>
{
var table = Assert.Single(model.Tables);
var index = Assert.Single(table.Indexes);
Assert.Collection(index.IsDescending, Assert.False, Assert.True, Assert.False);
});
[ConditionalFact(Skip = "https://github.com/npgsql/efcore.pg/issues/2267")]
public override Task Create_index_descending_mixed()
=> Task.CompletedTask;
AssertSql(
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");");
}
public override async Task Create_index_with_filter()
{
......@@ -2089,32 +2153,6 @@ public virtual async Task Create_index_with_operators()
// so we test support for this on the generated SQL only, in NpgsqlMigrationSqlGeneratorTest, and not against
// the database here.
[Fact]
public virtual async Task Create_index_with_sort_order()
{
await Test(
builder => builder.Entity(
"People", e =>
{
e.Property<int>("Id");
e.Property<string>("FirstName");
e.Property<string>("LastName");
}),
_ => { },
builder => builder.Entity("People").HasIndex("FirstName", "LastName")
.HasSortOrder(SortOrder.Descending, SortOrder.Ascending),
model =>
{
var table = Assert.Single(model.Tables);
var index = Assert.Single(table.Indexes);
Assert.Equal(new[] { SortOrder.Descending, SortOrder.Ascending },
index[NpgsqlAnnotationNames.IndexSortOrder]);
});
AssertSql(
@"CREATE INDEX ""IX_People_FirstName_LastName"" ON ""People"" (""FirstName"" DESC, ""LastName"");");
}
[Fact]
public virtual async Task Create_index_with_null_sort_order()
{
......@@ -2183,9 +2221,15 @@ public virtual async Task Create_index_tsvector_using_gin()
@"CREATE INDEX ""IX_Blogs_Title_Description"" ON ""Blogs"" USING GIN (to_tsvector('simple', ""Title"" || ' ' || coalesce(""Description"", '')));");
}
[ConditionalFact(Skip = "https://github.com/npgsql/efcore.pg/issues/2267")]
public override Task Alter_index_change_sort_order()
=> Task.CompletedTask;
public override async Task Alter_index_change_sort_order()
{
await base.Alter_index_change_sort_order();
AssertSql(
@"DROP INDEX ""IX_People_X_Y_Z"";",
//
@"CREATE INDEX ""IX_People_X_Y_Z"" ON ""People"" (""X"", ""Y"" DESC, ""Z"");");
}
public override async Task Drop_index()
{
......
......@@ -1665,12 +1665,12 @@ public void Index_collation()
@"DROP TABLE ""IndexCollation""");
[Theory]
[InlineData("gin", null)]
[InlineData("gist", null)]
[InlineData("hash", null)]
[InlineData("brin", null)]
[InlineData("btree", new[] { SortOrder.Ascending, SortOrder.Descending })]
public void Index_sort_order(string method, SortOrder[] expected)
[InlineData("gin", new bool[0])]
[InlineData("gist", new bool[0])]
[InlineData("hash", new bool[0])]
[InlineData("brin", new bool[0])]
[InlineData("btree", new[] { false, true })]
public void Index_IsDescending(string method, bool[] expected)
=> Test(@"
CREATE TABLE ""IndexSortOrder"" (a text, b text, c tsvector);
CREATE INDEX ix_gin ON ""IndexSortOrder"" USING gin (c);
......@@ -1686,10 +1686,11 @@ public void Index_sort_order(string method, SortOrder[] expected)
var table = dbModel.Tables.Single();
var indexWith = table.Indexes.Single(i => i.Name == $"ix_{method}");
Assert.Equal(expected, indexWith.FindAnnotation(NpgsqlAnnotationNames.IndexSortOrder)?.Value);
// Assert.True(indexWith.IsDescending.SequenceEqual(expected));
Assert.Equal(expected, indexWith.IsDescending);
var indexWithout = table.Indexes.Single(i => i.Name == "ix_without");
Assert.Null(indexWithout.FindAnnotation(NpgsqlAnnotationNames.IndexSortOrder));
Assert.Equal(new[] { false, false }, indexWithout.IsDescending);
},
@"DROP TABLE ""IndexSortOrder""");
......@@ -1985,4 +1986,4 @@ public override async Task InitializeAsync()
protected override bool ShouldLogCategory(string logCategory)
=> logCategory == DbLoggerCategory.Scaffolding.Name;
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册