Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 262
Add support for INCLUDE clause in indexes#699
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,11 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq.Expressions; | ||
| using JetBrains.Annotations; | ||
| using Microsoft.EntityFrameworkCore.Infrastructure; | ||
| using Microsoft.EntityFrameworkCore.Internal; | ||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
| using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
| using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; | ||
| // ReSharper disable once CheckNamespace | ||
| @@ -136,5 +140,40 @@ public static EntityTypeBuilder<TEntity> ForCockroachDbInterleaveInParent<TEntit | ||
| => (EntityTypeBuilder<TEntity>)ForCockroachDbInterleaveInParent((EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); | ||
| #endregion CockroachDB Interleave-in-parent | ||
| #region Generic Index | ||
| /// <summary> | ||
| /// Configures an index on the specified properties. If there is an existing index on the given | ||
| /// set of properties, then the existing index will be returned for configuration. | ||
| /// </summary> | ||
| /// <typeparam name="TEntity"> The entity type being configured. </typeparam> | ||
| /// <param name="entityTypeBuilder"> The builder for the entity type being configured. </param> | ||
austindrenski marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// <param name="indexExpression"> | ||
| /// <para> | ||
| /// A lambda expression representing the property(s) to be included in the index | ||
| /// (<c>blog => blog.Url</c>). | ||
| /// </para> | ||
| /// <para> | ||
| /// If the index is made up of multiple properties then specify an anonymous type including the | ||
| /// properties (<c>post => new { post.Title, post.BlogId }</c>). | ||
| /// </para> | ||
| /// </param> | ||
| /// <returns> An object that can be used to configure the index. </returns> | ||
austindrenski marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| public static IndexBuilder<TEntity> ForNpgsqlHasIndex<TEntity>( | ||
| [NotNull] this EntityTypeBuilder<TEntity> entityTypeBuilder, | ||
| [NotNull] Expression<Func<TEntity, object>> indexExpression) | ||
| where TEntity : class | ||
| { | ||
| Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); | ||
| Check.NotNull(indexExpression, nameof(indexExpression)); | ||
| var builder = ((IInfrastructure<InternalEntityTypeBuilder>)entityTypeBuilder).GetInfrastructure(); | ||
| return new IndexBuilder<TEntity>( | ||
| builder.HasIndex(indexExpression.GetPropertyAccessList(), ConfigurationSource.Explicit)); | ||
| } | ||
| #endregion | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,9 @@ | ||
| using JetBrains.Annotations; | ||
| using System; | ||
| using System.Linq; | ||
| using System.Linq.Expressions; | ||
| using System.Runtime.CompilerServices; | ||
| using JetBrains.Annotations; | ||
| using Microsoft.EntityFrameworkCore.Internal; | ||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
| using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; | ||
| @@ -19,7 +24,9 @@ public static class NpgsqlIndexBuilderExtensions | ||
| /// <param name="indexBuilder"> The builder for the index being configured. </param> | ||
| /// <param name="method"> The name of the index. </param> | ||
| /// <returns> A builder to further configure the index. </returns> | ||
| public static IndexBuilder ForNpgsqlHasMethod([NotNull] this IndexBuilder indexBuilder, [CanBeNull] string method) | ||
| public static IndexBuilder ForNpgsqlHasMethod( | ||
| [NotNull] this IndexBuilder indexBuilder, | ||
| [CanBeNull] string method) | ||
| { | ||
| Check.NotNull(indexBuilder, nameof(indexBuilder)); | ||
| Check.NullButNotEmpty(method, nameof(method)); | ||
| @@ -38,7 +45,9 @@ public static IndexBuilder ForNpgsqlHasMethod([NotNull] this IndexBuilder indexB | ||
| /// <param name="indexBuilder"> The builder for the index being configured. </param> | ||
| /// <param name="operators"> The operators to use for each column. </param> | ||
| /// <returns> A builder to further configure the index. </returns> | ||
| public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder indexBuilder, [CanBeNull] params string[] operators) | ||
| public static IndexBuilder ForNpgsqlHasOperators( | ||
| [NotNull] this IndexBuilder indexBuilder, | ||
| [CanBeNull, ItemNotNull] params string[] operators) | ||
| { | ||
| Check.NotNull(indexBuilder, nameof(indexBuilder)); | ||
| Check.NullButNotEmpty(operators, nameof(operators)); | ||
| @@ -47,5 +56,58 @@ public static IndexBuilder ForNpgsqlHasOperators([NotNull] this IndexBuilder ind | ||
| return indexBuilder; | ||
| } | ||
| /// <summary> | ||
| /// Adds an INCLUDE clause to the index definition with the specified property names. | ||
| /// This clause specifies a list of columns which will be included as a non-key part in the index. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// https://www.postgresql.org/docs/current/sql-createindex.html | ||
| /// </remarks> | ||
| /// <param name="indexBuilder"> The builder for the index being configured. </param> | ||
| /// <param name="propertyNames"> An array of property names to be used in INCLUDE clause. </param> | ||
| /// <returns> A builder to further configure the index. </returns> | ||
austindrenski marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| public static IndexBuilder ForNpgsqlInclude( | ||
| [NotNull] this IndexBuilder indexBuilder, | ||
| [CanBeNull, ItemNotNull] params string[] propertyNames) | ||
| { | ||
| Check.NotNull(indexBuilder, nameof(indexBuilder)); | ||
| Check.NullButNotEmpty(propertyNames, nameof(propertyNames)); | ||
| indexBuilder.Metadata.Npgsql().IncludeProperties = propertyNames; | ||
| return indexBuilder; | ||
| } | ||
| /// <summary> | ||
| /// Adds an INCLUDE clause to the index definition with property names from the specified expression. | ||
| /// This clause specifies a list of columns which will be included as a non-key part in the index. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// https://www.postgresql.org/docs/current/sql-createindex.html | ||
| /// </remarks> | ||
| /// <param name="indexBuilder"> The builder for the index being configured. </param> | ||
| /// <param name="includeExpression"> | ||
| /// <para> | ||
| /// A lambda expression representing the property(s) to be included in the INCLUDE clause | ||
| /// (<c>blog => blog.Url</c>). | ||
| /// </para> | ||
| /// <para> | ||
| /// If multiple properties are to be included then specify an anonymous type including the | ||
| /// properties (<c>post => new { post.Title, post.BlogId }</c>). | ||
| /// </para> | ||
| /// </param> | ||
| /// <returns> A builder to further configure the index. </returns> | ||
| public static IndexBuilder<TEntity> ForNpgsqlInclude<TEntity>( | ||
| [NotNull] this IndexBuilder<TEntity> indexBuilder, | ||
| [NotNull] Expression<Func<TEntity, object>> includeExpression) | ||
| { | ||
| Check.NotNull(indexBuilder, nameof(indexBuilder)); | ||
| Check.NotNull(includeExpression, nameof(includeExpression)); | ||
| indexBuilder.ForNpgsqlInclude(includeExpression.GetPropertyAccessList().Select(x => x.Name).ToArray()); | ||
| return indexBuilder; | ||
khellang marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -14,11 +14,19 @@ public interface INpgsqlIndexAnnotations : IRelationalIndexAnnotations | ||
| string Method { get; } | ||
| /// <summary> | ||
| /// The PostgreSQL index operators to be used. | ||
| /// The PostgreSQL index operators to be used, or <c>null</c> if they have not been specified. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// https://www.postgresql.org/docs/current/static/indexes-opclass.html | ||
| /// </remarks> | ||
| IReadOnlyList<string> Operators { get; } | ||
| /// <summary> | ||
| /// The PostgreSQL included property names, or <c>null</c> if they have not been specified. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// https://www.postgresql.org/docs/current/sql-createindex.html | ||
| /// </remarks> | ||
| IReadOnlyList<string> IncludeProperties { get; } | ||
khellang marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -112,8 +112,7 @@ protected override void Generate( | ||
| } | ||
| // Comment on the table | ||
| var comment = operation[NpgsqlAnnotationNames.Comment] as string; | ||
| if (comment != null) | ||
| if (operation[NpgsqlAnnotationNames.Comment] is string comment && comment.Length > 0) | ||
| { | ||
| builder.AppendLine(';'); | ||
| @@ -245,8 +244,7 @@ protected override void Generate( | ||
| base.Generate(operation, model, builder, terminate: false); | ||
| var comment = operation[NpgsqlAnnotationNames.Comment] as string; | ||
| if (comment != null) | ||
| if (operation[NpgsqlAnnotationNames.Comment] is string comment && comment.Length > 0) | ||
| { | ||
| builder.AppendLine(';'); | ||
| @@ -535,9 +533,6 @@ protected override void Generate( | ||
| Check.NotNull(operation, nameof(operation)); | ||
| Check.NotNull(builder, nameof(builder)); | ||
| var method = (string)operation[NpgsqlAnnotationNames.IndexMethod]; | ||
| var operators = (string[])operation[NpgsqlAnnotationNames.IndexOperators]; | ||
| builder.Append("CREATE "); | ||
| if (operation.IsUnique) | ||
| @@ -551,30 +546,40 @@ protected override void Generate( | ||
| .Append(" ON ") | ||
| .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema)); | ||
| if (method != null) | ||
| if (operation[NpgsqlAnnotationNames.IndexMethod] is string method && method.Length > 0) | ||
| { | ||
| builder | ||
| .Append(" USING ") | ||
| .Append(method); | ||
| } | ||
| var operators = operation[NpgsqlAnnotationNames.IndexOperators] as string[]; | ||
| builder | ||
| .Append(" (") | ||
| .Append(IndexColumnList(operation.Columns, operators)) | ||
| .Append(")"); | ||
| if (!string.IsNullOrEmpty(operation.Filter)) | ||
| ||
| { | ||
| builder | ||
| .Append(" WHERE ") | ||
| .Append(operation.Filter); | ||
| } | ||
| IndexOptions(operation, model, builder); | ||
| builder.AppendLine(';'); | ||
| EndStatement(builder); | ||
| } | ||
| protected override void IndexOptions(CreateIndexOperation operation, IModel model, MigrationCommandListBuilder builder) | ||
| { | ||
| if (operation[NpgsqlAnnotationNames.IndexInclude] is string[] includeProperties && includeProperties.Length > 0) | ||
| { | ||
| builder | ||
| .Append(" INCLUDE (") | ||
| .Append(ColumnList(includeProperties)) | ||
| .Append(")"); | ||
| } | ||
| base.IndexOptions(operation, model, builder); | ||
roji marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| } | ||
| protected override void Generate(EnsureSchemaOperation operation, [CanBeNull] IModel model, MigrationCommandListBuilder builder) | ||
| { | ||
| Check.NotNull(operation, nameof(operation)); | ||
Uh oh!
There was an error while loading. Please reload this page.