From 9c26c841e6d17c8eca017eaa36eddf59d3bb44d0 Mon Sep 17 00:00:00 2001 From: gh-actions Date: Sun, 14 Apr 2024 00:13:52 +0000 Subject: [PATCH] Deploy website - based on f023f46edb3c3f2d853585a9ea772489a94ccf2d --- 404.html | 4 ++-- assets/js/{3df1ab03.86b303cf.js => 3df1ab03.95fcbd98.js} | 2 +- .../{runtime~main.e35d0b3f.js => runtime~main.6aa1fbf5.js} | 2 +- blog.html | 4 ++-- blog/archive.html | 4 ++-- blog/tags.html | 4 ++-- blog/tags/aws.html | 4 ++-- blog/tags/c.html | 4 ++-- blog/tags/dotnet.html | 4 ++-- blog/tags/dynamodb.html | 4 ++-- blog/tags/release.html | 4 ++-- blog/welcome.html | 4 ++-- blog/whats-new-0.9.15.html | 4 ++-- docs.html | 4 ++-- docs/api-reference/builders.html | 4 ++-- docs/api-reference/builders/delete-item.html | 4 ++-- docs/api-reference/builders/get-item.html | 4 ++-- docs/api-reference/builders/put-item.html | 4 ++-- docs/api-reference/builders/query.html | 4 ++-- docs/api-reference/builders/scan.html | 4 ++-- docs/api-reference/builders/update-item.html | 4 ++-- docs/api-reference/options.html | 4 ++-- docs/api-reference/options/return-values.html | 4 ++-- docs/api-reference/options/select-mode.html | 4 ++-- docs/design.html | 4 ++-- docs/dev-guide/configuration/credentials.html | 4 ++-- docs/dev-guide/configuration/region-endpoint.html | 4 ++-- docs/dev-guide/configuration/retry-strategies.html | 4 ++-- docs/dev-guide/getting-started.html | 4 ++-- docs/dev-guide/high-level/attributes.html | 4 ++-- docs/dev-guide/high-level/batch.html | 4 ++-- docs/dev-guide/high-level/conditions.html | 4 ++-- docs/dev-guide/high-level/converters.html | 6 +++--- docs/dev-guide/high-level/read.html | 4 ++-- docs/dev-guide/high-level/transact.html | 4 ++-- docs/dev-guide/high-level/update-expression.html | 4 ++-- docs/dev-guide/high-level/write.html | 4 ++-- docs/dev-guide/low-level.html | 4 ++-- docs/dev-guide/sdk-compatibility.html | 4 ++-- index.html | 4 ++-- search.html | 4 ++-- 41 files changed, 81 insertions(+), 81 deletions(-) rename assets/js/{3df1ab03.86b303cf.js => 3df1ab03.95fcbd98.js} (70%) rename assets/js/{runtime~main.e35d0b3f.js => runtime~main.6aa1fbf5.js} (97%) diff --git a/404.html b/404.html index ef596547..5d215aa2 100644 --- a/404.html +++ b/404.html @@ -9,13 +9,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/3df1ab03.86b303cf.js b/assets/js/3df1ab03.95fcbd98.js similarity index 70% rename from assets/js/3df1ab03.86b303cf.js rename to assets/js/3df1ab03.95fcbd98.js index 354967ed..c3584fc4 100644 --- a/assets/js/3df1ab03.86b303cf.js +++ b/assets/js/3df1ab03.95fcbd98.js @@ -1 +1 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1002],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>v});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),d=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=d(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(n),m=a,v=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return n?r.createElement(v,o(o({ref:t},p),{},{components:n})):r.createElement(v,o({ref:t},p))}));function v(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=n(7462),a=(n(7294),n(3905));const i={id:"converters",title:"Converters",slug:"../../dev-guide/high-level/converters"},o=void 0,l={unversionedId:"dev_guide/high_level/converters",id:"dev_guide/high_level/converters",title:"Converters",description:"A converter is a class that converts a .NET type to and from DynamoDB JSON or low-level Document object. A custom converter allows working with unsupported types or overriding the default converter behavior.",source:"@site/docs/dev_guide/high_level/converters.md",sourceDirName:"dev_guide/high_level",slug:"/dev-guide/high-level/converters",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/converters",draft:!1,editUrl:"https://github.com/alloczero/EfficientDynamoDb/edit/main/website/docs/dev_guide/high_level/converters.md",tags:[],version:"current",frontMatter:{id:"converters",title:"Converters",slug:"../../dev-guide/high-level/converters"},sidebar:"someSidebar",previous:{title:"Transactions",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/transact"},next:{title:"Building Conditions",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/conditions"}},s={},d=[{value:"Built-in converters",id:"built-in-converters",level:2},{value:"Applying converters",id:"applying-converters",level:2},{value:"For a property",id:"for-a-property",level:3},{value:"For a type",id:"for-a-type",level:3},{value:"For a context",id:"for-a-context",level:3},{value:"Basic converter",id:"basic-converter",level:2},{value:"Direct JSON converter",id:"direct-json-converter",level:2},{value:"JSON reading",id:"json-reading",level:3},{value:"JSON writing",id:"json-writing",level:3},{value:"Sparse converters",id:"sparse-converters",level:2},{value:"Set converters",id:"set-converters",level:2},{value:"Dictionary key converters",id:"dictionary-key-converters",level:2}],p={toc:d},u="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A converter is a class that converts a .NET type to and from DynamoDB JSON or low-level ",(0,a.kt)("inlineCode",{parentName:"p"},"Document")," object. A custom converter allows working with unsupported types or overriding the default converter behavior."),(0,a.kt)("p",null,"Converters, along with with DynamoDB JSON parsing, are one of the most critical components from a performance perspective.\nAll ",(0,a.kt)("strong",{parentName:"p"},"EfficientDynamoDb")," built-in converters are optimized separately for both ",(0,a.kt)("inlineCode",{parentName:"p"},"Document")," and JSON conversion, in order to allocate no additional memory."),(0,a.kt)("h2",{id:"built-in-converters"},"Built-in converters"),(0,a.kt)("p",null,"EfficientDynamoDb does not require specifying a converter explicitly for the following built-in types:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Classes "),(0,a.kt)("li",{parentName:"ul"},"Strings"),(0,a.kt)("li",{parentName:"ul"},"Numbers: ",(0,a.kt)("inlineCode",{parentName:"li"},"byte"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"short"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"int"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"long"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"decimal"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"float"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"double"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"ushort"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"uint"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"ulong")),(0,a.kt)("li",{parentName:"ul"},"Enums (saved as numbers)"),(0,a.kt)("li",{parentName:"ul"},"DateTimes (saved in ISO8601 format)"),(0,a.kt)("li",{parentName:"ul"},"Guids"),(0,a.kt)("li",{parentName:"ul"},"Booleans"),(0,a.kt)("li",{parentName:"ul"},"Collections: arrays, lists, dictionaries, sets (including their read-only and mutable interfaces)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"AttributeValue")," structs (low-level API representation of the DynamoDB attribute)")),(0,a.kt)("p",null,"In addition, you can use one of the following converters to change the default behavior:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"StringEnumDdbConverter")," - saves enums as strings instead of numbers."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"DateTimeDdbConverter")," - allows to customize ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTime")," formatting parameters: ",(0,a.kt)("inlineCode",{parentName:"li"},"Format"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTimeStyles")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"CultureInfo"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"SdkDateTimeDdbConverter")," - makes ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTime")," behavior backward compatible with the official AWS SDK.")),(0,a.kt)("h2",{id:"applying-converters"},"Applying converters"),(0,a.kt)("h3",{id:"for-a-property"},"For a property"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'[DynamoDbProperty("address", typeof(CompositeAddressConverter))]\npublic Address Address { get; set; }\n')),(0,a.kt)("h3",{id:"for-a-type"},"For a type"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"[DynamoDbConverter(typeof(CompositeAddressConverter))]\npublic struct Address { ... }\n")),(0,a.kt)("h3",{id:"for-a-context"},"For a context"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"var config = new DynamoDbContextConfig(regionEndpoint, awsCredentials)\n{\n Converters = new[] {new CompositeAddressConverter()}\n};\n")),(0,a.kt)("p",null,"If a converter can't be instantiated in advance and depends on the target value type, a custom converter factory can be implemented by inheriting from the ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbConverterFactory")," class and registering it with the context the same way as other custom converters."),(0,a.kt)("p",null,"For example, a string enum converter factory can be defined like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public sealed class StringEnumDdbConverterFactory : DdbConverterFactory\n{\n public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum;\n\n public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata)\n {\n return (DdbConverter) Activator.CreateInstance(typeof(StringEnumDdbConverter<>).MakeGenericType(typeToConvert));\n }\n}\n")),(0,a.kt)("h2",{id:"basic-converter"},"Basic converter"),(0,a.kt)("p",null,"To create a custom converter:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Inherit from ",(0,a.kt)("inlineCode",{parentName:"li"},"DdbConverter")," class."),(0,a.kt)("li",{parentName:"ul"},"Implement both ",(0,a.kt)("inlineCode",{parentName:"li"},"Read")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"Write")," methods.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CompositeAddressConverter : DdbConverter
\n{\n // Converts DynamoDb attribute to the .NET type\n public override Address Read(in AttributeValue attributeValue)\n {\n var parts = attributeValue.AsString().Split('#');\n return new Address(parts[0], parts[1]);\n }\n\n // Converts .NET type to the DynamoDb attribute\n public override AttributeValue Write(ref Address address)\n {\n return new StringAttributeValue($\"{address.Country}#{address.Street}\");\n }\n}\n")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Check out the ",(0,a.kt)("a",{parentName:"em",href:"/EfficientDynamoDb/docs/dev-guide/low-level#working-with-documents"},"working with documents")," chapter to better understand how to work with attribute values.")),(0,a.kt)("h2",{id:"direct-json-converter"},"Direct JSON converter"),(0,a.kt)("p",null,"Not all .NET types map nicely to DynamoDb attributes. Creation of intermediate ",(0,a.kt)("inlineCode",{parentName:"p"},"AttributeValue")," struct can involve unnecessary allocations that can be avoided by reading/writing directly into JSON buffer.\nIn case when a custom type can't be converted to the ",(0,a.kt)("inlineCode",{parentName:"p"},"AttributeValue")," without allocations, it is possible to implement two additional low-level ",(0,a.kt)("inlineCode",{parentName:"p"},"Read")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"Write")," methods that work with JSON buffers.\nDuring deserialization/serialization of entities to JSON, more optimized low-level implementations will be called."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomIntConverter : DdbConverter\n{\n // Efficient zero-allocation JSON to int conversion\n public override int Read(ref DdbReader reader)\n {\n if (!Utf8Parser.TryParse(reader.JsonReader.ValueSpan, out int value, out _))\n throw new DdbException($\"Couldn't parse int ddb value from '{reader.JsonReaderValue.GetString()}'.\");\n\n return value;\n }\n \n // Efficient zero-allocation int to JSON conversion\n public override void Write(in DdbWriter writer, ref int value)\n {\n writer.JsonWriter.WriteStartObject();\n writer.JsonWriter.WriteString(DdbTypeNames.Number, value);\n writer.JsonWriter.WriteEndObject();\n }\n \n public override int Read(in AttributeValue attributeValue) => attributeValue.AsNumberAttribute().ToInt();\n \n public override AttributeValue Write(ref T value) => new NumberAttributeValue(value.ToString()); \n}\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"EfficientDynamoDb")," uses ",(0,a.kt)("inlineCode",{parentName:"p"},"System.Text.Json")," for all JSON manipulations."),(0,a.kt)("h3",{id:"json-reading"},"JSON reading"),(0,a.kt)("p",null,"When a low-level read is called, ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.JsonReader")," is already pointed to the JSON value. Current attribute type is automatically parsed and can be accessed using ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.AttributeType")," property."),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.JsonReader.Read")," method should not be explicitly called unless you are writing a converter for a non-primitive JSON type like an object or array."),(0,a.kt)("h3",{id:"json-writing"},"JSON writing"),(0,a.kt)("p",null,"When a low-level write is called, a converter has to write DynamoDb JSON, including the attribute type.\n",(0,a.kt)("inlineCode",{parentName:"p"},"DdbWriter")," class provides various simplified overloads that write attribute types automatically. But in case if suitable overload does not exist, the attribute type has to be written manually like in the ",(0,a.kt)("inlineCode",{parentName:"p"},"CustomIntConverter")," example above."),(0,a.kt)("h2",{id:"sparse-converters"},"Sparse converters"),(0,a.kt)("p",null,"Sparse converters don't save certain values and completely remove an attribute instead. It is a powerful concept that can be used for various purposes like size savings or to conditionally include an entity in the GSI."),(0,a.kt)("p",null,"By default, all built-in converters act as sparse converters when it comes to handling ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," values, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," properties are never saved and the entire attribute is deleted."),(0,a.kt)("p",null,"To add an additional sparse condition, ",(0,a.kt)("inlineCode",{parentName:"p"},"ShouldWrite")," method has to be overridden. For example. here is a simple sparse int converter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class SparseIntConverter : DdbConverter\n{\n public override bool ShouldWrite(ref int value) => value != 0;\n \n ...\n}\n")),(0,a.kt)("p",null,"Note: Sparse converters don't remove attributes when they are part of a ",(0,a.kt)("inlineCode",{parentName:"p"},"Dictionary")," class."),(0,a.kt)("h2",{id:"set-converters"},"Set converters"),(0,a.kt)("p",null,"Both string and number sets store values as strings in the DB.\nTo store a custom type inside a set, a converter should implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"ISetValueConverter")," interface:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomDdbConverter : DdbConverter, ISetValueConverter\n{\n public string WriteStringValue(ref CustomType value) => value.ToString();\n \n // Optionally implement direct write method\n public void WriteStringValue(in DdbWriter ddbWriter, ref CustomType value) => \n ddbWriter.JsonWriter.WriteStringValue(value.AsSpan());\n}\n")),(0,a.kt)("h2",{id:"dictionary-key-converters"},"Dictionary key converters"),(0,a.kt)("p",null,"To store a custom type as a dictionary key, a converter should implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"IDicitonaryKeyConverter")," interface:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomDdbConverter : DdbConverter, ISetValueConverter\n{\n public string WriteStringValue(ref CustomType value) => value.ToString();\n \n // Optionally implement direct write method\n public void WritePropertyName(in DdbWriter ddbWriter, ref CustomType value) => \n ddbWriter.JsonWriter.WritePropertyName(value.AsSpan());\n}\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[1002],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>v});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),d=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=d(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(n),m=a,v=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return n?r.createElement(v,o(o({ref:t},p),{},{components:n})):r.createElement(v,o({ref:t},p))}));function v(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=n(7462),a=(n(7294),n(3905));const i={id:"converters",title:"Converters",slug:"../../dev-guide/high-level/converters"},o=void 0,l={unversionedId:"dev_guide/high_level/converters",id:"dev_guide/high_level/converters",title:"Converters",description:"A converter is a class that converts a .NET type to and from DynamoDB JSON or low-level Document object. A custom converter allows working with unsupported types or overriding the default converter behavior.",source:"@site/docs/dev_guide/high_level/converters.md",sourceDirName:"dev_guide/high_level",slug:"/dev-guide/high-level/converters",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/converters",draft:!1,editUrl:"https://github.com/alloczero/EfficientDynamoDb/edit/main/website/docs/dev_guide/high_level/converters.md",tags:[],version:"current",frontMatter:{id:"converters",title:"Converters",slug:"../../dev-guide/high-level/converters"},sidebar:"someSidebar",previous:{title:"Transactions",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/transact"},next:{title:"Building Conditions",permalink:"/EfficientDynamoDb/docs/dev-guide/high-level/conditions"}},s={},d=[{value:"Built-in converters",id:"built-in-converters",level:2},{value:"Applying converters",id:"applying-converters",level:2},{value:"For a property",id:"for-a-property",level:3},{value:"For a type",id:"for-a-type",level:3},{value:"For a context",id:"for-a-context",level:3},{value:"Basic converter",id:"basic-converter",level:2},{value:"Direct JSON converter",id:"direct-json-converter",level:2},{value:"JSON reading",id:"json-reading",level:3},{value:"JSON writing",id:"json-writing",level:3},{value:"Sparse converters",id:"sparse-converters",level:2},{value:"Set converters",id:"set-converters",level:2},{value:"Dictionary key converters",id:"dictionary-key-converters",level:2}],p={toc:d},u="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A converter is a class that converts a .NET type to and from DynamoDB JSON or low-level ",(0,a.kt)("inlineCode",{parentName:"p"},"Document")," object. A custom converter allows working with unsupported types or overriding the default converter behavior."),(0,a.kt)("p",null,"Converters, along with with DynamoDB JSON parsing, are one of the most critical components from a performance perspective.\nAll ",(0,a.kt)("strong",{parentName:"p"},"EfficientDynamoDb")," built-in converters are optimized separately for both ",(0,a.kt)("inlineCode",{parentName:"p"},"Document")," and JSON conversion, in order to allocate no additional memory."),(0,a.kt)("h2",{id:"built-in-converters"},"Built-in converters"),(0,a.kt)("p",null,"EfficientDynamoDb does not require specifying a converter explicitly for the following built-in types:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Classes "),(0,a.kt)("li",{parentName:"ul"},"Strings"),(0,a.kt)("li",{parentName:"ul"},"Numbers: ",(0,a.kt)("inlineCode",{parentName:"li"},"byte"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"short"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"int"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"long"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"decimal"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"float"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"double"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"ushort"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"uint"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"ulong")),(0,a.kt)("li",{parentName:"ul"},"Enums (saved as numbers)"),(0,a.kt)("li",{parentName:"ul"},"DateTimes (saved in ISO8601 format)"),(0,a.kt)("li",{parentName:"ul"},"Guids"),(0,a.kt)("li",{parentName:"ul"},"Booleans"),(0,a.kt)("li",{parentName:"ul"},"Collections: arrays, lists, dictionaries, sets (including their read-only and mutable interfaces)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"AttributeValue")," structs (low-level API representation of the DynamoDB attribute)")),(0,a.kt)("p",null,"In addition, you can use one of the following converters to change the default behavior:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"StringEnumDdbConverter")," - saves enums as strings instead of numbers."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"DateTimeDdbConverter")," - allows to customize ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTime")," formatting parameters: ",(0,a.kt)("inlineCode",{parentName:"li"},"Format"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTimeStyles")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"CultureInfo"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"SdkDateTimeDdbConverter")," - makes ",(0,a.kt)("inlineCode",{parentName:"li"},"DateTime")," behavior backward compatible with the official AWS SDK.")),(0,a.kt)("h2",{id:"applying-converters"},"Applying converters"),(0,a.kt)("h3",{id:"for-a-property"},"For a property"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},'[DynamoDbProperty("address", typeof(CompositeAddressConverter))]\npublic Address Address { get; set; }\n')),(0,a.kt)("h3",{id:"for-a-type"},"For a type"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"[DynamoDbConverter(typeof(CompositeAddressConverter))]\npublic struct Address { ... }\n")),(0,a.kt)("h3",{id:"for-a-context"},"For a context"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"var config = new DynamoDbContextConfig(regionEndpoint, awsCredentials)\n{\n Converters = new[] {new CompositeAddressConverter()}\n};\n")),(0,a.kt)("p",null,"If a converter can't be instantiated in advance and depends on the target value type, a custom converter factory can be implemented by inheriting from the ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbConverterFactory")," class and registering it with the context the same way as other custom converters."),(0,a.kt)("p",null,"For example, a string enum converter factory can be defined like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public sealed class StringEnumDdbConverterFactory : DdbConverterFactory\n{\n public override bool CanConvert(Type typeToConvert) => typeToConvert.IsEnum;\n\n public override DdbConverter CreateConverter(Type typeToConvert, DynamoDbContextMetadata metadata)\n {\n return (DdbConverter) Activator.CreateInstance(typeof(StringEnumDdbConverter<>).MakeGenericType(typeToConvert));\n }\n}\n")),(0,a.kt)("h2",{id:"basic-converter"},"Basic converter"),(0,a.kt)("p",null,"To create a custom converter:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Inherit from ",(0,a.kt)("inlineCode",{parentName:"li"},"DdbConverter")," class."),(0,a.kt)("li",{parentName:"ul"},"Implement both ",(0,a.kt)("inlineCode",{parentName:"li"},"Read")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"Write")," methods.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CompositeAddressConverter : DdbConverter
\n{\n // Converts DynamoDb attribute to the .NET type\n public override Address Read(in AttributeValue attributeValue)\n {\n var parts = attributeValue.AsString().Split('#');\n return new Address(parts[0], parts[1]);\n }\n\n // Converts .NET type to the DynamoDb attribute\n public override AttributeValue Write(ref Address address)\n {\n return new StringAttributeValue($\"{address.Country}#{address.Street}\");\n }\n}\n")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Check out the ",(0,a.kt)("a",{parentName:"em",href:"/EfficientDynamoDb/docs/dev-guide/low-level#working-with-documents"},"working with documents")," chapter to better understand how to work with attribute values.")),(0,a.kt)("h2",{id:"direct-json-converter"},"Direct JSON converter"),(0,a.kt)("p",null,"Not all .NET types map nicely to DynamoDb attributes. Creation of intermediate ",(0,a.kt)("inlineCode",{parentName:"p"},"AttributeValue")," struct can involve unnecessary allocations that can be avoided by reading/writing directly into JSON buffer.\nIn case when a custom type can't be converted to the ",(0,a.kt)("inlineCode",{parentName:"p"},"AttributeValue")," without allocations, it is possible to implement two additional low-level ",(0,a.kt)("inlineCode",{parentName:"p"},"Read")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"Write")," methods that work with JSON buffers.\nDuring deserialization/serialization of entities to JSON, more optimized low-level implementations will be called."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomIntConverter : DdbConverter\n{\n // Efficient zero-allocation JSON to int conversion\n public override int Read(ref DdbReader reader)\n {\n if (!Utf8Parser.TryParse(reader.JsonReader.ValueSpan, out int value, out _))\n throw new DdbException($\"Couldn't parse int ddb value from '{reader.JsonReader.GetString()}'.\");\n\n return value;\n }\n \n // Efficient zero-allocation int to JSON conversion\n public override void Write(in DdbWriter writer, ref int value)\n {\n writer.JsonWriter.WriteStartObject();\n writer.JsonWriter.WriteString(DdbTypeNames.Number, value);\n writer.JsonWriter.WriteEndObject();\n }\n \n public override int Read(in AttributeValue attributeValue) => attributeValue.AsNumberAttribute().ToInt();\n \n public override AttributeValue Write(ref int value) => new NumberAttributeValue(value.ToString()); \n}\n")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"EfficientDynamoDb")," uses ",(0,a.kt)("inlineCode",{parentName:"p"},"System.Text.Json")," for all JSON manipulations."),(0,a.kt)("h3",{id:"json-reading"},"JSON reading"),(0,a.kt)("p",null,"When a low-level read is called, ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.JsonReader")," is already pointed to the JSON value. Current attribute type is automatically parsed and can be accessed using ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.AttributeType")," property."),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"reader.JsonReader.HasValueSequence")," is guaranteed to be false at this point, so it's safe to use ",(0,a.kt)("inlineCode",{parentName:"p"},"reader.JsonReader.ValueSpan")," to access the JSON buffer."),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"DdbReader.JsonReader.Read")," method should not be explicitly called unless you are writing a converter for a non-primitive JSON type like an object or array."),(0,a.kt)("h3",{id:"json-writing"},"JSON writing"),(0,a.kt)("p",null,"When a low-level write is called, a converter has to write DynamoDb JSON, including the attribute type.\n",(0,a.kt)("inlineCode",{parentName:"p"},"DdbWriter")," class provides various simplified overloads that write attribute types automatically. But in case if suitable overload does not exist, the attribute type has to be written manually like in the ",(0,a.kt)("inlineCode",{parentName:"p"},"CustomIntConverter")," example above."),(0,a.kt)("h2",{id:"sparse-converters"},"Sparse converters"),(0,a.kt)("p",null,"Sparse converters don't save certain values and completely remove an attribute instead. It is a powerful concept that can be used for various purposes like size savings or to conditionally include an entity in the GSI."),(0,a.kt)("p",null,"By default, all built-in converters act as sparse converters when it comes to handling ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," values, meaning that ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," properties are never saved and the entire attribute is deleted."),(0,a.kt)("p",null,"To add an additional sparse condition, ",(0,a.kt)("inlineCode",{parentName:"p"},"ShouldWrite")," method has to be overridden. For example. here is a simple sparse int converter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class SparseIntConverter : DdbConverter\n{\n public override bool ShouldWrite(ref int value) => value != 0;\n \n ...\n}\n")),(0,a.kt)("p",null,"Note: Sparse converters don't remove attributes when they are part of a ",(0,a.kt)("inlineCode",{parentName:"p"},"Dictionary")," class."),(0,a.kt)("h2",{id:"set-converters"},"Set converters"),(0,a.kt)("p",null,"Both string and number sets store values as strings in the DB.\nTo store a custom type inside a set, a converter should implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"ISetValueConverter")," interface:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomDdbConverter : DdbConverter, ISetValueConverter\n{\n public string WriteStringValue(ref CustomType value) => value.ToString();\n \n // Optionally implement direct write method\n public void WriteStringValue(in DdbWriter ddbWriter, ref CustomType value) => \n ddbWriter.JsonWriter.WriteStringValue(value.AsSpan());\n}\n")),(0,a.kt)("h2",{id:"dictionary-key-converters"},"Dictionary key converters"),(0,a.kt)("p",null,"To store a custom type as a dictionary key, a converter should implement the ",(0,a.kt)("inlineCode",{parentName:"p"},"IDicitonaryKeyConverter")," interface:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-csharp"},"public class CustomDdbConverter : DdbConverter, ISetValueConverter\n{\n public string WriteStringValue(ref CustomType value) => value.ToString();\n \n // Optionally implement direct write method\n public void WritePropertyName(in DdbWriter ddbWriter, ref CustomType value) => \n ddbWriter.JsonWriter.WritePropertyName(value.AsSpan());\n}\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.e35d0b3f.js b/assets/js/runtime~main.6aa1fbf5.js similarity index 97% rename from assets/js/runtime~main.e35d0b3f.js rename to assets/js/runtime~main.6aa1fbf5.js index dd2dba77..4cbb6648 100644 --- a/assets/js/runtime~main.e35d0b3f.js +++ b/assets/js/runtime~main.6aa1fbf5.js @@ -1 +1 @@ -(()=>{"use strict";var e,f,a,c,t,d={},r={};function b(e){var f=r[e];if(void 0!==f)return f.exports;var a=r[e]={id:e,loaded:!1,exports:{}};return d[e].call(a.exports,a,a.exports,b),a.loaded=!0,a.exports}b.m=d,b.c=r,e=[],b.O=(f,a,c,t)=>{if(!a){var d=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](a[o])))?a.splice(o--,1):(r=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[a,c,t]},b.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return b.d(f,{a:f}),f},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var d={};f=f||[null,a({}),a([]),a(a)];for(var r=2&c&&e;"object"==typeof r&&!~f.indexOf(r);r=a(r))Object.getOwnPropertyNames(r).forEach((f=>d[f]=()=>e[f]));return d.default=()=>e,b.d(t,d),t},b.d=(e,f)=>{for(var a in f)b.o(f,a)&&!b.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:f[a]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((f,a)=>(b.f[a](e,f),f)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",228:"1155039a",274:"a3c1b243",516:"11627d40",595:"b9d88015",708:"260fa5f4",873:"bfb671d9",988:"05f1e2f6",998:"835b2de0",1002:"3df1ab03",1270:"57f17f53",1276:"4a711172",1680:"17464717",1728:"93ddd364",2042:"9c1171d9",2120:"19ff6abc",2200:"9622c849",2332:"c784c900",2535:"814f3328",2888:"c8437248",3042:"23d51ede",3089:"a6aa9e1f",3608:"9e4087bc",3716:"3370138b",4013:"01a85c17",4195:"c4f5d8e4",4707:"f8ce8b4d",5038:"36f18142",5041:"3366ddf7",5125:"9b187b5f",5162:"c1907475",5535:"9dc44634",5587:"ab469123",5855:"25393d2f",6103:"ccc49370",6146:"b5c7bbc6",6193:"cd142753",6249:"4a3d4e91",6433:"19900921",6956:"0897ba3a",7362:"192f4ebe",7635:"e12edb21",7918:"17896441",7920:"1a4e3797",7941:"427f9263",8089:"6e6fe12a",8138:"73afc245",8301:"48eb8e55",8397:"3190a842",8422:"8425197c",8610:"6875c492",8666:"f8fd219f",8667:"c260cec5",8691:"2bec7c7c",8766:"6c683d63",9320:"a04c356d",9345:"e7bd64b6",9514:"1be78505",9817:"14eb3368"}[e]||e)+"."+{53:"26359d8d",228:"842d7717",274:"74ffaa95",516:"111cbdf5",595:"4bfa5d66",708:"8859a50d",873:"4b263558",988:"adb0eda4",998:"36621a90",1002:"86b303cf",1270:"cae7a160",1276:"a16b0787",1426:"65331c22",1680:"16fa700f",1728:"4a37f817",2042:"b21ae505",2120:"2ad0e4d2",2200:"dcf29315",2332:"56ccfbe4",2535:"6f3e8ba2",2888:"ad0b8a62",3042:"e27220c4",3089:"54f5059b",3608:"519c7a78",3716:"0d8dcb0e",4013:"1d6b692f",4195:"11127df6",4707:"31b6c7b7",4972:"e3352a90",5038:"ee63f0dc",5041:"99acb4dd",5125:"3b24e5ca",5162:"2db9df12",5535:"d989385e",5587:"48e8c24b",5855:"6af0d434",6048:"67487f6d",6103:"1276696f",6146:"ebb213bf",6193:"0606bd0e",6249:"29a8fe37",6433:"e17bfa6c",6945:"8e8e2060",6956:"6513fcb5",7362:"9e3586e4",7635:"68c5b2e2",7918:"e5ef40c0",7920:"2462ce44",7941:"82a3470e",8089:"e87502a6",8105:"58796c58",8138:"81ed1a04",8301:"4dab67b5",8397:"f2c0860a",8422:"90ae3c44",8610:"f486a385",8666:"58705e14",8667:"28fc11e1",8691:"83089343",8766:"32c1fe51",8894:"46125374",9320:"46f838fa",9345:"41ac8cb2",9514:"29153ead",9817:"7d9e2317"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),c={},t="website:",b.l=(e,f,a,d)=>{if(c[e])c[e].push(f);else{var r,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{r.onerror=r.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],r.parentNode&&r.parentNode.removeChild(r),t&&t.forEach((e=>e(a))),f)return f(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=l.bind(null,r.onerror),r.onload=l.bind(null,r.onload),o&&document.head.appendChild(r)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/EfficientDynamoDb/",b.gca=function(e){return e={17464717:"1680",17896441:"7918",19900921:"6433","935f2afb":"53","1155039a":"228",a3c1b243:"274","11627d40":"516",b9d88015:"595","260fa5f4":"708",bfb671d9:"873","05f1e2f6":"988","835b2de0":"998","3df1ab03":"1002","57f17f53":"1270","4a711172":"1276","93ddd364":"1728","9c1171d9":"2042","19ff6abc":"2120","9622c849":"2200",c784c900:"2332","814f3328":"2535",c8437248:"2888","23d51ede":"3042",a6aa9e1f:"3089","9e4087bc":"3608","3370138b":"3716","01a85c17":"4013",c4f5d8e4:"4195",f8ce8b4d:"4707","36f18142":"5038","3366ddf7":"5041","9b187b5f":"5125",c1907475:"5162","9dc44634":"5535",ab469123:"5587","25393d2f":"5855",ccc49370:"6103",b5c7bbc6:"6146",cd142753:"6193","4a3d4e91":"6249","0897ba3a":"6956","192f4ebe":"7362",e12edb21:"7635","1a4e3797":"7920","427f9263":"7941","6e6fe12a":"8089","73afc245":"8138","48eb8e55":"8301","3190a842":"8397","8425197c":"8422","6875c492":"8610",f8fd219f:"8666",c260cec5:"8667","2bec7c7c":"8691","6c683d63":"8766",a04c356d:"9320",e7bd64b6:"9345","1be78505":"9514","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(f,a)=>{var c=b.o(e,f)?e[f]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var t=new Promise(((a,t)=>c=e[f]=[a,t]));a.push(c[2]=t);var d=b.p+b.u(f),r=new Error;b.l(d,(a=>{if(b.o(e,f)&&(0!==(c=e[f])&&(e[f]=void 0),c)){var t=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;r.message="Loading chunk "+f+" failed.\n("+t+": "+d+")",r.name="ChunkLoadError",r.type=t,r.request=d,c[1](r)}}),"chunk-"+f,f)}},b.O.j=f=>0===e[f];var f=(f,a)=>{var c,t,d=a[0],r=a[1],o=a[2],n=0;if(d.some((f=>0!==e[f]))){for(c in r)b.o(r,c)&&(b.m[c]=r[c]);if(o)var i=o(b)}for(f&&f(a);n{"use strict";var e,f,a,c,t,d={},r={};function b(e){var f=r[e];if(void 0!==f)return f.exports;var a=r[e]={id:e,loaded:!1,exports:{}};return d[e].call(a.exports,a,a.exports,b),a.loaded=!0,a.exports}b.m=d,b.c=r,e=[],b.O=(f,a,c,t)=>{if(!a){var d=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](a[o])))?a.splice(o--,1):(r=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[a,c,t]},b.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return b.d(f,{a:f}),f},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var d={};f=f||[null,a({}),a([]),a(a)];for(var r=2&c&&e;"object"==typeof r&&!~f.indexOf(r);r=a(r))Object.getOwnPropertyNames(r).forEach((f=>d[f]=()=>e[f]));return d.default=()=>e,b.d(t,d),t},b.d=(e,f)=>{for(var a in f)b.o(f,a)&&!b.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:f[a]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((f,a)=>(b.f[a](e,f),f)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",228:"1155039a",274:"a3c1b243",516:"11627d40",595:"b9d88015",708:"260fa5f4",873:"bfb671d9",988:"05f1e2f6",998:"835b2de0",1002:"3df1ab03",1270:"57f17f53",1276:"4a711172",1680:"17464717",1728:"93ddd364",2042:"9c1171d9",2120:"19ff6abc",2200:"9622c849",2332:"c784c900",2535:"814f3328",2888:"c8437248",3042:"23d51ede",3089:"a6aa9e1f",3608:"9e4087bc",3716:"3370138b",4013:"01a85c17",4195:"c4f5d8e4",4707:"f8ce8b4d",5038:"36f18142",5041:"3366ddf7",5125:"9b187b5f",5162:"c1907475",5535:"9dc44634",5587:"ab469123",5855:"25393d2f",6103:"ccc49370",6146:"b5c7bbc6",6193:"cd142753",6249:"4a3d4e91",6433:"19900921",6956:"0897ba3a",7362:"192f4ebe",7635:"e12edb21",7918:"17896441",7920:"1a4e3797",7941:"427f9263",8089:"6e6fe12a",8138:"73afc245",8301:"48eb8e55",8397:"3190a842",8422:"8425197c",8610:"6875c492",8666:"f8fd219f",8667:"c260cec5",8691:"2bec7c7c",8766:"6c683d63",9320:"a04c356d",9345:"e7bd64b6",9514:"1be78505",9817:"14eb3368"}[e]||e)+"."+{53:"26359d8d",228:"842d7717",274:"74ffaa95",516:"111cbdf5",595:"4bfa5d66",708:"8859a50d",873:"4b263558",988:"adb0eda4",998:"36621a90",1002:"95fcbd98",1270:"cae7a160",1276:"a16b0787",1426:"65331c22",1680:"16fa700f",1728:"4a37f817",2042:"b21ae505",2120:"2ad0e4d2",2200:"dcf29315",2332:"56ccfbe4",2535:"6f3e8ba2",2888:"ad0b8a62",3042:"e27220c4",3089:"54f5059b",3608:"519c7a78",3716:"0d8dcb0e",4013:"1d6b692f",4195:"11127df6",4707:"31b6c7b7",4972:"e3352a90",5038:"ee63f0dc",5041:"99acb4dd",5125:"3b24e5ca",5162:"2db9df12",5535:"d989385e",5587:"48e8c24b",5855:"6af0d434",6048:"67487f6d",6103:"1276696f",6146:"ebb213bf",6193:"0606bd0e",6249:"29a8fe37",6433:"e17bfa6c",6945:"8e8e2060",6956:"6513fcb5",7362:"9e3586e4",7635:"68c5b2e2",7918:"e5ef40c0",7920:"2462ce44",7941:"82a3470e",8089:"e87502a6",8105:"58796c58",8138:"81ed1a04",8301:"4dab67b5",8397:"f2c0860a",8422:"90ae3c44",8610:"f486a385",8666:"58705e14",8667:"28fc11e1",8691:"83089343",8766:"32c1fe51",8894:"46125374",9320:"46f838fa",9345:"41ac8cb2",9514:"29153ead",9817:"7d9e2317"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),c={},t="website:",b.l=(e,f,a,d)=>{if(c[e])c[e].push(f);else{var r,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{r.onerror=r.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],r.parentNode&&r.parentNode.removeChild(r),t&&t.forEach((e=>e(a))),f)return f(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=l.bind(null,r.onerror),r.onload=l.bind(null,r.onload),o&&document.head.appendChild(r)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/EfficientDynamoDb/",b.gca=function(e){return e={17464717:"1680",17896441:"7918",19900921:"6433","935f2afb":"53","1155039a":"228",a3c1b243:"274","11627d40":"516",b9d88015:"595","260fa5f4":"708",bfb671d9:"873","05f1e2f6":"988","835b2de0":"998","3df1ab03":"1002","57f17f53":"1270","4a711172":"1276","93ddd364":"1728","9c1171d9":"2042","19ff6abc":"2120","9622c849":"2200",c784c900:"2332","814f3328":"2535",c8437248:"2888","23d51ede":"3042",a6aa9e1f:"3089","9e4087bc":"3608","3370138b":"3716","01a85c17":"4013",c4f5d8e4:"4195",f8ce8b4d:"4707","36f18142":"5038","3366ddf7":"5041","9b187b5f":"5125",c1907475:"5162","9dc44634":"5535",ab469123:"5587","25393d2f":"5855",ccc49370:"6103",b5c7bbc6:"6146",cd142753:"6193","4a3d4e91":"6249","0897ba3a":"6956","192f4ebe":"7362",e12edb21:"7635","1a4e3797":"7920","427f9263":"7941","6e6fe12a":"8089","73afc245":"8138","48eb8e55":"8301","3190a842":"8397","8425197c":"8422","6875c492":"8610",f8fd219f:"8666",c260cec5:"8667","2bec7c7c":"8691","6c683d63":"8766",a04c356d:"9320",e7bd64b6:"9345","1be78505":"9514","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(f,a)=>{var c=b.o(e,f)?e[f]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var t=new Promise(((a,t)=>c=e[f]=[a,t]));a.push(c[2]=t);var d=b.p+b.u(f),r=new Error;b.l(d,(a=>{if(b.o(e,f)&&(0!==(c=e[f])&&(e[f]=void 0),c)){var t=a&&("load"===a.type?"missing":a.type),d=a&&a.target&&a.target.src;r.message="Loading chunk "+f+" failed.\n("+t+": "+d+")",r.name="ChunkLoadError",r.type=t,r.request=d,c[1](r)}}),"chunk-"+f,f)}},b.O.j=f=>0===e[f];var f=(f,a)=>{var c,t,d=a[0],r=a[1],o=a[2],n=0;if(d.some((f=>0!==e[f]))){for(c in r)b.o(r,c)&&(b.m[c]=r[c]);if(o)var i=o(b)}for(f&&f(a);n