-
Notifications
You must be signed in to change notification settings - Fork 256
Expand file tree
/
Copy pathNpgsqlAnnotationProvider.cs
More file actions
142 lines (126 loc) · 7.66 KB
/
NpgsqlAnnotationProvider.cs
File metadata and controls
142 lines (126 loc) · 7.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using RelationalPropertyExtensions = Microsoft.EntityFrameworkCore.RelationalPropertyExtensions;
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal
{
public class NpgsqlAnnotationProvider : RelationalAnnotationProvider
{
public NpgsqlAnnotationProvider(RelationalAnnotationProviderDependencies dependencies)
: base(dependencies)
{
}
public override IEnumerable<IAnnotation> For(ITable table)
{
// Model validation ensures that these facets are the same on all mapped entity types
var entityType = table.EntityTypeMappings.First().EntityType;
if (entityType.GetIsUnlogged())
yield return new Annotation(NpgsqlAnnotationNames.UnloggedTable, entityType.GetIsUnlogged());
if (entityType[CockroachDbAnnotationNames.InterleaveInParent] != null)
yield return new Annotation(CockroachDbAnnotationNames.InterleaveInParent, entityType[CockroachDbAnnotationNames.InterleaveInParent]);
if (entityType[NpgsqlAnnotationNames.TablePartitioning] != null)
yield return new Annotation(NpgsqlAnnotationNames.TablePartitioning, entityType[NpgsqlAnnotationNames.TablePartitioning]);
foreach (var storageParamAnnotation in entityType.GetAnnotations()
.Where(a => a.Name.StartsWith(NpgsqlAnnotationNames.StorageParameterPrefix, StringComparison.Ordinal)))
{
yield return storageParamAnnotation;
}
}
public override IEnumerable<IAnnotation> For(IColumn column)
{
var table = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema);
var valueGeneratedProperty = column.PropertyMappings.Where(
m =>
m.TableMapping.IsSharedTablePrincipal && m.TableMapping.EntityType == m.Property.DeclaringEntityType)
.Select(m => m.Property)
.FirstOrDefault(
p => p.GetValueGenerationStrategy(table) switch
{
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn => true,
NpgsqlValueGenerationStrategy.IdentityAlwaysColumn => true,
NpgsqlValueGenerationStrategy.SerialColumn => true,
_ => false
});
if (valueGeneratedProperty != null)
{
var valueGenerationStrategy = valueGeneratedProperty.GetValueGenerationStrategy();
yield return new Annotation(NpgsqlAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy);
if (valueGenerationStrategy == NpgsqlValueGenerationStrategy.IdentityByDefaultColumn ||
valueGenerationStrategy == NpgsqlValueGenerationStrategy.IdentityAlwaysColumn)
{
if (valueGeneratedProperty[NpgsqlAnnotationNames.IdentityOptions] is string identityOptions)
{
yield return new Annotation(NpgsqlAnnotationNames.IdentityOptions, identityOptions);
}
}
}
// If the property has a collation explicitly defined on it via the standard EF mechanism, it will get
// passed on the Collation property (we don't need to do anything).
// Otherwise, a model-wide default column collation exists, pass that through our custom annotation.
if (column.PropertyMappings.All(m => RelationalPropertyExtensions.GetCollation(m.Property) == null) &&
column.PropertyMappings.Select(m => m.Property.GetDefaultCollation())
.FirstOrDefault(c => c != null) is string defaultColumnCollation)
{
yield return new Annotation(NpgsqlAnnotationNames.DefaultColumnCollation, defaultColumnCollation);
}
if (column.PropertyMappings.Select(m => m.Property.GetTsVectorConfig())
.FirstOrDefault(c => c != null) is string tsVectorConfig)
{
yield return new Annotation(NpgsqlAnnotationNames.TsVectorConfig, tsVectorConfig);
}
valueGeneratedProperty = column.PropertyMappings.Select(m => m.Property)
.FirstOrDefault(p => p.GetTsVectorProperties() != null);
if (valueGeneratedProperty != null)
{
var tableIdentifier = StoreObjectIdentifier.Table(column.Table.Name, column.Table.Schema);
yield return new Annotation(
NpgsqlAnnotationNames.TsVectorProperties,
valueGeneratedProperty.GetTsVectorProperties()!
.Select(p2 => valueGeneratedProperty.DeclaringEntityType.FindProperty(p2)!.GetColumnName(tableIdentifier))
.ToArray());
}
}
public override IEnumerable<IAnnotation> For(ITableIndex index)
{
// Model validation ensures that these facets are the same on all mapped indexes
var modelIndex = index.MappedIndexes.First();
if (modelIndex.GetCollation() is IReadOnlyList<string> collation)
yield return new Annotation(RelationalAnnotationNames.Collation, collation);
if (modelIndex.GetMethod() is string method)
yield return new Annotation(NpgsqlAnnotationNames.IndexMethod, method);
if (modelIndex.GetOperators() is IReadOnlyList<string> operators)
yield return new Annotation(NpgsqlAnnotationNames.IndexOperators, operators);
if (modelIndex.GetSortOrder() is IReadOnlyList<SortOrder> sortOrder)
yield return new Annotation(NpgsqlAnnotationNames.IndexSortOrder, sortOrder);
if (modelIndex.GetNullSortOrder() is IReadOnlyList<SortOrder> nullSortOrder)
yield return new Annotation(NpgsqlAnnotationNames.IndexNullSortOrder, nullSortOrder);
if (modelIndex.GetTsVectorConfig() is string configName)
yield return new Annotation(NpgsqlAnnotationNames.TsVectorConfig, configName);
if (modelIndex.GetIncludeProperties() is IReadOnlyList<string> includeProperties)
{
var tableIdentifier = StoreObjectIdentifier.Table(index.Table.Name, index.Table.Schema);
yield return new Annotation(
NpgsqlAnnotationNames.IndexInclude,
includeProperties
.Select(p => modelIndex.DeclaringEntityType.FindProperty(p)!.GetColumnName(tableIdentifier))
.ToArray());
}
var isCreatedConcurrently = modelIndex.IsCreatedConcurrently();
if (isCreatedConcurrently.HasValue)
{
yield return new Annotation(
NpgsqlAnnotationNames.CreatedConcurrently,
isCreatedConcurrently.Value);
}
}
public override IEnumerable<IAnnotation> For(IRelationalModel model)
=> model.Model.GetAnnotations().Where(a =>
a.Name.StartsWith(NpgsqlAnnotationNames.PostgresExtensionPrefix, StringComparison.Ordinal) ||
a.Name.StartsWith(NpgsqlAnnotationNames.EnumPrefix, StringComparison.Ordinal) ||
a.Name.StartsWith(NpgsqlAnnotationNames.RangePrefix, StringComparison.Ordinal) ||
a.Name.StartsWith(NpgsqlAnnotationNames.CollationDefinitionPrefix, StringComparison.Ordinal));
}
}