serialized has two valid values byName and byIndex. When using byName the string literal of the enum is used, when using byIndex the index value (0, 1, 2, etc) is used.
-
info
It's recommended to always set serialized to byName in any new Enum models, as this is less fragile and will be changed to the default setting in version 2 of Serverpod.
+
info
It's recommended to always set serialized to byName in any new Enum models, as this is less fragile and will be changed to the default setting in version 3 of Serverpod.
Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation.
### Information about a company. class: Company fields: ### The name of the company. name: String ### The date the company was founded, if known. foundedDate: DateTime? ### A list of people currently employed at the company. employees: List<Employee>
Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation.
### Information about a company. class: Company fields: ### The name of the company. name: String ### The date the company was founded, if known. foundedDate: DateTime? ### A list of people currently employed at the company. employees: List<Employee>
The SerializableEntity class is deprecated and will be removed in version 2.1. Please implement the SerializableModel interface instead for creating serializable models.
+
The SerializableEntity class is deprecated and will be removed in version 3. Please implement the SerializableModel interface instead for creating serializable models.
To migrate your code from SerializableEntity to SerializableModel, replace extends SerializableEntity with implements SerializableModel in your model classes.
diff --git a/docs/404.html b/docs/404.html
index 2b65b100b..e17a53eda 100644
--- a/docs/404.html
+++ b/docs/404.html
@@ -4,7 +4,7 @@
Serverpod
-
+
diff --git a/docs/assets/js/1b218eaa.7f79a47a.js b/docs/assets/js/1b218eaa.4a46f698.js
similarity index 99%
rename from docs/assets/js/1b218eaa.7f79a47a.js
rename to docs/assets/js/1b218eaa.4a46f698.js
index 70c70601c..6c2094bd4 100644
--- a/docs/assets/js/1b218eaa.7f79a47a.js
+++ b/docs/assets/js/1b218eaa.4a46f698.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[57790],{2080:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var s=n(74848),d=n(28453);const l={},i="Working with models",r={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-2.1.0/06-concepts/02-models.md",sourceDirName:"06-concepts",slug:"/concepts/models",permalink:"/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.1.0/06-concepts/02-models.md",tags:[],version:"2.1.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/concepts/serialization"}},a={},c=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Default Values",id:"default-values",level:2},{value:"Keywords",id:"keywords",level:3},{value:"How priorities work",id:"how-priorities-work",level:3},{value:"Supported default values",id:"supported-default-values",level:3},{value:"Boolean",id:"boolean",level:4},{value:"DateTime",id:"datetime",level:4},{value:"Double",id:"double",level:4},{value:"Duration",id:"duration",level:4},{value:"Enum",id:"enum-1",level:4},{value:"Integer",id:"integer",level:4},{value:"String",id:"string",level:4},{value:"UuidValue",id:"uuidvalue",level:4},{value:"Example",id:"example",level:3},{value:"Keywords",id:"keywords-1",level:2}];function o(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 2 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"default-values",children:"Default Values"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod supports defining default values for fields in your models. These default values can be specified using three different keywords that determine how and where the defaults are applied:"}),"\n",(0,s.jsx)(t.h3,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"default"}),": This keyword sets a default value for both the model (code) and the database (persisted data). It acts as a general fallback if more specific defaults aren't provided."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultModel"}),": This keyword sets a default value specifically for the model (the code side). If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, the model will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultPersist"}),": This keyword sets a default value specifically for the database. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, the database will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"how-priorities-work",children:"How priorities work"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the model (code side):"})," If both ",(0,s.jsx)(t.code,{children:"defaultModel"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the model will use the ",(0,s.jsx)(t.code,{children:"defaultModel"})," value. If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the database (persisted data):"})," If both ",(0,s.jsx)(t.code,{children:"defaultPersist"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the database will use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"You can use these default values individually or in combination as needed. It is not required to use all default types for a field."}),"\n",(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsxs)(t.p,{children:["When using ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," in combination with ",(0,s.jsx)(t.code,{children:"defaultPersist"}),", it's important to understand how the interaction between these keywords affects the final value in the database."]}),(0,s.jsxs)(t.p,{children:["If you set a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," value, the model's field or variable will have a value when it's passed to the database\u2014it will not be ",(0,s.jsx)(t.code,{children:"null"}),". Because of this, the SQL query will not use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value since the field already has a value assigned by the model. In essence, assigning a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," is like directly providing a value to the field, and the database will use this provided value instead of its own default."]}),(0,s.jsxs)(t.p,{children:["This means that ",(0,s.jsx)(t.code,{children:"defaultPersist"})," only comes into play when the model does not provide a value, allowing the database to apply its own default setting."]})]}),"\n",(0,s.jsx)(t.h3,{id:"supported-default-values",children:"Supported default values"}),"\n",(0,s.jsx)(t.h4,{id:"boolean",children:"Boolean"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Boolean"})}),(0,s.jsxs)(t.td,{children:[(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a boolean value, either ",(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"}),"."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"boolDefault: bool, default=true\n"})}),"\n",(0,s.jsx)(t.h4,{id:"datetime",children:"DateTime"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Current Date and Time"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"now"})}),(0,s.jsx)(t.td,{children:"Sets the field to the current date and time."})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific UTC DateTime"})}),(0,s.jsxs)(t.td,{children:["UTC DateTime string in the format ",(0,s.jsx)(t.code,{children:"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"})]}),(0,s.jsx)(t.td,{children:"Sets the field to a specific date and time."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"dateTimeDefaultNow: DateTime, default=now\ndateTimeDefaultUtc: DateTime, default=2024-05-01T22:00:00.000Z\n"})}),"\n",(0,s.jsx)(t.h4,{id:"double",children:"Double"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Double"})}),(0,s.jsx)(t.td,{children:"Any double value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific double value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"doubleDefault: double, default=10.5\n"})}),"\n",(0,s.jsx)(t.h4,{id:"duration",children:"Duration"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific Duration"})}),(0,s.jsxs)(t.td,{children:["A valid duration in the format ",(0,s.jsx)(t.code,{children:"Xd Xh Xmin Xs Xms"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a specific duration value. For example, ",(0,s.jsx)(t.code,{children:"1d 2h 10min 30s 100ms"})," represents 1 day, 2 hours, 10 minutes, 30 seconds, and 100 milliseconds."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"durationDefault: Duration, default=1d 2h 10min 30s 100ms\n"})}),"\n",(0,s.jsx)(t.h4,{id:"enum-1",children:"Enum"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Enum"})}),(0,s.jsx)(t.td,{children:"Any valid enum value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific enum value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByNameEnum\nserialized: byName\nvalues:\n - byName1\n - byName2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByIndexEnum\nserialized: byIndex\nvalues:\n - byIndex1\n - byIndex2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: EnumDefault\ntable: enum_default\nfields:\n byNameEnumDefault: ByNameEnum, default=byName1\n byIndexEnumDefault: ByIndexEnum, default=byIndex1\n"})}),"\n",(0,s.jsx)(t.p,{children:"In this example:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byNameEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"'byName1'"})," in the database."]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byIndexEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"0"})," (the index of ",(0,s.jsx)(t.code,{children:"byIndex1"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h4,{id:"integer",children:"Integer"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Integer"})}),(0,s.jsx)(t.td,{children:"Any integer value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific integer value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"intDefault: int, default=10\n"})}),"\n",(0,s.jsx)(t.h4,{id:"string",children:"String"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"String"})}),(0,s.jsx)(t.td,{children:"Any string value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific string value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stringDefault: String, default='This is a string'\n"})}),"\n",(0,s.jsx)(t.h4,{id:"uuidvalue",children:"UuidValue"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Random UUID"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"random"})}),(0,s.jsxs)(t.td,{children:["Generates a random UUID. On the Dart side, ",(0,s.jsx)(t.code,{children:"Uuid().v4obj()"})," is used. On the database side, ",(0,s.jsx)(t.code,{children:"gen_random_uuid()"})," is used."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"UUID String"})}),(0,s.jsx)(t.td,{children:"A valid UUID version 4 string"}),(0,s.jsx)(t.td,{children:"Assigns a specific UUID to the field."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"uuidDefaultRandom: UuidValue, default=random\nuuidDefaultUuid: UuidValue, default='550e8400-e29b-41d4-a716-446655440000'\n"})}),"\n",(0,s.jsx)(t.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:'class: DefaultValue\ntable: default_value\nfields:\n ### Sets the current date and time as the default value.\n dateTimeDefault: DateTime, default=now\n\n ### Sets the default value for a boolean field.\n boolDefault: bool, defaultModel=false, defaultPersist=true\n\n ### Sets the default value for an integer field.\n intDefault: int, defaultPersist=20\n\n ### Sets the default value for a double field.\n doubleDefault: double, default=10.5, defaultPersist=20.5\n\n ### Sets the default value for a string field.\n stringDefault: String, default="This is a string", defaultModel="This is a string"\n'})}),"\n",(0,s.jsx)(t.h2,{id:"keywords-1",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"default"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for both the model and the database. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultModel"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the model side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultPersist"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the database side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"})," and ",(0,s.jsx)(t.strong,{children:"!persist"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>r});var s=n(96540);const d={},l=s.createContext(d);function i(e){const t=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),s.createElement(l.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[57790],{2080:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var s=n(74848),d=n(28453);const l={},i="Working with models",r={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-2.1.0/06-concepts/02-models.md",sourceDirName:"06-concepts",slug:"/concepts/models",permalink:"/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.1.0/06-concepts/02-models.md",tags:[],version:"2.1.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/concepts/serialization"}},a={},c=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Default Values",id:"default-values",level:2},{value:"Keywords",id:"keywords",level:3},{value:"How priorities work",id:"how-priorities-work",level:3},{value:"Supported default values",id:"supported-default-values",level:3},{value:"Boolean",id:"boolean",level:4},{value:"DateTime",id:"datetime",level:4},{value:"Double",id:"double",level:4},{value:"Duration",id:"duration",level:4},{value:"Enum",id:"enum-1",level:4},{value:"Integer",id:"integer",level:4},{value:"String",id:"string",level:4},{value:"UuidValue",id:"uuidvalue",level:4},{value:"Example",id:"example",level:3},{value:"Keywords",id:"keywords-1",level:2}];function o(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 3 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"default-values",children:"Default Values"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod supports defining default values for fields in your models. These default values can be specified using three different keywords that determine how and where the defaults are applied:"}),"\n",(0,s.jsx)(t.h3,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"default"}),": This keyword sets a default value for both the model (code) and the database (persisted data). It acts as a general fallback if more specific defaults aren't provided."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultModel"}),": This keyword sets a default value specifically for the model (the code side). If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, the model will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultPersist"}),": This keyword sets a default value specifically for the database. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, the database will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"how-priorities-work",children:"How priorities work"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the model (code side):"})," If both ",(0,s.jsx)(t.code,{children:"defaultModel"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the model will use the ",(0,s.jsx)(t.code,{children:"defaultModel"})," value. If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the database (persisted data):"})," If both ",(0,s.jsx)(t.code,{children:"defaultPersist"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the database will use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"You can use these default values individually or in combination as needed. It is not required to use all default types for a field."}),"\n",(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsxs)(t.p,{children:["When using ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," in combination with ",(0,s.jsx)(t.code,{children:"defaultPersist"}),", it's important to understand how the interaction between these keywords affects the final value in the database."]}),(0,s.jsxs)(t.p,{children:["If you set a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," value, the model's field or variable will have a value when it's passed to the database\u2014it will not be ",(0,s.jsx)(t.code,{children:"null"}),". Because of this, the SQL query will not use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value since the field already has a value assigned by the model. In essence, assigning a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," is like directly providing a value to the field, and the database will use this provided value instead of its own default."]}),(0,s.jsxs)(t.p,{children:["This means that ",(0,s.jsx)(t.code,{children:"defaultPersist"})," only comes into play when the model does not provide a value, allowing the database to apply its own default setting."]})]}),"\n",(0,s.jsx)(t.h3,{id:"supported-default-values",children:"Supported default values"}),"\n",(0,s.jsx)(t.h4,{id:"boolean",children:"Boolean"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Boolean"})}),(0,s.jsxs)(t.td,{children:[(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a boolean value, either ",(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"}),"."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"boolDefault: bool, default=true\n"})}),"\n",(0,s.jsx)(t.h4,{id:"datetime",children:"DateTime"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Current Date and Time"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"now"})}),(0,s.jsx)(t.td,{children:"Sets the field to the current date and time."})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific UTC DateTime"})}),(0,s.jsxs)(t.td,{children:["UTC DateTime string in the format ",(0,s.jsx)(t.code,{children:"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"})]}),(0,s.jsx)(t.td,{children:"Sets the field to a specific date and time."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"dateTimeDefaultNow: DateTime, default=now\ndateTimeDefaultUtc: DateTime, default=2024-05-01T22:00:00.000Z\n"})}),"\n",(0,s.jsx)(t.h4,{id:"double",children:"Double"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Double"})}),(0,s.jsx)(t.td,{children:"Any double value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific double value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"doubleDefault: double, default=10.5\n"})}),"\n",(0,s.jsx)(t.h4,{id:"duration",children:"Duration"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific Duration"})}),(0,s.jsxs)(t.td,{children:["A valid duration in the format ",(0,s.jsx)(t.code,{children:"Xd Xh Xmin Xs Xms"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a specific duration value. For example, ",(0,s.jsx)(t.code,{children:"1d 2h 10min 30s 100ms"})," represents 1 day, 2 hours, 10 minutes, 30 seconds, and 100 milliseconds."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"durationDefault: Duration, default=1d 2h 10min 30s 100ms\n"})}),"\n",(0,s.jsx)(t.h4,{id:"enum-1",children:"Enum"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Enum"})}),(0,s.jsx)(t.td,{children:"Any valid enum value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific enum value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByNameEnum\nserialized: byName\nvalues:\n - byName1\n - byName2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByIndexEnum\nserialized: byIndex\nvalues:\n - byIndex1\n - byIndex2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: EnumDefault\ntable: enum_default\nfields:\n byNameEnumDefault: ByNameEnum, default=byName1\n byIndexEnumDefault: ByIndexEnum, default=byIndex1\n"})}),"\n",(0,s.jsx)(t.p,{children:"In this example:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byNameEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"'byName1'"})," in the database."]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byIndexEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"0"})," (the index of ",(0,s.jsx)(t.code,{children:"byIndex1"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h4,{id:"integer",children:"Integer"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Integer"})}),(0,s.jsx)(t.td,{children:"Any integer value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific integer value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"intDefault: int, default=10\n"})}),"\n",(0,s.jsx)(t.h4,{id:"string",children:"String"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"String"})}),(0,s.jsx)(t.td,{children:"Any string value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific string value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stringDefault: String, default='This is a string'\n"})}),"\n",(0,s.jsx)(t.h4,{id:"uuidvalue",children:"UuidValue"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Random UUID"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"random"})}),(0,s.jsxs)(t.td,{children:["Generates a random UUID. On the Dart side, ",(0,s.jsx)(t.code,{children:"Uuid().v4obj()"})," is used. On the database side, ",(0,s.jsx)(t.code,{children:"gen_random_uuid()"})," is used."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"UUID String"})}),(0,s.jsx)(t.td,{children:"A valid UUID version 4 string"}),(0,s.jsx)(t.td,{children:"Assigns a specific UUID to the field."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"uuidDefaultRandom: UuidValue, default=random\nuuidDefaultUuid: UuidValue, default='550e8400-e29b-41d4-a716-446655440000'\n"})}),"\n",(0,s.jsx)(t.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:'class: DefaultValue\ntable: default_value\nfields:\n ### Sets the current date and time as the default value.\n dateTimeDefault: DateTime, default=now\n\n ### Sets the default value for a boolean field.\n boolDefault: bool, defaultModel=false, defaultPersist=true\n\n ### Sets the default value for an integer field.\n intDefault: int, defaultPersist=20\n\n ### Sets the default value for a double field.\n doubleDefault: double, default=10.5, defaultPersist=20.5\n\n ### Sets the default value for a string field.\n stringDefault: String, default="This is a string", defaultModel="This is a string"\n'})}),"\n",(0,s.jsx)(t.h2,{id:"keywords-1",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"default"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for both the model and the database. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultModel"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the model side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultPersist"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the database side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"})," and ",(0,s.jsx)(t.strong,{children:"!persist"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>r});var s=n(96540);const d={},l=s.createContext(d);function i(e){const t=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),s.createElement(l.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/32b8fafb.d51c7aa0.js b/docs/assets/js/32b8fafb.439ef5f1.js
similarity index 99%
rename from docs/assets/js/32b8fafb.d51c7aa0.js
rename to docs/assets/js/32b8fafb.439ef5f1.js
index 2ac109154..0f99f6659 100644
--- a/docs/assets/js/32b8fafb.d51c7aa0.js
+++ b/docs/assets/js/32b8fafb.439ef5f1.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[92113],{82853:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var s=n(74848),d=n(28453);const l={},i="Working with models",r={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/docs/06-concepts/02-models.md",sourceDirName:"06-concepts",slug:"/concepts/models",permalink:"/next/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/docs/06-concepts/02-models.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/next/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/next/concepts/serialization"}},a={},c=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Default Values",id:"default-values",level:2},{value:"Keywords",id:"keywords",level:3},{value:"How priorities work",id:"how-priorities-work",level:3},{value:"Supported default values",id:"supported-default-values",level:3},{value:"Boolean",id:"boolean",level:4},{value:"DateTime",id:"datetime",level:4},{value:"Double",id:"double",level:4},{value:"Duration",id:"duration",level:4},{value:"Enum",id:"enum-1",level:4},{value:"Integer",id:"integer",level:4},{value:"String",id:"string",level:4},{value:"UuidValue",id:"uuidvalue",level:4},{value:"Example",id:"example",level:3},{value:"Keywords",id:"keywords-1",level:2}];function o(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"none"})," is not typically used in serverpod apps. It is intended for the serverpod framework, itself."]})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 2 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"default-values",children:"Default Values"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod supports defining default values for fields in your models. These default values can be specified using three different keywords that determine how and where the defaults are applied:"}),"\n",(0,s.jsx)(t.h3,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"default"}),": This keyword sets a default value for both the model (code) and the database (persisted data). It acts as a general fallback if more specific defaults aren't provided."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultModel"}),": This keyword sets a default value specifically for the model (the code side). If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, the model will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultPersist"}),": This keyword sets a default value specifically for the database. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, the database will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"how-priorities-work",children:"How priorities work"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the model (code side):"})," If both ",(0,s.jsx)(t.code,{children:"defaultModel"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the model will use the ",(0,s.jsx)(t.code,{children:"defaultModel"})," value. If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the database (persisted data):"})," If both ",(0,s.jsx)(t.code,{children:"defaultPersist"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the database will use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"You can use these default values individually or in combination as needed. It is not required to use all default types for a field."}),"\n",(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsxs)(t.p,{children:["When using ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," in combination with ",(0,s.jsx)(t.code,{children:"defaultPersist"}),", it's important to understand how the interaction between these keywords affects the final value in the database."]}),(0,s.jsxs)(t.p,{children:["If you set a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," value, the model's field or variable will have a value when it's passed to the database\u2014it will not be ",(0,s.jsx)(t.code,{children:"null"}),". Because of this, the SQL query will not use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value since the field already has a value assigned by the model. In essence, assigning a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," is like directly providing a value to the field, and the database will use this provided value instead of its own default."]}),(0,s.jsxs)(t.p,{children:["This means that ",(0,s.jsx)(t.code,{children:"defaultPersist"})," only comes into play when the model does not provide a value, allowing the database to apply its own default setting."]})]}),"\n",(0,s.jsx)(t.h3,{id:"supported-default-values",children:"Supported default values"}),"\n",(0,s.jsx)(t.h4,{id:"boolean",children:"Boolean"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Boolean"})}),(0,s.jsxs)(t.td,{children:[(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a boolean value, either ",(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"}),"."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"boolDefault: bool, default=true\n"})}),"\n",(0,s.jsx)(t.h4,{id:"datetime",children:"DateTime"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Current Date and Time"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"now"})}),(0,s.jsx)(t.td,{children:"Sets the field to the current date and time."})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific UTC DateTime"})}),(0,s.jsxs)(t.td,{children:["UTC DateTime string in the format ",(0,s.jsx)(t.code,{children:"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"})]}),(0,s.jsx)(t.td,{children:"Sets the field to a specific date and time."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"dateTimeDefaultNow: DateTime, default=now\ndateTimeDefaultUtc: DateTime, default=2024-05-01T22:00:00.000Z\n"})}),"\n",(0,s.jsx)(t.h4,{id:"double",children:"Double"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Double"})}),(0,s.jsx)(t.td,{children:"Any double value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific double value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"doubleDefault: double, default=10.5\n"})}),"\n",(0,s.jsx)(t.h4,{id:"duration",children:"Duration"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific Duration"})}),(0,s.jsxs)(t.td,{children:["A valid duration in the format ",(0,s.jsx)(t.code,{children:"Xd Xh Xmin Xs Xms"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a specific duration value. For example, ",(0,s.jsx)(t.code,{children:"1d 2h 10min 30s 100ms"})," represents 1 day, 2 hours, 10 minutes, 30 seconds, and 100 milliseconds."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"durationDefault: Duration, default=1d 2h 10min 30s 100ms\n"})}),"\n",(0,s.jsx)(t.h4,{id:"enum-1",children:"Enum"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Enum"})}),(0,s.jsx)(t.td,{children:"Any valid enum value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific enum value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByNameEnum\nserialized: byName\nvalues:\n - byName1\n - byName2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByIndexEnum\nserialized: byIndex\nvalues:\n - byIndex1\n - byIndex2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: EnumDefault\ntable: enum_default\nfields:\n byNameEnumDefault: ByNameEnum, default=byName1\n byIndexEnumDefault: ByIndexEnum, default=byIndex1\n"})}),"\n",(0,s.jsx)(t.p,{children:"In this example:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byNameEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"'byName1'"})," in the database."]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byIndexEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"0"})," (the index of ",(0,s.jsx)(t.code,{children:"byIndex1"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h4,{id:"integer",children:"Integer"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Integer"})}),(0,s.jsx)(t.td,{children:"Any integer value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific integer value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"intDefault: int, default=10\n"})}),"\n",(0,s.jsx)(t.h4,{id:"string",children:"String"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"String"})}),(0,s.jsx)(t.td,{children:"Any string value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific string value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stringDefault: String, default='This is a string'\n"})}),"\n",(0,s.jsx)(t.h4,{id:"uuidvalue",children:"UuidValue"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Random UUID"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"random"})}),(0,s.jsxs)(t.td,{children:["Generates a random UUID. On the Dart side, ",(0,s.jsx)(t.code,{children:"Uuid().v4obj()"})," is used. On the database side, ",(0,s.jsx)(t.code,{children:"gen_random_uuid()"})," is used."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"UUID String"})}),(0,s.jsx)(t.td,{children:"A valid UUID version 4 string"}),(0,s.jsx)(t.td,{children:"Assigns a specific UUID to the field."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"uuidDefaultRandom: UuidValue, default=random\nuuidDefaultUuid: UuidValue, default='550e8400-e29b-41d4-a716-446655440000'\n"})}),"\n",(0,s.jsx)(t.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:'class: DefaultValue\ntable: default_value\nfields:\n ### Sets the current date and time as the default value.\n dateTimeDefault: DateTime, default=now\n\n ### Sets the default value for a boolean field.\n boolDefault: bool, defaultModel=false, defaultPersist=true\n\n ### Sets the default value for an integer field.\n intDefault: int, defaultPersist=20\n\n ### Sets the default value for a double field.\n doubleDefault: double, default=10.5, defaultPersist=20.5\n\n ### Sets the default value for a string field.\n stringDefault: String, default="This is a string", defaultModel="This is a string"\n'})}),"\n",(0,s.jsx)(t.h2,{id:"keywords-1",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"default"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for both the model and the database. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultModel"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the model side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultPersist"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the database side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"})," and ",(0,s.jsx)(t.strong,{children:"!persist"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>r});var s=n(96540);const d={},l=s.createContext(d);function i(e){const t=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),s.createElement(l.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[92113],{82853:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>i,default:()=>h,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var s=n(74848),d=n(28453);const l={},i="Working with models",r={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/docs/06-concepts/02-models.md",sourceDirName:"06-concepts",slug:"/concepts/models",permalink:"/next/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/docs/06-concepts/02-models.md",tags:[],version:"current",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/next/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/next/concepts/serialization"}},a={},c=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Default Values",id:"default-values",level:2},{value:"Keywords",id:"keywords",level:3},{value:"How priorities work",id:"how-priorities-work",level:3},{value:"Supported default values",id:"supported-default-values",level:3},{value:"Boolean",id:"boolean",level:4},{value:"DateTime",id:"datetime",level:4},{value:"Double",id:"double",level:4},{value:"Duration",id:"duration",level:4},{value:"Enum",id:"enum-1",level:4},{value:"Integer",id:"integer",level:4},{value:"String",id:"string",level:4},{value:"UuidValue",id:"uuidvalue",level:4},{value:"Example",id:"example",level:3},{value:"Keywords",id:"keywords-1",level:2}];function o(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.strong,{children:"none"})," is not typically used in serverpod apps. It is intended for the serverpod framework, itself."]})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 3 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"default-values",children:"Default Values"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod supports defining default values for fields in your models. These default values can be specified using three different keywords that determine how and where the defaults are applied:"}),"\n",(0,s.jsx)(t.h3,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"default"}),": This keyword sets a default value for both the model (code) and the database (persisted data). It acts as a general fallback if more specific defaults aren't provided."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultModel"}),": This keyword sets a default value specifically for the model (the code side). If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, the model will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"defaultPersist"}),": This keyword sets a default value specifically for the database. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, the database will use the value specified by ",(0,s.jsx)(t.code,{children:"default"})," if it's available."]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"how-priorities-work",children:"How priorities work"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the model (code side):"})," If both ",(0,s.jsx)(t.code,{children:"defaultModel"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the model will use the ",(0,s.jsx)(t.code,{children:"defaultModel"})," value. If ",(0,s.jsx)(t.code,{children:"defaultModel"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.strong,{children:"For the database (persisted data):"})," If both ",(0,s.jsx)(t.code,{children:"defaultPersist"})," and ",(0,s.jsx)(t.code,{children:"default"})," are provided, the database will use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value. If ",(0,s.jsx)(t.code,{children:"defaultPersist"})," is not provided, it will fall back to using the ",(0,s.jsx)(t.code,{children:"default"})," value."]}),"\n"]}),"\n",(0,s.jsx)(t.p,{children:"You can use these default values individually or in combination as needed. It is not required to use all default types for a field."}),"\n",(0,s.jsxs)(t.admonition,{type:"info",children:[(0,s.jsxs)(t.p,{children:["When using ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," in combination with ",(0,s.jsx)(t.code,{children:"defaultPersist"}),", it's important to understand how the interaction between these keywords affects the final value in the database."]}),(0,s.jsxs)(t.p,{children:["If you set a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," value, the model's field or variable will have a value when it's passed to the database\u2014it will not be ",(0,s.jsx)(t.code,{children:"null"}),". Because of this, the SQL query will not use the ",(0,s.jsx)(t.code,{children:"defaultPersist"})," value since the field already has a value assigned by the model. In essence, assigning a ",(0,s.jsx)(t.code,{children:"default"})," or ",(0,s.jsx)(t.code,{children:"defaultModel"})," is like directly providing a value to the field, and the database will use this provided value instead of its own default."]}),(0,s.jsxs)(t.p,{children:["This means that ",(0,s.jsx)(t.code,{children:"defaultPersist"})," only comes into play when the model does not provide a value, allowing the database to apply its own default setting."]})]}),"\n",(0,s.jsx)(t.h3,{id:"supported-default-values",children:"Supported default values"}),"\n",(0,s.jsx)(t.h4,{id:"boolean",children:"Boolean"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Boolean"})}),(0,s.jsxs)(t.td,{children:[(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a boolean value, either ",(0,s.jsx)(t.code,{children:"true"})," or ",(0,s.jsx)(t.code,{children:"false"}),"."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"boolDefault: bool, default=true\n"})}),"\n",(0,s.jsx)(t.h4,{id:"datetime",children:"DateTime"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Current Date and Time"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"now"})}),(0,s.jsx)(t.td,{children:"Sets the field to the current date and time."})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific UTC DateTime"})}),(0,s.jsxs)(t.td,{children:["UTC DateTime string in the format ",(0,s.jsx)(t.code,{children:"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"})]}),(0,s.jsx)(t.td,{children:"Sets the field to a specific date and time."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"dateTimeDefaultNow: DateTime, default=now\ndateTimeDefaultUtc: DateTime, default=2024-05-01T22:00:00.000Z\n"})}),"\n",(0,s.jsx)(t.h4,{id:"double",children:"Double"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Double"})}),(0,s.jsx)(t.td,{children:"Any double value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific double value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"doubleDefault: double, default=10.5\n"})}),"\n",(0,s.jsx)(t.h4,{id:"duration",children:"Duration"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Specific Duration"})}),(0,s.jsxs)(t.td,{children:["A valid duration in the format ",(0,s.jsx)(t.code,{children:"Xd Xh Xmin Xs Xms"})]}),(0,s.jsxs)(t.td,{children:["Sets the field to a specific duration value. For example, ",(0,s.jsx)(t.code,{children:"1d 2h 10min 30s 100ms"})," represents 1 day, 2 hours, 10 minutes, 30 seconds, and 100 milliseconds."]})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"durationDefault: Duration, default=1d 2h 10min 30s 100ms\n"})}),"\n",(0,s.jsx)(t.h4,{id:"enum-1",children:"Enum"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Enum"})}),(0,s.jsx)(t.td,{children:"Any valid enum value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific enum value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByNameEnum\nserialized: byName\nvalues:\n - byName1\n - byName2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: ByIndexEnum\nserialized: byIndex\nvalues:\n - byIndex1\n - byIndex2\n"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: EnumDefault\ntable: enum_default\nfields:\n byNameEnumDefault: ByNameEnum, default=byName1\n byIndexEnumDefault: ByIndexEnum, default=byIndex1\n"})}),"\n",(0,s.jsx)(t.p,{children:"In this example:"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byNameEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"'byName1'"})," in the database."]}),"\n",(0,s.jsxs)(t.li,{children:["The ",(0,s.jsx)(t.code,{children:"byIndexEnumDefault"})," field will default to ",(0,s.jsx)(t.code,{children:"0"})," (the index of ",(0,s.jsx)(t.code,{children:"byIndex1"}),")."]}),"\n"]}),"\n",(0,s.jsx)(t.h4,{id:"integer",children:"Integer"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Integer"})}),(0,s.jsx)(t.td,{children:"Any integer value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific integer value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"intDefault: int, default=10\n"})}),"\n",(0,s.jsx)(t.h4,{id:"string",children:"String"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsx)(t.tbody,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"String"})}),(0,s.jsx)(t.td,{children:"Any string value"}),(0,s.jsx)(t.td,{children:"Sets the field to a specific string value."})]})})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"stringDefault: String, default='This is a string'\n"})}),"\n",(0,s.jsx)(t.h4,{id:"uuidvalue",children:"UuidValue"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:"Type"}),(0,s.jsx)(t.th,{children:"Keyword"}),(0,s.jsx)(t.th,{children:"Description"})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"Random UUID"})}),(0,s.jsx)(t.td,{children:(0,s.jsx)(t.code,{children:"random"})}),(0,s.jsxs)(t.td,{children:["Generates a random UUID. On the Dart side, ",(0,s.jsx)(t.code,{children:"Uuid().v4obj()"})," is used. On the database side, ",(0,s.jsx)(t.code,{children:"gen_random_uuid()"})," is used."]})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.strong,{children:"UUID String"})}),(0,s.jsx)(t.td,{children:"A valid UUID version 4 string"}),(0,s.jsx)(t.td,{children:"Assigns a specific UUID to the field."})]})]})]}),"\n",(0,s.jsx)(t.p,{children:(0,s.jsx)(t.strong,{children:"Example:"})}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"uuidDefaultRandom: UuidValue, default=random\nuuidDefaultUuid: UuidValue, default='550e8400-e29b-41d4-a716-446655440000'\n"})}),"\n",(0,s.jsx)(t.h3,{id:"example",children:"Example"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:'class: DefaultValue\ntable: default_value\nfields:\n ### Sets the current date and time as the default value.\n dateTimeDefault: DateTime, default=now\n\n ### Sets the default value for a boolean field.\n boolDefault: bool, defaultModel=false, defaultPersist=true\n\n ### Sets the default value for an integer field.\n intDefault: int, defaultPersist=20\n\n ### Sets the default value for a double field.\n doubleDefault: double, default=10.5, defaultPersist=20.5\n\n ### Sets the default value for a string field.\n stringDefault: String, default="This is a string", defaultModel="This is a string"\n'})}),"\n",(0,s.jsx)(t.h2,{id:"keywords-1",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"default"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for both the model and the database. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultModel"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the model side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#default-values",children:(0,s.jsx)(t.strong,{children:"defaultPersist"})})}),(0,s.jsxs)(t.td,{children:["Sets the default value for the database side. This keyword cannot be used with ",(0,s.jsx)(t.strong,{children:"relation"})," and ",(0,s.jsx)(t.strong,{children:"!persist"}),"."]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,d.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(o,{...e})}):o(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>i,x:()=>r});var s=n(96540);const d={},l=s.createContext(d);function i(e){const t=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:i(e.components),s.createElement(l.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/441fd5fc.c6c289b1.js b/docs/assets/js/441fd5fc.fa9f8a31.js
similarity index 99%
rename from docs/assets/js/441fd5fc.c6c289b1.js
rename to docs/assets/js/441fd5fc.fa9f8a31.js
index c78cd4fa6..7d8dbd823 100644
--- a/docs/assets/js/441fd5fc.c6c289b1.js
+++ b/docs/assets/js/441fd5fc.fa9f8a31.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[37990],{87360:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>o});var s=n(74848),i=n(28453);const r={},d="Working with models",l={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-2.0.0/05-concepts/02-models.md",sourceDirName:"05-concepts",slug:"/concepts/models",permalink:"/2.0.0/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.0.0/05-concepts/02-models.md",tags:[],version:"2.0.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/2.0.0/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/2.0.0/concepts/serialization"}},a={},o=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Keywords",id:"keywords",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 2 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>l});var s=n(96540);const i={},r=s.createContext(i);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[37990],{87360:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>o});var s=n(74848),i=n(28453);const r={},d="Working with models",l={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-2.0.0/05-concepts/02-models.md",sourceDirName:"05-concepts",slug:"/concepts/models",permalink:"/2.0.0/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.0.0/05-concepts/02-models.md",tags:[],version:"2.0.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/2.0.0/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/2.0.0/concepts/serialization"}},a={},o=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Keywords",id:"keywords",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 3 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>l});var s=n(96540);const i={},r=s.createContext(i);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/7ac69e68.07813519.js b/docs/assets/js/7ac69e68.e3dc9e21.js
similarity index 93%
rename from docs/assets/js/7ac69e68.07813519.js
rename to docs/assets/js/7ac69e68.e3dc9e21.js
index 1a0c1d73a..3c5102a87 100644
--- a/docs/assets/js/7ac69e68.07813519.js
+++ b/docs/assets/js/7ac69e68.e3dc9e21.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[27168],{65650:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/versioned_docs/version-2.0.0/12-upgrading/01-upgrade-to-two.md",sourceDirName:"12-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/2.0.0/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.0.0/12-upgrading/01-upgrade-to-two.md",tags:[],version:"2.0.0",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Contribute",permalink:"/2.0.0/contribute"},next:{title:"Upgrade to 1.2",permalink:"/2.0.0/upgrading/upgrade-to-one-point-two"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 2.1. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[27168],{65650:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/versioned_docs/version-2.0.0/12-upgrading/01-upgrade-to-two.md",sourceDirName:"12-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/2.0.0/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.0.0/12-upgrading/01-upgrade-to-two.md",tags:[],version:"2.0.0",sidebarPosition:1,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Contribute",permalink:"/2.0.0/contribute"},next:{title:"Upgrade to 1.2",permalink:"/2.0.0/upgrading/upgrade-to-one-point-two"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 3. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/8615e055.46cbd86e.js b/docs/assets/js/8615e055.a738aae6.js
similarity index 93%
rename from docs/assets/js/8615e055.46cbd86e.js
rename to docs/assets/js/8615e055.a738aae6.js
index 89fcf8cc5..3e3f9985b 100644
--- a/docs/assets/js/8615e055.46cbd86e.js
+++ b/docs/assets/js/8615e055.a738aae6.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[76238],{16681:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/docs/08-upgrading/03-upgrade-to-two.md",sourceDirName:"08-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/next/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/docs/08-upgrading/03-upgrade-to-two.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrade to 1.2",permalink:"/next/upgrading/upgrade-to-one-point-two"},next:{title:"Serverpod Insights",permalink:"/next/tools/insights"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 2.1. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[76238],{16681:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/docs/08-upgrading/03-upgrade-to-two.md",sourceDirName:"08-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/next/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/docs/08-upgrading/03-upgrade-to-two.md",tags:[],version:"current",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrade to 1.2",permalink:"/next/upgrading/upgrade-to-one-point-two"},next:{title:"Serverpod Insights",permalink:"/next/tools/insights"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 3. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/ac5db01d.433c50c6.js b/docs/assets/js/ac5db01d.bf926c46.js
similarity index 93%
rename from docs/assets/js/ac5db01d.433c50c6.js
rename to docs/assets/js/ac5db01d.bf926c46.js
index 17b58d5bb..f36c102a8 100644
--- a/docs/assets/js/ac5db01d.433c50c6.js
+++ b/docs/assets/js/ac5db01d.bf926c46.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[97785],{56458:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/versioned_docs/version-2.1.0/08-upgrading/03-upgrade-to-two.md",sourceDirName:"08-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.1.0/08-upgrading/03-upgrade-to-two.md",tags:[],version:"2.1.0",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrade to 1.2",permalink:"/upgrading/upgrade-to-one-point-two"},next:{title:"Serverpod Insights",permalink:"/tools/insights"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 2.1. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[97785],{56458:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>l});var a=t(74848),i=t(28453);const s={},r="Upgrade to 2.0",o={id:"upgrading/upgrade-to-two",title:"Upgrade to 2.0",description:"Changes to authentication",source:"@site/versioned_docs/version-2.1.0/08-upgrading/03-upgrade-to-two.md",sourceDirName:"08-upgrading",slug:"/upgrading/upgrade-to-two",permalink:"/upgrading/upgrade-to-two",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-2.1.0/08-upgrading/03-upgrade-to-two.md",tags:[],version:"2.1.0",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Upgrade to 1.2",permalink:"/upgrading/upgrade-to-one-point-two"},next:{title:"Serverpod Insights",permalink:"/tools/insights"}},d={},l=[{value:"Changes to authentication",id:"changes-to-authentication",level:2},{value:"Advanced integrations",id:"advanced-integrations",level:3},{value:"Changes to the Session Object",id:"changes-to-the-session-object",level:2},{value:"Removed deprecated fields",id:"removed-deprecated-fields",level:3},{value:"Authenticated user information retrieval",id:"authenticated-user-information-retrieval",level:3},{value:"Authentication helpers",id:"authentication-helpers",level:3},{value:"Changes to database queries",id:"changes-to-database-queries",level:2},{value:"Removed unsafeQueryMappedResults(...)",id:"removed-unsafequerymappedresults",level:3},{value:"Update return type for delete operations",id:"update-return-type-for-delete-operations",level:3},{value:"Changes to database tables",id:"changes-to-database-tables",level:2},{value:"Integer representation changed to bigint",id:"integer-representation-changed-to-bigint",level:3},{value:"Why is this change made?",id:"why-is-this-change-made",level:4},{value:"Ensuring new databases are created with the new representation",id:"ensuring-new-databases-are-created-with-the-new-representation",level:4},{value:"Migration of existing tables",id:"migration-of-existing-tables",level:4},{value:"Small tables",id:"small-tables",level:5},{value:"Large tables",id:"large-tables",level:5},{value:"Changes in the authentication module",id:"changes-in-the-authentication-module",level:2},{value:"Unsecure random disabled by default",id:"unsecure-random-disabled-by-default",level:3},{value:"Updates to Serialization in Serverpod 2.0",id:"updates-to-serialization-in-serverpod-20",level:2},{value:"General Changes to Model Serialization",id:"general-changes-to-model-serialization",level:3},{value:"Before change",id:"before-change",level:4},{value:"After change",id:"after-change",level:4},{value:"Enhancements for Custom Serialization",id:"enhancements-for-custom-serialization",level:3},{value:"Previous Implementation",id:"previous-implementation",level:4},{value:"Updated Implementation",id:"updated-implementation",level:4},{value:"Deprecation Notice for SerializableEntity",id:"deprecation-notice-for-serializableentity",level:2},{value:"Migration Guide",id:"migration-guide",level:3},{value:"Example",id:"example",level:4}];function c(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"upgrade-to-20",children:"Upgrade to 2.0"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-authentication",children:"Changes to authentication"}),"\n",(0,a.jsxs)(n.p,{children:["The base auth implementation has been removed from Serverpod core and moved into the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," package. If you are not using authentication at all this change does not impact you. If you are using the auth module already the transition is simple."]}),"\n",(0,a.jsxs)(n.p,{children:["The default authentication handler will now throw an ",(0,a.jsx)(n.code,{children:"UnimplementedError"}),". It is now required to supply the authentication handler to the Serverpod object, in your server.dart file make the following change:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"import 'package:serverpod_auth_server/serverpod_auth_server.dart' as auth;\n\nvoid run(List args) async {\n var pod = Serverpod(\n args,\n Protocol(),\n Endpoints(),\n authenticationHandler: auth.authenticationHandler, // Add this line\n );\n\n ...\n}\n"})}),"\n",(0,a.jsx)(n.h3,{id:"advanced-integrations",children:"Advanced integrations"}),"\n",(0,a.jsxs)(n.p,{children:["The methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," now takes the session object as a param and is no longer available on the session object. Instead import the class ",(0,a.jsx)(n.code,{children:"UserAuthentication"})," from the auth module to access these static methods."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"UserAuthentication.signInUser(session, userId, 'provider');\n\nUserAuthentication.signOutUser(session);\n"})}),"\n",(0,a.jsxs)(n.p,{children:["The table ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," has been removed from Serverpod core but is available in the serverpod_auth module instead. This means that if you wrote a custom integration before without using the serverpod_auth module you have to take care of managing your token implementation."]}),"\n",(0,a.jsxs)(n.p,{children:["Adding the definition of the ",(0,a.jsx)(n.code,{children:"serverpod_auth_key"})," table to your project is the simplest way to do a seamless migration."]}),"\n",(0,a.jsx)(n.p,{children:"The table was defined in the following way:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-yaml",children:"### Provides a method of access for a user to authenticate with the server.\nclass: AuthKey\ntable: serverpod_auth_key\nfields:\n ### The id of the user to provide access to.\n userId: int\n\n ### The hashed version of the key.\n hash: String\n\n ### The key sent to the server to authenticate.\n key: String?, !persist\n\n ### The scopes this key provides access to.\n scopeNames: List\n\n ### The method of signing in this key was generated through. This can be email\n ### or different social logins.\n method: String\nindexes:\n serverpod_auth_key_userId_idx:\n fields: userId\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Your are then responsible for creating/removing entries in this table, the old ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," that used to provide this functionality can be found ",(0,a.jsx)(n.a,{href:"https://github.com/serverpod/serverpod/blob/13795a7bd4c0cc5a03101b6f378cb914673046dd/packages/serverpod/lib/src/server/session.dart#L359-L394",children:"here"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-the-session-object",children:"Changes to the Session Object"}),"\n",(0,a.jsx)(n.h3,{id:"removed-deprecated-fields",children:"Removed deprecated fields"}),"\n",(0,a.jsxs)(n.p,{children:["With Serverpod 2.0, we have removed the deprecated legacy database layer from the ",(0,a.jsx)(n.code,{children:"Session"})," object. The ",(0,a.jsx)(n.code,{children:"Session"})," object now incorporates the new database layer, accessed via the ",(0,a.jsx)(n.code,{children:"dbNext"})," field in Serverpod 1.2, under the ",(0,a.jsx)(n.code,{children:"db"})," field."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.dbNext.find(...);\n"})}),"\n",(0,a.jsx)(n.p,{children:"becomes"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"session.db.find(...);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"authenticated-user-information-retrieval",children:"Authenticated user information retrieval"}),"\n",(0,a.jsxs)(n.p,{children:["In Serverpod 2.0, we have removed the getters ",(0,a.jsx)(n.code,{children:"scopes"})," and ",(0,a.jsx)(n.code,{children:"authenticatedUser"})," from session. This information is now retrievable through the ",(0,a.jsx)(n.code,{children:"authenticated"})," getter as fields of the returned object."]}),"\n",(0,a.jsx)(n.p,{children:"Replace this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int? userId = await session.auth.authenticatedUser;\n\nSet? scopes = await session.scopes;\n"})}),"\n",(0,a.jsx)(n.p,{children:"With this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final authenticated = await session.authenticated;\n\n//Read authenticated userId\nint? userId = authenticated?.userId;\n\n//Read scopes\nSet? scopes = authenticated?.scopes;\n"})}),"\n",(0,a.jsxs)(n.p,{children:["If the ",(0,a.jsx)(n.code,{children:"authenticated"})," property is set on the session it effectively means there is an authenticated user making the request."]}),"\n",(0,a.jsx)(n.h3,{id:"authentication-helpers",children:"Authentication helpers"}),"\n",(0,a.jsxs)(n.p,{children:["The field ",(0,a.jsx)(n.code,{children:"auth"})," has been removed and the methods ",(0,a.jsx)(n.code,{children:"signInUser"})," and ",(0,a.jsx)(n.code,{children:"signOutUser"})," have been moved to the ",(0,a.jsx)(n.code,{children:"serverpod_auth"})," module."]}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-queries",children:"Changes to database queries"}),"\n",(0,a.jsx)(n.h3,{id:"removed-unsafequerymappedresults",children:"Removed unsafeQueryMappedResults(...)"}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," method has been removed. A similar result can now instead be formatted from the ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," result by calling the ",(0,a.jsx)(n.code,{children:"toColumnMap()"})," method for each row of the result. ",(0,a.jsx)(n.code,{children:"toColumnMap"})," returns a map containing the query alias for the column as key and the row-column value as value."]}),"\n",(0,a.jsx)(n.p,{children:"Given a query that performs a join like this:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "company"."id" AS "company.id",\n "company"."name" AS "company.name",\n "company"."townId" AS "company.townId",\n "company_town_town"."id" AS "company_town_town.id",\n "company_town_town"."name" AS "company_town_town.name",\n "company_town_town"."mayorId" AS "company_town_town.mayorId"\nFROM\n "company"\nLEFT JOIN\n "town" AS "company_town_town" ON "company"."townId" = "company_town_town"."id"\nORDER BY\n "company"."name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "company.id": 40,\n "company.name": "Apple",\n "company.townId": 64\n },\n "town": {\n "company_town_town.id": 64,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n }\n },\n {\n "company": {\n "company.id": 39,\n "company.name": "Serverpod",\n "company.townId": 63\n },\n "town": {\n "company_town_town.id": 63,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["And if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company.id": 38,\n "company.name": "Apple",\n "company.townId": 62,\n "company_town_town.id": 62,\n "company_town_town.name": "San Francisco",\n "company_town_town.mayorId": null\n },\n {\n "company.id": 37,\n "company.name": "Serverpod",\n "company.townId": 61,\n "company_town_town.id": 61,\n "company_town_town.name": "Stockholm",\n "company_town_town.mayorId": null\n }\n]\n'})}),"\n",(0,a.jsx)(n.p,{children:"or for a simple query without aliases:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'SELECT\n "id",\n "name",\n "townId"\nFROM\n "company"\nORDER BY\n "name"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["the return type from ",(0,a.jsx)(n.code,{children:"unsafeQueryMappedResults(...)"})," in 1.2 was:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'[\n {\n "company": {\n "id": 54,\n "name": "Apple",\n "townId": 86\n }\n },\n {\n "company": {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n }\n]\n'})}),"\n",(0,a.jsxs)(n.p,{children:["and if ",(0,a.jsx)(n.code,{children:"result.map((row) => row.toColumnMap())"})," is used to format the result from ",(0,a.jsx)(n.code,{children:"unsafeQuery(...)"})," in 2.0, the following result is obtained:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:' [\n {\n "id": 54,\n "name": "Apple",\n "townId": 86\n },\n {\n "id": 53,\n "name": "Serverpod",\n "townId": 85\n }\n]\n'})}),"\n",(0,a.jsx)(n.h3,{id:"update-return-type-for-delete-operations",children:"Update return type for delete operations"}),"\n",(0,a.jsxs)(n.p,{children:["The return type for all delete operations has been changed from the ",(0,a.jsx)(n.code,{children:"id"})," of the deleted rows to the actual deleted rows. This makes the return type for the delete operations consistent with the return type of the other database operations. It also dramatically simplifies retrieving and removing rows in concurrent environments."]}),"\n",(0,a.jsx)(n.p,{children:"Return type before the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"int companyId = await Company.db.deleteRow(session, company);\nList companyIds = await Company.db.delete(session, [company]);\nList companyIds = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.p,{children:"Return types after the change:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"Company company = await Company.db.deleteRow(session, company);\nList companies = await Company.db.delete(session, [company]);\nList companies = await Company.db.deleteWhere(session, where: (t) => t.name.like('%Ltd'));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"changes-to-database-tables",children:"Changes to database tables"}),"\n",(0,a.jsx)(n.h3,{id:"integer-representation-changed-to-bigint",children:"Integer representation changed to bigint"}),"\n",(0,a.jsxs)(n.p,{children:["Integer representation in the database has changed from ",(0,a.jsx)(n.code,{children:"int"})," to ",(0,a.jsx)(n.code,{children:"bigint"}),". From now on, models with ",(0,a.jsx)(n.code,{children:"int"})," fields will generate database migrations where that field is defined as a ",(0,a.jsx)(n.code,{children:"bigint"})," type in the database."]}),"\n",(0,a.jsxs)(n.p,{children:["This change also applies to the ",(0,a.jsx)(n.code,{children:"id"})," field of models where ",(0,a.jsx)(n.code,{children:"bigserial"})," is now used to generate the id."]}),"\n",(0,a.jsx)(n.p,{children:"The change is compatible with existing databases. Existing migrations therefore, won't be changed by the Serverpod migration system. No manual modification to the database is required if this data representation is not essential for the application. However, all new migrations will be created with the new representation."}),"\n",(0,a.jsx)(n.h4,{id:"why-is-this-change-made",children:"Why is this change made?"}),"\n",(0,a.jsxs)(n.p,{children:["The change was made to ensure that ",(0,a.jsx)(n.a,{href:"https://dart.dev/guides/language/numbers",children:"Dart"})," and the database representation of integers is consistent. Dart uses 64-bit integers, and the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart is a 64-bit integer. The ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL is a 32-bit integer. This means that the ",(0,a.jsx)(n.code,{children:"int"})," type in Dart can represent larger numbers than the ",(0,a.jsx)(n.code,{children:"int"})," type in PostgreSQL. By using ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL, the integer representation is consistent between Dart and the database."]}),"\n",(0,a.jsxs)(n.p,{children:["In terms of performance, there are usually no significant drawbacks with using ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". In most cases a good index strategy will be more important than the integer representation. Here is a guide that benchmarks the performance of ",(0,a.jsx)(n.code,{children:"int"})," and ",(0,a.jsx)(n.code,{children:"bigint"})," in PostgreSQL: ",(0,a.jsx)(n.a,{href:"https://blog.rustprooflabs.com/2021/06/postgres-bigint-by-default",children:"Use BIGINT in Postgres"})]}),"\n",(0,a.jsx)(n.h4,{id:"ensuring-new-databases-are-created-with-the-new-representation",children:"Ensuring new databases are created with the new representation"}),"\n",(0,a.jsxs)(n.p,{children:["Since existing migrations won't be changed, databases that are created with these will still use ",(0,a.jsx)(n.code,{children:"int"})," to represent integers."]}),"\n",(0,a.jsx)(n.p,{children:"To ensure new databases are created with the new representation, the latest migration should be generated using Serverpod 2.0. It is enough to have an empty migration to ensure new databases use the new representation."}),"\n",(0,a.jsx)(n.p,{children:"A new empty migration can be created by running the following command in the terminal:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:"$ serverpod create-migration --force\n"})}),"\n",(0,a.jsx)(n.h4,{id:"migration-of-existing-tables",children:"Migration of existing tables"}),"\n",(0,a.jsx)(n.p,{children:"The migration of existing tables to use the new representation will vary depending on the database content. Utilizing the wrong migration strategy might cause downtime for your application. That is the reason Serverpod does not automatically migrate existing tables."}),"\n",(0,a.jsx)(n.h5,{id:"small-tables",children:"Small tables"}),"\n",(0,a.jsx)(n.p,{children:"A simple way to migrate for small tables is to execute the following sql query to the database:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-sql",children:'ALTER SEQUENCE "my_table_id_seq" AS bigint;\nALTER TABLE "my_table" ALTER "id" TYPE bigint;\nALTER TABLE "my_table" ALTER "myNumber" TYPE bigint;\n'})}),"\n",(0,a.jsxs)(n.p,{children:["The first two lines modify the id sequence for a table named ",(0,a.jsx)(n.code,{children:'"my_table"'})," to use ",(0,a.jsx)(n.code,{children:"bigint"})," instead of ",(0,a.jsx)(n.code,{children:"int"}),". The last line modifies a column of the same table to use ",(0,a.jsx)(n.code,{children:"bigint"}),". The drawback of this approach is that it locks the table during the migration. Therefore, this strategy is not recommended for large tables."]}),"\n",(0,a.jsx)(n.h5,{id:"large-tables",children:"Large tables"}),"\n",(0,a.jsx)(n.p,{children:"Migrating large tables without application downtime is a more complex operation, and the approach will vary depending on the data structure. Below are some gathered resources on the subject."}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"http://zemanta.github.io/2021/08/25/column-migration-from-int-to-bigint-in-postgresql/",children:"Zemata - Column migration from INT to BIGINT"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://am2.co/2019/12/changing-a-column-from-int-to-bigint-without-downtime/",children:"AM^2 - Changing a column from int to bigint, without downtime"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://www.crunchydata.com/blog/the-integer-at-the-end-of-the-universe-integer-overflow-in-postgres",children:"Crunch data - The integer at the End of the Universe"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"changes-in-the-authentication-module",children:"Changes in the authentication module"}),"\n",(0,a.jsx)(n.h3,{id:"unsecure-random-disabled-by-default",children:"Unsecure random disabled by default"}),"\n",(0,a.jsxs)(n.p,{children:["The authentication module's default value for allowing unsecure random number generation is now ",(0,a.jsx)(n.code,{children:"false"}),". An exception will be thrown when trying to hash a password if no secure random number generator is available. To preserve the old behavior and enable unsecure random number generation, set the ",(0,a.jsx)(n.code,{children:"allowUnsecureRandom"})," property in the ",(0,a.jsx)(n.code,{children:"AuthConfig"})," to ",(0,a.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"auth.AuthConfig.set(auth.AuthConfig(\n allowUnsecureRandom: true,\n));\n"})}),"\n",(0,a.jsx)(n.h2,{id:"updates-to-serialization-in-serverpod-20",children:"Updates to Serialization in Serverpod 2.0"}),"\n",(0,a.jsx)(n.h3,{id:"general-changes-to-model-serialization",children:"General Changes to Model Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["Serverpod 2.0 significantly streamlines the model serialization process. In earlier versions, the ",(0,a.jsx)(n.code,{children:"fromJson"})," factory constructors needed a ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter to handle object deserialization. This parameter has now been removed, enhancing simplicity and usability."]}),"\n",(0,a.jsx)(n.h4,{id:"before-change",children:"Before change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal SerializationManager serializationManager = Protocol();\nfinal ClassName test = ClassName.fromJson(json, serializationManager);\n"})}),"\n",(0,a.jsx)(n.h4,{id:"after-change",children:"After change"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"final Map json = classInstance.toJson();\nfinal ClassName test = ClassName.fromJson(json);\n"})}),"\n",(0,a.jsx)(n.h3,{id:"enhancements-for-custom-serialization",children:"Enhancements for Custom Serialization"}),"\n",(0,a.jsxs)(n.p,{children:["The removal of the ",(0,a.jsx)(n.code,{children:"serializationManager"})," parameter in Serverpod 2.0 simplifies the serialization process not only for general models but also significantly enhances custom serialization workflows.\nFor custom classes that previously utilized unique serialization logic with the ",(0,a.jsx)(n.code,{children:"serializationManager"}),", adjustments may be necessary."]}),"\n",(0,a.jsx)(n.h4,{id:"previous-implementation",children:"Previous Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["In the previous versions, models required the ",(0,a.jsx)(n.code,{children:"serializationManager"})," to be passed explicitly, as shown in the following code snippet:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n SerializationManager serializationManager,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsx)(n.h4,{id:"updated-implementation",children:"Updated Implementation"}),"\n",(0,a.jsxs)(n.p,{children:["With the release of Serverpod 2.0, the ",(0,a.jsx)(n.code,{children:"fromJson"})," constructor has been simplified and the ",(0,a.jsx)(n.code,{children:"serializationManager"})," has been removed:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"factory ClassName.fromJson(\n Map json,\n ) {\n return ClassName(\n json['name'],\n );\n }\n"})}),"\n",(0,a.jsxs)(n.h2,{id:"deprecation-notice-for-serializableentity",children:["Deprecation Notice for ",(0,a.jsx)(n.code,{children:"SerializableEntity"})]}),"\n",(0,a.jsxs)(n.p,{children:["The ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," class is deprecated and will be removed in version 3. Please implement the ",(0,a.jsx)(n.code,{children:"SerializableModel"})," interface instead for creating serializable models."]}),"\n",(0,a.jsx)(n.h3,{id:"migration-guide",children:"Migration Guide"}),"\n",(0,a.jsxs)(n.p,{children:["To migrate your code from ",(0,a.jsx)(n.code,{children:"SerializableEntity"})," to ",(0,a.jsx)(n.code,{children:"SerializableModel"}),", replace ",(0,a.jsx)(n.code,{children:"extends SerializableEntity"})," with ",(0,a.jsx)(n.code,{children:"implements SerializableModel"})," in your model classes."]}),"\n",(0,a.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"Before:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass extends SerializableEntity {\n // Your code here\n}\n"})}),"\n",(0,a.jsx)(n.p,{children:(0,a.jsx)(n.strong,{children:"After:"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-dart",children:"class CustomClass implements SerializableModel {\n // Your code here\n}\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(c,{...e})}):c(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>o});var a=t(96540);const i={},s=a.createContext(i);function r(e){const n=a.useContext(s);return a.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),a.createElement(s.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/cce58fe7.dbb843db.js b/docs/assets/js/cce58fe7.dd0a4d50.js
similarity index 99%
rename from docs/assets/js/cce58fe7.dbb843db.js
rename to docs/assets/js/cce58fe7.dd0a4d50.js
index b36d90937..11a6c5801 100644
--- a/docs/assets/js/cce58fe7.dbb843db.js
+++ b/docs/assets/js/cce58fe7.dd0a4d50.js
@@ -1 +1 @@
-"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[6157],{53451:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>o});var s=n(74848),i=n(28453);const r={},d="Working with models",l={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-1.2.0/05-concepts/02-models.md",sourceDirName:"05-concepts",slug:"/concepts/models",permalink:"/1.2.0/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.2.0/05-concepts/02-models.md",tags:[],version:"1.2.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/1.2.0/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/1.2.0/concepts/serialization"}},a={},o=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Keywords",id:"keywords",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 2 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>l});var s=n(96540);const i={},r=s.createContext(i);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[6157],{53451:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>d,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>o});var s=n(74848),i=n(28453);const r={},d="Working with models",l={id:"concepts/models",title:"Working with models",description:'Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular .yaml files within lib/src/models is supported, but it is recommended to use .spy.yaml (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the Serverpod Extension for VS Code.',source:"@site/versioned_docs/version-1.2.0/05-concepts/02-models.md",sourceDirName:"05-concepts",slug:"/concepts/models",permalink:"/1.2.0/concepts/models",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.2.0/05-concepts/02-models.md",tags:[],version:"1.2.0",sidebarPosition:2,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Working with endpoints",permalink:"/1.2.0/concepts/working-with-endpoints"},next:{title:"Custom serialization",permalink:"/1.2.0/concepts/serialization"}},a={},o=[{value:"Class",id:"class",level:2},{value:"Limiting visibility of a generated class",id:"limiting-visibility-of-a-generated-class",level:3},{value:"Exception",id:"exception",level:2},{value:"Enum",id:"enum",level:2},{value:"Adding documentation",id:"adding-documentation",level:2},{value:"Generated code",id:"generated-code",level:2},{value:"copyWith",id:"copywith",level:3},{value:"toJson / fromJson",id:"tojson--fromjson",level:3},{value:"Custom methods",id:"custom-methods",level:3},{value:"Keywords",id:"keywords",level:2}];function c(e){const t={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"working-with-models",children:"Working with models"})}),"\n",(0,s.jsxs)(t.p,{children:["Models are Yaml files used to define serializable classes in Serverpod. They are used to generate Dart code for the server and client, and, if a database table is defined, to generate database code for the server. Using regular ",(0,s.jsx)(t.code,{children:".yaml"})," files within ",(0,s.jsx)(t.code,{children:"lib/src/models"})," is supported, but it is recommended to use ",(0,s.jsx)(t.code,{children:".spy.yaml"}),' (.spy stands for "Server Pod Yaml") to leverage syntax highlighting provided by the ',(0,s.jsx)(t.a,{href:"https://marketplace.visualstudio.com/items?itemName=serverpod.serverpod",children:"Serverpod Extension"})," for VS Code."]}),"\n",(0,s.jsx)(t.p,{children:"The files are analyzed by the Serverpod CLI when generating the project and creating migrations."}),"\n",(0,s.jsxs)(t.p,{children:["Run ",(0,s.jsx)(t.code,{children:"serverpod generate"})," to generate dart classes from the model files."]}),"\n",(0,s.jsx)(t.h2,{id:"class",children:"Class"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: Company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(t.p,{children:["Supported types are ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/bool-class.html",children:"bool"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/int-class.html",children:"int"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/double-class.html",children:"double"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/String-class.html",children:"String"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Duration-class.html",children:"Duration"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/DateTime-class.html",children:"DateTime"}),", ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-typed_data/ByteData-class.html",children:"ByteData"}),", ",(0,s.jsx)(t.a,{href:"https://pub.dev/documentation/uuid/latest/uuid_value/UuidValue-class.html",children:"UuidValue"}),", and other serializable ",(0,s.jsx)(t.a,{href:"#class",children:"classes"}),", ",(0,s.jsx)(t.a,{href:"#exception",children:"exceptions"})," and ",(0,s.jsx)(t.a,{href:"#enum",children:"enums"}),". You can also use ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/List-class.html",children:"List"}),"s and ",(0,s.jsx)(t.a,{href:"https://api.dart.dev/dart-core/Map-class.html",children:"Map"}),"s of the supported types, just make sure to specify the types. Null safety is supported. Once your classes are generated, you can use them as parameters or return types to endpoint methods."]}),"\n",(0,s.jsx)(t.h3,{id:"limiting-visibility-of-a-generated-class",children:"Limiting visibility of a generated class"}),"\n",(0,s.jsx)(t.p,{children:"By default, generated code for your serializable objects is available both on the server and the client. You may want to have the code on the server side only. E.g., if the serializable object is connected to a database table containing private information."}),"\n",(0,s.jsx)(t.p,{children:"To make a serializable class generated only on the server side, set the serverOnly property to true."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: MyPrivateClass\nserverOnly: true\nfields:\n hiddenSecretKey: String\n"})}),"\n",(0,s.jsxs)(t.p,{children:["It is also possible to set a ",(0,s.jsx)(t.code,{children:"scope"})," on a per-field basis. By default all fields are visible to both the server and the client. The available scopes are ",(0,s.jsx)(t.code,{children:"all"}),", ",(0,s.jsx)(t.code,{children:"serverOnly"}),", ",(0,s.jsx)(t.code,{children:"none"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"class: SelectivelyHiddenClass\nfields:\n hiddenSecretKey: String, scope=serverOnly\n publicKey: String\n"})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Serverpod's models can easily be saved to or read from the database. You can read more about this in the ",(0,s.jsx)(t.a,{href:"database/models",children:"Database"})," section."]})}),"\n",(0,s.jsx)(t.h2,{id:"exception",children:"Exception"}),"\n",(0,s.jsxs)(t.p,{children:["The Serverpod models supports creating exceptions that can be thrown in endpoints by using the ",(0,s.jsx)(t.code,{children:"exception"})," keyword. For more in-depth description on how to work with exceptions see ",(0,s.jsx)(t.a,{href:"exceptions",children:"Error handling and exceptions"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"exception: MyException\nfields:\n message: String\n errorType: MyEnum\n"})}),"\n",(0,s.jsx)(t.h2,{id:"enum",children:"Enum"}),"\n",(0,s.jsxs)(t.p,{children:["It is easy to add custom enums with serialization support by using the ",(0,s.jsx)(t.code,{children:"enum"})," keyword."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsx)(t.p,{children:"By default the serialization will convert the enum to an int representing the index of the value. Changing the order may therefore have unforeseen consequences when reusing old data (such as from a database). Changing the serialization to be based on the name instead of index is easy."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"enum: Animal\nserialized: byName\nvalues:\n - dog\n - cat\n - bird\n"})}),"\n",(0,s.jsxs)(t.p,{children:[(0,s.jsx)(t.code,{children:"serialized"})," has two valid values ",(0,s.jsx)(t.code,{children:"byName"})," and ",(0,s.jsx)(t.code,{children:"byIndex"}),". When using ",(0,s.jsx)(t.code,{children:"byName"})," the string literal of the enum is used, when using ",(0,s.jsx)(t.code,{children:"byIndex"})," the index value (0, 1, 2, etc) is used."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["It's recommended to always set ",(0,s.jsx)(t.code,{children:"serialized"})," to ",(0,s.jsx)(t.code,{children:"byName"})," in any new Enum models, as this is less fragile and will be changed to the default setting in version 3 of Serverpod."]})}),"\n",(0,s.jsx)(t.h2,{id:"adding-documentation",children:"Adding documentation"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation."}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-yaml",children:"### Information about a company.\nclass: Company\nfields:\n ### The name of the company.\n name: String\n\n ### The date the company was founded, if known.\n foundedDate: DateTime?\n\n ### A list of people currently employed at the company.\n employees: List\n"})}),"\n",(0,s.jsx)(t.h2,{id:"generated-code",children:"Generated code"}),"\n",(0,s.jsx)(t.p,{children:"Serverpod generates some convenience methods on the Dart classes."}),"\n",(0,s.jsx)(t.h3,{id:"copywith",children:"copyWith"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method allows for efficient object copying with selective field updates and is available on all generated ",(0,s.jsx)(t.code,{children:"class"}),"es. Here's how it operates:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"var john = User(name: 'John Doe', age: 25);\nvar jane = john.copyWith(name: 'Jane Doe');\n"})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"copyWith"})," method generates a deep copy of an object, preserving all original fields unless explicitly modified. It can distinguish between a field set to ",(0,s.jsx)(t.code,{children:"null"})," and a field left unspecified (undefined). When using ",(0,s.jsx)(t.code,{children:"copyWith"}),", any field you don't update remains unchanged in the new object."]}),"\n",(0,s.jsx)(t.h3,{id:"tojson--fromjson",children:"toJson / fromJson"}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"toJson"})," and ",(0,s.jsx)(t.code,{children:"fromJson"})," methods are generated on all models to help with serialization. Serverpod manages all serialization for you out of the box and you will rarely have to use these methods by your self. See the ",(0,s.jsx)(t.a,{href:"serialization",children:"Serialization"})," section for more info."]}),"\n",(0,s.jsx)(t.h3,{id:"custom-methods",children:"Custom methods"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes you will want to add custom methods to the generated classes. The easiest way to do this is with ",(0,s.jsx)(t.a,{href:"https://dart.dev/language/extension-methods",children:"Dart's extension feature"}),"."]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-dart",children:"extension MyExtension on MyClass {\n bool isCustomMethod() {\n return true;\n }\n}\n"})}),"\n",(0,s.jsx)(t.h2,{id:"keywords",children:"Keywords"}),"\n",(0,s.jsxs)(t.table,{children:[(0,s.jsx)(t.thead,{children:(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.th,{children:(0,s.jsx)(t.strong,{children:"Keyword"})}),(0,s.jsx)(t.th,{children:"Note"}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#class",children:"class"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#exception",children:"exception"})}),(0,s.jsx)(t.th,{style:{textAlign:"center"},children:(0,s.jsx)(t.a,{href:"#enum",children:"enum"})})]})}),(0,s.jsxs)(t.tbody,{children:[(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"values"})})}),(0,s.jsx)(t.td,{children:"A special key for enums with a list of all enum values."}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#enum",children:(0,s.jsx)(t.strong,{children:"serialized"})})}),(0,s.jsx)(t.td,{children:"Sets the mode enums are serialized in"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"serverOnly"})})}),(0,s.jsx)(t.td,{children:"Boolean flag if code generator only should create the code for the server."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"table"})})}),(0,s.jsx)(t.td,{children:"A name for the database table, enables generation of database code."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/migrations#opt-out-of-migrations",children:(0,s.jsx)(t.strong,{children:"managedMigration"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to opt out of the database migration system."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"fields"})})}),(0,s.jsx)(t.td,{children:"All fields in the generated class should be listed here."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#class",children:(0,s.jsx)(t.strong,{children:"type (fields)"})})}),(0,s.jsx)(t.td,{children:"Denotes the data type for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"#limiting-visibility-of-a-generated-class",children:(0,s.jsx)(t.strong,{children:"scope"})})}),(0,s.jsx)(t.td,{children:"Denotes the scope for a field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/models",children:(0,s.jsx)(t.strong,{children:"persist"})})}),(0,s.jsxs)(t.td,{children:["A boolean flag if the data should be stored in the database or not can be negated with ",(0,s.jsx)(t.code,{children:"!persist"})]}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one",children:(0,s.jsx)(t.strong,{children:"relation"})})}),(0,s.jsx)(t.td,{children:"Sets a relation between model files, requires a table name to be set."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#bidirectional-relations",children:(0,s.jsx)(t.strong,{children:"name"})})}),(0,s.jsx)(t.td,{children:"Give a name to a relation to pair them."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#with-an-id-field",children:(0,s.jsx)(t.strong,{children:"parent"})})}),(0,s.jsx)(t.td,{children:"Sets the parent table on a relation."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#custom-foreign-key-field",children:(0,s.jsx)(t.strong,{children:"field"})})}),(0,s.jsx)(t.td,{children:"A manual specified foreign key field."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onUpdate"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when updating data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/referential-actions",children:(0,s.jsx)(t.strong,{children:"onDelete"})})}),(0,s.jsx)(t.td,{children:"Set the referential actions when deleting data in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/relations/one-to-one#optional-relation",children:(0,s.jsx)(t.strong,{children:"optional"})})}),(0,s.jsx)(t.td,{children:"A boolean flag to make a relation optional."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"indexes"})})}),(0,s.jsx)(t.td,{children:"Create indexes on your fields / columns."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"fields (index)"})})}),(0,s.jsx)(t.td,{children:"List the fields to create the indexes on."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"type (index)"})})}),(0,s.jsx)(t.td,{children:"The type of index to create."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]}),(0,s.jsxs)(t.tr,{children:[(0,s.jsx)(t.td,{children:(0,s.jsx)(t.a,{href:"database/indexing",children:(0,s.jsx)(t.strong,{children:"unique"})})}),(0,s.jsx)(t.td,{children:"Boolean flag to make the entries unique in the database."}),(0,s.jsx)(t.td,{style:{textAlign:"center"},children:"\u2705"}),(0,s.jsx)(t.td,{style:{textAlign:"center"}}),(0,s.jsx)(t.td,{style:{textAlign:"center"}})]})]})]})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},28453:(e,t,n)=>{n.d(t,{R:()=>d,x:()=>l});var s=n(96540);const i={},r=s.createContext(i);function d(e){const t=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),s.createElement(r.Provider,{value:t},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/runtime~main.e1bfa786.js b/docs/assets/js/runtime~main.238171b8.js
similarity index 98%
rename from docs/assets/js/runtime~main.e1bfa786.js
rename to docs/assets/js/runtime~main.238171b8.js
index ac465d937..982fd3f78 100644
--- a/docs/assets/js/runtime~main.e1bfa786.js
+++ b/docs/assets/js/runtime~main.238171b8.js
@@ -1 +1 @@
-(()=>{"use strict";var e,a,c,f,d,b={},r={};function t(e){var a=r[e];if(void 0!==a)return a.exports;var c=r[e]={exports:{}};return b[e].call(c.exports,c,c.exports,t),c.exports}t.m=b,e=[],t.O=(a,c,f,d)=>{if(!c){var b=1/0;for(n=0;n=d)&&Object.keys(t.O).every((e=>t.O[e](c[o])))?c.splice(o--,1):(r=!1,d0&&e[n-1][2]>d;n--)e[n]=e[n-1];e[n]=[c,f,d]},t.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return t.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var d=Object.create(null);t.r(d);var b={};a=a||[null,c({}),c([]),c(c)];for(var r=2&f&&e;"object"==typeof r&&!~a.indexOf(r);r=c(r))Object.getOwnPropertyNames(r).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,t.d(d,b),d},t.d=(e,a)=>{for(var c in a)t.o(a,c)&&!t.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((a,c)=>(t.f[c](e,a),a)),[])),t.u=e=>"assets/js/"+({456:"cb867d98",565:"3f04b2f3",762:"cdc118a8",1160:"638e38ae",1171:"b685e31b",1572:"02c0cfe0",1705:"1921e4ca",1832:"bdc5a52e",1923:"b32c213b",1970:"dbf9e27d",2278:"27e827f8",2295:"0a5c01b2",2496:"3874f1bf",2730:"ac6e050c",3202:"8e7261c9",3230:"9d217e1f",3249:"05ec9480",3392:"reactPlayerVidyard",3607:"d8d6d57b",3783:"a6c3ea4a",3877:"79840965",3900:"ecb3c634",4272:"17dc776d",4276:"7a3d47b3",4499:"f149b10e",4550:"e3443ce0",4574:"976a2d80",4645:"9644aa4e",5e3:"da698f4c",5344:"8baf194b",5352:"52f87500",5441:"af1c5d2b",5623:"10ad1fa6",5819:"e4a796aa",5827:"3d277f18",5885:"3e4a4cb2",6157:"cce58fe7",6215:"f3467f26",6262:"27b43779",6265:"46b54090",6308:"2890c80c",6463:"reactPlayerKaltura",6486:"2e1ee4ed",6497:"5112ebe3",6615:"7b06977d",6918:"89b55a09",7161:"19e323d1",7267:"2db5c390",7606:"7517a61c",7701:"c2b45dbb",7785:"95bf5f56",8271:"94b2bc9a",8349:"06a408fe",8500:"4c5c4c2e",8734:"82e43b76",8927:"b8787c81",9264:"1caa8cdb",9524:"daec0d60",9606:"4519f039",9640:"5589c54d",9647:"5e95c892",9671:"e64edb60",9837:"5a0a1617",10348:"fca5fdb4",10700:"313c9eb1",10845:"5c1eff22",10907:"f7ae65ac",11139:"dc7352a7",11184:"8af032d3",11301:"f584139f",11567:"22dd74f7",11607:"ef2492df",11784:"45dd886d",11934:"b809d820",11965:"1457ddcd",12007:"90ec8c6b",12042:"reactPlayerTwitch",12237:"b6f81eaa",12716:"d2aa311d",12766:"4934de22",12827:"28967b3e",13018:"076cf272",13019:"d3938b1f",13455:"5839343c",13535:"e84b4e80",13585:"ea237062",13650:"2d11a680",14237:"95a5d2b2",14715:"fc8c8cde",14936:"7c8e5227",15066:"fe3f3783",15246:"83c6f999",15447:"30bd0f5b",16328:"reactPlayerDailyMotion",16602:"616631fd",16678:"710ac1c1",16869:"444a6d4e",16884:"4ed1e0ac",16945:"5596dd05",17021:"828ace52",17209:"f9bde383",17289:"45939ed5",17320:"55f37562",17776:"070c8c93",17820:"ebd05845",18093:"0841186f",18401:"17896441",18446:"reactPlayerYouTube",19049:"2fca5c64",19738:"87ab7385",20033:"986f0f98",20210:"68401255",20423:"22f51758",20515:"704545ab",20681:"e66f2658",20773:"d4fc3158",20826:"4ab30eec",21611:"82444e58",21983:"57012fa6",22422:"d3af5b3c",22451:"f5a589e7",22611:"59df87e8",22750:"141135bb",23321:"676f1bdb",23452:"5af30237",23453:"ed64c12e",23619:"f6affd6e",23870:"956829f8",24078:"ec91ff36",24158:"1d39c85d",24295:"96523456",24832:"02e41de2",25362:"5bc657fa",25427:"3edac44d",25504:"0f2c2e36",25666:"522ca66b",25691:"9a594c98",25692:"7ca2e59a",26173:"reactPlayerVimeo",26376:"431ffdb5",26499:"a4adf53f",26622:"d9107a6a",27168:"7ac69e68",27350:"65e04ea3",27646:"12407b36",27685:"6aee17c2",27740:"38e32826",28235:"965931d7",29248:"4a49065b",29250:"dec2bd4a",29436:"dc8c27bd",29773:"1a84c7fd",30248:"b1218054",30418:"6feb7661",30473:"3141060a",30528:"1323771c",30765:"85d514f3",30799:"1a39ee04",30941:"4aa94ec1",31165:"926056c1",31267:"08d55cf7",31471:"3f80bb14",31474:"564db590",31727:"2e18ba50",32055:"9037180b",32096:"c090764b",32141:"df1414bb",32163:"3d150a24",32178:"16116660",32406:"5cde491b",32461:"a6311318",32492:"4e689a0b",32504:"7de3e81f",32741:"d9e7b984",32759:"7800d508",32944:"272aa200",33048:"25c6d77a",33098:"71ba2dc1",33460:"9107c65f",33577:"a32c313f",33992:"cbf3c4ec",34321:"6f56eca8",34438:"54cab4d4",34662:"cf3c245e",34726:"1b6591f7",34750:"07e708e9",34935:"6da448d1",34975:"ff5ed6ba",35223:"db7d4591",35540:"ce86e3e6",35563:"e7977816",35654:"dc4059b2",35742:"aba21aa0",35748:"1312139a",35884:"9c9052d1",36058:"a2a1c245",36132:"e8f4756d",36353:"reactPlayerPreview",36731:"bd568e77",36886:"8abbb0ee",36920:"ed772d97",37107:"3817c387",37296:"a2757506",37516:"9f1829f0",37710:"abd13aa2",37850:"b28bd8b1",37990:"441fd5fc",38031:"8ee9837e",38419:"bd6f2233",38471:"caf7731d",38527:"5e7d099e",38610:"c868bccf",38691:"036b5431",38717:"897331c0",38792:"4f0519c7",38853:"fc67ad3d",38864:"fac0eceb",39026:"c7156cf2",39056:"5f6b1733",39080:"511f9951",39408:"fe2e2e26",39431:"cdd4a9c6",39482:"327b0a57",39558:"50f2f9f3",39757:"9e0c2c37",39911:"92466816",40271:"6a734661",40374:"b5dcbe95",40563:"39dec3ba",40575:"33c1d41a",41237:"88a48c42",41507:"16b03284",41865:"fe76eed8",42083:"4048090e",42206:"91aed80e",42434:"5b2d7e3c",42800:"3aa0ab0a",42901:"2115313f",43174:"6ba85e75",43246:"2d16d24d",43444:"d2f6d210",43773:"a81cb65f",43848:"44145933",43888:"ad61550a",43903:"8186ecf9",44046:"5d707891",44486:"c0650537",44602:"69fcd2fc",44609:"c5313007",44630:"65b7208a",44816:"36fcb744",44947:"39ec0930",45141:"b1394c86",45268:"ef4456b5",45295:"f29fc884",45474:"79d28454",45655:"4a55fe3a",45724:"8dfd8953",45742:"c377a04b",46119:"d58f1ee2",46364:"fe522f67",46563:"aeef55f7",46688:"ac3101e9",46921:"d0b9ca74",46961:"2bbc2deb",47120:"dcbfe205",47127:"999788b8",47264:"b9ec56c8",47341:"7f0714d1",47527:"93dcedec",47627:"reactPlayerStreamable",47719:"b7ea99f7",48124:"8f509517",48134:"356ce494",48235:"df15bc7d",48276:"b467d32a",48436:"f6adf820",48552:"954e932f",48579:"566f49fb",48665:"0f4a5c74",49316:"510b9307",49406:"b26210db",49455:"c8139b75",49658:"0d76317c",49921:"fc8b5a5d",50041:"ac002d2b",50404:"98f4e1ec",50765:"bf519c8d",50908:"3fbaac07",51143:"fc6f07d2",51205:"db42f242",51349:"4aec9039",51379:"17f04a83",51637:"81e4ed6a",51780:"eecc43ff",52302:"e7ee6027",52365:"280af06a",52529:"e3d58533",52723:"reactPlayerMux",53084:"23975af2",53148:"9b4ab8cd",53357:"1577f7ed",53774:"53998120",54049:"4867e743",54220:"092bf57d",54530:"a271ef09",54582:"984d6493",54905:"98d962c5",55011:"49145cdf",55388:"b2419a00",55664:"169f3d24",56264:"46eeb6cb",56282:"d636c09f",56383:"ecaa7076",56420:"fd4b36bb",56684:"378935ce",56764:"805a59dc",57035:"f527bef3",57356:"bb9c591b",57694:"21b7a589",57790:"1b218eaa",57869:"a7edc2bd",58022:"c134ef8a",58215:"1111b27e",58718:"afb7a97b",58800:"5144cf5e",59075:"6e29a506",59221:"76259cc3",59332:"857097c6",59409:"a64b2578",59599:"1e1f8072",59600:"ac9d9d69",59949:"5c6f6ba9",60365:"bd118f84",60759:"719163ad",60880:"640696ee",60886:"c10a0985",60893:"6fbf0c67",60908:"0eebd274",61114:"3cc71396",61252:"3b66921f",61273:"099a3596",61291:"d38e3f9f",61358:"3d1ae229",61368:"f28f059c",61505:"e58556b2",61977:"7570de64",62059:"0893faed",62134:"0d7acd84",62357:"6d2a4d3f",62362:"44463284",62573:"bd1cffff",62921:"1d7c691c",62929:"f5fed352",63474:"98c94590",63538:"06393fc1",63706:"2b67eda4",63737:"53e9dd7a",63747:"fb72d7b2",63960:"a6397568",64558:"b91fbf2a",64641:"eac16e1d",64651:"4c781063",64665:"6f44ab90",65110:"063d75bd",65142:"eb4c176e",65433:"616bfcf6",65542:"af754a1f",65655:"1ebbfca8",65755:"bafd283f",65784:"90239e6e",65866:"419cd6b8",66225:"9f8e6d57",66339:"03b2528f",66811:"3e87058f",66850:"0c695afe",66868:"3c4af576",66885:"5e253f2f",66929:"da54b976",67068:"ae0eacdd",67098:"a7bd4aaa",67217:"726a6c22",67349:"61ff6850",67458:"0d271e1e",67532:"49fed513",67570:"reactPlayerMixcloud",67714:"9d7352c0",68230:"3cf6fa35",68364:"812775a4",68391:"24557dbc",68700:"96331245",68874:"10ea0b82",68912:"2c2832e4",68915:"62de5d73",68960:"358c2507",68962:"af68ae04",69050:"4ac2e930",69779:"3c9432f0",69816:"20d56cb7",69891:"62037464",69979:"reactPlayerSoundCloud",70326:"c3373259",70934:"d44e0d1c",71247:"308471de",71383:"087cd58c",71826:"a4c89d62",71907:"86a8bb6c",71967:"4fa4eafa",72074:"71319bec",72132:"83ac10ed",72231:"fe170cc9",72561:"adce8179",73107:"646cbece",73379:"9d779d8b",73932:"2020ed93",73939:"2ed96714",74081:"ce4dbf6d",74583:"4bfca71d",74780:"ebde045d",74834:"d26a73b8",74860:"00d14154",75412:"5390e21f",75702:"307525ba",75822:"2db99065",75868:"071f33a8",75965:"b48f41b9",76093:"7d63aba8",76224:"03b3cfd2",76238:"8615e055",76372:"d802bb56",76768:"8bed5a26",76973:"78ae7ec8",77137:"42abcd4d",77313:"ee65edec",77318:"67e77328",77757:"f6f476f1",78007:"8eead450",78416:"068743c8",78631:"b7b014bf",78702:"82ea7079",79048:"a94703ab",79052:"6d717251",79225:"526e379a",79354:"4118187a",79825:"2d4af3bf",79956:"9e09f891",79983:"a7f483d1",80549:"afde3230",80721:"05fa9a60",81509:"4ead9a95",81657:"f8189ec4",81790:"42a9b3c5",81849:"2e3fc0f9",82075:"056b386b",82201:"18910d94",82261:"0c6fe626",82439:"e4eafb12",82477:"2ca08277",83287:"7af31c45",83752:"efe5610c",83943:"9c5d9512",84219:"51e50f95",84331:"79e0e7f1",84605:"8552f549",84656:"813cfb2f",84750:"aefdd881",84850:"bc03f89b",85462:"9270ba4f",85527:"5143312c",85528:"21e10cde",85556:"21a4ba71",85943:"05fbef88",86012:"da202fdd",86037:"eaeab60b",86057:"9fbfaf6d",86106:"1877d9d5",86298:"e2d6ba1f",86886:"7b33c27b",86887:"reactPlayerFacebook",86992:"3fe65583",87012:"869ae8a7",87126:"b916a1ab",87402:"c3094240",87510:"9d36f238",87760:"0773e78b",88048:"73ca4188",88131:"c2237e68",88494:"504d78e0",88495:"801276a1",88790:"51c7df8c",88843:"45926b62",88946:"95ec96e5",89598:"4b6eee9a",90049:"cc180519",90381:"869d42f3",90642:"07006f9e",90780:"098f2604",91131:"468d57a9",91258:"227d1fc4",91395:"a0aa5253",92113:"32b8fafb",92170:"4951b372",92687:"cd64d641",92811:"8093477b",92896:"bc69c5bc",93036:"c342bcae",93087:"b0f19176",93842:"26398b18",94594:"c7507218",94642:"da19ecb4",94725:"dd31e7e9",94811:"da071cb8",95191:"c75d145e",95409:"94f11012",96449:"19a6be06",96815:"8d02075b",96991:"4eee9c87",97191:"31b73615",97458:"reactPlayerFilePlayer",97499:"50a12feb",97785:"ac5db01d",98042:"819b642a",98116:"49849746",98175:"5a96e453",98498:"ae22b856",98548:"44a83f6a",98601:"13798859",98996:"65c67349",99094:"08aab21d",99180:"32ebcda7",99340:"reactPlayerWistia",99341:"a1154d73",99591:"e0bec135",99989:"51ddac88"}[e]||e)+"."+{456:"5c30ecdd",565:"94a09b6c",762:"df50c981",1160:"918efc1f",1171:"de34cd0e",1572:"ffbe0cfc",1705:"038460b6",1832:"9614689c",1923:"cb2bc5be",1970:"cac2a9b8",2278:"d475be2b",2295:"e81bbf25",2496:"b540b729",2730:"923b54e1",3202:"f35694a9",3230:"4129121e",3249:"82c7846c",3392:"8464e17b",3607:"2981ded1",3783:"71a2f8e8",3877:"58749100",3900:"0ba32b97",4272:"0900e2a1",4276:"8faf83a5",4499:"ca8d1432",4550:"46f5f770",4574:"1c78d390",4645:"e160e737",5e3:"e340e97d",5344:"1d1077a2",5352:"5ee75c06",5441:"151c62bf",5623:"9548c1a1",5819:"a4a89c82",5827:"5cc9996e",5885:"fcb3bbcb",6157:"dbb843db",6215:"51944600",6262:"794fd95d",6265:"83c21074",6308:"350484bc",6463:"bec1a06c",6486:"4b0eb0a1",6497:"42707b0b",6615:"7db76aa6",6918:"031ec4ab",7161:"2c411627",7267:"ce74b45c",7606:"45b626ad",7701:"316b1161",7785:"f569d217",8271:"bce6ddee",8349:"03f95123",8500:"a390a5ca",8734:"2de05990",8927:"f986535a",9264:"6ae52032",9524:"e7c42f6f",9606:"bff55b72",9640:"b703cc22",9647:"cac24016",9671:"0a30cd6c",9837:"ede23a01",10348:"ec8b3811",10700:"708d8037",10845:"2bc04da3",10907:"eb9d65c3",11139:"303df097",11184:"9d69cbad",11301:"8387b5bf",11567:"432c7b35",11607:"b64b2d67",11784:"9d3408ab",11934:"da61538a",11965:"d6e5dd4d",12007:"fb425a62",12042:"a0c42814",12237:"8a850fa6",12716:"faed95e1",12766:"97abbc05",12827:"144f3020",13018:"c5ad98c6",13019:"c5e3aef7",13455:"1451755d",13535:"88a06537",13585:"a746e017",13650:"62810914",14237:"8c2a2bc3",14715:"95abf808",14936:"6ee147d1",15066:"38ece79e",15246:"fd5943dc",15447:"82977fde",16328:"4fa8d3c8",16602:"f2bf07f8",16678:"cb38a105",16869:"995c6ef6",16884:"bf9abfa1",16945:"1eaf58e9",17021:"6c74822a",17209:"e94a64b5",17289:"e2e7eec1",17320:"9ddeadd7",17776:"f89fd2b8",17820:"623e6e0e",18093:"d4afddde",18401:"30c4f83a",18446:"150ff8a0",19049:"08036f4e",19738:"a816c680",20033:"fa674d6a",20210:"4ea135dd",20423:"076d2946",20515:"85d707fe",20681:"7e97a650",20773:"a2cebc00",20826:"8b874cbc",21611:"6e533a7e",21983:"f9a941e2",22422:"feb00a9e",22451:"ef972e5e",22611:"18587ae4",22750:"a52908e5",23321:"84054f56",23452:"ebba4448",23453:"2ff5cbe7",23619:"c27273de",23870:"3742bfab",24078:"730ca41c",24158:"ce6a000b",24295:"4aae9b71",24832:"af6b73df",25362:"f0170814",25427:"3244da9c",25504:"28938478",25666:"2f0c77bf",25691:"426557b6",25692:"585ab289",26173:"076fef9c",26376:"a1f11cb7",26499:"dd7640ab",26622:"f0629b1b",27168:"07813519",27350:"5fd6e6d7",27646:"0678c8f9",27685:"f20ffda9",27740:"8f7d4d98",28235:"f6cbcccb",29248:"d7c12529",29250:"925abd2b",29436:"7ca95c22",29773:"b8c6f670",30248:"0ad8a16e",30418:"5fc7b2a0",30473:"0abc4692",30528:"435813db",30765:"d86090af",30799:"388c9414",30941:"49876b37",31165:"02614496",31267:"933156b4",31471:"450344fc",31474:"dbbf8152",31727:"d3f3b0b1",32055:"a95bfc3b",32096:"04828676",32141:"bcdc361b",32163:"70936a3c",32178:"36e60316",32406:"bd1dc0ac",32461:"6b4a958d",32492:"30cd7c7f",32504:"754ac7de",32741:"552767cd",32759:"d8e2798a",32944:"6f349f74",33048:"1a010730",33098:"480f07f7",33460:"8f3f92e4",33577:"ce38b0c8",33992:"a7260a35",34321:"ab8e5c20",34438:"8f46a7dd",34662:"8da76618",34726:"90739fe9",34750:"13529313",34935:"59f5597e",34975:"41c5c4bb",35223:"2367e813",35540:"daa770e8",35563:"22b8fd33",35654:"72cb9c74",35742:"e08a145a",35748:"816249d7",35884:"a0bf4e6b",36058:"b63b94d9",36132:"75cbf3f9",36353:"4de9bab6",36731:"1ab1d6ee",36886:"9c9e515a",36920:"3a69befa",37107:"f19c047b",37296:"20763684",37516:"2ab4897d",37710:"5cf4ff57",37850:"ed2f760b",37990:"c6c289b1",38031:"396006c8",38419:"a12c2499",38471:"93b2d4dd",38527:"73056614",38610:"37df5efb",38691:"137dc0f8",38717:"6dbb7b59",38792:"7deb9f3e",38853:"5c9e45fe",38864:"4813ef31",39026:"f2f8a69b",39056:"60f70f39",39080:"b0c77b48",39408:"88db313c",39431:"2bcf2e6d",39482:"7e3b08ef",39503:"18fac5cf",39558:"41945f10",39757:"47703e3b",39911:"646e7dec",40271:"f790e023",40374:"179979e4",40563:"94247613",40575:"4d0b112e",41237:"3bbdf534",41507:"77c30778",41865:"c835f8b0",42083:"2aff9481",42206:"18d5693f",42434:"1f6d6607",42800:"bf6545c0",42901:"2fdbe13a",43174:"013544f4",43246:"ddc98077",43444:"cff02423",43773:"3cc7db7d",43848:"57247e24",43888:"d74ff318",43903:"41a52d13",44046:"a946825c",44486:"28ccbcec",44602:"aaf93cb1",44609:"32c1fd2c",44630:"f2d8976e",44816:"0e7f93b4",44947:"a24467f3",45141:"e3968051",45268:"7006193f",45295:"b0715bed",45474:"1abec566",45655:"c2164e90",45724:"b59ddc1b",45742:"2497dd34",46119:"7805de88",46364:"fdfddfc0",46563:"2e6253c5",46688:"a1d131c8",46921:"260d54e0",46961:"94b493aa",47120:"723a0b3e",47127:"de5390c4",47264:"44b44216",47341:"18ca620e",47527:"d950e87e",47627:"bb35fa43",47719:"646275e7",48124:"55af4038",48134:"b6137268",48235:"bc75728e",48276:"231a1e55",48436:"89305d4a",48552:"c704b5f4",48579:"bbd9e592",48665:"b81074e2",49316:"5e345ac8",49406:"a3ecaee8",49455:"15c58fe1",49658:"3da918b0",49921:"f2c2a1f0",50041:"f7cb55c7",50404:"eb1ab0f9",50765:"479f1916",50908:"a5b524ad",51143:"136727d9",51205:"ee2e77cb",51349:"1e076875",51379:"27ea6246",51637:"ffb79940",51780:"ce9149be",52302:"340b0e6b",52365:"d23ef6a9",52529:"e7cefacb",52723:"3e4df075",53084:"315da40f",53148:"4212deb6",53357:"b5a1c415",53774:"72126425",54049:"4089600b",54220:"d4f185d8",54530:"0bd12311",54582:"4e5700b0",54905:"feb41c26",55011:"95879cb0",55388:"33179a2f",55664:"258a4e6b",56264:"6318e439",56282:"b46c91af",56383:"1ff19ca5",56420:"1972625f",56684:"ab8eab18",56764:"ac5b41d7",57035:"ad79c7ab",57356:"42441995",57694:"a34951a6",57790:"7f79a47a",57869:"89931416",58022:"7b3238f1",58215:"5be13c8d",58718:"a820c36e",58800:"e98ceb1d",59075:"25749229",59221:"658e6207",59332:"84712487",59409:"be73a79d",59599:"780630f8",59600:"ca1b31c5",59949:"0c457c29",60365:"1fd2fa70",60759:"d322d307",60880:"f6ba7287",60886:"67c47b8d",60893:"fe1ea3f9",60908:"e76a5e92",61114:"46cf560e",61252:"0ab3ec6f",61273:"05750299",61291:"0f509abf",61358:"9defced7",61368:"88200516",61505:"1a21d780",61977:"3a915ac8",62059:"27a610be",62134:"136bb77a",62357:"dd821bdf",62362:"8db1be48",62573:"09b3ebf3",62921:"9d42f085",62929:"c76283aa",63474:"bb220697",63538:"7b7f0e14",63706:"6f94bc8f",63737:"af78b6a2",63747:"7c5b8fbd",63960:"9f0fe283",64558:"25e0c733",64641:"4002d9f9",64651:"7df9a0dc",64665:"b140ef8f",65110:"0c2123d1",65142:"d226848c",65433:"d959ad9b",65542:"a7c67c53",65655:"3f647a48",65755:"c46f5968",65784:"b94d85b3",65866:"f9e10c84",66225:"f10f224f",66339:"800c2e61",66811:"945f99d9",66850:"7753ee7f",66868:"65080ded",66885:"1bd3e9c3",66929:"d218d95f",67068:"046fc798",67098:"03929b29",67217:"c9c29188",67349:"b94a3a6a",67458:"f760b356",67532:"60df9b16",67570:"12aff88e",67714:"973cd9fc",68230:"835eaee7",68364:"53e94f68",68391:"262895ce",68700:"64fe7812",68874:"d1febe02",68912:"0c81f713",68915:"57e00474",68960:"18b5e3ad",68962:"d845c0a4",69050:"358b5513",69779:"faba2980",69816:"58af7b00",69891:"80af80ae",69979:"f8f19bc3",70326:"fafebdcb",70934:"73854ef9",71247:"5a63971c",71383:"75b257bc",71826:"9f1c6fe5",71907:"0751c0f3",71967:"1af4694c",72074:"522fdb31",72132:"6e4054d2",72231:"e3c174bf",72561:"1f9fbc90",73107:"ecc6be9c",73379:"16b17994",73932:"b35fd796",73939:"aba6bb06",74081:"b57cba4e",74583:"ce4c9b2f",74780:"b7d71cb3",74834:"15357603",74860:"426c5862",75412:"d72a934a",75702:"3926a131",75822:"1d9852b1",75868:"3118d0c9",75965:"19020673",76093:"8e28eeb6",76224:"8f29238e",76238:"46cbd86e",76372:"297afbc9",76768:"c3ca6e24",76973:"a72e321d",77137:"daff0432",77313:"b92d7b2e",77318:"44e1adab",77757:"eb1c1544",78007:"2b6a8f00",78416:"2ad246f2",78631:"b6f33b62",78702:"ed155bd3",79048:"0f54d2a9",79052:"634be361",79225:"bad5b331",79354:"d6957fa9",79825:"8c4cf900",79956:"4d5ec1eb",79983:"52b6f63f",80549:"a1b3777a",80721:"cdf43ae5",81509:"5a98113a",81657:"d230bb30",81790:"c56f6a89",81849:"0f44253c",82075:"7a5a588a",82201:"c855be90",82237:"787c04ec",82261:"2fc96e72",82439:"18a56b6c",82477:"12d174de",83287:"084dde1a",83752:"d91cc53e",83943:"a64bf43a",84219:"d24c437b",84331:"b37577e8",84605:"8cf0495c",84656:"73c53ede",84750:"1857e769",84850:"f287e029",85462:"ddca2c18",85527:"3afd894d",85528:"74b87448",85556:"fee97575",85943:"e5b4cdd6",86012:"ab7bdaa5",86037:"04050011",86057:"db95e34c",86106:"1290858d",86298:"92e42ef4",86886:"dad3b87b",86887:"508da014",86992:"82004d70",87012:"fd4f4b30",87126:"89adbb17",87402:"abdfd46c",87510:"720f0f93",87760:"72f8f4bb",88048:"2a1833d8",88131:"e11652fa",88494:"7d33658e",88495:"efabda4c",88790:"c5a360b0",88843:"ba8ab281",88946:"350ed3aa",89598:"30bcd67d",90049:"70470979",90381:"4acaccf6",90642:"83acf9a9",90780:"75e3e359",91131:"759062e1",91258:"0a10d55b",91395:"31f57203",92113:"d51c7aa0",92170:"f7b1e9bd",92687:"bed1a1d3",92811:"8a204457",92896:"b265749e",93036:"7c8d08ac",93087:"0090bbd7",93842:"d418eca4",94594:"42c52295",94642:"c0efeaa4",94725:"7118b112",94811:"933445a7",95191:"0ee87f70",95409:"6f87b63a",96449:"9cfed380",96815:"362b1a69",96991:"eca5cf70",97191:"ca75b3a5",97458:"036de6e1",97499:"1a4e721e",97785:"433c50c6",98042:"14a96714",98116:"a22cb511",98175:"b8bdaaeb",98498:"1128c3c9",98548:"0250dbf6",98601:"75b6fdce",98996:"433b1eca",99094:"54319916",99180:"e5d0a4e7",99340:"c5c0cf6c",99341:"4403c816",99591:"4e74c25b",99989:"1ffc7914"}[e]+".js",t.miniCssF=e=>{},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},d="serverpod-docs:",t.l=(e,a,c,b)=>{if(f[e])f[e].push(a);else{var r,o;if(void 0!==c)for(var l=document.getElementsByTagName("script"),n=0;n{r.onerror=r.onload=null,clearTimeout(s);var d=f[e];if(delete f[e],r.parentNode&&r.parentNode.removeChild(r),d&&d.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=u.bind(null,r.onerror),r.onload=u.bind(null,r.onload),o&&document.head.appendChild(r)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={13798859:"98601",16116660:"32178",17896441:"18401",44145933:"43848",44463284:"62362",49849746:"98116",53998120:"53774",62037464:"69891",68401255:"20210",79840965:"3877",92466816:"39911",96331245:"68700",96523456:"24295",cb867d98:"456","3f04b2f3":"565",cdc118a8:"762","638e38ae":"1160",b685e31b:"1171","02c0cfe0":"1572","1921e4ca":"1705",bdc5a52e:"1832",b32c213b:"1923",dbf9e27d:"1970","27e827f8":"2278","0a5c01b2":"2295","3874f1bf":"2496",ac6e050c:"2730","8e7261c9":"3202","9d217e1f":"3230","05ec9480":"3249",reactPlayerVidyard:"3392",d8d6d57b:"3607",a6c3ea4a:"3783",ecb3c634:"3900","17dc776d":"4272","7a3d47b3":"4276",f149b10e:"4499",e3443ce0:"4550","976a2d80":"4574","9644aa4e":"4645",da698f4c:"5000","8baf194b":"5344","52f87500":"5352",af1c5d2b:"5441","10ad1fa6":"5623",e4a796aa:"5819","3d277f18":"5827","3e4a4cb2":"5885",cce58fe7:"6157",f3467f26:"6215","27b43779":"6262","46b54090":"6265","2890c80c":"6308",reactPlayerKaltura:"6463","2e1ee4ed":"6486","5112ebe3":"6497","7b06977d":"6615","89b55a09":"6918","19e323d1":"7161","2db5c390":"7267","7517a61c":"7606",c2b45dbb:"7701","95bf5f56":"7785","94b2bc9a":"8271","06a408fe":"8349","4c5c4c2e":"8500","82e43b76":"8734",b8787c81:"8927","1caa8cdb":"9264",daec0d60:"9524","4519f039":"9606","5589c54d":"9640","5e95c892":"9647",e64edb60:"9671","5a0a1617":"9837",fca5fdb4:"10348","313c9eb1":"10700","5c1eff22":"10845",f7ae65ac:"10907",dc7352a7:"11139","8af032d3":"11184",f584139f:"11301","22dd74f7":"11567",ef2492df:"11607","45dd886d":"11784",b809d820:"11934","1457ddcd":"11965","90ec8c6b":"12007",reactPlayerTwitch:"12042",b6f81eaa:"12237",d2aa311d:"12716","4934de22":"12766","28967b3e":"12827","076cf272":"13018",d3938b1f:"13019","5839343c":"13455",e84b4e80:"13535",ea237062:"13585","2d11a680":"13650","95a5d2b2":"14237",fc8c8cde:"14715","7c8e5227":"14936",fe3f3783:"15066","83c6f999":"15246","30bd0f5b":"15447",reactPlayerDailyMotion:"16328","616631fd":"16602","710ac1c1":"16678","444a6d4e":"16869","4ed1e0ac":"16884","5596dd05":"16945","828ace52":"17021",f9bde383:"17209","45939ed5":"17289","55f37562":"17320","070c8c93":"17776",ebd05845:"17820","0841186f":"18093",reactPlayerYouTube:"18446","2fca5c64":"19049","87ab7385":"19738","986f0f98":"20033","22f51758":"20423","704545ab":"20515",e66f2658:"20681",d4fc3158:"20773","4ab30eec":"20826","82444e58":"21611","57012fa6":"21983",d3af5b3c:"22422",f5a589e7:"22451","59df87e8":"22611","141135bb":"22750","676f1bdb":"23321","5af30237":"23452",ed64c12e:"23453",f6affd6e:"23619","956829f8":"23870",ec91ff36:"24078","1d39c85d":"24158","02e41de2":"24832","5bc657fa":"25362","3edac44d":"25427","0f2c2e36":"25504","522ca66b":"25666","9a594c98":"25691","7ca2e59a":"25692",reactPlayerVimeo:"26173","431ffdb5":"26376",a4adf53f:"26499",d9107a6a:"26622","7ac69e68":"27168","65e04ea3":"27350","12407b36":"27646","6aee17c2":"27685","38e32826":"27740","965931d7":"28235","4a49065b":"29248",dec2bd4a:"29250",dc8c27bd:"29436","1a84c7fd":"29773",b1218054:"30248","6feb7661":"30418","3141060a":"30473","1323771c":"30528","85d514f3":"30765","1a39ee04":"30799","4aa94ec1":"30941","926056c1":"31165","08d55cf7":"31267","3f80bb14":"31471","564db590":"31474","2e18ba50":"31727","9037180b":"32055",c090764b:"32096",df1414bb:"32141","3d150a24":"32163","5cde491b":"32406",a6311318:"32461","4e689a0b":"32492","7de3e81f":"32504",d9e7b984:"32741","7800d508":"32759","272aa200":"32944","25c6d77a":"33048","71ba2dc1":"33098","9107c65f":"33460",a32c313f:"33577",cbf3c4ec:"33992","6f56eca8":"34321","54cab4d4":"34438",cf3c245e:"34662","1b6591f7":"34726","07e708e9":"34750","6da448d1":"34935",ff5ed6ba:"34975",db7d4591:"35223",ce86e3e6:"35540",e7977816:"35563",dc4059b2:"35654",aba21aa0:"35742","1312139a":"35748","9c9052d1":"35884",a2a1c245:"36058",e8f4756d:"36132",reactPlayerPreview:"36353",bd568e77:"36731","8abbb0ee":"36886",ed772d97:"36920","3817c387":"37107",a2757506:"37296","9f1829f0":"37516",abd13aa2:"37710",b28bd8b1:"37850","441fd5fc":"37990","8ee9837e":"38031",bd6f2233:"38419",caf7731d:"38471","5e7d099e":"38527",c868bccf:"38610","036b5431":"38691","897331c0":"38717","4f0519c7":"38792",fc67ad3d:"38853",fac0eceb:"38864",c7156cf2:"39026","5f6b1733":"39056","511f9951":"39080",fe2e2e26:"39408",cdd4a9c6:"39431","327b0a57":"39482","50f2f9f3":"39558","9e0c2c37":"39757","6a734661":"40271",b5dcbe95:"40374","39dec3ba":"40563","33c1d41a":"40575","88a48c42":"41237","16b03284":"41507",fe76eed8:"41865","4048090e":"42083","91aed80e":"42206","5b2d7e3c":"42434","3aa0ab0a":"42800","2115313f":"42901","6ba85e75":"43174","2d16d24d":"43246",d2f6d210:"43444",a81cb65f:"43773",ad61550a:"43888","8186ecf9":"43903","5d707891":"44046",c0650537:"44486","69fcd2fc":"44602",c5313007:"44609","65b7208a":"44630","36fcb744":"44816","39ec0930":"44947",b1394c86:"45141",ef4456b5:"45268",f29fc884:"45295","79d28454":"45474","4a55fe3a":"45655","8dfd8953":"45724",c377a04b:"45742",d58f1ee2:"46119",fe522f67:"46364",aeef55f7:"46563",ac3101e9:"46688",d0b9ca74:"46921","2bbc2deb":"46961",dcbfe205:"47120","999788b8":"47127",b9ec56c8:"47264","7f0714d1":"47341","93dcedec":"47527",reactPlayerStreamable:"47627",b7ea99f7:"47719","8f509517":"48124","356ce494":"48134",df15bc7d:"48235",b467d32a:"48276",f6adf820:"48436","954e932f":"48552","566f49fb":"48579","0f4a5c74":"48665","510b9307":"49316",b26210db:"49406",c8139b75:"49455","0d76317c":"49658",fc8b5a5d:"49921",ac002d2b:"50041","98f4e1ec":"50404",bf519c8d:"50765","3fbaac07":"50908",fc6f07d2:"51143",db42f242:"51205","4aec9039":"51349","17f04a83":"51379","81e4ed6a":"51637",eecc43ff:"51780",e7ee6027:"52302","280af06a":"52365",e3d58533:"52529",reactPlayerMux:"52723","23975af2":"53084","9b4ab8cd":"53148","1577f7ed":"53357","4867e743":"54049","092bf57d":"54220",a271ef09:"54530","984d6493":"54582","98d962c5":"54905","49145cdf":"55011",b2419a00:"55388","169f3d24":"55664","46eeb6cb":"56264",d636c09f:"56282",ecaa7076:"56383",fd4b36bb:"56420","378935ce":"56684","805a59dc":"56764",f527bef3:"57035",bb9c591b:"57356","21b7a589":"57694","1b218eaa":"57790",a7edc2bd:"57869",c134ef8a:"58022","1111b27e":"58215",afb7a97b:"58718","5144cf5e":"58800","6e29a506":"59075","76259cc3":"59221","857097c6":"59332",a64b2578:"59409","1e1f8072":"59599",ac9d9d69:"59600","5c6f6ba9":"59949",bd118f84:"60365","719163ad":"60759","640696ee":"60880",c10a0985:"60886","6fbf0c67":"60893","0eebd274":"60908","3cc71396":"61114","3b66921f":"61252","099a3596":"61273",d38e3f9f:"61291","3d1ae229":"61358",f28f059c:"61368",e58556b2:"61505","7570de64":"61977","0893faed":"62059","0d7acd84":"62134","6d2a4d3f":"62357",bd1cffff:"62573","1d7c691c":"62921",f5fed352:"62929","98c94590":"63474","06393fc1":"63538","2b67eda4":"63706","53e9dd7a":"63737",fb72d7b2:"63747",a6397568:"63960",b91fbf2a:"64558",eac16e1d:"64641","4c781063":"64651","6f44ab90":"64665","063d75bd":"65110",eb4c176e:"65142","616bfcf6":"65433",af754a1f:"65542","1ebbfca8":"65655",bafd283f:"65755","90239e6e":"65784","419cd6b8":"65866","9f8e6d57":"66225","03b2528f":"66339","3e87058f":"66811","0c695afe":"66850","3c4af576":"66868","5e253f2f":"66885",da54b976:"66929",ae0eacdd:"67068",a7bd4aaa:"67098","726a6c22":"67217","61ff6850":"67349","0d271e1e":"67458","49fed513":"67532",reactPlayerMixcloud:"67570","9d7352c0":"67714","3cf6fa35":"68230","812775a4":"68364","24557dbc":"68391","10ea0b82":"68874","2c2832e4":"68912","62de5d73":"68915","358c2507":"68960",af68ae04:"68962","4ac2e930":"69050","3c9432f0":"69779","20d56cb7":"69816",reactPlayerSoundCloud:"69979",c3373259:"70326",d44e0d1c:"70934","308471de":"71247","087cd58c":"71383",a4c89d62:"71826","86a8bb6c":"71907","4fa4eafa":"71967","71319bec":"72074","83ac10ed":"72132",fe170cc9:"72231",adce8179:"72561","646cbece":"73107","9d779d8b":"73379","2020ed93":"73932","2ed96714":"73939",ce4dbf6d:"74081","4bfca71d":"74583",ebde045d:"74780",d26a73b8:"74834","00d14154":"74860","5390e21f":"75412","307525ba":"75702","2db99065":"75822","071f33a8":"75868",b48f41b9:"75965","7d63aba8":"76093","03b3cfd2":"76224","8615e055":"76238",d802bb56:"76372","8bed5a26":"76768","78ae7ec8":"76973","42abcd4d":"77137",ee65edec:"77313","67e77328":"77318",f6f476f1:"77757","8eead450":"78007","068743c8":"78416",b7b014bf:"78631","82ea7079":"78702",a94703ab:"79048","6d717251":"79052","526e379a":"79225","4118187a":"79354","2d4af3bf":"79825","9e09f891":"79956",a7f483d1:"79983",afde3230:"80549","05fa9a60":"80721","4ead9a95":"81509",f8189ec4:"81657","42a9b3c5":"81790","2e3fc0f9":"81849","056b386b":"82075","18910d94":"82201","0c6fe626":"82261",e4eafb12:"82439","2ca08277":"82477","7af31c45":"83287",efe5610c:"83752","9c5d9512":"83943","51e50f95":"84219","79e0e7f1":"84331","8552f549":"84605","813cfb2f":"84656",aefdd881:"84750",bc03f89b:"84850","9270ba4f":"85462","5143312c":"85527","21e10cde":"85528","21a4ba71":"85556","05fbef88":"85943",da202fdd:"86012",eaeab60b:"86037","9fbfaf6d":"86057","1877d9d5":"86106",e2d6ba1f:"86298","7b33c27b":"86886",reactPlayerFacebook:"86887","3fe65583":"86992","869ae8a7":"87012",b916a1ab:"87126",c3094240:"87402","9d36f238":"87510","0773e78b":"87760","73ca4188":"88048",c2237e68:"88131","504d78e0":"88494","801276a1":"88495","51c7df8c":"88790","45926b62":"88843","95ec96e5":"88946","4b6eee9a":"89598",cc180519:"90049","869d42f3":"90381","07006f9e":"90642","098f2604":"90780","468d57a9":"91131","227d1fc4":"91258",a0aa5253:"91395","32b8fafb":"92113","4951b372":"92170",cd64d641:"92687","8093477b":"92811",bc69c5bc:"92896",c342bcae:"93036",b0f19176:"93087","26398b18":"93842",c7507218:"94594",da19ecb4:"94642",dd31e7e9:"94725",da071cb8:"94811",c75d145e:"95191","94f11012":"95409","19a6be06":"96449","8d02075b":"96815","4eee9c87":"96991","31b73615":"97191",reactPlayerFilePlayer:"97458","50a12feb":"97499",ac5db01d:"97785","819b642a":"98042","5a96e453":"98175",ae22b856:"98498","44a83f6a":"98548","65c67349":"98996","08aab21d":"99094","32ebcda7":"99180",reactPlayerWistia:"99340",a1154d73:"99341",e0bec135:"99591","51ddac88":"99989"}[e]||e,t.p+t.u(e)},(()=>{var e={45354:0,71869:0};t.f.j=(a,c)=>{var f=t.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(45354|71869)$/.test(a))e[a]=0;else{var d=new Promise(((c,d)=>f=e[a]=[c,d]));c.push(f[2]=d);var b=t.p+t.u(a),r=new Error;t.l(b,(c=>{if(t.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var d=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;r.message="Loading chunk "+a+" failed.\n("+d+": "+b+")",r.name="ChunkLoadError",r.type=d,r.request=b,f[1](r)}}),"chunk-"+a,a)}},t.O.j=a=>0===e[a];var a=(a,c)=>{var f,d,b=c[0],r=c[1],o=c[2],l=0;if(b.some((a=>0!==e[a]))){for(f in r)t.o(r,f)&&(t.m[f]=r[f]);if(o)var n=o(t)}for(a&&a(c);l{"use strict";var e,a,c,f,d,b={},r={};function t(e){var a=r[e];if(void 0!==a)return a.exports;var c=r[e]={exports:{}};return b[e].call(c.exports,c,c.exports,t),c.exports}t.m=b,e=[],t.O=(a,c,f,d)=>{if(!c){var b=1/0;for(n=0;n=d)&&Object.keys(t.O).every((e=>t.O[e](c[o])))?c.splice(o--,1):(r=!1,d0&&e[n-1][2]>d;n--)e[n]=e[n-1];e[n]=[c,f,d]},t.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return t.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var d=Object.create(null);t.r(d);var b={};a=a||[null,c({}),c([]),c(c)];for(var r=2&f&&e;"object"==typeof r&&!~a.indexOf(r);r=c(r))Object.getOwnPropertyNames(r).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,t.d(d,b),d},t.d=(e,a)=>{for(var c in a)t.o(a,c)&&!t.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((a,c)=>(t.f[c](e,a),a)),[])),t.u=e=>"assets/js/"+({456:"cb867d98",565:"3f04b2f3",762:"cdc118a8",1160:"638e38ae",1171:"b685e31b",1572:"02c0cfe0",1705:"1921e4ca",1832:"bdc5a52e",1923:"b32c213b",1970:"dbf9e27d",2278:"27e827f8",2295:"0a5c01b2",2496:"3874f1bf",2730:"ac6e050c",3202:"8e7261c9",3230:"9d217e1f",3249:"05ec9480",3392:"reactPlayerVidyard",3607:"d8d6d57b",3783:"a6c3ea4a",3877:"79840965",3900:"ecb3c634",4272:"17dc776d",4276:"7a3d47b3",4499:"f149b10e",4550:"e3443ce0",4574:"976a2d80",4645:"9644aa4e",5e3:"da698f4c",5344:"8baf194b",5352:"52f87500",5441:"af1c5d2b",5623:"10ad1fa6",5819:"e4a796aa",5827:"3d277f18",5885:"3e4a4cb2",6157:"cce58fe7",6215:"f3467f26",6262:"27b43779",6265:"46b54090",6308:"2890c80c",6463:"reactPlayerKaltura",6486:"2e1ee4ed",6497:"5112ebe3",6615:"7b06977d",6918:"89b55a09",7161:"19e323d1",7267:"2db5c390",7606:"7517a61c",7701:"c2b45dbb",7785:"95bf5f56",8271:"94b2bc9a",8349:"06a408fe",8500:"4c5c4c2e",8734:"82e43b76",8927:"b8787c81",9264:"1caa8cdb",9524:"daec0d60",9606:"4519f039",9640:"5589c54d",9647:"5e95c892",9671:"e64edb60",9837:"5a0a1617",10348:"fca5fdb4",10700:"313c9eb1",10845:"5c1eff22",10907:"f7ae65ac",11139:"dc7352a7",11184:"8af032d3",11301:"f584139f",11567:"22dd74f7",11607:"ef2492df",11784:"45dd886d",11934:"b809d820",11965:"1457ddcd",12007:"90ec8c6b",12042:"reactPlayerTwitch",12237:"b6f81eaa",12716:"d2aa311d",12766:"4934de22",12827:"28967b3e",13018:"076cf272",13019:"d3938b1f",13455:"5839343c",13535:"e84b4e80",13585:"ea237062",13650:"2d11a680",14237:"95a5d2b2",14715:"fc8c8cde",14936:"7c8e5227",15066:"fe3f3783",15246:"83c6f999",15447:"30bd0f5b",16328:"reactPlayerDailyMotion",16602:"616631fd",16678:"710ac1c1",16869:"444a6d4e",16884:"4ed1e0ac",16945:"5596dd05",17021:"828ace52",17209:"f9bde383",17289:"45939ed5",17320:"55f37562",17776:"070c8c93",17820:"ebd05845",18093:"0841186f",18401:"17896441",18446:"reactPlayerYouTube",19049:"2fca5c64",19738:"87ab7385",20033:"986f0f98",20210:"68401255",20423:"22f51758",20515:"704545ab",20681:"e66f2658",20773:"d4fc3158",20826:"4ab30eec",21611:"82444e58",21983:"57012fa6",22422:"d3af5b3c",22451:"f5a589e7",22611:"59df87e8",22750:"141135bb",23321:"676f1bdb",23452:"5af30237",23453:"ed64c12e",23619:"f6affd6e",23870:"956829f8",24078:"ec91ff36",24158:"1d39c85d",24295:"96523456",24832:"02e41de2",25362:"5bc657fa",25427:"3edac44d",25504:"0f2c2e36",25666:"522ca66b",25691:"9a594c98",25692:"7ca2e59a",26173:"reactPlayerVimeo",26376:"431ffdb5",26499:"a4adf53f",26622:"d9107a6a",27168:"7ac69e68",27350:"65e04ea3",27646:"12407b36",27685:"6aee17c2",27740:"38e32826",28235:"965931d7",29248:"4a49065b",29250:"dec2bd4a",29436:"dc8c27bd",29773:"1a84c7fd",30248:"b1218054",30418:"6feb7661",30473:"3141060a",30528:"1323771c",30765:"85d514f3",30799:"1a39ee04",30941:"4aa94ec1",31165:"926056c1",31267:"08d55cf7",31471:"3f80bb14",31474:"564db590",31727:"2e18ba50",32055:"9037180b",32096:"c090764b",32141:"df1414bb",32163:"3d150a24",32178:"16116660",32406:"5cde491b",32461:"a6311318",32492:"4e689a0b",32504:"7de3e81f",32741:"d9e7b984",32759:"7800d508",32944:"272aa200",33048:"25c6d77a",33098:"71ba2dc1",33460:"9107c65f",33577:"a32c313f",33992:"cbf3c4ec",34321:"6f56eca8",34438:"54cab4d4",34662:"cf3c245e",34726:"1b6591f7",34750:"07e708e9",34935:"6da448d1",34975:"ff5ed6ba",35223:"db7d4591",35540:"ce86e3e6",35563:"e7977816",35654:"dc4059b2",35742:"aba21aa0",35748:"1312139a",35884:"9c9052d1",36058:"a2a1c245",36132:"e8f4756d",36353:"reactPlayerPreview",36731:"bd568e77",36886:"8abbb0ee",36920:"ed772d97",37107:"3817c387",37296:"a2757506",37516:"9f1829f0",37710:"abd13aa2",37850:"b28bd8b1",37990:"441fd5fc",38031:"8ee9837e",38419:"bd6f2233",38471:"caf7731d",38527:"5e7d099e",38610:"c868bccf",38691:"036b5431",38717:"897331c0",38792:"4f0519c7",38853:"fc67ad3d",38864:"fac0eceb",39026:"c7156cf2",39056:"5f6b1733",39080:"511f9951",39408:"fe2e2e26",39431:"cdd4a9c6",39482:"327b0a57",39558:"50f2f9f3",39757:"9e0c2c37",39911:"92466816",40271:"6a734661",40374:"b5dcbe95",40563:"39dec3ba",40575:"33c1d41a",41237:"88a48c42",41507:"16b03284",41865:"fe76eed8",42083:"4048090e",42206:"91aed80e",42434:"5b2d7e3c",42800:"3aa0ab0a",42901:"2115313f",43174:"6ba85e75",43246:"2d16d24d",43444:"d2f6d210",43773:"a81cb65f",43848:"44145933",43888:"ad61550a",43903:"8186ecf9",44046:"5d707891",44486:"c0650537",44602:"69fcd2fc",44609:"c5313007",44630:"65b7208a",44816:"36fcb744",44947:"39ec0930",45141:"b1394c86",45268:"ef4456b5",45295:"f29fc884",45474:"79d28454",45655:"4a55fe3a",45724:"8dfd8953",45742:"c377a04b",46119:"d58f1ee2",46364:"fe522f67",46563:"aeef55f7",46688:"ac3101e9",46921:"d0b9ca74",46961:"2bbc2deb",47120:"dcbfe205",47127:"999788b8",47264:"b9ec56c8",47341:"7f0714d1",47527:"93dcedec",47627:"reactPlayerStreamable",47719:"b7ea99f7",48124:"8f509517",48134:"356ce494",48235:"df15bc7d",48276:"b467d32a",48436:"f6adf820",48552:"954e932f",48579:"566f49fb",48665:"0f4a5c74",49316:"510b9307",49406:"b26210db",49455:"c8139b75",49658:"0d76317c",49921:"fc8b5a5d",50041:"ac002d2b",50404:"98f4e1ec",50765:"bf519c8d",50908:"3fbaac07",51143:"fc6f07d2",51205:"db42f242",51349:"4aec9039",51379:"17f04a83",51637:"81e4ed6a",51780:"eecc43ff",52302:"e7ee6027",52365:"280af06a",52529:"e3d58533",52723:"reactPlayerMux",53084:"23975af2",53148:"9b4ab8cd",53357:"1577f7ed",53774:"53998120",54049:"4867e743",54220:"092bf57d",54530:"a271ef09",54582:"984d6493",54905:"98d962c5",55011:"49145cdf",55388:"b2419a00",55664:"169f3d24",56264:"46eeb6cb",56282:"d636c09f",56383:"ecaa7076",56420:"fd4b36bb",56684:"378935ce",56764:"805a59dc",57035:"f527bef3",57356:"bb9c591b",57694:"21b7a589",57790:"1b218eaa",57869:"a7edc2bd",58022:"c134ef8a",58215:"1111b27e",58718:"afb7a97b",58800:"5144cf5e",59075:"6e29a506",59221:"76259cc3",59332:"857097c6",59409:"a64b2578",59599:"1e1f8072",59600:"ac9d9d69",59949:"5c6f6ba9",60365:"bd118f84",60759:"719163ad",60880:"640696ee",60886:"c10a0985",60893:"6fbf0c67",60908:"0eebd274",61114:"3cc71396",61252:"3b66921f",61273:"099a3596",61291:"d38e3f9f",61358:"3d1ae229",61368:"f28f059c",61505:"e58556b2",61977:"7570de64",62059:"0893faed",62134:"0d7acd84",62357:"6d2a4d3f",62362:"44463284",62573:"bd1cffff",62921:"1d7c691c",62929:"f5fed352",63474:"98c94590",63538:"06393fc1",63706:"2b67eda4",63737:"53e9dd7a",63747:"fb72d7b2",63960:"a6397568",64558:"b91fbf2a",64641:"eac16e1d",64651:"4c781063",64665:"6f44ab90",65110:"063d75bd",65142:"eb4c176e",65433:"616bfcf6",65542:"af754a1f",65655:"1ebbfca8",65755:"bafd283f",65784:"90239e6e",65866:"419cd6b8",66225:"9f8e6d57",66339:"03b2528f",66811:"3e87058f",66850:"0c695afe",66868:"3c4af576",66885:"5e253f2f",66929:"da54b976",67068:"ae0eacdd",67098:"a7bd4aaa",67217:"726a6c22",67349:"61ff6850",67458:"0d271e1e",67532:"49fed513",67570:"reactPlayerMixcloud",67714:"9d7352c0",68230:"3cf6fa35",68364:"812775a4",68391:"24557dbc",68700:"96331245",68874:"10ea0b82",68912:"2c2832e4",68915:"62de5d73",68960:"358c2507",68962:"af68ae04",69050:"4ac2e930",69779:"3c9432f0",69816:"20d56cb7",69891:"62037464",69979:"reactPlayerSoundCloud",70326:"c3373259",70934:"d44e0d1c",71247:"308471de",71383:"087cd58c",71826:"a4c89d62",71907:"86a8bb6c",71967:"4fa4eafa",72074:"71319bec",72132:"83ac10ed",72231:"fe170cc9",72561:"adce8179",73107:"646cbece",73379:"9d779d8b",73932:"2020ed93",73939:"2ed96714",74081:"ce4dbf6d",74583:"4bfca71d",74780:"ebde045d",74834:"d26a73b8",74860:"00d14154",75412:"5390e21f",75702:"307525ba",75822:"2db99065",75868:"071f33a8",75965:"b48f41b9",76093:"7d63aba8",76224:"03b3cfd2",76238:"8615e055",76372:"d802bb56",76768:"8bed5a26",76973:"78ae7ec8",77137:"42abcd4d",77313:"ee65edec",77318:"67e77328",77757:"f6f476f1",78007:"8eead450",78416:"068743c8",78631:"b7b014bf",78702:"82ea7079",79048:"a94703ab",79052:"6d717251",79225:"526e379a",79354:"4118187a",79825:"2d4af3bf",79956:"9e09f891",79983:"a7f483d1",80549:"afde3230",80721:"05fa9a60",81509:"4ead9a95",81657:"f8189ec4",81790:"42a9b3c5",81849:"2e3fc0f9",82075:"056b386b",82201:"18910d94",82261:"0c6fe626",82439:"e4eafb12",82477:"2ca08277",83287:"7af31c45",83752:"efe5610c",83943:"9c5d9512",84219:"51e50f95",84331:"79e0e7f1",84605:"8552f549",84656:"813cfb2f",84750:"aefdd881",84850:"bc03f89b",85462:"9270ba4f",85527:"5143312c",85528:"21e10cde",85556:"21a4ba71",85943:"05fbef88",86012:"da202fdd",86037:"eaeab60b",86057:"9fbfaf6d",86106:"1877d9d5",86298:"e2d6ba1f",86886:"7b33c27b",86887:"reactPlayerFacebook",86992:"3fe65583",87012:"869ae8a7",87126:"b916a1ab",87402:"c3094240",87510:"9d36f238",87760:"0773e78b",88048:"73ca4188",88131:"c2237e68",88494:"504d78e0",88495:"801276a1",88790:"51c7df8c",88843:"45926b62",88946:"95ec96e5",89598:"4b6eee9a",90049:"cc180519",90381:"869d42f3",90642:"07006f9e",90780:"098f2604",91131:"468d57a9",91258:"227d1fc4",91395:"a0aa5253",92113:"32b8fafb",92170:"4951b372",92687:"cd64d641",92811:"8093477b",92896:"bc69c5bc",93036:"c342bcae",93087:"b0f19176",93842:"26398b18",94594:"c7507218",94642:"da19ecb4",94725:"dd31e7e9",94811:"da071cb8",95191:"c75d145e",95409:"94f11012",96449:"19a6be06",96815:"8d02075b",96991:"4eee9c87",97191:"31b73615",97458:"reactPlayerFilePlayer",97499:"50a12feb",97785:"ac5db01d",98042:"819b642a",98116:"49849746",98175:"5a96e453",98498:"ae22b856",98548:"44a83f6a",98601:"13798859",98996:"65c67349",99094:"08aab21d",99180:"32ebcda7",99340:"reactPlayerWistia",99341:"a1154d73",99591:"e0bec135",99989:"51ddac88"}[e]||e)+"."+{456:"5c30ecdd",565:"94a09b6c",762:"df50c981",1160:"918efc1f",1171:"de34cd0e",1572:"ffbe0cfc",1705:"038460b6",1832:"9614689c",1923:"cb2bc5be",1970:"cac2a9b8",2278:"d475be2b",2295:"e81bbf25",2496:"b540b729",2730:"923b54e1",3202:"f35694a9",3230:"4129121e",3249:"82c7846c",3392:"8464e17b",3607:"2981ded1",3783:"71a2f8e8",3877:"58749100",3900:"0ba32b97",4272:"0900e2a1",4276:"8faf83a5",4499:"ca8d1432",4550:"46f5f770",4574:"1c78d390",4645:"e160e737",5e3:"e340e97d",5344:"1d1077a2",5352:"5ee75c06",5441:"151c62bf",5623:"9548c1a1",5819:"a4a89c82",5827:"5cc9996e",5885:"fcb3bbcb",6157:"dd0a4d50",6215:"51944600",6262:"794fd95d",6265:"83c21074",6308:"350484bc",6463:"bec1a06c",6486:"4b0eb0a1",6497:"42707b0b",6615:"7db76aa6",6918:"031ec4ab",7161:"2c411627",7267:"ce74b45c",7606:"45b626ad",7701:"316b1161",7785:"f569d217",8271:"bce6ddee",8349:"03f95123",8500:"a390a5ca",8734:"2de05990",8927:"f986535a",9264:"6ae52032",9524:"e7c42f6f",9606:"bff55b72",9640:"b703cc22",9647:"cac24016",9671:"0a30cd6c",9837:"ede23a01",10348:"ec8b3811",10700:"708d8037",10845:"2bc04da3",10907:"eb9d65c3",11139:"303df097",11184:"9d69cbad",11301:"8387b5bf",11567:"432c7b35",11607:"b64b2d67",11784:"9d3408ab",11934:"da61538a",11965:"d6e5dd4d",12007:"fb425a62",12042:"a0c42814",12237:"8a850fa6",12716:"faed95e1",12766:"97abbc05",12827:"144f3020",13018:"c5ad98c6",13019:"c5e3aef7",13455:"1451755d",13535:"88a06537",13585:"a746e017",13650:"62810914",14237:"8c2a2bc3",14715:"95abf808",14936:"6ee147d1",15066:"38ece79e",15246:"fd5943dc",15447:"82977fde",16328:"4fa8d3c8",16602:"f2bf07f8",16678:"cb38a105",16869:"995c6ef6",16884:"bf9abfa1",16945:"1eaf58e9",17021:"6c74822a",17209:"e94a64b5",17289:"e2e7eec1",17320:"9ddeadd7",17776:"f89fd2b8",17820:"623e6e0e",18093:"d4afddde",18401:"30c4f83a",18446:"150ff8a0",19049:"08036f4e",19738:"a816c680",20033:"fa674d6a",20210:"4ea135dd",20423:"076d2946",20515:"85d707fe",20681:"7e97a650",20773:"a2cebc00",20826:"8b874cbc",21611:"6e533a7e",21983:"f9a941e2",22422:"feb00a9e",22451:"ef972e5e",22611:"18587ae4",22750:"a52908e5",23321:"84054f56",23452:"ebba4448",23453:"2ff5cbe7",23619:"c27273de",23870:"3742bfab",24078:"730ca41c",24158:"ce6a000b",24295:"4aae9b71",24832:"af6b73df",25362:"f0170814",25427:"3244da9c",25504:"28938478",25666:"2f0c77bf",25691:"426557b6",25692:"585ab289",26173:"076fef9c",26376:"a1f11cb7",26499:"dd7640ab",26622:"f0629b1b",27168:"e3dc9e21",27350:"5fd6e6d7",27646:"0678c8f9",27685:"f20ffda9",27740:"8f7d4d98",28235:"f6cbcccb",29248:"d7c12529",29250:"925abd2b",29436:"7ca95c22",29773:"b8c6f670",30248:"0ad8a16e",30418:"5fc7b2a0",30473:"0abc4692",30528:"435813db",30765:"d86090af",30799:"388c9414",30941:"49876b37",31165:"02614496",31267:"933156b4",31471:"450344fc",31474:"dbbf8152",31727:"d3f3b0b1",32055:"a95bfc3b",32096:"04828676",32141:"bcdc361b",32163:"70936a3c",32178:"36e60316",32406:"bd1dc0ac",32461:"6b4a958d",32492:"30cd7c7f",32504:"754ac7de",32741:"552767cd",32759:"d8e2798a",32944:"6f349f74",33048:"1a010730",33098:"480f07f7",33460:"8f3f92e4",33577:"ce38b0c8",33992:"a7260a35",34321:"ab8e5c20",34438:"8f46a7dd",34662:"8da76618",34726:"90739fe9",34750:"13529313",34935:"59f5597e",34975:"41c5c4bb",35223:"2367e813",35540:"daa770e8",35563:"22b8fd33",35654:"72cb9c74",35742:"e08a145a",35748:"816249d7",35884:"a0bf4e6b",36058:"b63b94d9",36132:"75cbf3f9",36353:"4de9bab6",36731:"1ab1d6ee",36886:"9c9e515a",36920:"3a69befa",37107:"f19c047b",37296:"20763684",37516:"2ab4897d",37710:"5cf4ff57",37850:"ed2f760b",37990:"fa9f8a31",38031:"396006c8",38419:"a12c2499",38471:"93b2d4dd",38527:"73056614",38610:"37df5efb",38691:"137dc0f8",38717:"6dbb7b59",38792:"7deb9f3e",38853:"5c9e45fe",38864:"4813ef31",39026:"f2f8a69b",39056:"60f70f39",39080:"b0c77b48",39408:"88db313c",39431:"2bcf2e6d",39482:"7e3b08ef",39503:"18fac5cf",39558:"41945f10",39757:"47703e3b",39911:"646e7dec",40271:"f790e023",40374:"179979e4",40563:"94247613",40575:"4d0b112e",41237:"3bbdf534",41507:"77c30778",41865:"c835f8b0",42083:"2aff9481",42206:"18d5693f",42434:"1f6d6607",42800:"bf6545c0",42901:"2fdbe13a",43174:"013544f4",43246:"ddc98077",43444:"cff02423",43773:"3cc7db7d",43848:"57247e24",43888:"d74ff318",43903:"41a52d13",44046:"a946825c",44486:"28ccbcec",44602:"aaf93cb1",44609:"32c1fd2c",44630:"f2d8976e",44816:"0e7f93b4",44947:"a24467f3",45141:"e3968051",45268:"7006193f",45295:"b0715bed",45474:"1abec566",45655:"c2164e90",45724:"b59ddc1b",45742:"2497dd34",46119:"7805de88",46364:"fdfddfc0",46563:"2e6253c5",46688:"a1d131c8",46921:"260d54e0",46961:"94b493aa",47120:"723a0b3e",47127:"de5390c4",47264:"44b44216",47341:"18ca620e",47527:"d950e87e",47627:"bb35fa43",47719:"646275e7",48124:"55af4038",48134:"b6137268",48235:"bc75728e",48276:"231a1e55",48436:"89305d4a",48552:"c704b5f4",48579:"bbd9e592",48665:"b81074e2",49316:"5e345ac8",49406:"a3ecaee8",49455:"15c58fe1",49658:"3da918b0",49921:"f2c2a1f0",50041:"f7cb55c7",50404:"eb1ab0f9",50765:"479f1916",50908:"a5b524ad",51143:"136727d9",51205:"ee2e77cb",51349:"1e076875",51379:"27ea6246",51637:"ffb79940",51780:"ce9149be",52302:"340b0e6b",52365:"d23ef6a9",52529:"e7cefacb",52723:"3e4df075",53084:"315da40f",53148:"4212deb6",53357:"b5a1c415",53774:"72126425",54049:"4089600b",54220:"d4f185d8",54530:"0bd12311",54582:"4e5700b0",54905:"feb41c26",55011:"95879cb0",55388:"33179a2f",55664:"258a4e6b",56264:"6318e439",56282:"b46c91af",56383:"1ff19ca5",56420:"1972625f",56684:"ab8eab18",56764:"ac5b41d7",57035:"ad79c7ab",57356:"42441995",57694:"a34951a6",57790:"4a46f698",57869:"89931416",58022:"7b3238f1",58215:"5be13c8d",58718:"a820c36e",58800:"e98ceb1d",59075:"25749229",59221:"658e6207",59332:"84712487",59409:"be73a79d",59599:"780630f8",59600:"ca1b31c5",59949:"0c457c29",60365:"1fd2fa70",60759:"d322d307",60880:"f6ba7287",60886:"67c47b8d",60893:"fe1ea3f9",60908:"e76a5e92",61114:"46cf560e",61252:"0ab3ec6f",61273:"05750299",61291:"0f509abf",61358:"9defced7",61368:"88200516",61505:"1a21d780",61977:"3a915ac8",62059:"27a610be",62134:"136bb77a",62357:"dd821bdf",62362:"8db1be48",62573:"09b3ebf3",62921:"9d42f085",62929:"c76283aa",63474:"bb220697",63538:"7b7f0e14",63706:"6f94bc8f",63737:"af78b6a2",63747:"7c5b8fbd",63960:"9f0fe283",64558:"25e0c733",64641:"4002d9f9",64651:"7df9a0dc",64665:"b140ef8f",65110:"0c2123d1",65142:"d226848c",65433:"d959ad9b",65542:"a7c67c53",65655:"3f647a48",65755:"c46f5968",65784:"b94d85b3",65866:"f9e10c84",66225:"f10f224f",66339:"800c2e61",66811:"945f99d9",66850:"7753ee7f",66868:"65080ded",66885:"1bd3e9c3",66929:"d218d95f",67068:"046fc798",67098:"03929b29",67217:"c9c29188",67349:"b94a3a6a",67458:"f760b356",67532:"60df9b16",67570:"12aff88e",67714:"973cd9fc",68230:"835eaee7",68364:"53e94f68",68391:"262895ce",68700:"64fe7812",68874:"d1febe02",68912:"0c81f713",68915:"57e00474",68960:"18b5e3ad",68962:"d845c0a4",69050:"358b5513",69779:"faba2980",69816:"58af7b00",69891:"80af80ae",69979:"f8f19bc3",70326:"fafebdcb",70934:"73854ef9",71247:"5a63971c",71383:"75b257bc",71826:"9f1c6fe5",71907:"0751c0f3",71967:"1af4694c",72074:"522fdb31",72132:"6e4054d2",72231:"e3c174bf",72561:"1f9fbc90",73107:"ecc6be9c",73379:"16b17994",73932:"b35fd796",73939:"aba6bb06",74081:"b57cba4e",74583:"ce4c9b2f",74780:"b7d71cb3",74834:"15357603",74860:"426c5862",75412:"d72a934a",75702:"3926a131",75822:"1d9852b1",75868:"3118d0c9",75965:"19020673",76093:"8e28eeb6",76224:"8f29238e",76238:"a738aae6",76372:"297afbc9",76768:"c3ca6e24",76973:"a72e321d",77137:"daff0432",77313:"b92d7b2e",77318:"44e1adab",77757:"eb1c1544",78007:"2b6a8f00",78416:"2ad246f2",78631:"b6f33b62",78702:"ed155bd3",79048:"0f54d2a9",79052:"634be361",79225:"bad5b331",79354:"d6957fa9",79825:"8c4cf900",79956:"4d5ec1eb",79983:"52b6f63f",80549:"a1b3777a",80721:"cdf43ae5",81509:"5a98113a",81657:"d230bb30",81790:"c56f6a89",81849:"0f44253c",82075:"7a5a588a",82201:"c855be90",82237:"787c04ec",82261:"2fc96e72",82439:"18a56b6c",82477:"12d174de",83287:"084dde1a",83752:"d91cc53e",83943:"a64bf43a",84219:"d24c437b",84331:"b37577e8",84605:"8cf0495c",84656:"73c53ede",84750:"1857e769",84850:"f287e029",85462:"ddca2c18",85527:"3afd894d",85528:"74b87448",85556:"fee97575",85943:"e5b4cdd6",86012:"ab7bdaa5",86037:"04050011",86057:"db95e34c",86106:"1290858d",86298:"92e42ef4",86886:"dad3b87b",86887:"508da014",86992:"82004d70",87012:"fd4f4b30",87126:"89adbb17",87402:"abdfd46c",87510:"720f0f93",87760:"72f8f4bb",88048:"2a1833d8",88131:"e11652fa",88494:"7d33658e",88495:"efabda4c",88790:"c5a360b0",88843:"ba8ab281",88946:"350ed3aa",89598:"30bcd67d",90049:"70470979",90381:"4acaccf6",90642:"83acf9a9",90780:"75e3e359",91131:"759062e1",91258:"0a10d55b",91395:"31f57203",92113:"439ef5f1",92170:"f7b1e9bd",92687:"bed1a1d3",92811:"8a204457",92896:"b265749e",93036:"7c8d08ac",93087:"0090bbd7",93842:"d418eca4",94594:"42c52295",94642:"c0efeaa4",94725:"7118b112",94811:"933445a7",95191:"0ee87f70",95409:"6f87b63a",96449:"9cfed380",96815:"362b1a69",96991:"eca5cf70",97191:"ca75b3a5",97458:"036de6e1",97499:"1a4e721e",97785:"bf926c46",98042:"14a96714",98116:"a22cb511",98175:"b8bdaaeb",98498:"1128c3c9",98548:"0250dbf6",98601:"75b6fdce",98996:"433b1eca",99094:"54319916",99180:"e5d0a4e7",99340:"c5c0cf6c",99341:"4403c816",99591:"4e74c25b",99989:"1ffc7914"}[e]+".js",t.miniCssF=e=>{},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},d="serverpod-docs:",t.l=(e,a,c,b)=>{if(f[e])f[e].push(a);else{var r,o;if(void 0!==c)for(var l=document.getElementsByTagName("script"),n=0;n{r.onerror=r.onload=null,clearTimeout(s);var d=f[e];if(delete f[e],r.parentNode&&r.parentNode.removeChild(r),d&&d.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=u.bind(null,r.onerror),r.onload=u.bind(null,r.onload),o&&document.head.appendChild(r)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={13798859:"98601",16116660:"32178",17896441:"18401",44145933:"43848",44463284:"62362",49849746:"98116",53998120:"53774",62037464:"69891",68401255:"20210",79840965:"3877",92466816:"39911",96331245:"68700",96523456:"24295",cb867d98:"456","3f04b2f3":"565",cdc118a8:"762","638e38ae":"1160",b685e31b:"1171","02c0cfe0":"1572","1921e4ca":"1705",bdc5a52e:"1832",b32c213b:"1923",dbf9e27d:"1970","27e827f8":"2278","0a5c01b2":"2295","3874f1bf":"2496",ac6e050c:"2730","8e7261c9":"3202","9d217e1f":"3230","05ec9480":"3249",reactPlayerVidyard:"3392",d8d6d57b:"3607",a6c3ea4a:"3783",ecb3c634:"3900","17dc776d":"4272","7a3d47b3":"4276",f149b10e:"4499",e3443ce0:"4550","976a2d80":"4574","9644aa4e":"4645",da698f4c:"5000","8baf194b":"5344","52f87500":"5352",af1c5d2b:"5441","10ad1fa6":"5623",e4a796aa:"5819","3d277f18":"5827","3e4a4cb2":"5885",cce58fe7:"6157",f3467f26:"6215","27b43779":"6262","46b54090":"6265","2890c80c":"6308",reactPlayerKaltura:"6463","2e1ee4ed":"6486","5112ebe3":"6497","7b06977d":"6615","89b55a09":"6918","19e323d1":"7161","2db5c390":"7267","7517a61c":"7606",c2b45dbb:"7701","95bf5f56":"7785","94b2bc9a":"8271","06a408fe":"8349","4c5c4c2e":"8500","82e43b76":"8734",b8787c81:"8927","1caa8cdb":"9264",daec0d60:"9524","4519f039":"9606","5589c54d":"9640","5e95c892":"9647",e64edb60:"9671","5a0a1617":"9837",fca5fdb4:"10348","313c9eb1":"10700","5c1eff22":"10845",f7ae65ac:"10907",dc7352a7:"11139","8af032d3":"11184",f584139f:"11301","22dd74f7":"11567",ef2492df:"11607","45dd886d":"11784",b809d820:"11934","1457ddcd":"11965","90ec8c6b":"12007",reactPlayerTwitch:"12042",b6f81eaa:"12237",d2aa311d:"12716","4934de22":"12766","28967b3e":"12827","076cf272":"13018",d3938b1f:"13019","5839343c":"13455",e84b4e80:"13535",ea237062:"13585","2d11a680":"13650","95a5d2b2":"14237",fc8c8cde:"14715","7c8e5227":"14936",fe3f3783:"15066","83c6f999":"15246","30bd0f5b":"15447",reactPlayerDailyMotion:"16328","616631fd":"16602","710ac1c1":"16678","444a6d4e":"16869","4ed1e0ac":"16884","5596dd05":"16945","828ace52":"17021",f9bde383:"17209","45939ed5":"17289","55f37562":"17320","070c8c93":"17776",ebd05845:"17820","0841186f":"18093",reactPlayerYouTube:"18446","2fca5c64":"19049","87ab7385":"19738","986f0f98":"20033","22f51758":"20423","704545ab":"20515",e66f2658:"20681",d4fc3158:"20773","4ab30eec":"20826","82444e58":"21611","57012fa6":"21983",d3af5b3c:"22422",f5a589e7:"22451","59df87e8":"22611","141135bb":"22750","676f1bdb":"23321","5af30237":"23452",ed64c12e:"23453",f6affd6e:"23619","956829f8":"23870",ec91ff36:"24078","1d39c85d":"24158","02e41de2":"24832","5bc657fa":"25362","3edac44d":"25427","0f2c2e36":"25504","522ca66b":"25666","9a594c98":"25691","7ca2e59a":"25692",reactPlayerVimeo:"26173","431ffdb5":"26376",a4adf53f:"26499",d9107a6a:"26622","7ac69e68":"27168","65e04ea3":"27350","12407b36":"27646","6aee17c2":"27685","38e32826":"27740","965931d7":"28235","4a49065b":"29248",dec2bd4a:"29250",dc8c27bd:"29436","1a84c7fd":"29773",b1218054:"30248","6feb7661":"30418","3141060a":"30473","1323771c":"30528","85d514f3":"30765","1a39ee04":"30799","4aa94ec1":"30941","926056c1":"31165","08d55cf7":"31267","3f80bb14":"31471","564db590":"31474","2e18ba50":"31727","9037180b":"32055",c090764b:"32096",df1414bb:"32141","3d150a24":"32163","5cde491b":"32406",a6311318:"32461","4e689a0b":"32492","7de3e81f":"32504",d9e7b984:"32741","7800d508":"32759","272aa200":"32944","25c6d77a":"33048","71ba2dc1":"33098","9107c65f":"33460",a32c313f:"33577",cbf3c4ec:"33992","6f56eca8":"34321","54cab4d4":"34438",cf3c245e:"34662","1b6591f7":"34726","07e708e9":"34750","6da448d1":"34935",ff5ed6ba:"34975",db7d4591:"35223",ce86e3e6:"35540",e7977816:"35563",dc4059b2:"35654",aba21aa0:"35742","1312139a":"35748","9c9052d1":"35884",a2a1c245:"36058",e8f4756d:"36132",reactPlayerPreview:"36353",bd568e77:"36731","8abbb0ee":"36886",ed772d97:"36920","3817c387":"37107",a2757506:"37296","9f1829f0":"37516",abd13aa2:"37710",b28bd8b1:"37850","441fd5fc":"37990","8ee9837e":"38031",bd6f2233:"38419",caf7731d:"38471","5e7d099e":"38527",c868bccf:"38610","036b5431":"38691","897331c0":"38717","4f0519c7":"38792",fc67ad3d:"38853",fac0eceb:"38864",c7156cf2:"39026","5f6b1733":"39056","511f9951":"39080",fe2e2e26:"39408",cdd4a9c6:"39431","327b0a57":"39482","50f2f9f3":"39558","9e0c2c37":"39757","6a734661":"40271",b5dcbe95:"40374","39dec3ba":"40563","33c1d41a":"40575","88a48c42":"41237","16b03284":"41507",fe76eed8:"41865","4048090e":"42083","91aed80e":"42206","5b2d7e3c":"42434","3aa0ab0a":"42800","2115313f":"42901","6ba85e75":"43174","2d16d24d":"43246",d2f6d210:"43444",a81cb65f:"43773",ad61550a:"43888","8186ecf9":"43903","5d707891":"44046",c0650537:"44486","69fcd2fc":"44602",c5313007:"44609","65b7208a":"44630","36fcb744":"44816","39ec0930":"44947",b1394c86:"45141",ef4456b5:"45268",f29fc884:"45295","79d28454":"45474","4a55fe3a":"45655","8dfd8953":"45724",c377a04b:"45742",d58f1ee2:"46119",fe522f67:"46364",aeef55f7:"46563",ac3101e9:"46688",d0b9ca74:"46921","2bbc2deb":"46961",dcbfe205:"47120","999788b8":"47127",b9ec56c8:"47264","7f0714d1":"47341","93dcedec":"47527",reactPlayerStreamable:"47627",b7ea99f7:"47719","8f509517":"48124","356ce494":"48134",df15bc7d:"48235",b467d32a:"48276",f6adf820:"48436","954e932f":"48552","566f49fb":"48579","0f4a5c74":"48665","510b9307":"49316",b26210db:"49406",c8139b75:"49455","0d76317c":"49658",fc8b5a5d:"49921",ac002d2b:"50041","98f4e1ec":"50404",bf519c8d:"50765","3fbaac07":"50908",fc6f07d2:"51143",db42f242:"51205","4aec9039":"51349","17f04a83":"51379","81e4ed6a":"51637",eecc43ff:"51780",e7ee6027:"52302","280af06a":"52365",e3d58533:"52529",reactPlayerMux:"52723","23975af2":"53084","9b4ab8cd":"53148","1577f7ed":"53357","4867e743":"54049","092bf57d":"54220",a271ef09:"54530","984d6493":"54582","98d962c5":"54905","49145cdf":"55011",b2419a00:"55388","169f3d24":"55664","46eeb6cb":"56264",d636c09f:"56282",ecaa7076:"56383",fd4b36bb:"56420","378935ce":"56684","805a59dc":"56764",f527bef3:"57035",bb9c591b:"57356","21b7a589":"57694","1b218eaa":"57790",a7edc2bd:"57869",c134ef8a:"58022","1111b27e":"58215",afb7a97b:"58718","5144cf5e":"58800","6e29a506":"59075","76259cc3":"59221","857097c6":"59332",a64b2578:"59409","1e1f8072":"59599",ac9d9d69:"59600","5c6f6ba9":"59949",bd118f84:"60365","719163ad":"60759","640696ee":"60880",c10a0985:"60886","6fbf0c67":"60893","0eebd274":"60908","3cc71396":"61114","3b66921f":"61252","099a3596":"61273",d38e3f9f:"61291","3d1ae229":"61358",f28f059c:"61368",e58556b2:"61505","7570de64":"61977","0893faed":"62059","0d7acd84":"62134","6d2a4d3f":"62357",bd1cffff:"62573","1d7c691c":"62921",f5fed352:"62929","98c94590":"63474","06393fc1":"63538","2b67eda4":"63706","53e9dd7a":"63737",fb72d7b2:"63747",a6397568:"63960",b91fbf2a:"64558",eac16e1d:"64641","4c781063":"64651","6f44ab90":"64665","063d75bd":"65110",eb4c176e:"65142","616bfcf6":"65433",af754a1f:"65542","1ebbfca8":"65655",bafd283f:"65755","90239e6e":"65784","419cd6b8":"65866","9f8e6d57":"66225","03b2528f":"66339","3e87058f":"66811","0c695afe":"66850","3c4af576":"66868","5e253f2f":"66885",da54b976:"66929",ae0eacdd:"67068",a7bd4aaa:"67098","726a6c22":"67217","61ff6850":"67349","0d271e1e":"67458","49fed513":"67532",reactPlayerMixcloud:"67570","9d7352c0":"67714","3cf6fa35":"68230","812775a4":"68364","24557dbc":"68391","10ea0b82":"68874","2c2832e4":"68912","62de5d73":"68915","358c2507":"68960",af68ae04:"68962","4ac2e930":"69050","3c9432f0":"69779","20d56cb7":"69816",reactPlayerSoundCloud:"69979",c3373259:"70326",d44e0d1c:"70934","308471de":"71247","087cd58c":"71383",a4c89d62:"71826","86a8bb6c":"71907","4fa4eafa":"71967","71319bec":"72074","83ac10ed":"72132",fe170cc9:"72231",adce8179:"72561","646cbece":"73107","9d779d8b":"73379","2020ed93":"73932","2ed96714":"73939",ce4dbf6d:"74081","4bfca71d":"74583",ebde045d:"74780",d26a73b8:"74834","00d14154":"74860","5390e21f":"75412","307525ba":"75702","2db99065":"75822","071f33a8":"75868",b48f41b9:"75965","7d63aba8":"76093","03b3cfd2":"76224","8615e055":"76238",d802bb56:"76372","8bed5a26":"76768","78ae7ec8":"76973","42abcd4d":"77137",ee65edec:"77313","67e77328":"77318",f6f476f1:"77757","8eead450":"78007","068743c8":"78416",b7b014bf:"78631","82ea7079":"78702",a94703ab:"79048","6d717251":"79052","526e379a":"79225","4118187a":"79354","2d4af3bf":"79825","9e09f891":"79956",a7f483d1:"79983",afde3230:"80549","05fa9a60":"80721","4ead9a95":"81509",f8189ec4:"81657","42a9b3c5":"81790","2e3fc0f9":"81849","056b386b":"82075","18910d94":"82201","0c6fe626":"82261",e4eafb12:"82439","2ca08277":"82477","7af31c45":"83287",efe5610c:"83752","9c5d9512":"83943","51e50f95":"84219","79e0e7f1":"84331","8552f549":"84605","813cfb2f":"84656",aefdd881:"84750",bc03f89b:"84850","9270ba4f":"85462","5143312c":"85527","21e10cde":"85528","21a4ba71":"85556","05fbef88":"85943",da202fdd:"86012",eaeab60b:"86037","9fbfaf6d":"86057","1877d9d5":"86106",e2d6ba1f:"86298","7b33c27b":"86886",reactPlayerFacebook:"86887","3fe65583":"86992","869ae8a7":"87012",b916a1ab:"87126",c3094240:"87402","9d36f238":"87510","0773e78b":"87760","73ca4188":"88048",c2237e68:"88131","504d78e0":"88494","801276a1":"88495","51c7df8c":"88790","45926b62":"88843","95ec96e5":"88946","4b6eee9a":"89598",cc180519:"90049","869d42f3":"90381","07006f9e":"90642","098f2604":"90780","468d57a9":"91131","227d1fc4":"91258",a0aa5253:"91395","32b8fafb":"92113","4951b372":"92170",cd64d641:"92687","8093477b":"92811",bc69c5bc:"92896",c342bcae:"93036",b0f19176:"93087","26398b18":"93842",c7507218:"94594",da19ecb4:"94642",dd31e7e9:"94725",da071cb8:"94811",c75d145e:"95191","94f11012":"95409","19a6be06":"96449","8d02075b":"96815","4eee9c87":"96991","31b73615":"97191",reactPlayerFilePlayer:"97458","50a12feb":"97499",ac5db01d:"97785","819b642a":"98042","5a96e453":"98175",ae22b856:"98498","44a83f6a":"98548","65c67349":"98996","08aab21d":"99094","32ebcda7":"99180",reactPlayerWistia:"99340",a1154d73:"99341",e0bec135:"99591","51ddac88":"99989"}[e]||e,t.p+t.u(e)},(()=>{var e={45354:0,71869:0};t.f.j=(a,c)=>{var f=t.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(45354|71869)$/.test(a))e[a]=0;else{var d=new Promise(((c,d)=>f=e[a]=[c,d]));c.push(f[2]=d);var b=t.p+t.u(a),r=new Error;t.l(b,(c=>{if(t.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var d=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;r.message="Loading chunk "+a+" failed.\n("+d+": "+b+")",r.name="ChunkLoadError",r.type=d,r.request=b,f[1](r)}}),"chunk-"+a,a)}},t.O.j=a=>0===e[a];var a=(a,c)=>{var f,d,b=c[0],r=c[1],o=c[2],l=0;if(b.some((a=>0!==e[a]))){for(f in r)t.o(r,f)&&(t.m[f]=r[f]);if(o)var n=o(t)}for(a&&a(c);lCapabilities | Serverpod
-
+
diff --git a/docs/concepts/authentication/basics.html b/docs/concepts/authentication/basics.html
index 37e80b9f0..320a2cad3 100644
--- a/docs/concepts/authentication/basics.html
+++ b/docs/concepts/authentication/basics.html
@@ -4,7 +4,7 @@
The basics | Serverpod
-
+
diff --git a/docs/concepts/authentication/custom-overrides.html b/docs/concepts/authentication/custom-overrides.html
index 8a89d774e..96f82f422 100644
--- a/docs/concepts/authentication/custom-overrides.html
+++ b/docs/concepts/authentication/custom-overrides.html
@@ -4,7 +4,7 @@
Custom overrides | Serverpod
-
+
diff --git a/docs/concepts/authentication/providers/apple.html b/docs/concepts/authentication/providers/apple.html
index c32f9a016..6414f23da 100644
--- a/docs/concepts/authentication/providers/apple.html
+++ b/docs/concepts/authentication/providers/apple.html
@@ -4,7 +4,7 @@
Apple | Serverpod
-
+
diff --git a/docs/concepts/authentication/providers/custom-providers.html b/docs/concepts/authentication/providers/custom-providers.html
index 06f8a161f..694fcd606 100644
--- a/docs/concepts/authentication/providers/custom-providers.html
+++ b/docs/concepts/authentication/providers/custom-providers.html
@@ -4,7 +4,7 @@
Custom providers | Serverpod
-
+
diff --git a/docs/concepts/authentication/providers/email.html b/docs/concepts/authentication/providers/email.html
index 57385204b..16fc82218 100644
--- a/docs/concepts/authentication/providers/email.html
+++ b/docs/concepts/authentication/providers/email.html
@@ -4,7 +4,7 @@
Email | Serverpod
-
+
diff --git a/docs/concepts/authentication/providers/firebase.html b/docs/concepts/authentication/providers/firebase.html
index cbcd2a8f7..b392db5be 100644
--- a/docs/concepts/authentication/providers/firebase.html
+++ b/docs/concepts/authentication/providers/firebase.html
@@ -4,7 +4,7 @@
Firebase | Serverpod
-
+
diff --git a/docs/concepts/authentication/providers/google.html b/docs/concepts/authentication/providers/google.html
index acda14e79..776cd461a 100644
--- a/docs/concepts/authentication/providers/google.html
+++ b/docs/concepts/authentication/providers/google.html
@@ -4,7 +4,7 @@
Google | Serverpod
-
+
diff --git a/docs/concepts/authentication/setup.html b/docs/concepts/authentication/setup.html
index 6a3b90e23..5ebe68a52 100644
--- a/docs/concepts/authentication/setup.html
+++ b/docs/concepts/authentication/setup.html
@@ -4,7 +4,7 @@
Setup | Serverpod
-
+
diff --git a/docs/concepts/authentication/working-with-users.html b/docs/concepts/authentication/working-with-users.html
index 013eace4f..ff219256b 100644
--- a/docs/concepts/authentication/working-with-users.html
+++ b/docs/concepts/authentication/working-with-users.html
@@ -4,7 +4,7 @@
Working with users | Serverpod
-
+
diff --git a/docs/concepts/backward-compatibility.html b/docs/concepts/backward-compatibility.html
index fa6442a71..7e8312cac 100644
--- a/docs/concepts/backward-compatibility.html
+++ b/docs/concepts/backward-compatibility.html
@@ -4,7 +4,7 @@
Backward compatibility | Serverpod
-
+
diff --git a/docs/concepts/caching.html b/docs/concepts/caching.html
index c18c64338..011a32ef6 100644
--- a/docs/concepts/caching.html
+++ b/docs/concepts/caching.html
@@ -4,7 +4,7 @@
Caching | Serverpod
-
+
diff --git a/docs/concepts/configuration.html b/docs/concepts/configuration.html
index 039db2f2c..48ca0a1bc 100644
--- a/docs/concepts/configuration.html
+++ b/docs/concepts/configuration.html
@@ -4,7 +4,7 @@
Configurations | Serverpod
-
+
diff --git a/docs/concepts/database/connection.html b/docs/concepts/database/connection.html
index 86f79d57e..f620f420f 100644
--- a/docs/concepts/database/connection.html
+++ b/docs/concepts/database/connection.html
@@ -4,7 +4,7 @@
Connection | Serverpod
-
+
diff --git a/docs/concepts/database/crud.html b/docs/concepts/database/crud.html
index 2d2dc6e90..75fc9e103 100644
--- a/docs/concepts/database/crud.html
+++ b/docs/concepts/database/crud.html
@@ -4,7 +4,7 @@
CRUD | Serverpod
-
+
diff --git a/docs/concepts/database/filter.html b/docs/concepts/database/filter.html
index 3adaa7312..77e636321 100644
--- a/docs/concepts/database/filter.html
+++ b/docs/concepts/database/filter.html
@@ -4,7 +4,7 @@
Filter | Serverpod
-
+
diff --git a/docs/concepts/database/indexing.html b/docs/concepts/database/indexing.html
index e3e79551f..3d27162b7 100644
--- a/docs/concepts/database/indexing.html
+++ b/docs/concepts/database/indexing.html
@@ -4,7 +4,7 @@
Indexing | Serverpod
-
+
diff --git a/docs/concepts/database/migrations.html b/docs/concepts/database/migrations.html
index eb775bacc..6bea0bad6 100644
--- a/docs/concepts/database/migrations.html
+++ b/docs/concepts/database/migrations.html
@@ -4,7 +4,7 @@
Migrations | Serverpod
-
+
diff --git a/docs/concepts/database/models.html b/docs/concepts/database/models.html
index fb0a13484..b50e7f55c 100644
--- a/docs/concepts/database/models.html
+++ b/docs/concepts/database/models.html
@@ -4,7 +4,7 @@
Models | Serverpod
-
+
diff --git a/docs/concepts/database/pagination.html b/docs/concepts/database/pagination.html
index 547e2fb7d..6ca52950b 100644
--- a/docs/concepts/database/pagination.html
+++ b/docs/concepts/database/pagination.html
@@ -4,7 +4,7 @@
Pagination | Serverpod
-
+
diff --git a/docs/concepts/database/raw-access.html b/docs/concepts/database/raw-access.html
index 4d9a7918d..ee2834357 100644
--- a/docs/concepts/database/raw-access.html
+++ b/docs/concepts/database/raw-access.html
@@ -4,7 +4,7 @@
Raw access | Serverpod
-
+
diff --git a/docs/concepts/database/relation-queries.html b/docs/concepts/database/relation-queries.html
index 7f8bd4cf8..6cc4c7361 100644
--- a/docs/concepts/database/relation-queries.html
+++ b/docs/concepts/database/relation-queries.html
@@ -4,7 +4,7 @@
Relation queries | Serverpod
-
+
diff --git a/docs/concepts/database/relations/many-to-many.html b/docs/concepts/database/relations/many-to-many.html
index 1a525aaa5..9f1e7b063 100644
--- a/docs/concepts/database/relations/many-to-many.html
+++ b/docs/concepts/database/relations/many-to-many.html
@@ -4,7 +4,7 @@
Many-to-many | Serverpod
-
+
diff --git a/docs/concepts/database/relations/modules.html b/docs/concepts/database/relations/modules.html
index d3385101f..444a08172 100644
--- a/docs/concepts/database/relations/modules.html
+++ b/docs/concepts/database/relations/modules.html
@@ -4,7 +4,7 @@
Relations with modules | Serverpod
-
+
diff --git a/docs/concepts/database/relations/one-to-many.html b/docs/concepts/database/relations/one-to-many.html
index 83b92da8e..886efa5c8 100644
--- a/docs/concepts/database/relations/one-to-many.html
+++ b/docs/concepts/database/relations/one-to-many.html
@@ -4,7 +4,7 @@
One-to-many | Serverpod
-
+
diff --git a/docs/concepts/database/relations/one-to-one.html b/docs/concepts/database/relations/one-to-one.html
index 44b64e28a..2817ef72a 100644
--- a/docs/concepts/database/relations/one-to-one.html
+++ b/docs/concepts/database/relations/one-to-one.html
@@ -4,7 +4,7 @@
One-to-one | Serverpod
-
+
diff --git a/docs/concepts/database/relations/referential-actions.html b/docs/concepts/database/relations/referential-actions.html
index 6ccc967bf..05b586762 100644
--- a/docs/concepts/database/relations/referential-actions.html
+++ b/docs/concepts/database/relations/referential-actions.html
@@ -4,7 +4,7 @@
Referential actions | Serverpod
-
+
diff --git a/docs/concepts/database/relations/self-relations.html b/docs/concepts/database/relations/self-relations.html
index 7c0ba5a3e..4a8613604 100644
--- a/docs/concepts/database/relations/self-relations.html
+++ b/docs/concepts/database/relations/self-relations.html
@@ -4,7 +4,7 @@
Self-relations | Serverpod
-
+
diff --git a/docs/concepts/database/sort.html b/docs/concepts/database/sort.html
index e5a49fe91..02d2acb72 100644
--- a/docs/concepts/database/sort.html
+++ b/docs/concepts/database/sort.html
@@ -4,7 +4,7 @@
Sort | Serverpod
-
+
diff --git a/docs/concepts/database/transactions.html b/docs/concepts/database/transactions.html
index 4e8526619..abe06f786 100644
--- a/docs/concepts/database/transactions.html
+++ b/docs/concepts/database/transactions.html
@@ -4,7 +4,7 @@
Transactions | Serverpod
-
+
diff --git a/docs/concepts/exceptions.html b/docs/concepts/exceptions.html
index ebc4f6350..79b5a7438 100644
--- a/docs/concepts/exceptions.html
+++ b/docs/concepts/exceptions.html
@@ -4,7 +4,7 @@
Error handling and exceptions | Serverpod
-
+
diff --git a/docs/concepts/file-uploads.html b/docs/concepts/file-uploads.html
index 7404994ad..c520ad04a 100644
--- a/docs/concepts/file-uploads.html
+++ b/docs/concepts/file-uploads.html
@@ -4,7 +4,7 @@
Uploading files | Serverpod
-
+
diff --git a/docs/concepts/health-checks.html b/docs/concepts/health-checks.html
index 6749e83fe..4e78cfef6 100644
--- a/docs/concepts/health-checks.html
+++ b/docs/concepts/health-checks.html
@@ -4,7 +4,7 @@
Health checks | Serverpod
-
+
diff --git a/docs/concepts/logging.html b/docs/concepts/logging.html
index 537500c76..3e03f8d1d 100644
--- a/docs/concepts/logging.html
+++ b/docs/concepts/logging.html
@@ -4,7 +4,7 @@
Logging | Serverpod
-
+
diff --git a/docs/concepts/models.html b/docs/concepts/models.html
index e43dc20ba..a4e45959b 100644
--- a/docs/concepts/models.html
+++ b/docs/concepts/models.html
@@ -4,7 +4,7 @@
Working with models | Serverpod
-
+
@@ -31,7 +31,7 @@
Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation.
### Information about a company. class: Company fields: ### The name of the company. name: String ### The date the company was founded, if known. foundedDate: DateTime? ### A list of people currently employed at the company. employees: List<Employee>
Serverpod allows you to add documentation to your serializable objects in a similar way that you would add documentation to your Dart code. Use three hashes (###) to indicate that a comment should be considered documentation.
### Information about a company. class: Company fields: ### The name of the company. name: String ### The date the company was founded, if known. foundedDate: DateTime? ### A list of people currently employed at the company. employees: List<Employee>
The SerializableEntity class is deprecated and will be removed in version 2.1. Please implement the SerializableModel interface instead for creating serializable models.
+
The SerializableEntity class is deprecated and will be removed in version 3. Please implement the SerializableModel interface instead for creating serializable models.
To migrate your code from SerializableEntity to SerializableModel, replace extends SerializableEntity with implements SerializableModel in your model classes.
The SerializableEntity class is deprecated and will be removed in version 2.1. Please implement the SerializableModel interface instead for creating serializable models.
+
The SerializableEntity class is deprecated and will be removed in version 3. Please implement the SerializableModel interface instead for creating serializable models.
To migrate your code from SerializableEntity to SerializableModel, replace extends SerializableEntity with implements SerializableModel in your model classes.