Skip to content

Commit

Permalink
Support new EF Core way for specifying descending indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Feb 11, 2022
1 parent a6017db commit 08d8cc5
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 228 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -369,99 +369,6 @@ public static bool CanSetCollation(

#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>
Expand All @@ -480,9 +387,7 @@ public static IndexBuilder HasNullSortOrder(
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);
}
Expand Down Expand Up @@ -521,9 +426,7 @@ public static IndexBuilder<TEntity> HasNullSortOrder<TEntity>(
{
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);
}
Expand Down Expand Up @@ -763,6 +666,111 @@ public static bool CanSetIsCreatedConcurrently(

#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>
Expand Down
100 changes: 52 additions & 48 deletions src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlIndexExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
}
4 changes: 3 additions & 1 deletion src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
}
11 changes: 6 additions & 5 deletions src/EFCore.PG/Metadata/Internal/NpgsqlAnnotationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 08d8cc5

Please sign in to comment.