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