1
+ using DynamoDBGenerator . SourceGenerator . Extensions ;
2
+ using DynamoDBGenerator . SourceGenerator . Types ;
3
+ using Microsoft . CodeAnalysis ;
4
+ using static DynamoDBGenerator . SourceGenerator . Constants . DynamoDBGenerator ;
5
+
6
+ namespace DynamoDBGenerator . SourceGenerator . Generations . Marshalling ;
7
+
8
+ internal static partial class Marshaller
9
+ {
10
+ internal static class KeyMarshaller
11
+ {
12
+ private const string DictionaryName = "attributeValues" ;
13
+ private const string EnforcePkReference = "isPartitionKey" ;
14
+ private const string EnforceRkReference = "isRangeKey" ;
15
+
16
+ private static readonly Func < ITypeSymbol , string > MethodName =
17
+ TypeExtensions . SuffixedTypeSymbolNameFactory ( "Keys" , SymbolEqualityComparer . IncludeNullability ) ;
18
+
19
+ private const string PkReference = "partitionKey" ;
20
+ private const string RkReference = "rangeKey" ;
21
+
22
+ private static IEnumerable < string > CreateAssignment ( string validateReference , string keyReference ,
23
+ DynamoDbDataMember dataMember , MarshallerOptions options )
24
+ {
25
+ const string reference = "value" ;
26
+ var expectedType = dataMember . DataMember . Type . Representation ( ) . original ;
27
+ var expression = $ "{ keyReference } is { expectedType } {{ }} { reference } ";
28
+
29
+ var innerContent = $ "if ({ expression } ) "
30
+ . CreateScope (
31
+ $@ "{ DictionaryName } .Add(""{ dataMember . AttributeName } "", { InvokeMarshallerMethod ( dataMember . DataMember . Type , reference , $ "nameof({ keyReference } )", options ) } );")
32
+ . Concat ( $ "else if ({ keyReference } is null) ". CreateScope (
33
+ $@ "throw { ExceptionHelper . KeysArgumentNullExceptionMethod } (""{ dataMember . DataMember . Name } "", ""{ keyReference } "");") )
34
+ . Concat ( "else" . CreateScope (
35
+ $@ "throw { ExceptionHelper . KeysInvalidConversionExceptionMethod } (""{ dataMember . DataMember . Name } "", ""{ keyReference } "", { keyReference } , ""{ expectedType } "");") ) ;
36
+
37
+ return $ "if ({ validateReference } )". CreateScope ( innerContent ) ;
38
+ }
39
+
40
+ private static IEnumerable < string > MethodBody ( ITypeSymbol typeSymbol ,
41
+ Func < ITypeSymbol , DynamoDbDataMember [ ] > fn , MarshallerOptions options )
42
+ {
43
+ var keyStructure = DynamoDbDataMember . GetKeyStructure ( fn ( typeSymbol ) ) ;
44
+ if ( keyStructure is null )
45
+ {
46
+ yield return @$ "throw { ExceptionHelper . NoDynamoDBKeyAttributesExceptionMethod } (""{ typeSymbol } "");";
47
+
48
+ yield break ;
49
+ }
50
+
51
+ yield return $ "var { DictionaryName } = new Dictionary<string, AttributeValue>(2);";
52
+
53
+ var switchBody = GetAssignments ( keyStructure . Value , options )
54
+ . SelectMany ( x =>
55
+ $ "case { ( x . IndexName is null ? "null" : @$ """{ x . IndexName } """)}:". CreateScope ( x . assignments )
56
+ . Append ( "break;" ) )
57
+ . Append ( $ "default: throw { ExceptionHelper . MissMatchedIndexNameExceptionMethod } (nameof(index), index);") ;
58
+
59
+ foreach ( var s in "switch (index)" . CreateScope ( switchBody ) )
60
+ yield return s;
61
+
62
+ var validateSwitch = $"if ( { EnforcePkReference } && { EnforceRkReference } && { DictionaryName } . Count == 2 ) "
63
+ . CreateScope ( $ "return { DictionaryName } ;")
64
+ . Concat ( $ "if ({ EnforcePkReference } && { EnforceRkReference } is false && { DictionaryName } .Count == 1)"
65
+ . CreateScope ( $ "return { DictionaryName } ;") )
66
+ . Concat ( $ "if ({ EnforcePkReference } is false && { EnforceRkReference } && { DictionaryName } .Count == 1)"
67
+ . CreateScope ( $ "return { DictionaryName } ;") )
68
+ . Concat ( $ "if ({ EnforcePkReference } && { EnforceRkReference } && { DictionaryName } .Count == 1)". CreateScope (
69
+ $ "throw { ExceptionHelper . KeysMissingDynamoDBAttributeExceptionMethod } ({ PkReference } , { RkReference } );") )
70
+ . Append ( $ "throw { ExceptionHelper . ShouldNeverHappenExceptionMethod } ();") ;
71
+
72
+ foreach ( var s in validateSwitch )
73
+ yield return s;
74
+ }
75
+
76
+ internal static IEnumerable< string > CreateKeys ( IEnumerable < DynamoDBMarshallerArguments > arguments ,
77
+ Func < ITypeSymbol , DynamoDbDataMember [ ] > getDynamoDbProperties , MarshallerOptions options )
78
+ {
79
+ var hashSet = new HashSet< ITypeSymbol > ( SymbolEqualityComparer . IncludeNullability ) ;
80
+
81
+ return arguments
82
+ . SelectMany ( x => CodeFactory . Create ( x . EntityTypeSymbol ,
83
+ y => StaticAttributeValueDictionaryKeys ( y , getDynamoDbProperties , options ) , hashSet ) ) ;
84
+ }
85
+
86
+ private static IEnumerable< ( string ? IndexName , IEnumerable < string > assignments ) > GetAssignments (
87
+ DynamoDBKeyStructure keyStructure , MarshallerOptions options )
88
+ {
89
+ yield return keyStructure switch
90
+ {
91
+ { PartitionKey : var pk , SortKey : { } sortKey } => ( null ,
92
+ CreateAssignment ( EnforcePkReference , PkReference , pk , options )
93
+ . Concat ( CreateAssignment ( EnforceRkReference , RkReference , sortKey , options ) ) ) ,
94
+ { PartitionKey : var pk , SortKey : null } => ( null ,
95
+ CreateAssignment ( EnforcePkReference , PkReference , pk , options )
96
+ . Concat ( MissingAssigment ( EnforceRkReference , RkReference ) ) )
97
+ } ;
98
+
99
+ foreach ( var gsi in keyStructure . GlobalSecondaryIndices )
100
+ {
101
+ yield return gsi switch
102
+ {
103
+ { PartitionKey : var pk , SortKey : { } sortKey } => ( gsi . Name ,
104
+ CreateAssignment ( EnforcePkReference , PkReference , pk , options )
105
+ . Concat ( CreateAssignment ( EnforceRkReference , RkReference , sortKey , options ) ) ) ,
106
+ { PartitionKey : var pk , SortKey : null } => ( gsi . Name ,
107
+ CreateAssignment ( EnforcePkReference , PkReference , pk , options )
108
+ . Concat ( MissingAssigment ( EnforceRkReference , RkReference ) ) )
109
+ } ;
110
+ }
111
+
112
+ foreach ( var lsi in keyStructure . LocalSecondaryIndices )
113
+ {
114
+ yield return ( lsi , keyStructure . PartitionKey ) switch
115
+ {
116
+ { PartitionKey : var pk , lsi : var sortKey } => ( lsi . Name ,
117
+ CreateAssignment ( EnforcePkReference , PkReference , pk , options )
118
+ . Concat ( CreateAssignment ( EnforceRkReference , RkReference , sortKey . SortKey , options ) ) )
119
+ } ;
120
+ }
121
+ }
122
+
123
+ private static IEnumerable< string > MissingAssigment ( string validateReference , string keyReference )
124
+ {
125
+ var expression = $"{validateReference} && {keyReference} is not null" ;
126
+ return $"if ({expression})" . CreateScope (
127
+ $ "throw { ExceptionHelper . KeysValueWithNoCorrespondenceMethod } (\" { keyReference } \" , { keyReference } );") ;
128
+ }
129
+
130
+ internal static IEnumerable < string > IndexKeyMarshallerRootSignature ( ITypeSymbol typeSymbol )
131
+ {
132
+ return
133
+ $"public {Constants.DynamoDBGenerator.Marshaller.IndexKeyMarshallerInterface} IndexKeyMarshaller(string index)"
134
+ . CreateScope (
135
+ "ArgumentNullException.ThrowIfNull(index);" ,
136
+ $ "return new { IndexKeyMarshallerImplementationTypeName } ((pk, rk, ipk, irk, dm) => { ClassName } .{ MethodName ( typeSymbol ) } ({ MarshallerOptions . FieldReference } , pk, rk, ipk, irk, dm), index);"
137
+ ) ;
138
+ }
139
+
140
+ public const string PrimaryKeyMarshallerReference = "PrimaryKeyMarshaller";
141
+
142
+ public const string PrimaryKeyMarshallerDeclaration =
143
+ $"public {Constants.DynamoDBGenerator.Marshaller.KeyMarshallerInterface} {PrimaryKeyMarshallerReference} {{ get; }}" ;
144
+
145
+ internal static string AssignmentRoot ( ITypeSymbol typeSymbol )
146
+ {
147
+ return
148
+ $"new {KeyMarshallerImplementationTypeName}((pk, rk, ipk, irk, dm) => {ClassName}.{MethodName(typeSymbol)}({MarshallerOptions.FieldReference}, pk, rk, ipk, irk, dm))" ;
149
+ }
150
+
151
+ private static CodeFactory StaticAttributeValueDictionaryKeys ( ITypeSymbol typeSymbol ,
152
+ Func < ITypeSymbol , DynamoDbDataMember [ ] > fn , MarshallerOptions options )
153
+ {
154
+ var code =
155
+ $"public static Dictionary<string, AttributeValue> {MethodName(typeSymbol)}({MarshallerOptions.Name} {MarshallerOptions.ParamReference}, object? {PkReference}, object? {RkReference}, bool {EnforcePkReference}, bool {EnforceRkReference}, string? index = null)"
156
+ . CreateScope ( MethodBody ( typeSymbol , fn , options ) ) ;
157
+
158
+ return new CodeFactory ( code ) ;
159
+ }
160
+ }
161
+ }
0 commit comments