To update a row, use the update method. The object that you update must have its id set to a non-null value.
var myCompany =awaitCompany.findById(session, companyId); myCompany.name ='New name'; await session.db.update(myCompany);
diff --git a/docs/1.1.1/concepts/exceptions.html b/docs/1.1.1/concepts/exceptions.html
index 49c0733f8..f025c7360 100644
--- a/docs/1.1.1/concepts/exceptions.html
+++ b/docs/1.1.1/concepts/exceptions.html
@@ -4,7 +4,7 @@
Error handling and exceptions | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/file-uploads.html b/docs/1.1.1/concepts/file-uploads.html
index 743661c6a..4c826ced4 100644
--- a/docs/1.1.1/concepts/file-uploads.html
+++ b/docs/1.1.1/concepts/file-uploads.html
@@ -4,7 +4,7 @@
Uploading files | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/health-checks.html b/docs/1.1.1/concepts/health-checks.html
index 15404300b..78be48eb2 100644
--- a/docs/1.1.1/concepts/health-checks.html
+++ b/docs/1.1.1/concepts/health-checks.html
@@ -4,7 +4,7 @@
Health checks | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/logging.html b/docs/1.1.1/concepts/logging.html
index 96e8330db..50b9bc6bd 100644
--- a/docs/1.1.1/concepts/logging.html
+++ b/docs/1.1.1/concepts/logging.html
@@ -4,7 +4,7 @@
Logging | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/modules.html b/docs/1.1.1/concepts/modules.html
index e3bdff62c..0395ce19a 100644
--- a/docs/1.1.1/concepts/modules.html
+++ b/docs/1.1.1/concepts/modules.html
@@ -4,7 +4,7 @@
Modules | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/serialization.html b/docs/1.1.1/concepts/serialization.html
index a74023e21..d68dc4eaa 100644
--- a/docs/1.1.1/concepts/serialization.html
+++ b/docs/1.1.1/concepts/serialization.html
@@ -4,7 +4,7 @@
Serialization | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/sessions.html b/docs/1.1.1/concepts/sessions.html
index a40cf3984..71f77e341 100644
--- a/docs/1.1.1/concepts/sessions.html
+++ b/docs/1.1.1/concepts/sessions.html
@@ -4,7 +4,7 @@
Sessions | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/streams.html b/docs/1.1.1/concepts/streams.html
index c56df3830..6884fb89e 100644
--- a/docs/1.1.1/concepts/streams.html
+++ b/docs/1.1.1/concepts/streams.html
@@ -4,7 +4,7 @@
Streams and messaging | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/webserver.html b/docs/1.1.1/concepts/webserver.html
index ed8865db2..714a9a082 100644
--- a/docs/1.1.1/concepts/webserver.html
+++ b/docs/1.1.1/concepts/webserver.html
@@ -4,7 +4,7 @@
Web server | Serverpod
-
+
diff --git a/docs/1.1.1/concepts/working-with-endpoints.html b/docs/1.1.1/concepts/working-with-endpoints.html
index 7e2989080..85b01f26a 100644
--- a/docs/1.1.1/concepts/working-with-endpoints.html
+++ b/docs/1.1.1/concepts/working-with-endpoints.html
@@ -4,7 +4,7 @@
Working with endpoints | Serverpod
-
+
diff --git a/docs/1.1.1/contribute.html b/docs/1.1.1/contribute.html
index 19f4e7ff0..078ed594e 100644
--- a/docs/1.1.1/contribute.html
+++ b/docs/1.1.1/contribute.html
@@ -4,7 +4,7 @@
Contribute | Serverpod
-
+
diff --git a/docs/1.1.1/deployments/deploying-to-aws.html b/docs/1.1.1/deployments/deploying-to-aws.html
index a7d136699..77ecf0ce0 100644
--- a/docs/1.1.1/deployments/deploying-to-aws.html
+++ b/docs/1.1.1/deployments/deploying-to-aws.html
@@ -4,7 +4,7 @@
AWS EC2 with Terraform | Serverpod
-
+
diff --git a/docs/1.1.1/deployments/deploying-to-gce-terraform.html b/docs/1.1.1/deployments/deploying-to-gce-terraform.html
index a039f770b..f8413c554 100644
--- a/docs/1.1.1/deployments/deploying-to-gce-terraform.html
+++ b/docs/1.1.1/deployments/deploying-to-gce-terraform.html
@@ -4,7 +4,7 @@
Google Cloud Engine with Terraform | Serverpod
-
+
diff --git a/docs/1.1.1/deployments/deploying-to-gcr-console.html b/docs/1.1.1/deployments/deploying-to-gcr-console.html
index 9b54b287c..f8883b477 100644
--- a/docs/1.1.1/deployments/deploying-to-gcr-console.html
+++ b/docs/1.1.1/deployments/deploying-to-gcr-console.html
@@ -4,7 +4,7 @@
Google Cloud Run with CGP Console | Serverpod
-
+
diff --git a/docs/1.1.1/deployments/deployment-strategy.html b/docs/1.1.1/deployments/deployment-strategy.html
index 176912a94..067b1d1d5 100644
--- a/docs/1.1.1/deployments/deployment-strategy.html
+++ b/docs/1.1.1/deployments/deployment-strategy.html
@@ -4,7 +4,7 @@
Choosing deployment strategy | Serverpod
-
+
diff --git a/docs/1.1.1/deployments/general.html b/docs/1.1.1/deployments/general.html
index e99e466b8..9c9aad415 100644
--- a/docs/1.1.1/deployments/general.html
+++ b/docs/1.1.1/deployments/general.html
@@ -4,7 +4,7 @@
Hosting elsewhere | Serverpod
-
+
diff --git a/docs/1.1.1/get-started.html b/docs/1.1.1/get-started.html
index 64db65e5d..4a4a32a9e 100644
--- a/docs/1.1.1/get-started.html
+++ b/docs/1.1.1/get-started.html
@@ -4,7 +4,7 @@
Get started | Serverpod
-
+
diff --git a/docs/1.1.1/insights.html b/docs/1.1.1/insights.html
index 21d463ff7..a7f878f82 100644
--- a/docs/1.1.1/insights.html
+++ b/docs/1.1.1/insights.html
@@ -4,7 +4,7 @@
Serverpod Insights | Serverpod
-
+
diff --git a/docs/1.1.1/roadmap.html b/docs/1.1.1/roadmap.html
index 9dc5ca550..cf37884f0 100644
--- a/docs/1.1.1/roadmap.html
+++ b/docs/1.1.1/roadmap.html
@@ -4,7 +4,7 @@
Roadmap | Serverpod
-
+
diff --git a/docs/1.1.1/support.html b/docs/1.1.1/support.html
index 012753009..b47968fde 100644
--- a/docs/1.1.1/support.html
+++ b/docs/1.1.1/support.html
@@ -4,7 +4,7 @@
Support & community | Serverpod
-
+
diff --git a/docs/1.1.1/tutorials/authentication.html b/docs/1.1.1/tutorials/authentication.html
index 38e98993d..77c85b3e9 100644
--- a/docs/1.1.1/tutorials/authentication.html
+++ b/docs/1.1.1/tutorials/authentication.html
@@ -4,7 +4,7 @@
Authentication | Serverpod
-
+
diff --git a/docs/1.1.1/tutorials/code-example.html b/docs/1.1.1/tutorials/code-example.html
index da5d5a6ea..f63a69b63 100644
--- a/docs/1.1.1/tutorials/code-example.html
+++ b/docs/1.1.1/tutorials/code-example.html
@@ -4,7 +4,7 @@
Code examples | Serverpod
-
+
diff --git a/docs/1.1.1/tutorials/first-app.html b/docs/1.1.1/tutorials/first-app.html
index 6de4b5cf3..893bd17f8 100644
--- a/docs/1.1.1/tutorials/first-app.html
+++ b/docs/1.1.1/tutorials/first-app.html
@@ -4,7 +4,7 @@
Build your first app | Serverpod
-
+
diff --git a/docs/1.1.1/tutorials/videos.html b/docs/1.1.1/tutorials/videos.html
index 04ef48869..9c6ab5934 100644
--- a/docs/1.1.1/tutorials/videos.html
+++ b/docs/1.1.1/tutorials/videos.html
@@ -4,7 +4,7 @@
Videos | Serverpod
-
+
diff --git a/docs/404.html b/docs/404.html
index 31b64371d..d6c019398 100644
--- a/docs/404.html
+++ b/docs/404.html
@@ -4,7 +4,7 @@
Serverpod
-
+
diff --git a/docs/assets/js/056b386b.3eb1996f.js b/docs/assets/js/056b386b.3eb1996f.js
new file mode 100644
index 000000000..212ae7562
--- /dev/null
+++ b/docs/assets/js/056b386b.3eb1996f.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[8571],{95429:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.7/03-concepts/03-database-communication.md",sourceDirName:"03-concepts",slug:"/concepts/database-communication",permalink:"/0.9.7/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.7/03-concepts/03-database-communication.md",tags:[],version:"0.9.7",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.7/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.7/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/4c781063.f02dc04a.js b/docs/assets/js/4c781063.f02dc04a.js
new file mode 100644
index 000000000..5204c4076
--- /dev/null
+++ b/docs/assets/js/4c781063.f02dc04a.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[9639],{75556:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>d,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",d={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.11/03-concepts/03-database-communication.md",sourceDirName:"03-concepts",slug:"/concepts/database-communication",permalink:"/0.9.11/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.11/03-concepts/03-database-communication.md",tags:[],version:"0.9.11",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.11/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.11/concepts/caching"}},r={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>d,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/511f9951.bae60e3b.js b/docs/assets/js/511f9951.bae60e3b.js
new file mode 100644
index 000000000..3e6a20db3
--- /dev/null
+++ b/docs/assets/js/511f9951.bae60e3b.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[399],{2726:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.21/04-concepts/03-database-communication.md",sourceDirName:"04-concepts",slug:"/concepts/database-communication",permalink:"/0.9.21/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.21/04-concepts/03-database-communication.md",tags:[],version:"0.9.21",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.21/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.21/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/638e38ae.b24dcfbe.js b/docs/assets/js/638e38ae.b24dcfbe.js
new file mode 100644
index 000000000..85f0f3782
--- /dev/null
+++ b/docs/assets/js/638e38ae.b24dcfbe.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[7673],{74352:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-1.1.1/05-concepts/05-database-communication.md",sourceDirName:"05-concepts",slug:"/concepts/database-communication",permalink:"/1.1.1/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.1.1/05-concepts/05-database-communication.md",tags:[],version:"1.1.1",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Error handling and exceptions",permalink:"/1.1.1/concepts/exceptions"},next:{title:"Caching",permalink:"/1.1.1/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Ordering rows",id:"ordering-rows",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, its ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n session,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"ordering-rows",children:"Ordering rows"}),"\n",(0,s.jsxs)(n.p,{children:["It is often desirable to order the results of a database query. The ",(0,s.jsx)(n.code,{children:"find"})," method contains an ",(0,s.jsx)(n.code,{children:"orderBy"})," parameter, to which you can pass a column to order by. The static ",(0,s.jsx)(n.code,{children:"t"})," field on your serializable objects includes a reference to a representation of your table. It has a field for each column."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n session,\n orderBy: Company.t.name,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/704545ab.c94cb47d.js b/docs/assets/js/704545ab.c94cb47d.js
new file mode 100644
index 000000000..58f2e70dc
--- /dev/null
+++ b/docs/assets/js/704545ab.c94cb47d.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[5724],{45828:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.20/04-concepts/03-database-communication.md",sourceDirName:"04-concepts",slug:"/concepts/database-communication",permalink:"/0.9.20/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.20/04-concepts/03-database-communication.md",tags:[],version:"0.9.20",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.20/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.20/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/8dfd8953.b1a2272b.js b/docs/assets/js/8dfd8953.b1a2272b.js
new file mode 100644
index 000000000..a2d4f3d23
--- /dev/null
+++ b/docs/assets/js/8dfd8953.b1a2272b.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[7065],{77088:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.5/02-concepts/03-database-communication.md",sourceDirName:"02-concepts",slug:"/concepts/database-communication",permalink:"/0.9.5/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.5/02-concepts/03-database-communication.md",tags:[],version:"0.9.5",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.5/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.5/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/98c94590.2a56ce4c.js b/docs/assets/js/98c94590.2a56ce4c.js
new file mode 100644
index 000000000..f40b2bd4b
--- /dev/null
+++ b/docs/assets/js/98c94590.2a56ce4c.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[8213],{45894:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>h,frontMatter:()=>a,metadata:()=>r,toc:()=>l});var s=i(85893),t=i(11151);const a={},d="CRUD",r={id:"concepts/database/crud",title:"CRUD",description:"To interact with the database you need a Session object as this object holds the connection to the database. All CRUD operations are accessible via the session object and the generated models. The methods can be found under the static db field in your generated models.",source:"@site/versioned_docs/version-1.2.0/05-concepts/06-database/05-crud.md",sourceDirName:"05-concepts/06-database",slug:"/concepts/database/crud",permalink:"/concepts/database/crud",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.2.0/05-concepts/06-database/05-crud.md",tags:[],version:"1.2.0",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Indexing",permalink:"/concepts/database/indexing"},next:{title:"Filter",permalink:"/concepts/database/filter"}},o={},l=[{value:"Create",id:"create",level:2},{value:"Inserting a single row",id:"inserting-a-single-row",level:3},{value:"Inserting several rows",id:"inserting-several-rows",level:3},{value:"Read",id:"read",level:2},{value:"Finding by id",id:"finding-by-id",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Update",id:"update",level:2},{value:"Update a single row",id:"update-a-single-row",level:3},{value:"Update several rows",id:"update-several-rows",level:3},{value:"Delete",id:"delete",level:2},{value:"Delete a single row",id:"delete-a-single-row",level:3},{value:"Delete several rows",id:"delete-several-rows",level:3},{value:"Delete by filter",id:"delete-by-filter",level:3},{value:"Count",id:"count",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"crud",children:"CRUD"}),"\n",(0,s.jsxs)(n.p,{children:["To interact with the database you need a ",(0,s.jsx)(n.a,{href:"../sessions",children:(0,s.jsx)(n.code,{children:"Session"})})," object as this object holds the connection to the database. All CRUD operations are accessible via the session object and the generated models. The methods can be found under the static ",(0,s.jsx)(n.code,{children:"db"})," field in your generated models."]}),"\n",(0,s.jsx)(n.p,{children:"For the following examples we will use this model:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["You can also access the database methods through the session object under the field ",(0,s.jsx)(n.code,{children:"dbNext"}),". However, this is typically only recommended if you want to do custom queries where you explicitly type out your SQL queries. The ",(0,s.jsx)(n.code,{children:"db"})," field on ",(0,s.jsx)(n.code,{children:"Session"})," contains legacy methods that are included for compatibility. In version 2 of Serverpod, the old legacy methods will be removed and ",(0,s.jsx)(n.code,{children:"db"})," will be replaced by ",(0,s.jsx)(n.code,{children:"dbNext"}),"."]})}),"\n",(0,s.jsx)(n.h2,{id:"create",children:"Create"}),"\n",(0,s.jsx)(n.p,{children:"There are two ways to create a new row in the database."}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-single-row",children:"Inserting a single row"}),"\n",(0,s.jsxs)(n.p,{children:["Inserting a single row to the database is done by calling the ",(0,s.jsx)(n.code,{children:"insertRow"})," method on your generated model. The method will return the entire company object with the ",(0,s.jsx)(n.code,{children:"id"})," field set."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var row = Company(name: 'Serverpod');\nvar company = await Company.db.insertRow(session, row);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"inserting-several-rows",children:"Inserting several rows"}),"\n",(0,s.jsxs)(n.p,{children:["Inserting several rows in a batch operation is done by calling the ",(0,s.jsx)(n.code,{children:"insert"})," method. This is an atomic operation, meaning no entries will be created if any entry fails to be created."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var rows = [Company(name: 'Serverpod'), Company(name: 'Google')];\nvar companies = await Company.db.insert(session, rows);\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["In previous versions of Serverpod the ",(0,s.jsx)(n.code,{children:"insert"})," method mutated the input object by setting the ",(0,s.jsx)(n.code,{children:"id"})," field. In the example above the input variable remains unmodified after the ",(0,s.jsx)(n.code,{children:"insert"}),"/",(0,s.jsx)(n.code,{children:"insertRow"})," call."]})}),"\n",(0,s.jsx)(n.h2,{id:"read",children:"Read"}),"\n",(0,s.jsx)(n.p,{children:"There are three different read operations available."}),"\n",(0,s.jsx)(n.h3,{id:"finding-by-id",children:"Finding by id"}),"\n",(0,s.jsxs)(n.p,{children:["You can retrieve a single row by its ",(0,s.jsx)(n.code,{children:"id"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation either returns the model or ",(0,s.jsx)(n.code,{children:"null"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsx)(n.p,{children:"You can find a single row using an expression."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findRow(\n session,\n where: (t) => t.name.equals('Serverpod'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation returns the first model matching the filtering criteria or ",(0,s.jsx)(n.code,{children:"null"}),". See ",(0,s.jsx)(n.a,{href:"filter",children:"filter"})," and ",(0,s.jsx)(n.a,{href:"sort",children:"sort"})," for all filter operations."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Note that ordering of the entries is important here as it will return the fist row returned by the database query."})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsx)(n.p,{children:"To find multiple rows, use the same principle as for finding a single row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.db.find(\n session,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation returns a ",(0,s.jsx)(n.code,{children:"List"})," of your models matching the filtering criteria."]}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"filter",children:"filter"})," and ",(0,s.jsx)(n.a,{href:"sort",children:"sort"})," for all filter and sorting operations and ",(0,s.jsx)(n.a,{href:"pagination",children:"pagination"})," for how to paginate the result."]}),"\n",(0,s.jsx)(n.h2,{id:"update",children:"Update"}),"\n",(0,s.jsx)(n.p,{children:"There are two update operations available."}),"\n",(0,s.jsx)(n.h3,{id:"update-a-single-row",children:"Update a single row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a single row, use the ",(0,s.jsx)(n.code,{children:"updateRow"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId); // Fetched company has its id set \ncompany.name = 'New name';\nvar updatedCompany = await Company.db.updateRow(session, company);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value and the id needs to exist on a row in the database. The ",(0,s.jsx)(n.code,{children:"updateRow"})," method returns the updated object."]}),"\n",(0,s.jsx)(n.h3,{id:"update-several-rows",children:"Update several rows"}),"\n",(0,s.jsxs)(n.p,{children:["To batch update several rows use the ",(0,s.jsx)(n.code,{children:"update"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.db.find(session);\ncompanies = companies.map((c) => c.copyWith(name: 'New name')).toList();\nvar updatedCompanies = await Company.db.update(session, companies);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is an atomic operation, meaning no entries will be updated if any entry fails to be updated. The ",(0,s.jsx)(n.code,{children:"update"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the updated objects."]}),"\n",(0,s.jsx)(n.h2,{id:"delete",children:"Delete"}),"\n",(0,s.jsx)(n.p,{children:"Deleting rows from the database is done in a similar way to updating rows. However, there are three delete operations available."}),"\n",(0,s.jsx)(n.h3,{id:"delete-a-single-row",children:"Delete a single row"}),"\n",(0,s.jsxs)(n.p,{children:["To delete a single row, use the ",(0,s.jsx)(n.code,{children:"deleteRow"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId); // Fetched company has its id set \nvar id = await Company.db.deleteRow(session, company);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The input object needs to have the ",(0,s.jsx)(n.code,{children:"id"})," field set. The ",(0,s.jsx)(n.code,{children:"deleteRow"})," method returns the ",(0,s.jsx)(n.code,{children:"id"})," of the deleted row."]}),"\n",(0,s.jsx)(n.h3,{id:"delete-several-rows",children:"Delete several rows"}),"\n",(0,s.jsxs)(n.p,{children:["To batch delete several rows, use the ",(0,s.jsx)(n.code,{children:"delete"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var ids = await Company.db.delete(session, companies);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is an atomic operation, meaning no entries will be deleted if any entry fails to be deleted. The ",(0,s.jsx)(n.code,{children:"delete"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the ",(0,s.jsx)(n.code,{children:"id"}),"s of the deleted row(s)."]}),"\n",(0,s.jsx)(n.h3,{id:"delete-by-filter",children:"Delete by filter"}),"\n",(0,s.jsxs)(n.p,{children:["You can also do a ",(0,s.jsx)(n.a,{href:"filter",children:"filtered"})," delete and delete all entries matching a ",(0,s.jsx)(n.code,{children:"where"})," query, by using the ",(0,s.jsx)(n.code,{children:"deleteWhere"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var ids = await Company.db.deleteWhere(\n session,\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The above example will delete any row that ends in ",(0,s.jsx)(n.em,{children:"Ltd"}),". The ",(0,s.jsx)(n.code,{children:"deleteWhere"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the ",(0,s.jsx)(n.code,{children:"id"}),"s of the deleted row(s)."]}),"\n",(0,s.jsx)(n.h2,{id:"count",children:"Count"}),"\n",(0,s.jsxs)(n.p,{children:["Count is a special type of query that helps counting the number of rows in the database that matches a specific ",(0,s.jsx)(n.a,{href:"filter",children:"filter"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var count = await Company.db.count(\n session, \n where: (t) => t.name.like('s%'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The return value is an ",(0,s.jsx)(n.code,{children:"int"})," for the number of rows matching the filter."]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>d});var s=i(67294);const t={},a=s.createContext(t);function d(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:d(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/afde3230.988b02ff.js b/docs/assets/js/afde3230.988b02ff.js
new file mode 100644
index 000000000..1754c8093
--- /dev/null
+++ b/docs/assets/js/afde3230.988b02ff.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[8856],{3410:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.10/03-concepts/03-database-communication.md",sourceDirName:"03-concepts",slug:"/concepts/database-communication",permalink:"/0.9.10/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.10/03-concepts/03-database-communication.md",tags:[],version:"0.9.10",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.10/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.10/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/b79774cd.86948f6d.js b/docs/assets/js/b79774cd.86948f6d.js
new file mode 100644
index 000000000..572e42bff
--- /dev/null
+++ b/docs/assets/js/b79774cd.86948f6d.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[2284],{28250:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>h,frontMatter:()=>a,metadata:()=>r,toc:()=>l});var s=i(85893),t=i(11151);const a={},d="CRUD",r={id:"concepts/database/crud",title:"CRUD",description:"To interact with the database you need a Session object as this object holds the connection to the database. All CRUD operations are accessible via the session object and the generated models. The methods can be found under the static db field in your generated models.",source:"@site/docs/05-concepts/06-database/05-crud.md",sourceDirName:"05-concepts/06-database",slug:"/concepts/database/crud",permalink:"/next/concepts/database/crud",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/docs/05-concepts/06-database/05-crud.md",tags:[],version:"current",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Indexing",permalink:"/next/concepts/database/indexing"},next:{title:"Filter",permalink:"/next/concepts/database/filter"}},o={},l=[{value:"Create",id:"create",level:2},{value:"Inserting a single row",id:"inserting-a-single-row",level:3},{value:"Inserting several rows",id:"inserting-several-rows",level:3},{value:"Read",id:"read",level:2},{value:"Finding by id",id:"finding-by-id",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Update",id:"update",level:2},{value:"Update a single row",id:"update-a-single-row",level:3},{value:"Update several rows",id:"update-several-rows",level:3},{value:"Delete",id:"delete",level:2},{value:"Delete a single row",id:"delete-a-single-row",level:3},{value:"Delete several rows",id:"delete-several-rows",level:3},{value:"Delete by filter",id:"delete-by-filter",level:3},{value:"Count",id:"count",level:2}];function c(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"crud",children:"CRUD"}),"\n",(0,s.jsxs)(n.p,{children:["To interact with the database you need a ",(0,s.jsx)(n.a,{href:"../sessions",children:(0,s.jsx)(n.code,{children:"Session"})})," object as this object holds the connection to the database. All CRUD operations are accessible via the session object and the generated models. The methods can be found under the static ",(0,s.jsx)(n.code,{children:"db"})," field in your generated models."]}),"\n",(0,s.jsx)(n.p,{children:"For the following examples we will use this model:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["You can also access the database methods through the session object under the field ",(0,s.jsx)(n.code,{children:"db"}),". However, this is typically only recommended if you want to do custom queries where you explicitly type out your SQL queries."]})}),"\n",(0,s.jsx)(n.h2,{id:"create",children:"Create"}),"\n",(0,s.jsx)(n.p,{children:"There are two ways to create a new row in the database."}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-single-row",children:"Inserting a single row"}),"\n",(0,s.jsxs)(n.p,{children:["Inserting a single row to the database is done by calling the ",(0,s.jsx)(n.code,{children:"insertRow"})," method on your generated model. The method will return the entire company object with the ",(0,s.jsx)(n.code,{children:"id"})," field set."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var row = Company(name: 'Serverpod');\nvar company = await Company.db.insertRow(session, row);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"inserting-several-rows",children:"Inserting several rows"}),"\n",(0,s.jsxs)(n.p,{children:["Inserting several rows in a batch operation is done by calling the ",(0,s.jsx)(n.code,{children:"insert"})," method. This is an atomic operation, meaning no entries will be created if any entry fails to be created."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var rows = [Company(name: 'Serverpod'), Company(name: 'Google')];\nvar companies = await Company.db.insert(session, rows);\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["In previous versions of Serverpod the ",(0,s.jsx)(n.code,{children:"insert"})," method mutated the input object by setting the ",(0,s.jsx)(n.code,{children:"id"})," field. In the example above the input variable remains unmodified after the ",(0,s.jsx)(n.code,{children:"insert"}),"/",(0,s.jsx)(n.code,{children:"insertRow"})," call."]})}),"\n",(0,s.jsx)(n.h2,{id:"read",children:"Read"}),"\n",(0,s.jsx)(n.p,{children:"There are three different read operations available."}),"\n",(0,s.jsx)(n.h3,{id:"finding-by-id",children:"Finding by id"}),"\n",(0,s.jsxs)(n.p,{children:["You can retrieve a single row by its ",(0,s.jsx)(n.code,{children:"id"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation either returns the model or ",(0,s.jsx)(n.code,{children:"null"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsx)(n.p,{children:"You can find a single row using an expression."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findRow(\n session,\n where: (t) => t.name.equals('Serverpod'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation returns the first model matching the filtering criteria or ",(0,s.jsx)(n.code,{children:"null"}),". See ",(0,s.jsx)(n.a,{href:"filter",children:"filter"})," and ",(0,s.jsx)(n.a,{href:"sort",children:"sort"})," for all filter operations."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Note that ordering of the entries is important here as it will return the fist row returned by the database query."})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsx)(n.p,{children:"To find multiple rows, use the same principle as for finding a single row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.db.find(\n session,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This operation returns a ",(0,s.jsx)(n.code,{children:"List"})," of your models matching the filtering criteria."]}),"\n",(0,s.jsxs)(n.p,{children:["See ",(0,s.jsx)(n.a,{href:"filter",children:"filter"})," and ",(0,s.jsx)(n.a,{href:"sort",children:"sort"})," for all filter and sorting operations and ",(0,s.jsx)(n.a,{href:"pagination",children:"pagination"})," for how to paginate the result."]}),"\n",(0,s.jsx)(n.h2,{id:"update",children:"Update"}),"\n",(0,s.jsx)(n.p,{children:"There are two update operations available."}),"\n",(0,s.jsx)(n.h3,{id:"update-a-single-row",children:"Update a single row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a single row, use the ",(0,s.jsx)(n.code,{children:"updateRow"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId); // Fetched company has its id set \ncompany.name = 'New name';\nvar updatedCompany = await Company.db.updateRow(session, company);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value and the id needs to exist on a row in the database. The ",(0,s.jsx)(n.code,{children:"updateRow"})," method returns the updated object."]}),"\n",(0,s.jsx)(n.h3,{id:"update-several-rows",children:"Update several rows"}),"\n",(0,s.jsxs)(n.p,{children:["To batch update several rows use the ",(0,s.jsx)(n.code,{children:"update"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.db.find(session);\ncompanies = companies.map((c) => c.copyWith(name: 'New name')).toList();\nvar updatedCompanies = await Company.db.update(session, companies);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is an atomic operation, meaning no entries will be updated if any entry fails to be updated. The ",(0,s.jsx)(n.code,{children:"update"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the updated objects."]}),"\n",(0,s.jsx)(n.h2,{id:"delete",children:"Delete"}),"\n",(0,s.jsx)(n.p,{children:"Deleting rows from the database is done in a similar way to updating rows. However, there are three delete operations available."}),"\n",(0,s.jsx)(n.h3,{id:"delete-a-single-row",children:"Delete a single row"}),"\n",(0,s.jsxs)(n.p,{children:["To delete a single row, use the ",(0,s.jsx)(n.code,{children:"deleteRow"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.db.findById(session, companyId); // Fetched company has its id set \nvar companyDeleted = await Company.db.deleteRow(session, company);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The input object needs to have the ",(0,s.jsx)(n.code,{children:"id"})," field set. The ",(0,s.jsx)(n.code,{children:"deleteRow"})," method returns the deleted model."]}),"\n",(0,s.jsx)(n.h3,{id:"delete-several-rows",children:"Delete several rows"}),"\n",(0,s.jsxs)(n.p,{children:["To batch delete several rows, use the ",(0,s.jsx)(n.code,{children:"delete"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companiesDeleted = await Company.db.delete(session, companies);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This is an atomic operation, meaning no entries will be deleted if any entry fails to be deleted. The ",(0,s.jsx)(n.code,{children:"delete"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the models deleted."]}),"\n",(0,s.jsx)(n.h3,{id:"delete-by-filter",children:"Delete by filter"}),"\n",(0,s.jsxs)(n.p,{children:["You can also do a ",(0,s.jsx)(n.a,{href:"filter",children:"filtered"})," delete and delete all entries matching a ",(0,s.jsx)(n.code,{children:"where"})," query, by using the ",(0,s.jsx)(n.code,{children:"deleteWhere"})," method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companiesDeleted = await Company.db.deleteWhere(\n session,\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The above example will delete any row that ends in ",(0,s.jsx)(n.em,{children:"Ltd"}),". The ",(0,s.jsx)(n.code,{children:"deleteWhere"})," method returns a ",(0,s.jsx)(n.code,{children:"List"})," of the models deleted."]}),"\n",(0,s.jsx)(n.h2,{id:"count",children:"Count"}),"\n",(0,s.jsxs)(n.p,{children:["Count is a special type of query that helps counting the number of rows in the database that matches a specific ",(0,s.jsx)(n.a,{href:"filter",children:"filter"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var count = await Company.db.count(\n session, \n where: (t) => t.name.like('s%'),\n);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The return value is an ",(0,s.jsx)(n.code,{children:"int"})," for the number of rows matching the filter."]})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>d});var s=i(67294);const t={},a=s.createContext(t);function d(e){const n=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:d(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/b9ec56c8.42068d6e.js b/docs/assets/js/b9ec56c8.42068d6e.js
new file mode 100644
index 000000000..6801b6f35
--- /dev/null
+++ b/docs/assets/js/b9ec56c8.42068d6e.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[3029],{56271:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.22/04-concepts/03-database-communication.md",sourceDirName:"04-concepts",slug:"/concepts/database-communication",permalink:"/0.9.22/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.22/04-concepts/03-database-communication.md",tags:[],version:"0.9.22",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.22/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.22/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/e3443ce0.5d1e4720.js b/docs/assets/js/e3443ce0.5d1e4720.js
new file mode 100644
index 000000000..a2891175b
--- /dev/null
+++ b/docs/assets/js/e3443ce0.5d1e4720.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[7427],{71494:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.9/03-concepts/03-database-communication.md",sourceDirName:"03-concepts",slug:"/concepts/database-communication",permalink:"/0.9.9/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.9/03-concepts/03-database-communication.md",tags:[],version:"0.9.9",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.9/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.9/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/eecc43ff.a7c864af.js b/docs/assets/js/eecc43ff.a7c864af.js
new file mode 100644
index 000000000..04ba2639d
--- /dev/null
+++ b/docs/assets/js/eecc43ff.a7c864af.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[845],{64050:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-1.1.0/04-concepts/05-database-communication.md",sourceDirName:"04-concepts",slug:"/concepts/database-communication",permalink:"/1.1.0/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.1.0/04-concepts/05-database-communication.md",tags:[],version:"1.1.0",sidebarPosition:5,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Error handling and exceptions",permalink:"/1.1.0/concepts/exceptions"},next:{title:"Caching",permalink:"/1.1.0/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Ordering rows",id:"ordering-rows",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"ordering-rows",children:"Ordering rows"}),"\n",(0,s.jsxs)(n.p,{children:["It is often desirable to order the results of a database query. The ",(0,s.jsx)(n.code,{children:"find"})," method contains an ",(0,s.jsx)(n.code,{children:"orderBy"})," parameter, to which you can pass a column to order by. The static ",(0,s.jsx)(n.code,{children:"t"})," field on your serializable objects includes a reference to a representation of your table. It has a field for each column."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n session,\n orderBy: Company.t.name,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/ef4456b5.d6afbb0a.js b/docs/assets/js/ef4456b5.d6afbb0a.js
new file mode 100644
index 000000000..8f2b33531
--- /dev/null
+++ b/docs/assets/js/ef4456b5.d6afbb0a.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[3283],{88655:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.6/02-concepts/03-database-communication.md",sourceDirName:"02-concepts",slug:"/concepts/database-communication",permalink:"/0.9.6/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.6/02-concepts/03-database-communication.md",tags:[],version:"0.9.6",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.6/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.6/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/efe5610c.73ada662.js b/docs/assets/js/efe5610c.73ada662.js
new file mode 100644
index 000000000..794aada14
--- /dev/null
+++ b/docs/assets/js/efe5610c.73ada662.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[5738],{47810:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>l});var s=a(85893),t=a(11151);const i={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-1.0.0/04-concepts/03-database-communication.md",sourceDirName:"04-concepts",slug:"/concepts/database-communication",permalink:"/1.0.0/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-1.0.0/04-concepts/03-database-communication.md",tags:[],version:"1.0.0",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/1.0.0/concepts/serialization"},next:{title:"Caching",permalink:"/1.0.0/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Field scopes",id:"field-scopes",level:3},{value:"Database indexes",id:"database-indexes",level:3},{value:"Parent/child relationships",id:"parentchild-relationships",level:3},{value:"Storing objects or references",id:"storing-objects-or-references",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Joining tables and nesting objects",id:"joining-tables-and-nesting-objects",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,t.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["When you add a ",(0,s.jsx)(n.code,{children:"table"})," to a serializable class, Serverpod will automatically add an ",(0,s.jsx)(n.code,{children:"id"})," field of type ",(0,s.jsx)(n.code,{children:"int?"})," to the class. You should not define this field yourself. The ",(0,s.jsx)(n.code,{children:"id"})," is set when you insert or select a row from the database. The ",(0,s.jsx)(n.code,{children:"id"})," field allows you to do updates and reference the rows from other objects and tables."]})}),"\n",(0,s.jsx)(n.h3,{id:"field-scopes",children:"Field scopes"}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," scope to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String?, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you use the ",(0,s.jsx)(n.code,{children:"database"})," or ",(0,s.jsx)(n.code,{children:"api"})," options the field must be nullable."]})}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List?, api\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h3,{id:"parentchild-relationships",children:"Parent/child relationships"}),"\n",(0,s.jsx)(n.p,{children:"With a field's parent property, you can define a relationship with a table's parent table. This relationship ensures that the parent id is always valid and that if you delete the referenced parent, the referencing row will automatically be deleted."}),"\n",(0,s.jsxs)(n.p,{children:["The employee's ",(0,s.jsx)(n.code,{children:"parent"})," is set to the ",(0,s.jsx)(n.code,{children:"company"})," table in the example below. If you remove the company, all employees of the company will automatically be removed. When you insert the employee into the database, you must specify a valid ",(0,s.jsx)(n.code,{children:"companyId"})," that corresponds to the id field in the ",(0,s.jsx)(n.code,{children:"company"})," table."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Employee\ntable: employee\nfields:\n companyId: int, parent=company\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsx)(n.h3,{id:"storing-objects-or-references",children:"Storing objects or references"}),"\n",(0,s.jsxs)(n.p,{children:["If you reference another serializable object in your yaml file, it will be stored as a JSON entry in the database. This creates a copy of that object. In many cases, this is not desirable. Instead, you may want to reference that object by an id from another table. See the section on ",(0,s.jsx)(n.a,{href:"#joining-tables-and-nesting-objects",children:"joining tables and nesting objects"})," below for more information."]}),"\n",(0,s.jsx)(n.p,{children:"In the example below, a list of employees is stored as a JSON structure for each company in the database. A better solution would be to create a database row for each employee and reference the company. However, there are cases where it is convenient to store whole JSON structures in each row."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n employees: List # Stored as JSON structure\n"})}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non-",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"joining-tables-and-nesting-objects",children:"Joining tables and nesting objects"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod does not yet support joins automatically. However, you can easily create nested objects by performing two or more queries."}),"\n",(0,s.jsxs)(n.p,{children:["For instance, if you have a ",(0,s.jsx)(n.code,{children:"Company"})," object with a list of ",(0,s.jsx)(n.code,{children:"Employee"})," it can be declared like this:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"# company.yaml\nclass: Company\ntable: company\nfields:\n name: String\n employees: List?, api\n\n# employee.yaml\nclass: Employee\ntable: employee\nfields:\n companyId: int\n name: String\n birthday: DateTime\n"})}),"\n",(0,s.jsxs)(n.p,{children:["This prevents the list of ",(0,s.jsx)(n.code,{children:"Employee"})," to be automatically fetched or stored in the database. After you fetch a ",(0,s.jsx)(n.code,{children:"Company"})," object from the database, format it by fetching the list of ",(0,s.jsx)(n.code,{children:"Employees"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var company = await Company.findById(session, id);\n\nvar employees = await Employee.find(\n session,\n where: (t) => t.companyId.equals(company.id),\n);\n\ncompany.employees = employees;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsx)(n.p,{children:"Future versions of Serverpod will add support for automatic joins and database views."})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"The essential point of a database transaction is that it bundles multiple steps into a single, all-or-nothing operation. The intermediate states between the steps are not visible to other concurrent transactions, and if some failure occurs that prevents the transaction from completing, then none of the steps affect the database at all."}),"\n",(0,s.jsxs)(n.p,{children:["Serverpod handles database transactions through the ",(0,s.jsx)(n.code,{children:"session.db.transaction"})," method. The transaction takes a method that performs any database queries or other operations and optionally returns a value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.transaction((transaction) async {\n // Do some database queries here.\n\n // Optionally return a value.\n return true;\n});\n"})}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const t={},i=s.createContext(t);function o(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/fc8b5a5d.8155e1ca.js b/docs/assets/js/fc8b5a5d.8155e1ca.js
new file mode 100644
index 000000000..a1e6729d5
--- /dev/null
+++ b/docs/assets/js/fc8b5a5d.8155e1ca.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkserverpod_docs=self.webpackChunkserverpod_docs||[]).push([[4135],{26347:(e,n,a)=>{a.r(n),a.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>h,frontMatter:()=>t,metadata:()=>r,toc:()=>l});var s=a(85893),i=a(11151);const t={},o="Database communication",r={id:"concepts/database-communication",title:"Database communication",description:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files.",source:"@site/versioned_docs/version-0.9.8/03-concepts/03-database-communication.md",sourceDirName:"03-concepts",slug:"/concepts/database-communication",permalink:"/0.9.8/concepts/database-communication",draft:!1,unlisted:!1,editUrl:"https://github.com/serverpod/serverpod_docs/tree/main/versioned_docs/version-0.9.8/03-concepts/03-database-communication.md",tags:[],version:"0.9.8",sidebarPosition:3,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Serialization",permalink:"/0.9.8/concepts/serialization"},next:{title:"Caching",permalink:"/0.9.8/concepts/caching"}},d={},l=[{value:"Database mappings",id:"database-mappings",level:2},{value:"Database indexes",id:"database-indexes",level:3},{value:"Making queries",id:"making-queries",level:2},{value:"Inserting a table row",id:"inserting-a-table-row",level:3},{value:"Finding a single row",id:"finding-a-single-row",level:3},{value:"Finding multiple rows",id:"finding-multiple-rows",level:3},{value:"Updating a row",id:"updating-a-row",level:3},{value:"Deleting rows",id:"deleting-rows",level:3},{value:"Creating expressions",id:"creating-expressions",level:3},{value:"Transactions",id:"transactions",level:3},{value:"Executing raw queries",id:"executing-raw-queries",level:3}];function c(e){const n={code:"code",h1:"h1",h2:"h2",h3:"h3",p:"p",pre:"pre",...(0,i.a)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"database-communication",children:"Database communication"}),"\n",(0,s.jsx)(n.p,{children:"Serverpod makes it easy to communicate with your database using strictly typed objects without a single SQL line. But, if you need to do more complex tasks, you can always do direct SQL calls. You define your database mappings right in the protocol yaml files."}),"\n",(0,s.jsx)(n.h2,{id:"database-mappings",children:"Database mappings"}),"\n",(0,s.jsxs)(n.p,{children:["It's possible to map serializable classes straight to tables in your database. To do this, add the ",(0,s.jsx)(n.code,{children:"table"})," key to your yaml file:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\n"})}),"\n",(0,s.jsxs)(n.p,{children:["When running ",(0,s.jsx)(n.code,{children:"serverpod generate"}),", the database schema will be saved in the ",(0,s.jsx)(n.code,{children:"generated/tables.pgsql"})," file. You can use this to create the corresponding database tables."]}),"\n",(0,s.jsxs)(n.p,{children:["In some cases, you want to save a field to the database, but it should never be sent to the server. You can exclude it from the protocol by adding the ",(0,s.jsx)(n.code,{children:"database"})," flag to the type."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: UserData\nfields:\n name: String\n password: String, database\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Likewise, if you only want a field to be accessible in the protocol but not stored in the server, you can add the ",(0,s.jsx)(n.code,{children:"api"})," flag. By default, a field is accessible to both the API and the database."]}),"\n",(0,s.jsx)(n.h3,{id:"database-indexes",children:"Database indexes"}),"\n",(0,s.jsx)(n.p,{children:"For performance reasons, you may want to add indexes to your database tables. You add these in the yaml-files defining the serializable objects."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-yaml",children:"class: Company\ntable: company\nfields:\n name: String\n foundedDate: DateTime?\n employees: List\nindexes:\n company_name_idx:\n fields: name\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fields"})," key holds a comma-separated list of column names. In addition, it's possible to add a type key (default is ",(0,s.jsx)(n.code,{children:"btree"}),"), and a ",(0,s.jsx)(n.code,{children:"unique"})," key (default is ",(0,s.jsx)(n.code,{children:"false"}),")."]}),"\n",(0,s.jsx)(n.h2,{id:"making-queries",children:"Making queries"}),"\n",(0,s.jsxs)(n.p,{children:["For the communication to work, you need to have generated serializable classes with the ",(0,s.jsx)(n.code,{children:"table"})," key set, and the corresponding table must have been created in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"inserting-a-table-row",children:"Inserting a table row"}),"\n",(0,s.jsxs)(n.p,{children:["Insert a new row in the database by calling the insert method of the ",(0,s.jsx)(n.code,{children:"db"})," field in your ",(0,s.jsx)(n.code,{children:"Session"})," object."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myRow = Company(name: 'Serverpod corp.', employees: []);\nawait Company.insert(session, myRow);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["After the object has been inserted, it's ",(0,s.jsx)(n.code,{children:"id"})," field is set from its row in the database."]}),"\n",(0,s.jsx)(n.h3,{id:"finding-a-single-row",children:"Finding a single row"}),"\n",(0,s.jsxs)(n.p,{children:["You can find a single row, either by its ",(0,s.jsx)(n.code,{children:"id"})," or using an expression. You need to pass a reference to the a session in the call. Tables are accessible through generated serializable classes."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findById(session, companyId);\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If no matching row is found, ",(0,s.jsx)(n.code,{children:"null"})," is returned. You can also search for rows using expressions with the ",(0,s.jsx)(n.code,{children:"where"})," parameter. The ",(0,s.jsx)(n.code,{children:"where"})," parameter is a typed expression builder. The builder's parameter, ",(0,s.jsx)(n.code,{children:"t"}),", contains a description of the table which gives access to the table's columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await Company.findSingleRow(\n session,\n where: (t) => t.name.equals('My Company'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"finding-multiple-rows",children:"Finding multiple rows"}),"\n",(0,s.jsxs)(n.p,{children:["To find multiple rows, use the same principle as for finding a single row. Returned will be a ",(0,s.jsx)(n.code,{children:"List"})," of ",(0,s.jsx)(n.code,{children:"TableRow"}),"s."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var companies = await Company.find(\n tCompany,\n where: (t) => t.id < 100,\n limit: 50,\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-a-row",children:"Updating a row"}),"\n",(0,s.jsxs)(n.p,{children:["To update a row, use the ",(0,s.jsx)(n.code,{children:"update"})," method. The object that you update must have its ",(0,s.jsx)(n.code,{children:"id"})," set to a non ",(0,s.jsx)(n.code,{children:"null"})," value."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var myCompany = await session.db.findById(tCompany, companyId) as Company?;\nmyCompany.name = 'New name';\nawait session.db.update(myCompany);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"deleting-rows",children:"Deleting rows"}),"\n",(0,s.jsxs)(n.p,{children:["Deleting a single row works similarly to the ",(0,s.jsx)(n.code,{children:"update"})," method, but you can also delete rows using the where parameter."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// Delete a single row\nawait Company.deleteRow(session, myCompany);\n\n// Delete all rows where the company name ends with 'Ltd'\nawait Company.delete(\n where: (t) => t.name.like('%Ltd'),\n);\n"})}),"\n",(0,s.jsx)(n.h3,{id:"creating-expressions",children:"Creating expressions"}),"\n",(0,s.jsxs)(n.p,{children:["To find or delete specific rows, most often, expressions are needed. Serverpod makes it easy to build expressions that are statically type-checked. Columns are referenced using the global table descriptor objects. The table descriptors, ",(0,s.jsx)(n.code,{children:"t"})," are passed to the expression builder function. The ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:">="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:"<="}),", ",(0,s.jsx)(n.code,{children:"&"}),", and ",(0,s.jsx)(n.code,{children:"|"})," operators are overridden to make it easier to work with column values. When using the operators, it's a good practice to place them within a set of parentheses as the precedence rules are not always what would be expected. These are some examples of expressions."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"// The name column of the Company table equals 'My company')\nt.name.equals('My company')\n\n// Companies founded at or after 2020\nt.foundedDate >= DateTime.utc(2020)\n\n// Companies with number of employees between 10 and 100\n(t.numEmployees > 10) & (t.numEmployees <= 100)\n\n// Companies that has the founded date set\nt.foundedDate.notEquals(null)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"transactions",children:"Transactions"}),"\n",(0,s.jsx)(n.p,{children:"Docs coming."}),"\n",(0,s.jsx)(n.h3,{id:"executing-raw-queries",children:"Executing raw queries"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes more advanced tasks need to be performed on the database. For those occasions, it's possible to run raw SQL queries on the database. Use the ",(0,s.jsx)(n.code,{children:"query"})," method. A ",(0,s.jsx)(n.code,{children:"List>"})," will be returned with rows and columns."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-dart",children:"var result = await session.db.query('SELECT * FROM mytable WHERE ...');\n"})})]})}function h(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},11151:(e,n,a)=>{a.d(n,{Z:()=>r,a:()=>o});var s=a(67294);const i={},t=s.createContext(i);function o(e){const n=s.useContext(t);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/docs/assets/js/runtime~main.1ae0fba7.js b/docs/assets/js/runtime~main.1ae0fba7.js
new file mode 100644
index 000000000..97c9c3c55
--- /dev/null
+++ b/docs/assets/js/runtime~main.1ae0fba7.js
@@ -0,0 +1 @@
+(()=>{"use strict";var e,d,a,c,f,b={},r={};function t(e){var d=r[e];if(void 0!==d)return d.exports;var a=r[e]={exports:{}};return b[e].call(a.exports,a,a.exports,t),a.exports}t.m=b,e=[],t.O=(d,a,c,f)=>{if(!a){var b=1/0;for(i=0;i=f)&&Object.keys(t.O).every((e=>t.O[e](a[o])))?a.splice(o--,1):(r=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[a,c,f]},t.n=e=>{var d=e&&e.__esModule?()=>e.default:()=>e;return t.d(d,{a:d}),d},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var f=Object.create(null);t.r(f);var b={};d=d||[null,a({}),a([]),a(a)];for(var r=2&c&&e;"object"==typeof r&&!~d.indexOf(r);r=a(r))Object.getOwnPropertyNames(r).forEach((d=>b[d]=()=>e[d]));return b.default=()=>e,t.d(f,b),f},t.d=(e,d)=>{for(var a in d)t.o(d,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:d[a]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((d,a)=>(t.f[a](e,d),d)),[])),t.u=e=>"assets/js/"+({45:"984d6493",53:"935f2afb",58:"313c9eb1",99:"b1394c86",102:"7d63aba8",114:"c10a0985",131:"986f0f98",187:"a2a1c245",281:"566f49fb",282:"072aa2d8",334:"f28f059c",372:"2d11a680",397:"b809d820",399:"511f9951",420:"da071cb8",550:"6ba85e75",578:"4f0519c7",599:"83c6f999",669:"bd568e77",770:"94b2bc9a",832:"719163ad",845:"eecc43ff",847:"1b6591f7",860:"1a84c7fd",870:"85d514f3",887:"71ba2dc1",967:"51ddac88",969:"45939ed5",979:"8b75b47c",1017:"0d76317c",1027:"f6adf820",1086:"17dc776d",1103:"a1154d73",1129:"a4adf53f",1131:"bd118f84",1162:"dc4059b2",1251:"1323771c",1308:"fc6f07d2",1315:"6feb7661",1332:"6e29a506",1362:"8e0e42ad",1370:"2bbc2deb",1372:"8552f549",1400:"5143312c",1414:"9c9052d1",1419:"9d779d8b",1444:"dec2bd4a",1453:"c3373259",1458:"e3d58533",1481:"3d277f18",1483:"9f8e6d57",1485:"da19ecb4",1499:"87ab7385",1567:"4f83adf9",1569:"805a59dc",1577:"897331c0",1582:"4519f039",1616:"25c6d77a",1651:"ea237062",1656:"1d39c85d",1681:"44a83f6a",1697:"9639af7c",1703:"9906d6d9",1733:"61ff6850",1754:"61aeda71",1816:"3817c387",1826:"7de3e81f",1827:"669968f9",1834:"419cd6b8",1843:"ce4dbf6d",1876:"3aa0ab0a",1898:"801276a1",1938:"afb7a97b",1978:"812cd700",1982:"ecb3c634",1996:"be37811c",2001:"e7977816",2020:"444a6d4e",2029:"f2c30f0a",2040:"54cab4d4",2058:"93dcedec",2068:"819b642a",2105:"cdc118a8",2128:"4aa94ec1",2151:"7570de64",2154:"2b67eda4",2165:"956829f8",2181:"c8139b75",2265:"0893faed",2284:"b79774cd",2330:"6d2a4d3f",2372:"33c1d41a",2394:"9b4ab8cd",2400:"15f7c149",2428:"fe76eed8",2475:"869ae8a7",2500:"ae0eacdd",2544:"5f6b1733",2559:"4a197f0b",2631:"071f33a8",2696:"1921e4ca",2733:"1457ddcd",2743:"c3094240",2768:"676f1bdb",2784:"3e87058f",2793:"2955939d",2890:"ad61550a",2917:"44463284",2924:"95a5d2b2",2935:"467a9f36",2981:"526e379a",2989:"6a2e0576",3012:"710ac1c1",3029:"b9ec56c8",3036:"4cbee5e0",3057:"4e689a0b",3083:"2590f46b",3095:"d2aa311d",3109:"d8d6d57b",3172:"7479a3f8",3174:"4a49065b",3238:"dc8c27bd",3243:"997397e3",3283:"ef4456b5",3310:"30bd0f5b",3314:"d2f6d210",3357:"49849746",3377:"7f0714d1",3380:"13798859",3414:"ec91ff36",3446:"96e80ddd",3457:"068743c8",3525:"227d1fc4",3537:"c342bcae",3624:"a6311318",3642:"d84f251f",3768:"5d707891",3770:"6da448d1",3786:"4867e743",3866:"0c695afe",3889:"b0f19176",3905:"f7ae65ac",3929:"4ab30eec",3949:"82ea7079",3954:"2db99065",3962:"af754a1f",3978:"cce58fe7",3983:"2db5c390",3988:"d4067975",4013:"9e0c2c37",4039:"24557dbc",4055:"272aa200",4056:"27b43779",4081:"5c6f6ba9",4086:"b5dcbe95",4102:"98f4e1ec",4135:"fc8b5a5d",4161:"da698f4c",4169:"e4a796aa",4201:"dd31e7e9",4235:"abd13aa2",4302:"999788b8",4325:"9fbfaf6d",4331:"8e7261c9",4351:"bdc5a52e",4368:"a94703ab",4378:"daec0d60",4384:"bafd283f",4426:"8b6141b3",4453:"afa99621",4477:"070c8c93",4531:"50f02128",4571:"51e50f95",4613:"dd059c51",4641:"a32c313f",4650:"c090764b",4652:"ebd05845",4665:"327b0a57",4786:"52f87500",4799:"d6dc384d",4801:"378935ce",4807:"099a3596",4842:"813cfb2f",4939:"d8020439",4955:"646cbece",4969:"fac0eceb",5002:"ee65edec",5069:"9107c65f",5080:"a6397568",5085:"59c6c1db",5109:"3c9432f0",5151:"e2d6ba1f",5172:"b26210db",5182:"945c4294",5183:"21b7a589",5190:"6458864c",5217:"3cc71396",5227:"522ca66b",5239:"89b55a09",5261:"18910d94",5265:"62dc82db",5267:"9ed3f7e3",5285:"45dd886d",5293:"5839343c",5321:"c0650537",5329:"62e81aa6",5367:"9e09f891",5413:"06393fc1",5478:"d58f1ee2",5482:"90239e6e",5515:"726a6c22",5532:"26398b18",5630:"79d28454",5664:"504d78e0",5666:"2ace8790",5688:"2e1ee4ed",5710:"cd461806",5724:"704545ab",5730:"f5fed352",5738:"efe5610c",5754:"05552792",5767:"2d16d24d",5801:"a81cb65f",5805:"42abcd4d",5836:"92f483f2",5838:"4a209014",5873:"564db590",5900:"616631fd",5935:"03b3cfd2",5955:"e84b4e80",5963:"69cda322",5969:"5c1eff22",6031:"4aec9039",6055:"cb867d98",6086:"5887a6b3",6092:"b28bd8b1",6099:"e8f4756d",6107:"9f1829f0",6183:"adce8179",6199:"1dda0a07",6223:"bd6f2233",6265:"3fe65583",6279:"055b225f",6288:"a4c89d62",6297:"45926b62",6302:"1a30ce1a",6401:"0a5c01b2",6490:"62037464",6495:"e4eafb12",6506:"03b2528f",6508:"d95655b8",6527:"07e708e9",6536:"65c67349",6553:"4bfca71d",6570:"79840965",6582:"3113b236",6611:"33f4c6a9",6640:"3f80bb14",6714:"92466816",6719:"5bc657fa",6738:"5112ebe3",6740:"53e9dd7a",6777:"d802bb56",6789:"9f85e773",6837:"0ae57e5e",6845:"141135bb",6863:"c7156cf2",6864:"08aab21d",6895:"5f5da5ff",6971:"c377a04b",6974:"954e932f",7001:"82444e58",7051:"c2b45dbb",7065:"8dfd8953",7071:"8a5390a0",7112:"10e37c04",7123:"fd4b36bb",7129:"23975af2",7136:"098f2604",7139:"926056c1",7250:"8e374c01",7251:"b32c213b",7262:"9a594c98",7265:"9d36f238",7273:"cdd4a9c6",7311:"8bed5a26",7395:"7af31c45",7425:"44145933",7427:"e3443ce0",7485:"b7ea99f7",7486:"67e77328",7489:"3e4a4cb2",7492:"81e4ed6a",7503:"16116660",7512:"07006f9e",7539:"616bfcf6",7566:"063d75bd",7613:"2e18ba50",7670:"49145cdf",7673:"638e38ae",7677:"c75d145e",7708:"b744c57f",7718:"ed64c12e",7800:"59df87e8",7819:"3141060a",7847:"c6e65aef",7858:"7ca2e59a",7918:"17896441",7927:"68401255",7932:"5af30237",7955:"b8787c81",7980:"db7d4591",8018:"65399378",8044:"e64edb60",8047:"3d150a24",8076:"169f3d24",8110:"26a0dea9",8143:"0773e78b",8172:"4934de22",8202:"9644aa4e",8213:"98c94590",8232:"2596363d",8278:"fe3f3783",8287:"d4fc3158",8299:"7974de6c",8317:"d26a73b8",8326:"e15bcb33",8341:"bd1cffff",8344:"e66f2658",8349:"eac16e1d",8369:"be895d61",8378:"38e32826",8413:"ac6e050c",8438:"aee9697b",8456:"f584139f",8457:"ac3101e9",8486:"a0aa5253",8492:"eb4c176e",8518:"a7bd4aaa",8524:"9d7352c0",8539:"5d8361b1",8548:"96331245",8560:"6a734661",8571:"056b386b",8573:"1d3ec39f",8618:"00d14154",8658:"2c2832e4",8675:"28967b3e",8686:"02e41de2",8746:"8af032d3",8752:"d44e0d1c",8757:"73ca4188",8778:"5e7d099e",8818:"d636c09f",8849:"5e253f2f",8853:"c05c66f0",8856:"afde3230",8864:"4eee9c87",8919:"8a14b359",8961:"ed942358",9006:"0f4a5c74",9048:"640696ee",9055:"10ad1fa6",9073:"a64b2578",9120:"e0bec135",9231:"31b73615",9241:"092bf57d",9261:"d86e4bec",9297:"f9bde383",9298:"6aee17c2",9434:"8ee9837e",9450:"3874f1bf",9523:"05fa9a60",9533:"8baf194b",9570:"f149b10e",9610:"f4f85478",9627:"f3467f26",9639:"4c781063",9652:"bb9c591b",9654:"5589c54d",9661:"5e95c892",9667:"cbf3c4ec",9670:"86a8bb6c",9705:"a7edc2bd",9726:"10ea0b82",9735:"b1218054",9773:"12407b36",9783:"4b6eee9a",9792:"7c4a294c",9835:"4ac2e930",9953:"2020ed93"}[e]||e)+"."+{45:"c54b64d6",53:"ff1143a6",58:"d89ace65",99:"6a2d6998",102:"1c17e5b1",114:"0c4ea37c",131:"55708207",187:"42fe0537",281:"af1ae895",282:"f7c0f822",334:"4c3b9833",372:"230bf69c",397:"54385e57",399:"bae60e3b",420:"d9ed7f78",550:"9d6fb543",578:"4d633456",599:"77b90007",669:"c3580291",770:"4922872a",832:"193c9e25",845:"a7c864af",847:"bde924af",860:"38706e3a",870:"c87ba2ef",887:"f51ccc1a",967:"e2c345f0",969:"9c52f9ab",979:"c1de2063",1017:"b66f5e13",1027:"f7f0795d",1086:"a3f719ee",1103:"c09ce126",1129:"78038a9d",1131:"ab9fe841",1162:"6667aebc",1251:"787da051",1308:"e2e6925a",1315:"1483bd71",1332:"217033db",1362:"d31998cd",1370:"3f4afda9",1372:"8aee3440",1400:"377a145f",1414:"a0350e3a",1419:"19b8929d",1444:"d728e633",1453:"749459a2",1458:"3afb2ac0",1481:"3343378a",1483:"85dd220e",1485:"1872039d",1499:"4956c5c3",1567:"50e4fdd2",1569:"4a8ac4a6",1577:"370ebae2",1582:"b3fa3a9d",1616:"85c668b2",1651:"fcf9ba2a",1656:"304e016d",1681:"c78ff86d",1697:"da290aeb",1703:"44f77352",1733:"e41fb7e5",1754:"6283ac47",1772:"01952d7f",1816:"dfa36167",1826:"bb65e083",1827:"87fa8eaf",1834:"43d07b6d",1843:"ba8ab343",1876:"4613dd75",1898:"041ddb38",1938:"ae6ae937",1978:"e42b66eb",1982:"746e5951",1996:"3c8f0e12",2001:"ead0e063",2020:"30dadc3e",2029:"e69a3948",2040:"bd5e4216",2058:"8a8990a5",2068:"006ffbde",2105:"873f2e59",2128:"f516246e",2151:"be6a0f20",2154:"5647de9d",2165:"64797f5a",2181:"37af1b0e",2265:"c36d4f81",2284:"86948f6d",2330:"f025d616",2372:"61bb1689",2394:"c024db12",2400:"feac5b56",2428:"ff3954a9",2475:"9760a622",2500:"1e360109",2544:"5373e235",2559:"997922fe",2631:"93ef3132",2696:"12f764d0",2733:"f456f2f5",2743:"ac06da09",2768:"bc82fe13",2784:"b4d7a119",2793:"edaf9023",2890:"24f987c6",2917:"06852bb5",2924:"b090940e",2935:"81f9e7b4",2981:"6d448690",2989:"85d60160",3012:"b8ba5e6c",3029:"42068d6e",3036:"1b43d381",3057:"8f32e8a2",3083:"3d8e21e6",3095:"e7b9482c",3109:"731a7f6c",3172:"e776ece7",3174:"fb1114c0",3238:"dc1f576e",3243:"d9b61b81",3283:"d6afbb0a",3310:"c886f148",3314:"9ec183be",3357:"75dabc99",3377:"5cd42774",3380:"704dfbfe",3414:"a7cf5a79",3446:"937cb941",3457:"055a7f2a",3525:"9bec2fd9",3537:"149674a7",3624:"ae0e4c0a",3642:"c4122d0d",3768:"489f4310",3770:"fff87b90",3786:"c2e541db",3866:"9727968b",3889:"8e409948",3905:"8e67668e",3929:"f83db984",3949:"f22912aa",3954:"eaa22abc",3962:"dbe57387",3978:"718dbe81",3983:"3046099d",3988:"a92167ee",4013:"e2de6367",4039:"543c1f00",4055:"c1899d2a",4056:"2af60df2",4081:"cd1980fd",4086:"dae878b5",4102:"754347e6",4135:"8155e1ca",4161:"e740c3d5",4169:"b0db8952",4201:"0399337f",4235:"c586f2ed",4302:"01525b26",4325:"ebb1785b",4331:"6ceaaa70",4351:"f23facd2",4368:"dff6e541",4378:"c513dd81",4384:"b0805a9b",4426:"560123aa",4453:"12fa8609",4477:"0a776bbd",4531:"541f8c6a",4571:"46619d04",4613:"a8efbb4d",4641:"98d78771",4650:"7353206f",4652:"56162133",4665:"8dbd41d3",4685:"beef0944",4786:"e94dbb4d",4799:"98ee6b33",4801:"dc5f0917",4807:"0bc222da",4842:"d700fd99",4939:"2d9dcfca",4955:"460626b9",4969:"ca4b19a5",5002:"b8f165c3",5069:"f4e41127",5080:"6689c9bf",5085:"f253cde2",5109:"6ed8240d",5151:"197e48f7",5172:"064cdaef",5182:"c323acc5",5183:"99e4c592",5190:"4f8db539",5217:"2911c07c",5227:"f0b9524b",5239:"6882fa8f",5261:"3ddebced",5265:"d8b485bf",5267:"93487111",5285:"0b9c0d74",5293:"e8cd6002",5321:"d3664bb2",5329:"966140c0",5367:"b76f3ef6",5413:"e4527c12",5478:"262d2fb2",5482:"6a44426e",5515:"fe945ea1",5532:"cebf9440",5630:"5cd3f743",5664:"8f8f19b3",5666:"ce449cb5",5688:"25bbed3a",5710:"6d70d6d1",5724:"c94cb47d",5730:"08d3bc06",5738:"73ada662",5754:"303186d9",5767:"e154d86c",5801:"b38076ff",5805:"53aba75e",5836:"5856e918",5838:"cebb9ea9",5873:"4fbd2ed1",5900:"0636d6ad",5935:"04020a32",5955:"ad223fc0",5963:"5c54719b",5969:"49486dcf",6031:"cadd7b19",6055:"f0fa2fea",6086:"0f061d88",6092:"d33b6b35",6099:"0e0c2707",6107:"66e73b2c",6183:"eb7fc255",6199:"fe4410d8",6223:"0a001c13",6265:"51332d25",6279:"7a3b2cec",6288:"2465dab0",6297:"6108586e",6302:"9ed912ac",6401:"9521ffe5",6490:"19d8f177",6495:"89edcc0e",6506:"0b416d39",6508:"f7d1e636",6527:"609f8145",6536:"c6372736",6553:"194c28d3",6570:"e394c678",6582:"3661920f",6611:"8cdf2270",6640:"444a798d",6714:"c9b32a43",6719:"9e88c14c",6738:"fc90b218",6740:"4f36427c",6777:"37b6b447",6789:"183f8ad7",6837:"3d3ccb71",6845:"cbfe9736",6863:"928fee2d",6864:"7cbda3a4",6895:"8cbc8c9e",6971:"73a4560a",6974:"74faaa9e",7001:"719e1ce4",7051:"8031deb4",7065:"b1a2272b",7071:"d3e90e55",7112:"f13123ad",7123:"3ef91cf3",7129:"22db06a7",7136:"d0594551",7139:"8955b52b",7250:"7c48ade1",7251:"e9398645",7262:"35dd374e",7265:"a86b3249",7273:"b21514d1",7311:"d09612ab",7395:"9df7e1e0",7425:"9e8f1d22",7427:"5d1e4720",7485:"e02d32f8",7486:"3549e7b3",7489:"2cdbbca1",7492:"d657d713",7503:"17ae88e5",7512:"d52a8537",7539:"29514747",7566:"3cfb01c6",7613:"d67b2dd2",7670:"c09c3c18",7673:"b24dcfbe",7677:"43598d7b",7708:"dfacc186",7718:"0cf2c286",7800:"470f25e4",7819:"590ce699",7847:"cb4b1fd3",7858:"a36b4059",7918:"d5edfc9d",7927:"7be27921",7932:"9510ae52",7955:"19000061",7980:"7e864817",8018:"bba26f76",8044:"80155196",8047:"30350cec",8076:"487d22fe",8110:"33dd7dbf",8143:"4aee0994",8172:"20d8130b",8202:"7af08790",8213:"2a56ce4c",8232:"ebdfdca5",8278:"3dcf1976",8287:"b796bd72",8299:"3e4308c9",8317:"a3fdd3d1",8326:"f7b1837e",8341:"70598be9",8344:"229b1fbd",8349:"c90ba1a8",8369:"27ad13f1",8378:"44e9afa2",8413:"c038c348",8438:"e517f740",8456:"0cc743de",8457:"4d9b6209",8486:"c9141254",8492:"77b55e1c",8518:"b47ce817",8524:"c2020712",8539:"b1e0c316",8548:"0aac657c",8560:"725dbabc",8571:"3eb1996f",8573:"5c64e67c",8618:"deaf4687",8658:"915e8c20",8675:"9798f4d9",8686:"64d5bca2",8746:"8a11dd40",8752:"99de598e",8757:"31f39ca8",8778:"5677aa36",8818:"8a533cd9",8849:"bf911669",8853:"a9080be1",8856:"988b02ff",8864:"6e99380a",8919:"643fc552",8961:"c98fc885",9006:"e2b039a7",9048:"953ebb91",9055:"be624869",9073:"0a342404",9120:"cc4ee629",9231:"87b00d7f",9241:"121f8efa",9261:"d75ca43a",9297:"f777844d",9298:"70354ce4",9434:"177d3556",9450:"866e1a94",9523:"390b1e27",9533:"9e9f1577",9570:"ebdf0d03",9610:"9c6acb63",9627:"d2cd1008",9639:"f02dc04a",9652:"5e59f0b7",9654:"cd620f12",9661:"697f2be4",9667:"4d91b24c",9670:"7572de5c",9705:"c796222e",9726:"b5b58d3f",9735:"c4c22c4f",9773:"b78f4d98",9783:"afea5b69",9792:"a61a2dc6",9835:"a4405588",9953:"cd6ce099"}[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,d)=>Object.prototype.hasOwnProperty.call(e,d),c={},f="serverpod-docs:",t.l=(e,d,a,b)=>{if(c[e])c[e].push(d);else{var r,o;if(void 0!==a)for(var n=document.getElementsByTagName("script"),i=0;i{r.onerror=r.onload=null,clearTimeout(s);var f=c[e];if(delete c[e],r.parentNode&&r.parentNode.removeChild(r),f&&f.forEach((e=>e(a))),d)return d(a)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=l.bind(null,r.onerror),r.onload=l.bind(null,r.onload),o&&document.head.appendChild(r)}},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:"3380",16116660:"7503",17896441:"7918",44145933:"7425",44463284:"2917",49849746:"3357",62037464:"6490",65399378:"8018",68401255:"7927",79840965:"6570",92466816:"6714",96331245:"8548","984d6493":"45","935f2afb":"53","313c9eb1":"58",b1394c86:"99","7d63aba8":"102",c10a0985:"114","986f0f98":"131",a2a1c245:"187","566f49fb":"281","072aa2d8":"282",f28f059c:"334","2d11a680":"372",b809d820:"397","511f9951":"399",da071cb8:"420","6ba85e75":"550","4f0519c7":"578","83c6f999":"599",bd568e77:"669","94b2bc9a":"770","719163ad":"832",eecc43ff:"845","1b6591f7":"847","1a84c7fd":"860","85d514f3":"870","71ba2dc1":"887","51ddac88":"967","45939ed5":"969","8b75b47c":"979","0d76317c":"1017",f6adf820:"1027","17dc776d":"1086",a1154d73:"1103",a4adf53f:"1129",bd118f84:"1131",dc4059b2:"1162","1323771c":"1251",fc6f07d2:"1308","6feb7661":"1315","6e29a506":"1332","8e0e42ad":"1362","2bbc2deb":"1370","8552f549":"1372","5143312c":"1400","9c9052d1":"1414","9d779d8b":"1419",dec2bd4a:"1444",c3373259:"1453",e3d58533:"1458","3d277f18":"1481","9f8e6d57":"1483",da19ecb4:"1485","87ab7385":"1499","4f83adf9":"1567","805a59dc":"1569","897331c0":"1577","4519f039":"1582","25c6d77a":"1616",ea237062:"1651","1d39c85d":"1656","44a83f6a":"1681","9639af7c":"1697","9906d6d9":"1703","61ff6850":"1733","61aeda71":"1754","3817c387":"1816","7de3e81f":"1826","669968f9":"1827","419cd6b8":"1834",ce4dbf6d:"1843","3aa0ab0a":"1876","801276a1":"1898",afb7a97b:"1938","812cd700":"1978",ecb3c634:"1982",be37811c:"1996",e7977816:"2001","444a6d4e":"2020",f2c30f0a:"2029","54cab4d4":"2040","93dcedec":"2058","819b642a":"2068",cdc118a8:"2105","4aa94ec1":"2128","7570de64":"2151","2b67eda4":"2154","956829f8":"2165",c8139b75:"2181","0893faed":"2265",b79774cd:"2284","6d2a4d3f":"2330","33c1d41a":"2372","9b4ab8cd":"2394","15f7c149":"2400",fe76eed8:"2428","869ae8a7":"2475",ae0eacdd:"2500","5f6b1733":"2544","4a197f0b":"2559","071f33a8":"2631","1921e4ca":"2696","1457ddcd":"2733",c3094240:"2743","676f1bdb":"2768","3e87058f":"2784","2955939d":"2793",ad61550a:"2890","95a5d2b2":"2924","467a9f36":"2935","526e379a":"2981","6a2e0576":"2989","710ac1c1":"3012",b9ec56c8:"3029","4cbee5e0":"3036","4e689a0b":"3057","2590f46b":"3083",d2aa311d:"3095",d8d6d57b:"3109","7479a3f8":"3172","4a49065b":"3174",dc8c27bd:"3238","997397e3":"3243",ef4456b5:"3283","30bd0f5b":"3310",d2f6d210:"3314","7f0714d1":"3377",ec91ff36:"3414","96e80ddd":"3446","068743c8":"3457","227d1fc4":"3525",c342bcae:"3537",a6311318:"3624",d84f251f:"3642","5d707891":"3768","6da448d1":"3770","4867e743":"3786","0c695afe":"3866",b0f19176:"3889",f7ae65ac:"3905","4ab30eec":"3929","82ea7079":"3949","2db99065":"3954",af754a1f:"3962",cce58fe7:"3978","2db5c390":"3983",d4067975:"3988","9e0c2c37":"4013","24557dbc":"4039","272aa200":"4055","27b43779":"4056","5c6f6ba9":"4081",b5dcbe95:"4086","98f4e1ec":"4102",fc8b5a5d:"4135",da698f4c:"4161",e4a796aa:"4169",dd31e7e9:"4201",abd13aa2:"4235","999788b8":"4302","9fbfaf6d":"4325","8e7261c9":"4331",bdc5a52e:"4351",a94703ab:"4368",daec0d60:"4378",bafd283f:"4384","8b6141b3":"4426",afa99621:"4453","070c8c93":"4477","50f02128":"4531","51e50f95":"4571",dd059c51:"4613",a32c313f:"4641",c090764b:"4650",ebd05845:"4652","327b0a57":"4665","52f87500":"4786",d6dc384d:"4799","378935ce":"4801","099a3596":"4807","813cfb2f":"4842",d8020439:"4939","646cbece":"4955",fac0eceb:"4969",ee65edec:"5002","9107c65f":"5069",a6397568:"5080","59c6c1db":"5085","3c9432f0":"5109",e2d6ba1f:"5151",b26210db:"5172","945c4294":"5182","21b7a589":"5183","6458864c":"5190","3cc71396":"5217","522ca66b":"5227","89b55a09":"5239","18910d94":"5261","62dc82db":"5265","9ed3f7e3":"5267","45dd886d":"5285","5839343c":"5293",c0650537:"5321","62e81aa6":"5329","9e09f891":"5367","06393fc1":"5413",d58f1ee2:"5478","90239e6e":"5482","726a6c22":"5515","26398b18":"5532","79d28454":"5630","504d78e0":"5664","2ace8790":"5666","2e1ee4ed":"5688",cd461806:"5710","704545ab":"5724",f5fed352:"5730",efe5610c:"5738","05552792":"5754","2d16d24d":"5767",a81cb65f:"5801","42abcd4d":"5805","92f483f2":"5836","4a209014":"5838","564db590":"5873","616631fd":"5900","03b3cfd2":"5935",e84b4e80:"5955","69cda322":"5963","5c1eff22":"5969","4aec9039":"6031",cb867d98:"6055","5887a6b3":"6086",b28bd8b1:"6092",e8f4756d:"6099","9f1829f0":"6107",adce8179:"6183","1dda0a07":"6199",bd6f2233:"6223","3fe65583":"6265","055b225f":"6279",a4c89d62:"6288","45926b62":"6297","1a30ce1a":"6302","0a5c01b2":"6401",e4eafb12:"6495","03b2528f":"6506",d95655b8:"6508","07e708e9":"6527","65c67349":"6536","4bfca71d":"6553","3113b236":"6582","33f4c6a9":"6611","3f80bb14":"6640","5bc657fa":"6719","5112ebe3":"6738","53e9dd7a":"6740",d802bb56:"6777","9f85e773":"6789","0ae57e5e":"6837","141135bb":"6845",c7156cf2:"6863","08aab21d":"6864","5f5da5ff":"6895",c377a04b:"6971","954e932f":"6974","82444e58":"7001",c2b45dbb:"7051","8dfd8953":"7065","8a5390a0":"7071","10e37c04":"7112",fd4b36bb:"7123","23975af2":"7129","098f2604":"7136","926056c1":"7139","8e374c01":"7250",b32c213b:"7251","9a594c98":"7262","9d36f238":"7265",cdd4a9c6:"7273","8bed5a26":"7311","7af31c45":"7395",e3443ce0:"7427",b7ea99f7:"7485","67e77328":"7486","3e4a4cb2":"7489","81e4ed6a":"7492","07006f9e":"7512","616bfcf6":"7539","063d75bd":"7566","2e18ba50":"7613","49145cdf":"7670","638e38ae":"7673",c75d145e:"7677",b744c57f:"7708",ed64c12e:"7718","59df87e8":"7800","3141060a":"7819",c6e65aef:"7847","7ca2e59a":"7858","5af30237":"7932",b8787c81:"7955",db7d4591:"7980",e64edb60:"8044","3d150a24":"8047","169f3d24":"8076","26a0dea9":"8110","0773e78b":"8143","4934de22":"8172","9644aa4e":"8202","98c94590":"8213","2596363d":"8232",fe3f3783:"8278",d4fc3158:"8287","7974de6c":"8299",d26a73b8:"8317",e15bcb33:"8326",bd1cffff:"8341",e66f2658:"8344",eac16e1d:"8349",be895d61:"8369","38e32826":"8378",ac6e050c:"8413",aee9697b:"8438",f584139f:"8456",ac3101e9:"8457",a0aa5253:"8486",eb4c176e:"8492",a7bd4aaa:"8518","9d7352c0":"8524","5d8361b1":"8539","6a734661":"8560","056b386b":"8571","1d3ec39f":"8573","00d14154":"8618","2c2832e4":"8658","28967b3e":"8675","02e41de2":"8686","8af032d3":"8746",d44e0d1c:"8752","73ca4188":"8757","5e7d099e":"8778",d636c09f:"8818","5e253f2f":"8849",c05c66f0:"8853",afde3230:"8856","4eee9c87":"8864","8a14b359":"8919",ed942358:"8961","0f4a5c74":"9006","640696ee":"9048","10ad1fa6":"9055",a64b2578:"9073",e0bec135:"9120","31b73615":"9231","092bf57d":"9241",d86e4bec:"9261",f9bde383:"9297","6aee17c2":"9298","8ee9837e":"9434","3874f1bf":"9450","05fa9a60":"9523","8baf194b":"9533",f149b10e:"9570",f4f85478:"9610",f3467f26:"9627","4c781063":"9639",bb9c591b:"9652","5589c54d":"9654","5e95c892":"9661",cbf3c4ec:"9667","86a8bb6c":"9670",a7edc2bd:"9705","10ea0b82":"9726",b1218054:"9735","12407b36":"9773","4b6eee9a":"9783","7c4a294c":"9792","4ac2e930":"9835","2020ed93":"9953"}[e]||e,t.p+t.u(e)},(()=>{var e={1303:0,532:0};t.f.j=(d,a)=>{var c=t.o(e,d)?e[d]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1303|532)$/.test(d))e[d]=0;else{var f=new Promise(((a,f)=>c=e[d]=[a,f]));a.push(c[2]=f);var b=t.p+t.u(d),r=new Error;t.l(b,(a=>{if(t.o(e,d)&&(0!==(c=e[d])&&(e[d]=void 0),c)){var f=a&&("load"===a.type?"missing":a.type),b=a&&a.target&&a.target.src;r.message="Loading chunk "+d+" failed.\n("+f+": "+b+")",r.name="ChunkLoadError",r.type=f,r.request=b,c[1](r)}}),"chunk-"+d,d)}},t.O.j=d=>0===e[d];var d=(d,a)=>{var c,f,b=a[0],r=a[1],o=a[2],n=0;if(b.some((d=>0!==e[d]))){for(c in r)t.o(r,c)&&(t.m[c]=r[c]);if(o)var i=o(t)}for(d&&d(a);nCapabilities | Serverpod
-
+
diff --git a/docs/cli.html b/docs/cli.html
index e27d03dea..1519f5254 100644
--- a/docs/cli.html
+++ b/docs/cli.html
@@ -4,7 +4,7 @@
Serverpod CLI | Serverpod
-
+
diff --git a/docs/concepts/authentication/basics.html b/docs/concepts/authentication/basics.html
index 1f12a459c..900a1710c 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 45e88e667..49a19a708 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 6c6f88114..bb26fcf00 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 49b9c5f5c..fe8014900 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 2b1c4d19b..bb7d10a3c 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 36e8e8bbb..8fd5fe00e 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 737921463..d781622e9 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 32ab41fd7..906354c5c 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 9c7c9cb46..50eea46b2 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 094fddc7e..ecc2c90fd 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 496759175..3154c9441 100644
--- a/docs/concepts/caching.html
+++ b/docs/concepts/caching.html
@@ -4,7 +4,7 @@
Caching | Serverpod
-
+
diff --git a/docs/concepts/database/connection.html b/docs/concepts/database/connection.html
index 6de00c948..e0a68bedb 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 0d91a0251..04d018a82 100644
--- a/docs/concepts/database/crud.html
+++ b/docs/concepts/database/crud.html
@@ -4,7 +4,7 @@
CRUD | Serverpod
-
+
@@ -35,7 +35,7 @@
Finding
info
Note that ordering of the entries is important here as it will return the fist row returned by the database query.