@@ -49,7 +49,9 @@ The source generator will look for attributes and implement interfaces that exis
49
49
* Custom Converters: Create converters for your own types or override the [ default converters] ( https://github.com/inputfalken/DynamoDB.SourceGenerator/blob/main/src/DynamoDBGenerator/Options/AttributeValueConverters.cs ) built in to the library.
50
50
* ` ValueTuple<T> ` support: You don't have to declare your own types and could instead use [ tuples] ( https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples ) with custom named fields that will act as if the tuple was a type with with those data members.
51
51
52
- ## Conversion
52
+ ## Default conversion
53
+
54
+ If you do not override the conversion behaviour the following rules will be applied
53
55
54
56
### Primitive Types
55
57
@@ -105,7 +107,6 @@ Types not listed above will be treated as an object by being assigned to the `M`
105
107
106
108
## Reference Tracker
107
109
108
-
109
110
As part of the source generation process, two additional types will be mirrored to the provided DTO:
110
111
111
112
* A reference tracker that serves as attribute references on DynamoDB side.
@@ -131,12 +132,53 @@ public string MyRequiredString { get; set; }
131
132
public string MyUnknownString { get ; set ; }
132
133
```
133
134
134
- ## Code examples
135
+ ## Examples
136
+
137
+ ### [ Type support] ( ./samples/TypeSupport )
138
+ The functionality can be applied to more than classes:
139
+
140
+ ``` csharp
141
+ [DynamoDBMarshaller ]
142
+ public partial record Record ([property : DynamoDBHashKey ] string Id );
143
+
144
+ [DynamoDBMarshaller ]
145
+ public partial class Class
146
+ {
147
+ [DynamoDBHashKey ]
148
+ public string Id { get ; init ; }
149
+ }
150
+
151
+ [DynamoDBMarshaller ]
152
+ public partial struct Struct
153
+ {
154
+ [DynamoDBHashKey ]
155
+ public string Id { get ; init ; }
156
+ }
157
+
158
+ [DynamoDBMarshaller ]
159
+ public readonly partial struct ReadOnlyStruct
160
+ {
161
+ [DynamoDBHashKey ]
162
+ public string Id { get ; init ; }
163
+ }
164
+
165
+ [DynamoDBMarshaller ]
166
+ public readonly partial record struct ReadOnlyRecordStruct ([property : DynamoDBHashKey ] string Id );
167
+ ```
168
+
169
+ ### [ DTO sample] ( ./samples/RequestAndResponseObjects/Person.cs )
170
+
171
+ An example DTO class could look like the one below.
135
172
136
- An example DTO class could look like the one below. The following examples will use this sample class.
173
+ ** The following request examples will reuse this DTO. **
137
174
138
175
``` csharp
139
- public class Person
176
+ // A typical scenario would be that you would use multiple DynamoDBMarshaller and describe your operations via AccessName.
177
+ // If you do not specify an ArgumentType it will use your main entity Type instead which is typically useful for PUT operations.
178
+ [DynamoDBMarshaller ]
179
+ [DynamoDBMarshaller (ArgumentType = typeof ((string PersonId , string Firstname )), AccessName = " UpdateFirstName" )]
180
+ [DynamoDBMarshaller (ArgumentType = typeof (string ), AccessName = " GetById" )]
181
+ public partial class Person
140
182
{
141
183
// Will be included as 'PK' in DynamoDB.
142
184
[DynamoDBHashKey (" PK" )]
@@ -156,69 +198,106 @@ public class Person
156
198
public class Contact
157
199
{
158
200
// Will be included as 'Email' in DynamoDB.
159
- public string Email { get ; set ;}
201
+ public string Email { get ; set ; }
160
202
}
161
203
}
162
204
```
163
205
164
206
### Creating request objects
165
207
166
- #### UpdateRequest without providing the DTO
208
+ #### [ Put request] ( ./samples/Dto/Program.cs )
209
+
210
+ ``` csharp
211
+ static PutItemRequest PutPerson ()
212
+ {
213
+ return new PutItemRequest
214
+ {
215
+ TableName = " MyTable" ,
216
+ Item = Person .PersonMarshaller .Marshall (new Person
217
+ {
218
+ Firstname = " John" ,
219
+ Id = Guid .NewGuid ().ToString (),
220
+ ContactInfo = new Person .Contact { Email = " john@test.com" }
221
+ })
222
+ };
223
+ }
224
+ ```
225
+
226
+ #### [ Get Request & Response] ( ./samples/RequestAndResponseObjects/Program.cs )
167
227
168
228
``` csharp
169
- // A typical scenario would be that you would use multuple DynamoDBMarshaller and describe your operaitons via AccessName.
170
- // If you do not specify an ArgumentType it will use your main entity Type instead which is typically useful for PUT operations.
171
- [DynamoDBMarshaller (EntityType = typeof (Person ), ArgumentType = typeof ((string PersonId , string Firstname )), AccessName = " UpdateFirstName" )]
172
- public partial class Repository { }
173
229
174
- internal static class Program
230
+ static GetItemRequest CreateGetItemRequest ()
175
231
{
176
- public static void Main ()
232
+ return new GetItemRequest
177
233
{
178
- Repository repository = new Repository ();
234
+ Key = Person .GetById .PrimaryKeyMarshaller .PartitionKey (" 123" ),
235
+ TableName = " MyTable"
236
+ };
237
+ }
179
238
180
- // Creating an AttributeExpression can be done through string interpolation where the source generator will mimic your DTO types and give you an consistent API to build the attributeExpressions.
181
- var attributeExpression = repository .UpdateFirstName .ToAttributeExpression (
182
- (" personId" , " John" ),
183
- (dbRef , argRef ) => $" {dbRef .Id } = {argRef .PersonId }" , // The condition
184
- (dbRef , argRef ) => $" SET {dbRef .Firstname } = {argRef .FirstName }" // The update operation
185
- );
239
+ static Person DeserializeResponse (GetItemResponse response )
240
+ {
241
+ if (response .HttpStatusCode != HttpStatusCode .OK )
242
+ throw new NotImplementedException ();
243
+
244
+ return Person .GetById .Unmarshall (response .Item );
245
+ }
186
246
187
- // the index can be used to retrieve the expressions in the same order as you provide the string interpolations in the method call above.
188
- var condition = attributeExpression .Expressions [0 ];
189
- var update = attributeExpression .Expressions [1 ];
190
- var keys = repository .UpdateFirstName .PrimaryKeyMarshaller .PartitionKey (" personId" );
247
+ ```
191
248
192
- var request = new UpdateItemRequest
193
- {
194
- ConditionExpression = condition ,
195
- UpdateExpression = update ,
196
- ExpressionAttributeNames = attributeExpression .Names ,
197
- ExpressionAttributeValues = attributeExpression .Values ,
198
- Key = keys ,
199
- TableName = " MyTable"
200
- }
201
- }
249
+ #### [ Update request without providing the DTO] ( ./samples/RequestAndResponseObjects/Program.cs )
250
+
251
+ ``` csharp
252
+ static UpdateItemRequest UpdateFirstName ()
253
+ {
254
+ // Creating an AttributeExpression can be done through string interpolation where the source generator will mimic your DTO types and give you an consistent API to build the attributeExpressions.
255
+ var attributeExpression = Person .UpdateFirstName .ToAttributeExpression (
256
+ (" personId" , " John" ),
257
+ (dbRef , argRef ) => $" {dbRef .Id } = {argRef .PersonId }" , // The condition
258
+ (dbRef , argRef ) => $" SET {dbRef .Firstname } = {argRef .Firstname }" // The update operation
259
+ );
260
+
261
+ // the index can be used to retrieve the expressions in the same order as you provide the string interpolations in the method call above.
262
+ var condition = attributeExpression .Expressions [0 ];
263
+ var update = attributeExpression .Expressions [1 ];
264
+ var keys = Person .UpdateFirstName .PrimaryKeyMarshaller .PartitionKey (" personId" );
265
+
266
+ return new UpdateItemRequest
267
+ {
268
+ ConditionExpression = condition ,
269
+ UpdateExpression = update ,
270
+ ExpressionAttributeNames = attributeExpression .Names ,
271
+ ExpressionAttributeValues = attributeExpression .Values ,
272
+ Key = keys ,
273
+ TableName = " MyTable"
274
+ };
202
275
}
203
276
```
204
277
205
- ### Key conversion
278
+ ### [ Key conversion] ( ./samples/KeyConversion/Program.cs )
206
279
207
280
The key marshallers contain three methods based on your intent.
208
281
The source generator will internally validate your object arguments. So if you pass a ` int ` but the actual key is represented as a ` string ` , then you will get an ` exception ` .
209
282
210
283
* ` Keys(object partitionKey, object rangeKey) `
211
- * Used when you want convert both a partion key and a range key.
284
+ * Used when you want convert both a partition key and a range key.
212
285
* ` PartionKey(object key) `
213
- * Used when you only want to only convert a partiton key without a range key.
286
+ * Used when you only want to only convert a partition key without a range key.
214
287
* ` RangeKey(object key) `
215
288
* Used when you only want to only convert a range key without a partition key.
216
289
217
-
218
290
``` csharp
291
+ // PrimaryKeyMarshaller is used to convert the keys obtained from the [DynamoDBHashKey] and [DynamoDBRangeKey] attributes.
292
+ var keyMarshaller = EntityDTO .KeyMarshallerSample .PrimaryKeyMarshaller ;
219
293
220
- [DynamoDBMarshaller (AccessName = 'KeyMarshallerSample' )]
221
- public class EntityDTO
294
+ // IndexKeyMarshaller requires an argument that is the index name so it can provide you with the correct conversion based on the indexes you may have.
295
+ // It works the same way for both LocalSecondaryIndex and GlobalSecondaryIndex attributes.
296
+ var GSIKeyMarshaller = EntityDTO .KeyMarshallerSample .IndexKeyMarshaller (" GSI" );
297
+ var LSIKeyMarshaller = EntityDTO .KeyMarshallerSample .IndexKeyMarshaller (" LSI" );
298
+
299
+ [DynamoDBMarshaller (AccessName = " KeyMarshallerSample" )]
300
+ public partial class EntityDTO
222
301
{
223
302
[DynamoDBHashKey (" PK" )]
224
303
public string Id { get ; set ; }
@@ -235,33 +314,31 @@ public class EntityDTO
235
314
[DynamoDBGlobalSecondaryIndexRangeKey (" GSI" )]
236
315
public string GlobalSecondaryIndexRangeKey { get ; set ; }
237
316
}
238
- internal static class Program
239
- {
240
- public static void Main ()
241
- {
242
- // PrimaryKeyMarshaller is used to convert the keys obtained from the [DynamoDBHashKey] and [DynamoDBRangeKey] attributes.
243
- var keyMarshaller = EntityDTO .KeyMarshallerSample .PrimaryKeyMarshaller ;
244
-
245
- // IndexKeyMarshaller requires an argument that is the index name so it can provide you with the correct conversion based on the indexes you may have.
246
- // It works the same way for both LocalSecondaryIndex and GlobalSecondaryIndex attributes.
247
- var GSIKeyMarshaller = EntityDTO .KeyMarshallerSample .IndexKeyMarshaller (" GSI" );
248
- var LSIKeyMarshaller = EntityDTO .KeyMarshallerSample .IndexKeyMarshaller (" LSI" );
249
- }
250
- }
251
317
```
252
318
253
- ### Configuring the marshaller
319
+ ### Configuring marshalling behaviour
320
+
321
+ By applying the DynamoDbMarshallerOptions you're able to configure all DynamoDBMarshallers that's declared on the same type.
254
322
255
- #### Custom converters
323
+ #### [ Custom converters] ( ./samples/Configuration/Program.cs )
256
324
257
325
``` csharp
258
- // Implement an converter, there's also an IReferenceTypeConverter available for ReferenceTypes.
326
+ [DynamoDbMarshallerOptions (Converters = typeof (MyCustomConverters ))]
327
+ [DynamoDBMarshaller ]
328
+ public partial record OverriddenConverter ([property : DynamoDBHashKey ] string Id , DateTime Timestamp );
329
+
259
330
public class UnixEpochDateTimeConverter : IValueTypeConverter <DateTime >
260
331
{
332
+ public UnixEpochDateTimeConverter ()
333
+ {
334
+ }
335
+
261
336
// Convert the AttributeValue into a .NET type.
262
337
public DateTime ? Read (AttributeValue attributeValue )
263
338
{
264
- return long .TryParse (attributeValue .N , out var epoch ) ? DateTimeOffset .FromUnixTimeSeconds (epoch ).DateTime : null ;
339
+ return long .TryParse (attributeValue .N , out var epoch )
340
+ ? DateTimeOffset .FromUnixTimeSeconds (epoch ).DateTime
341
+ : null ;
265
342
}
266
343
267
344
// Convert the .NET type into an AttributeValue.
@@ -270,6 +347,7 @@ public class UnixEpochDateTimeConverter : IValueTypeConverter<DateTime>
270
347
return new AttributeValue { N = new DateTimeOffset (element ).ToUnixTimeSeconds ().ToString () };
271
348
}
272
349
}
350
+
273
351
// Create a new Converters class
274
352
// You don't have to inherit from AttributeValueConverters if you do not want to use the default converters provided.
275
353
public class MyCustomConverters : AttributeValueConverters
@@ -282,23 +360,15 @@ public class MyCustomConverters : AttributeValueConverters
282
360
DateTimeConverter = new UnixEpochDateTimeConverter ();
283
361
}
284
362
// You could add more converter DataMembers as fields or properties to add your own custom conversions.
285
-
286
- }
287
-
288
- [DynamoDBMarshallerOptions (Converter = typeof (MyCustomConverters ))]
289
- [DynamoDBMarshaller (EntityType = typeof (Person ), AccessName = " PersonMarshaller" )]
290
- public partial Repository
291
- {
292
-
293
363
}
294
364
```
295
365
296
- #### Enum conversion
366
+ #### [ Enum conversion] ( ./samples/Configuration/EnumBehaviour.cs )
297
367
298
368
``` csharp
299
- [DynamoDBMarshallerOptions (EnumConversion = EnumConversion .Name )]
300
- [DynamoDBMarshaller ( EntityType = typeof ( Person ), AccessName = " PersonMarshaller " ) ]
301
- public partial class Repository { }
369
+ [DynamoDbMarshallerOptions (EnumConversion = EnumConversion .Name )]
370
+ [DynamoDBMarshaller ]
371
+ public partial record EnumBehaviour ([ property : DynamoDBHashKey ] string Id , DayOfWeek Enum );
302
372
```
303
373
304
374
## Project structure
0 commit comments