@@ -49,7 +49,9 @@ The source generator will look for attributes and implement interfaces that exis
4949* 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.
5050* ` 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.
5151
52- ## Conversion
52+ ## Default conversion
53+
54+ If you do not override the conversion behaviour the following rules will be applied
5355
5456### Primitive Types
5557
@@ -105,7 +107,6 @@ Types not listed above will be treated as an object by being assigned to the `M`
105107
106108## Reference Tracker
107109
108-
109110As part of the source generation process, two additional types will be mirrored to the provided DTO:
110111
111112* A reference tracker that serves as attribute references on DynamoDB side.
@@ -131,12 +132,53 @@ public string MyRequiredString { get; set; }
131132public string MyUnknownString { get ; set ; }
132133```
133134
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.
135172
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. **
137174
138175``` 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
140182{
141183 // Will be included as 'PK' in DynamoDB.
142184 [DynamoDBHashKey (" PK" )]
@@ -156,69 +198,106 @@ public class Person
156198 public class Contact
157199 {
158200 // Will be included as 'Email' in DynamoDB.
159- public string Email { get ; set ;}
201+ public string Email { get ; set ; }
160202 }
161203}
162204```
163205
164206### Creating request objects
165207
166- #### UpdateRequest without providing the DTO
208+ #### [ Put request] ( ./samples/RequestAndResponseObjects/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 = " [email protected] " }
221+ })
222+ };
223+ }
224+ ```
225+
226+ #### [ Get Request & Response] ( ./samples/RequestAndResponseObjects/Program.cs )
167227
168228``` 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 { }
173229
174- internal static class Program
230+ static GetItemRequest CreateGetItemRequest ()
175231{
176- public static void Main ()
232+ return new GetItemRequest
177233 {
178- Repository repository = new Repository ();
234+ Key = Person .GetById .PrimaryKeyMarshaller .PartitionKey (" 123" ),
235+ TableName = " MyTable"
236+ };
237+ }
179238
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+ }
186246
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+ ```
191248
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+ };
202275}
203276```
204277
205- ### Key conversion
278+ ### [ Key conversion] ( ./samples/KeyConversion/Program.cs )
206279
207280The key marshallers contain three methods based on your intent.
208281The 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 ` .
209282
210283* ` 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.
212285* ` 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.
214287* ` RangeKey(object key) `
215288 * Used when you only want to only convert a range key without a partition key.
216289
217-
218290``` csharp
291+ // PrimaryKeyMarshaller is used to convert the keys obtained from the [DynamoDBHashKey] and [DynamoDBRangeKey] attributes.
292+ var keyMarshaller = EntityDTO .KeyMarshallerSample .PrimaryKeyMarshaller ;
219293
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
222301{
223302 [DynamoDBHashKey (" PK" )]
224303 public string Id { get ; set ; }
@@ -235,33 +314,32 @@ public class EntityDTO
235314 [DynamoDBGlobalSecondaryIndexRangeKey (" GSI" )]
236315 public string GlobalSecondaryIndexRangeKey { get ; set ; }
237316}
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- }
251317```
252318
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.
254322
255- #### Custom converters
323+ #### [ Custom converters] ( ./samples/Configuration/Program.cs )
256324
257325``` 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+
330+ // Implement a converter, there's also an IReferenceTypeConverter available for ReferenceTypes.
259331public class UnixEpochDateTimeConverter : IValueTypeConverter <DateTime >
260332{
333+ public UnixEpochDateTimeConverter ()
334+ {
335+ }
336+
261337 // Convert the AttributeValue into a .NET type.
262338 public DateTime ? Read (AttributeValue attributeValue )
263339 {
264- return long .TryParse (attributeValue .N , out var epoch ) ? DateTimeOffset .FromUnixTimeSeconds (epoch ).DateTime : null ;
340+ return long .TryParse (attributeValue .N , out var epoch )
341+ ? DateTimeOffset .FromUnixTimeSeconds (epoch ).DateTime
342+ : null ;
265343 }
266344
267345 // Convert the .NET type into an AttributeValue.
@@ -270,6 +348,7 @@ public class UnixEpochDateTimeConverter : IValueTypeConverter<DateTime>
270348 return new AttributeValue { N = new DateTimeOffset (element ).ToUnixTimeSeconds ().ToString () };
271349 }
272350}
351+
273352// Create a new Converters class
274353// You don't have to inherit from AttributeValueConverters if you do not want to use the default converters provided.
275354public class MyCustomConverters : AttributeValueConverters
@@ -282,23 +361,15 @@ public class MyCustomConverters : AttributeValueConverters
282361 DateTimeConverter = new UnixEpochDateTimeConverter ();
283362 }
284363 // 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-
293364 }
294365```
295366
296- #### Enum conversion
367+ #### [ Enum conversion] ( ./samples/Configuration/EnumBehaviour.cs )
297368
298369``` csharp
299- [DynamoDBMarshallerOptions (EnumConversion = EnumConversion .Name )]
300- [DynamoDBMarshaller ( EntityType = typeof ( Person ), AccessName = " PersonMarshaller " ) ]
301- public partial class Repository { }
370+ [DynamoDbMarshallerOptions (EnumConversion = EnumConversion .Name )]
371+ [DynamoDBMarshaller ]
372+ public partial record EnumBehaviour ([ property : DynamoDBHashKey ] string Id , DayOfWeek Enum );
302373```
303374
304375## Project structure
0 commit comments