|
10 | 10 | using System; |
11 | 11 | using System.Collections; |
12 | 12 | using System.Collections.Generic; |
| 13 | +using System.Globalization; |
13 | 14 | using System.IO; |
14 | 15 | using System.Linq; |
15 | 16 | using System.Net; |
@@ -57,16 +58,15 @@ public static class DynamoDBExtensions |
57 | 58 | private static readonly Dictionary<string, DynamoDBFieldType> DynamoDBFieldTypeMap = |
58 | 59 | FieldTypeDynamoDBMap.ToDictionary(kvp => kvp.Value, kvp => kvp.Key); |
59 | 60 |
|
60 | | - private static AttributeValue GetDynamoDBAttributeValue(KeyValuePair<string, DynamoDBFieldModel> field) |
| 61 | + private static AttributeValue GetDynamoDBAttributeValue(string name, DynamoDBFieldModel field) |
61 | 62 | { |
62 | | - if(field.Value?.Value == null || field.Value.Type == DynamoDBFieldType.Null) |
| 63 | + if(field.Value == null || field.Type == DynamoDBFieldType.Null) |
63 | 64 | return new AttributeValue() { NULL = true }; |
64 | 65 |
|
65 | | - var name = field.Key; |
66 | | - var value = field.Value.Value; |
| 66 | + var value = field.Value; |
67 | 67 | var attributeValue = new AttributeValue(); |
68 | 68 |
|
69 | | - switch(field.Value.Type) |
| 69 | + switch(field.Type) |
70 | 70 | { |
71 | 71 | case DynamoDBFieldType.String: |
72 | 72 | if(value is not string str) |
@@ -157,15 +157,131 @@ private static AttributeValue GetDynamoDBAttributeValue(KeyValuePair<string, Dyn |
157 | 157 | attributeValue.BOOL = boolVal; |
158 | 158 | break; |
159 | 159 |
|
160 | | - case DynamoDBFieldType.List: // TODO: Add support in the future? |
161 | | - case DynamoDBFieldType.Map: // TODO: Add support in the future? |
| 160 | + case DynamoDBFieldType.List: |
| 161 | + if(value is not IEnumerable<DynamoDBFieldModel> list) |
| 162 | + throw new AmazonDynamoDBException($"Field '{name}' was expected to be a list of values", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
| 163 | + |
| 164 | + attributeValue.L = new List<AttributeValue>(); |
| 165 | + |
| 166 | + int listIndex = -1; |
| 167 | + foreach(var item in list) |
| 168 | + { |
| 169 | + listIndex++; |
| 170 | + |
| 171 | + if(item == null) |
| 172 | + continue; |
| 173 | + |
| 174 | + var attributeItem = GetDynamoDBAttributeValue($"{name}[{listIndex}]", item); |
| 175 | + attributeValue.L.Add(attributeItem); |
| 176 | + } |
| 177 | + break; |
| 178 | + |
| 179 | + case DynamoDBFieldType.Map: |
| 180 | + if(value is not IDictionary<string, DynamoDBFieldModel> map) |
| 181 | + throw new AmazonDynamoDBException($"Field '{name}' was expected to be a map of values", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
| 182 | + |
| 183 | + attributeValue.M = new Dictionary<string, AttributeValue>(); |
| 184 | + |
| 185 | + foreach(var kvp in map) |
| 186 | + { |
| 187 | + if(string.IsNullOrWhiteSpace(kvp.Key) || kvp.Value == null) |
| 188 | + continue; |
| 189 | + |
| 190 | + var attributeItem = GetDynamoDBAttributeValue($"{name}[{kvp.Key}]", kvp.Value); |
| 191 | + attributeValue.M.Add(kvp.Key, attributeItem); |
| 192 | + } |
| 193 | + break; |
| 194 | + |
162 | 195 | default: |
163 | | - throw new AmazonDynamoDBException($"Unexpected field type '{field.Value.Type}'", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
| 196 | + throw new AmazonDynamoDBException($"Unknown type '{field.Type}' of field '{name}'", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
164 | 197 | } |
165 | 198 |
|
166 | 199 | return attributeValue; |
167 | 200 | } |
168 | 201 |
|
| 202 | + private static DynamoDBFieldModel GetDynamoDBFieldModel(string name, AttributeValue attribute) |
| 203 | + { |
| 204 | + if(attribute == null || attribute.NULL) |
| 205 | + return new DynamoDBFieldModel() { Type = DynamoDBFieldType.Null }; |
| 206 | + |
| 207 | + switch(GetDynamoDBFieldType(attribute)) |
| 208 | + { |
| 209 | + case DynamoDBFieldType.Null: |
| 210 | + return DynamoDBFieldModel.Null(); |
| 211 | + |
| 212 | + case DynamoDBFieldType.Bool: |
| 213 | + return DynamoDBFieldModel.Bool(attribute.BOOL); |
| 214 | + |
| 215 | + case DynamoDBFieldType.Binary: |
| 216 | + return DynamoDBFieldModel.Binary(attribute.B.ToArray()); |
| 217 | + |
| 218 | + case DynamoDBFieldType.BinarySet: |
| 219 | + return DynamoDBFieldModel.BinarySet( |
| 220 | + attribute.BS |
| 221 | + .Where(stream => stream != null) |
| 222 | + .Select(stream => stream.ToArray()) |
| 223 | + ); |
| 224 | + |
| 225 | + case DynamoDBFieldType.List: |
| 226 | + return DynamoDBFieldModel.List( |
| 227 | + attribute.L |
| 228 | + .Where(item => item != null) |
| 229 | + .Select((item, index) => GetDynamoDBFieldModel($"{name}[{index}]", item)) |
| 230 | + ); |
| 231 | + |
| 232 | + case DynamoDBFieldType.Map: |
| 233 | + return DynamoDBFieldModel.Map( |
| 234 | + attribute.M |
| 235 | + .Where(kvp => !string.IsNullOrWhiteSpace(kvp.Key) && kvp.Value != null) |
| 236 | + .ToDictionary(kvp => kvp.Key, kvp => GetDynamoDBFieldModel($"{name}[{kvp.Key}]", kvp.Value)) |
| 237 | + ); |
| 238 | + |
| 239 | + case DynamoDBFieldType.Number: |
| 240 | + return DynamoDBFieldModel.Number(decimal.Parse(attribute.N, CultureInfo.InvariantCulture)); |
| 241 | + |
| 242 | + case DynamoDBFieldType.NumberSet: |
| 243 | + return DynamoDBFieldModel.NumberSet( |
| 244 | + attribute.NS |
| 245 | + .Where(s => !string.IsNullOrWhiteSpace(s)) |
| 246 | + .Select(s => decimal.Parse(s, CultureInfo.InvariantCulture)) |
| 247 | + ); |
| 248 | + |
| 249 | + case DynamoDBFieldType.String: |
| 250 | + return DynamoDBFieldModel.String(attribute.S); |
| 251 | + |
| 252 | + case DynamoDBFieldType.StringSet: |
| 253 | + return DynamoDBFieldModel.StringSet(attribute.SS); |
| 254 | + } |
| 255 | + |
| 256 | + throw new AmazonDynamoDBException($"Unable to determine type of DynamoDB attribute '{name}'", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
| 257 | + } |
| 258 | + |
| 259 | + private static DynamoDBFieldType GetDynamoDBFieldType(AttributeValue attribute) |
| 260 | + { |
| 261 | + if(attribute.NULL) |
| 262 | + return DynamoDBFieldType.Null; |
| 263 | + if(attribute.IsBOOLSet) |
| 264 | + return DynamoDBFieldType.Bool; |
| 265 | + if(attribute.IsLSet) |
| 266 | + return DynamoDBFieldType.List; |
| 267 | + if(attribute.IsMSet) |
| 268 | + return DynamoDBFieldType.Map; |
| 269 | + if(attribute.B != null) |
| 270 | + return DynamoDBFieldType.Binary; |
| 271 | + if(attribute.BS != null && attribute.BS.Count > 0) |
| 272 | + return DynamoDBFieldType.BinarySet; |
| 273 | + if(!string.IsNullOrWhiteSpace(attribute.N)) |
| 274 | + return DynamoDBFieldType.Number; |
| 275 | + if(attribute.NS != null && attribute.NS.Count > 0) |
| 276 | + return DynamoDBFieldType.NumberSet; |
| 277 | + if(attribute.S != null) |
| 278 | + return DynamoDBFieldType.String; |
| 279 | + if(attribute.SS != null && attribute.SS.Count > 0) |
| 280 | + return DynamoDBFieldType.StringSet; |
| 281 | + |
| 282 | + return DynamoDBFieldType.Unknown; |
| 283 | + } |
| 284 | + |
169 | 285 | /// <summary> |
170 | 286 | /// Converts the <see cref="BillingMode"/> into a human-readable string. |
171 | 287 | /// </summary> |
@@ -240,12 +356,31 @@ public static DynamoDBItem ToDynamoDBItem(this IDictionary<string, DynamoDBField |
240 | 356 | throw new AmazonDynamoDBException($"DynamoDB field name cannot be empty", ErrorType.Sender, "GuiStack_InvalidField", null, HttpStatusCode.BadRequest); |
241 | 357 |
|
242 | 358 | var name = field.Key; |
243 | | - var attributeValue = GetDynamoDBAttributeValue(field); |
| 359 | + var attributeValue = GetDynamoDBAttributeValue(field.Key, field.Value); |
244 | 360 |
|
245 | 361 | result.Attributes.Add(name, attributeValue); |
246 | 362 | } |
247 | 363 |
|
248 | 364 | return result; |
249 | 365 | } |
| 366 | + |
| 367 | + /// <summary> |
| 368 | + /// Converts the item data into a DynamoDB item model. |
| 369 | + /// </summary> |
| 370 | + /// <param name="itemData">The item data to convert.</param> |
| 371 | + public static DynamoDBItemModel ToDynamoDBItemModel(this IDictionary<string, AttributeValue> itemData) |
| 372 | + { |
| 373 | + var result = new DynamoDBItemModel(); |
| 374 | + |
| 375 | + foreach(var field in itemData) |
| 376 | + { |
| 377 | + if(string.IsNullOrWhiteSpace(field.Key) || field.Value == null) |
| 378 | + continue; |
| 379 | + |
| 380 | + result.Add(field.Key, GetDynamoDBFieldModel(field.Key, field.Value)); |
| 381 | + } |
| 382 | + |
| 383 | + return result; |
| 384 | + } |
250 | 385 | } |
251 | 386 | } |
0 commit comments