From 702c550cf276bb0e973e381b39135ee344814cb0 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 31 Oct 2024 17:43:05 +0000 Subject: [PATCH 01/33] Adding placeholder for new API section. --- src/content/docs/d1/worker-api/index.mdx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/content/docs/d1/worker-api/index.mdx diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx new file mode 100644 index 000000000000000..68f24d2883b4e1c --- /dev/null +++ b/src/content/docs/d1/worker-api/index.mdx @@ -0,0 +1,12 @@ +--- +pcx_content_type: navigation +title: Worker API +sidebar: + order: 4 + group: + hideIndex: true +--- + +import { DirectoryListing } from "~/components"; + + From b59f2a80eeb76ed2a00be7a1e2882c116359e930 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 1 Nov 2024 16:46:39 +0000 Subject: [PATCH 02/33] Initializing await stmt API chapter. --- src/content/docs/d1/configuration/index.mdx | 2 +- src/content/docs/d1/demos.mdx | 2 +- src/content/docs/d1/examples/index.mdx | 2 +- src/content/docs/d1/observability/index.mdx | 2 +- src/content/docs/d1/platform/index.mdx | 2 +- src/content/docs/d1/reference/index.mdx | 2 +- src/content/docs/d1/tutorials/index.mdx | 2 +- src/content/docs/d1/worker-api/query.mdx | 282 ++++++++++++++++++++ 8 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 src/content/docs/d1/worker-api/query.mdx diff --git a/src/content/docs/d1/configuration/index.mdx b/src/content/docs/d1/configuration/index.mdx index 92b68dab0bdd2de..2ee9414af27efff 100644 --- a/src/content/docs/d1/configuration/index.mdx +++ b/src/content/docs/d1/configuration/index.mdx @@ -2,7 +2,7 @@ title: Configuration pcx_content_type: navigation sidebar: - order: 4 + order: 5 group: hideIndex: true --- diff --git a/src/content/docs/d1/demos.mdx b/src/content/docs/d1/demos.mdx index 49a368c3b69d2bc..62daa6a6dc2b377 100644 --- a/src/content/docs/d1/demos.mdx +++ b/src/content/docs/d1/demos.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Demos and architectures sidebar: - order: 8 + order: 9 --- diff --git a/src/content/docs/d1/examples/index.mdx b/src/content/docs/d1/examples/index.mdx index 2e23581cbb5b6f5..f886a3640931838 100644 --- a/src/content/docs/d1/examples/index.mdx +++ b/src/content/docs/d1/examples/index.mdx @@ -4,7 +4,7 @@ hideChildren: false pcx_content_type: navigation title: Examples sidebar: - order: 6 + order: 7 group: hideIndex: true --- diff --git a/src/content/docs/d1/observability/index.mdx b/src/content/docs/d1/observability/index.mdx index 7bc6b5bc6c2436f..a19d833118ed90a 100644 --- a/src/content/docs/d1/observability/index.mdx +++ b/src/content/docs/d1/observability/index.mdx @@ -2,7 +2,7 @@ title: Observability pcx_content_type: navigation sidebar: - order: 5 + order: 6 group: hideIndex: true --- diff --git a/src/content/docs/d1/platform/index.mdx b/src/content/docs/d1/platform/index.mdx index fe7a16eca104db5..23a6316facb02d7 100644 --- a/src/content/docs/d1/platform/index.mdx +++ b/src/content/docs/d1/platform/index.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Platform sidebar: - order: 8 + order: 9 group: hideIndex: true --- diff --git a/src/content/docs/d1/reference/index.mdx b/src/content/docs/d1/reference/index.mdx index 3daad7052a171b2..cb7005ee761b961 100644 --- a/src/content/docs/d1/reference/index.mdx +++ b/src/content/docs/d1/reference/index.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Reference sidebar: - order: 9 + order: 10 group: hideIndex: true --- diff --git a/src/content/docs/d1/tutorials/index.mdx b/src/content/docs/d1/tutorials/index.mdx index 40b4db6dc9ddf3f..f8276b38d24ec20 100644 --- a/src/content/docs/d1/tutorials/index.mdx +++ b/src/content/docs/d1/tutorials/index.mdx @@ -4,7 +4,7 @@ pcx_content_type: navigation title: Tutorials hideChildren: true sidebar: - order: 7 + order: 8 --- diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx new file mode 100644 index 000000000000000..e1a20f07712d9ce --- /dev/null +++ b/src/content/docs/d1/worker-api/query.mdx @@ -0,0 +1,282 @@ +--- +title: D1 Query SQL Statements +pcx_content_type: concept +sidebar: + order: 4 +--- + +import { Type, MetaInfo, Details } from "~/components"; + +## Description + +## Methods + +### await stmt.all() + +Returns all rows as an array of objects, with each result row represented as an object on the `results` property of the `D1Result` type. + +```js +const { results } = await stmt.all(); +``` + +#### Parameters + +- None. + +#### Return values + +- Array: + - An array of objects. + - Each row represents a row. + - Each object is created on the `results` property of the `D1Result` type. + +
+```js +const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); +const { results } = await stmt.all(); +console.log(results); +``` + +```js output +[ + { + name: "John", + age: 42, + }, + { + name: "Anthony", + age: 37, + }, + { + name: "Dave", + age: 29, + }, + ] +``` +
+ +#### Guidance + +- When joining tables with identical column names, only the leftmost column will be included in the row object. Use [`stmt.raw()`](#await-stmtraw) to return all rows as an array of arrays. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `all()` to return a typed result object. + +### await stmt.raw() + +Returns results as an array of arrays, with each row represented by an array. The return type is an array of arrays, and does not include query metadata. + +Column names are not included in the result set by default. To include column names as the first row of the result array, set `.raw({columnNames: true})`. + +```js +const rows = await stmt.raw(); +``` + +#### Parameters + +- columnNames: + - A boolean flag which includes column names as the first row of the result array. + +#### Return values + +- Array: + - An array of arrays. + - Each array represents a row. + +
+```js +const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); +const rows = await stmt.raw(); +console.log(rows); +``` +```js output +[ + [ "John", 42 ], + [ "Anthony", 37 ], + [ "Dave", 29 ], +] +``` + +With parameter `columnNames: true`: +```js +const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); +const [columns, ...rows] = await stmt.raw({ columnNames: true }); +console.log(columns); +``` +```js output +[ "name", age ], // The first result array includes the column names +``` +
+ +#### Guidance + +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `raw()` to return a typed result array. + +### await stmt.first() + +Returns the first row of the query result. This does not return metadata like the other methods. Instead, it directly returns the object. + +```js +const values = await stmt.first(); +const total = await stmt.first("columnName"); +``` + +#### Parameters + +- columnName: + - Specify a `columnName` to return the value from a specific column in the first row of the query result. +- None. + - Do not pass a parameter to obtain all columns from the first row. + +#### Return values + +- firstRow: + - An object containing the first row of the query result. + +- `null`: + - If the query returns no rows. + +
+ +Get all the columns from the first row: + +```js +const stmt = db.prepare("SELECT COUNT(*) AS total FROM users"); +const values = await stmt.first(); +console.log(values); +``` +```js output +{ total: 50 } +``` + +Get a specific column from the first row: + +```js +const stmt = db.prepare("SELECT COUNT(*) AS total FROM users"); +const total = await stmt.first("total"); +console.log(total); +``` +```js output +50 // NEED CONFIRMING +``` +
+ +#### Guidance + +- If the query returns rows but `column` does not exist, then `first()` throws the `D1_ERROR` exception. +- `stmt.first()` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `first()` to return a typed result object. + +### await stmt.run() + +Runs the query (or queries) and returns results. + +```js +const { results } = await stmt.run(); +``` + +#### Parameter + +- None. + +#### Return value + +- results: + - An array of objects, where each object represents a row of the query result. + - Each object is created on the `results` property of the `D1Result` type. {/*What does it return when `results` is actually empty?*/} + +
+```js +const stmt = await db.prepare("SELECT name, age FROM users LIMIT 3"); +const { results } = await stmt.run(); +console.log(results); +``` +```js output +[ + { + name: "John", + age: 42, + }, + { + name: "Anthony", + age: 37, + }, + { + name: "Dave", + age: 29, + }, + ] +``` +
+ +#### Guidance + +- `results` is empty for write operations such as UPDATE, DELETE, or INSERT. +- Run is functionally equivalent to `stmt.all()` and can be treated as an alias. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. + +### await db.dump() + +:::caution +This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. +::: + +Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. + +```js +const dump = await db.dump(); +return new Response(dump, { + status: 200, + headers: { + "Content-Type": "application/octet-stream", + }, +}); +``` + +#### Parameters + +- None. + +#### Return values + +- ??? + +#### Guidance + +- ??? + +### await db.exec() + +Executes one or more queries directly without prepared statements or parameters binding. + +```js +const out = await db.exec(); +``` + +#### Parameters + +- ??? + +#### Return values + +- ??? + +
+```js +const migration = await fetch("/migration.sql"); +const out = await db.exec(migration.text()); +console.log(out); +``` +```js output +{ + count: 80, + duration: 76 +} +``` +
+ +#### Guidance + +- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. +- Only use this method for maintenance and one-shot tasks (for example, migration jobs). +- The input can be one or multiple queries separated by `\n`. +- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. + From 192fa36908254d11d75cca11524cb8ce9149486a Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 4 Nov 2024 13:40:53 +0000 Subject: [PATCH 03/33] Reordering the sidebar. Adding intro to stmt.methods. --- src/content/docs/d1/configuration/index.mdx | 2 +- src/content/docs/d1/d1-api.mdx | 2 +- src/content/docs/d1/demos.mdx | 2 +- src/content/docs/d1/examples/index.mdx | 2 +- src/content/docs/d1/observability/index.mdx | 2 +- src/content/docs/d1/platform/index.mdx | 2 +- src/content/docs/d1/reference/index.mdx | 2 +- src/content/docs/d1/tutorials/index.mdx | 2 +- src/content/docs/d1/worker-api/query.mdx | 18 +++++++++++++++++- 9 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/content/docs/d1/configuration/index.mdx b/src/content/docs/d1/configuration/index.mdx index 2ee9414af27efff..ba06f8814c033de 100644 --- a/src/content/docs/d1/configuration/index.mdx +++ b/src/content/docs/d1/configuration/index.mdx @@ -2,7 +2,7 @@ title: Configuration pcx_content_type: navigation sidebar: - order: 5 + order: 6 group: hideIndex: true --- diff --git a/src/content/docs/d1/d1-api.mdx b/src/content/docs/d1/d1-api.mdx index 652625d597e522f..4c584b8c309de13 100644 --- a/src/content/docs/d1/d1-api.mdx +++ b/src/content/docs/d1/d1-api.mdx @@ -3,6 +3,6 @@ pcx_content_type: navigation title: D1 REST API external_link: /api/operations/cloudflare-d1-create-database sidebar: - order: 10 + order: 5 --- diff --git a/src/content/docs/d1/demos.mdx b/src/content/docs/d1/demos.mdx index 62daa6a6dc2b377..f06ad57badb19c1 100644 --- a/src/content/docs/d1/demos.mdx +++ b/src/content/docs/d1/demos.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Demos and architectures sidebar: - order: 9 + order: 10 --- diff --git a/src/content/docs/d1/examples/index.mdx b/src/content/docs/d1/examples/index.mdx index f886a3640931838..26bca1093d92752 100644 --- a/src/content/docs/d1/examples/index.mdx +++ b/src/content/docs/d1/examples/index.mdx @@ -4,7 +4,7 @@ hideChildren: false pcx_content_type: navigation title: Examples sidebar: - order: 7 + order: 8 group: hideIndex: true --- diff --git a/src/content/docs/d1/observability/index.mdx b/src/content/docs/d1/observability/index.mdx index a19d833118ed90a..c10d1fd64af068d 100644 --- a/src/content/docs/d1/observability/index.mdx +++ b/src/content/docs/d1/observability/index.mdx @@ -2,7 +2,7 @@ title: Observability pcx_content_type: navigation sidebar: - order: 6 + order: 7 group: hideIndex: true --- diff --git a/src/content/docs/d1/platform/index.mdx b/src/content/docs/d1/platform/index.mdx index 23a6316facb02d7..8b14ea8352a012c 100644 --- a/src/content/docs/d1/platform/index.mdx +++ b/src/content/docs/d1/platform/index.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Platform sidebar: - order: 9 + order: 10 group: hideIndex: true --- diff --git a/src/content/docs/d1/reference/index.mdx b/src/content/docs/d1/reference/index.mdx index cb7005ee761b961..b007e3d2bb291a4 100644 --- a/src/content/docs/d1/reference/index.mdx +++ b/src/content/docs/d1/reference/index.mdx @@ -2,7 +2,7 @@ pcx_content_type: navigation title: Reference sidebar: - order: 10 + order: 11 group: hideIndex: true --- diff --git a/src/content/docs/d1/tutorials/index.mdx b/src/content/docs/d1/tutorials/index.mdx index f8276b38d24ec20..2edc0d395da3f03 100644 --- a/src/content/docs/d1/tutorials/index.mdx +++ b/src/content/docs/d1/tutorials/index.mdx @@ -4,7 +4,7 @@ pcx_content_type: navigation title: Tutorials hideChildren: true sidebar: - order: 8 + order: 9 --- diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx index e1a20f07712d9ce..7598bc6ce93310f 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -1,5 +1,5 @@ --- -title: D1 Query SQL Statements +title: D1 SQL statement methods pcx_content_type: concept sidebar: order: 4 @@ -9,6 +9,22 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description +D1 client API supports prepared and static statements. The best practice is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. + +Below is an example of a prepared statement: + +```js +const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind("Joe"); +``` + +However, if you still choose to use a static statement you can use the following as an example: + +```js +const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); +``` + +You can subsequently combine the statements with the methods listed below. + ## Methods ### await stmt.all() From 3f7dee4dce7084a0086eb6ba060c8e7d576962fb Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 4 Nov 2024 17:47:09 +0000 Subject: [PATCH 04/33] Setting up Worker Bindings API chapters. --- .../{query.mdx => handle-query-results.mdx} | 20 ++---------- src/content/docs/d1/worker-api/index.mdx | 2 +- .../docs/d1/worker-api/query-statements.mdx | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 18 deletions(-) rename src/content/docs/d1/worker-api/{query.mdx => handle-query-results.mdx} (90%) create mode 100644 src/content/docs/d1/worker-api/query-statements.mdx diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/handle-query-results.mdx similarity index 90% rename from src/content/docs/d1/worker-api/query.mdx rename to src/content/docs/d1/worker-api/handle-query-results.mdx index 7598bc6ce93310f..fe5a569eccdcb62 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/handle-query-results.mdx @@ -1,29 +1,15 @@ --- -title: D1 SQL statement methods +title: Handle query results pcx_content_type: concept sidebar: - order: 4 + order: 2 --- import { Type, MetaInfo, Details } from "~/components"; ## Description -D1 client API supports prepared and static statements. The best practice is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. - -Below is an example of a prepared statement: - -```js -const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind("Joe"); -``` - -However, if you still choose to use a static statement you can use the following as an example: - -```js -const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); -``` - -You can subsequently combine the statements with the methods listed below. +You can manipulate the query results which has been obtained after executing a `.db()` method. ## Methods diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 68f24d2883b4e1c..57a08eb4f5b58ba 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: navigation -title: Worker API +title: Worker Bindings API sidebar: order: 4 group: diff --git a/src/content/docs/d1/worker-api/query-statements.mdx b/src/content/docs/d1/worker-api/query-statements.mdx new file mode 100644 index 000000000000000..d019e4c90f91c88 --- /dev/null +++ b/src/content/docs/d1/worker-api/query-statements.mdx @@ -0,0 +1,31 @@ +--- +title: Prepare query statements +pcx_content_type: concept +sidebar: + order: 1 +--- + +import { Type, MetaInfo, Details } from "~/components"; + +## Description + +D1 client API supports both prepared and static statements. The best practice is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. + +Below is an example of a prepared statement: + +```js +const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind("Joe"); +``` + +However, if you still choose to use a static statement you can use the following as an example: + +```js +const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); +``` + +## Methods + +### db.prepare() + +### db.batch() + From d1dcb91345711b23ab92cded9fc204f9730b3d2c Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 5 Nov 2024 18:07:00 +0000 Subject: [PATCH 05/33] Settling on naming convention, fleshing out .db chapter. --- src/content/docs/d1/worker-api/database.mdx | 51 +++++++++++++++++++ .../docs/d1/worker-api/query-statements.mdx | 31 ----------- .../{handle-query-results.mdx => query.mdx} | 4 +- 3 files changed, 53 insertions(+), 33 deletions(-) create mode 100644 src/content/docs/d1/worker-api/database.mdx delete mode 100644 src/content/docs/d1/worker-api/query-statements.mdx rename src/content/docs/d1/worker-api/{handle-query-results.mdx => query.mdx} (98%) diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx new file mode 100644 index 000000000000000..736adc3eed826ce --- /dev/null +++ b/src/content/docs/d1/worker-api/database.mdx @@ -0,0 +1,51 @@ +--- +title: D1 database +pcx_content_type: concept +sidebar: + order: 1 +--- + +import { Type, MetaInfo, Details } from "~/components"; + +## Description + +You can execute queries on your D1 database through SQL statements. + +## Methods + +### db.prepare() + +D1 API supports both prepared and static statements. The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. + +Example of a prepared statement: + +```js +const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind(someVariable); +// someVariable will replace the placeholder '?1' in the query. +``` + +Example of a static statement: + +```js +const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); +// "John Doe" is hard-coded into the query. This is a static statement. +``` + +#### Parameters + +- sqlQuery: + - The SQL query you wish to execute on the database. + +#### Return values + +- queryResult: + - The result of the SQL query. + +### db.batch() + + + +#### Parameters + +#### Return values + diff --git a/src/content/docs/d1/worker-api/query-statements.mdx b/src/content/docs/d1/worker-api/query-statements.mdx deleted file mode 100644 index d019e4c90f91c88..000000000000000 --- a/src/content/docs/d1/worker-api/query-statements.mdx +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Prepare query statements -pcx_content_type: concept -sidebar: - order: 1 ---- - -import { Type, MetaInfo, Details } from "~/components"; - -## Description - -D1 client API supports both prepared and static statements. The best practice is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. - -Below is an example of a prepared statement: - -```js -const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind("Joe"); -``` - -However, if you still choose to use a static statement you can use the following as an example: - -```js -const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); -``` - -## Methods - -### db.prepare() - -### db.batch() - diff --git a/src/content/docs/d1/worker-api/handle-query-results.mdx b/src/content/docs/d1/worker-api/query.mdx similarity index 98% rename from src/content/docs/d1/worker-api/handle-query-results.mdx rename to src/content/docs/d1/worker-api/query.mdx index fe5a569eccdcb62..8c739ba63da56c2 100644 --- a/src/content/docs/d1/worker-api/handle-query-results.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -1,5 +1,5 @@ --- -title: Handle query results +title: D1 Query pcx_content_type: concept sidebar: order: 2 @@ -9,7 +9,7 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description -You can manipulate the query results which has been obtained after executing a `.db()` method. +You can modify the query results which has been obtained after executing a `.db()` method. ## Methods From ce19b838797f2590524dd7bab679b0b3d3d45754 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 6 Nov 2024 14:04:42 +0000 Subject: [PATCH 06/33] Setting up the database API section. --- src/content/docs/d1/worker-api/database.mdx | 138 +++++++++++++++++++- 1 file changed, 136 insertions(+), 2 deletions(-) diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx index 736adc3eed826ce..d064f58969d09ae 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/database.mdx @@ -13,7 +13,7 @@ You can execute queries on your D1 database through SQL statements. ## Methods -### db.prepare() +### `db.prepare()` D1 API supports both prepared and static statements. The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. @@ -41,11 +41,145 @@ const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); - queryResult: - The result of the SQL query. -### db.batch() +#### Guidance +- You can pass multiple queries into a single `.prepare()` statement. Simply delineate each query with a semi-colon. + - The statement only returns the results of the last query, even though all queries are executed. + - You can only pass parameters to the last query. + ```js + const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") + ``` +### `db.batch()` + +Batching sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. + +Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. + +To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. + +```js +await db.batch([ + db.prepare("UPDATE users SET name = ?1 WHERE id = ?2").bind("John", 17), + db.prepare("UPDATE users SET age = ?1 WHERE id = ?2").bind(35, 19), +]); +``` #### Parameters +- statementArray: + - An array of `db.prepare()` statements. + #### Return values +- resultArray: + - An array of results of the `.db.prepare()` statements. Each result is contained in the array position corresponding to the array position of the `db.prepare()` statement within the `statementArray`. + +
+ +```js +const rows = await db.batch([ + db.prepare("SELECT * FROM users WHERE name = ?1").bind("John"), + db.prepare("SELECT * FROM users WHERE name = ?1").bind("Anthony") + ]); +``` +```js +console.log(rows[0].results); +``` +```js output +[ + { + name: "John Clemente", + age: 42, + }, + { + name: "John Davis", + age: 37, + }, + ] +``` +```js +console.log(rows[1].results); +``` +```js output +[ + { + name: "Anthony Hopkins", + age: 66, + }, + ] +``` +
+ +#### Guidance + +- You can construct batches reusing the same prepared statement: + + ```js + const stmt = db.prepare("SELECT * FROM users WHERE name = ?1"); + + const rows = await db.batch([stmt.bind("John"), stmt.bind("Anthony")]); + ``` + +### `db.exec()` + +Executes one or more queries directly without prepared statements or parameters binding. This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. Only use this method for maintenance and one-shot tasks (for example, migration jobs). The input can be one or multiple queries separated by `\n`. + +```js +const migration = await fetch("/migration.sql"); +const out = await db.exec(migration.text()); +``` + +#### Parameters + +- + +#### Return values + +- queryResult: + - Result of the query. + +
+```js +const migration = await fetch("/migration.sql"); +const out = await db.exec(migration.text()); +console.log(out); +``` +```js output +{ + count: 80, + duration: 76 +} +``` +
+ +#### Guidance + +- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. + +### `db.dump` + +:::caution +This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. +::: + +Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. + +```js +const dump = await db.dump(); +return new Response(dump, { + status: 200, + headers: { + "Content-Type": "application/octet-stream", + }, +}); +``` + +#### Parameters + +- + +#### Return values + +- + From 1684e9c99d77f560c0de1255c80a31f49da4d91a Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 6 Nov 2024 17:41:59 +0000 Subject: [PATCH 07/33] Fleshing out API chapters. --- src/content/docs/d1/worker-api/database.mdx | 37 +++++- src/content/docs/d1/worker-api/query.mdx | 129 +++++--------------- 2 files changed, 65 insertions(+), 101 deletions(-) diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx index d064f58969d09ae..ae2a26a996f4325 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/database.mdx @@ -21,14 +21,16 @@ Example of a prepared statement: ```js const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind(someVariable); -// someVariable will replace the placeholder '?1' in the query. +// A variable (someVariable) will replace the placeholder '?1' in the query. +// This is a prepared statement. ``` Example of a static statement: ```js const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); -// "John Doe" is hard-coded into the query. This is a static statement. +// "John Doe" is hard-coded into the query. +// This is a static statement. ``` #### Parameters @@ -49,6 +51,32 @@ const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); ```js const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") ``` +- D1 follows the [SQLite convention](https://www.sqlite.org/lang_expr.html#varparam) for prepared statements parameter binding. Currently, D1 only supports Ordered (`?NNNN`) and Anonymous (`?`) parameters. In the future, D1 will support named parameters as well. + + | Syntax | Type | Description | + | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | + | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than SQLITE_MAX_VARIABLE_NUMBER, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead | + + To bind a parameter, use the `stmt.bind()` method. + + Order and anonymous examples: + + ```js + const stmt = db.prepare("SELECT * FROM users WHERE name = ?").bind("John Doe"); + ``` + + ```js + const stmt = db + .prepare("SELECT * FROM users WHERE name = ? AND age = ?") + .bind("John Doe", 41); + ``` + + ```js + const stmt = db + .prepare("SELECT * FROM users WHERE name = ?2 AND age = ?1") + .bind(41, "John Doe"); + ``` ### `db.batch()` @@ -123,7 +151,7 @@ console.log(rows[1].results); ### `db.exec()` -Executes one or more queries directly without prepared statements or parameters binding. This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. Only use this method for maintenance and one-shot tasks (for example, migration jobs). The input can be one or multiple queries separated by `\n`. +Executes one or more queries directly without prepared statements or parameters binding. ```js const migration = await fetch("/migration.sql"); @@ -156,6 +184,9 @@ console.log(out); #### Guidance - If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. +- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. +- Only use this method for maintenance and one-shot tasks (for example, migration jobs). +- The input can be one or multiple queries separated by `\n`. ### `db.dump` diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx index 8c739ba63da56c2..9e854c642335304 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -1,5 +1,5 @@ --- -title: D1 Query +title: D1 query pcx_content_type: concept sidebar: order: 2 @@ -13,32 +13,30 @@ You can modify the query results which has been obtained after executing a `.db( ## Methods -### await stmt.all() +### `await stmt.run()` -Returns all rows as an array of objects, with each result row represented as an object on the `results` property of the `D1Result` type. +Runs the query (or queries) and returns results. ```js -const { results } = await stmt.all(); +const { results } = await stmt.run(); ``` -#### Parameters +#### Parameter - None. -#### Return values +#### Return value -- Array: - - An array of objects. - - Each row represents a row. - - Each object is created on the `results` property of the `D1Result` type. +- results: + - An array of objects, where each object represents a row of the query result. + - Each object is created on the `results` property of the `D1Result` type. {/*What does it return when `results` is actually empty?*/}
```js -const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); -const { results } = await stmt.all(); +const stmt = await db.prepare("SELECT name, age FROM users LIMIT 3"); +const { results } = await stmt.run(); console.log(results); ``` - ```js output [ { @@ -59,10 +57,12 @@ console.log(results); #### Guidance -- When joining tables with identical column names, only the leftmost column will be included in the row object. Use [`stmt.raw()`](#await-stmtraw) to return all rows as an array of arrays. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `all()` to return a typed result object. +- `results` is empty for write operations such as UPDATE, DELETE, or INSERT. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. +- `stmt.run()` is functionally equivalent to `stmt.all()` and can be treated as an alias. +- -### await stmt.raw() +### `await stmt.raw()` Returns results as an array of arrays, with each row represented by an array. The return type is an array of arrays, and does not include query metadata. @@ -112,7 +112,7 @@ console.log(columns); - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `raw()` to return a typed result array. -### await stmt.first() +### `await stmt.first()` Returns the first row of the query result. This does not return metadata like the other methods. Instead, it directly returns the object. @@ -167,30 +167,32 @@ console.log(total); - `stmt.first()` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `first()` to return a typed result object. -### await stmt.run() +{/* ### `stmt.all()` -Runs the query (or queries) and returns results. +Returns all rows as an array of objects, with each result row represented as an object on the `results` property of the `D1Result` type. ```js -const { results } = await stmt.run(); +const { results } = await stmt.all(); ``` -#### Parameter +#### Parameters - None. -#### Return value +#### Return values -- results: - - An array of objects, where each object represents a row of the query result. - - Each object is created on the `results` property of the `D1Result` type. {/*What does it return when `results` is actually empty?*/} +- Array: + - An array of objects. + - Each row represents a row. + - Each object is created on the `results` property of the `D1Result` type.
```js -const stmt = await db.prepare("SELECT name, age FROM users LIMIT 3"); -const { results } = await stmt.run(); +const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); +const { results } = await stmt.all(); console.log(results); ``` + ```js output [ { @@ -211,74 +213,5 @@ console.log(results); #### Guidance -- `results` is empty for write operations such as UPDATE, DELETE, or INSERT. -- Run is functionally equivalent to `stmt.all()` and can be treated as an alias. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. - -### await db.dump() - -:::caution -This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. -::: - -Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. - -```js -const dump = await db.dump(); -return new Response(dump, { - status: 200, - headers: { - "Content-Type": "application/octet-stream", - }, -}); -``` - -#### Parameters - -- None. - -#### Return values - -- ??? - -#### Guidance - -- ??? - -### await db.exec() - -Executes one or more queries directly without prepared statements or parameters binding. - -```js -const out = await db.exec(); -``` - -#### Parameters - -- ??? - -#### Return values - -- ??? - -
-```js -const migration = await fetch("/migration.sql"); -const out = await db.exec(migration.text()); -console.log(out); -``` -```js output -{ - count: 80, - duration: 76 -} -``` -
- -#### Guidance - -- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. -- Only use this method for maintenance and one-shot tasks (for example, migration jobs). -- The input can be one or multiple queries separated by `\n`. -- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. - +- When joining tables with identical column names, only the leftmost column will be included in the row object. Use [`stmt.raw()`](#await-stmtraw) to return all rows as an array of arrays. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `all()` to return a typed result object. */} From f5d8282a7698bde11876ecbd2065c24035188af6 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 7 Nov 2024 16:02:11 +0000 Subject: [PATCH 08/33] Updating D1 API docs. --- public/_redirects | 1 + .../docs/d1/build-with-d1/d1-client-api.mdx | 2 +- src/content/docs/d1/sql-api/index.mdx | 12 ++++++ .../{reference => sql-api}/sql-statements.mdx | 29 +++++++------ src/content/docs/d1/worker-api/database.mdx | 7 ++-- src/content/docs/d1/worker-api/query.mdx | 8 ++-- .../docs/d1/worker-api/return-object.mdx | 42 +++++++++++++++++++ .../partials/d1/use-pragma-statements.mdx | 10 ++--- 8 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 src/content/docs/d1/sql-api/index.mdx rename src/content/docs/d1/{reference => sql-api}/sql-statements.mdx (81%) create mode 100644 src/content/docs/d1/worker-api/return-object.mdx diff --git a/public/_redirects b/public/_redirects index 28f1e0c146e77e6..7775b851a90c68e 100644 --- a/public/_redirects +++ b/public/_redirects @@ -294,6 +294,7 @@ /d1/configuration/remote-development/ /d1/build-with-d1/remote-development/ 301 /d1/build-with-d1/import-data/ /d1/build-with-d1/import-export-data/ 301 /d1/reference/database-commands/ /d1/reference/sql-statements/ 301 +/d1/reference/sql-statements/ /d1/sql-api/sql-statements/ 301 # data loss prevention (dlp) /cloudflare-one/policies/data-loss-prevention/integration-profiles/ /cloudflare-one/policies/data-loss-prevention/dlp-profiles/integration-profiles/ 301 diff --git a/src/content/docs/d1/build-with-d1/d1-client-api.mdx b/src/content/docs/d1/build-with-d1/d1-client-api.mdx index 638e7af25c28fe3..81b33f307ec5c07 100644 --- a/src/content/docs/d1/build-with-d1/d1-client-api.mdx +++ b/src/content/docs/d1/build-with-d1/d1-client-api.mdx @@ -449,7 +449,7 @@ D1 PRAGMA statements only apply to the current transaction. ::: -For the full list of PRAGMA statements supported by D1, see [SQL statements](/d1/reference/sql-statements). +For the full list of PRAGMA statements supported by D1, see [SQL statements](/d1/sql-api/sql-statements). ## Errors diff --git a/src/content/docs/d1/sql-api/index.mdx b/src/content/docs/d1/sql-api/index.mdx new file mode 100644 index 000000000000000..8b74fb521d38d05 --- /dev/null +++ b/src/content/docs/d1/sql-api/index.mdx @@ -0,0 +1,12 @@ +--- +title: SQL API +pcx_content_type: navigation +sidebar: + order: 5 + group: + hideIndex: true +--- + +import { DirectoryListing } from "~/components"; + + diff --git a/src/content/docs/d1/reference/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx similarity index 81% rename from src/content/docs/d1/reference/sql-statements.mdx rename to src/content/docs/d1/sql-api/sql-statements.mdx index c7dc8e8c331b64d..a665b763b731e29 100644 --- a/src/content/docs/d1/reference/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -2,22 +2,33 @@ title: SQL statements pcx_content_type: concept sidebar: - order: 6 + order: 1 --- import { Details, Render } from "~/components"; -D1 supports a number of database-level commands that allow you to list tables, indexes, and inspect the schema for a given table or index. +D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. -## Database statements +You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 client API](/d1/worker-api/database). -D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. +## SQLite Extensions + +D1 supports a subset of SQLite extensions for added functionality, including: + +- Default SQLite extensions. +- [FTS5 module](https://www.sqlite.org/fts5.html) for full-text search. + +## PRAGMA statements -You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 client API](/d1/build-with-d1/d1-client-api/). +D1 supports [SQLite PRAGMA](https://www.sqlite.org/pragma.html) statements. The PRAGMA statement is an SQL extension for SQLite. PRAGMA commands can be used to: + +- Modify the behavior of certain SQLite operations. +- Query the SQLite library for internal data about schemas or tables (but note that PRAGMA statements cannot query the contents of a table). +- Control environmental variables. -### Query `sqlite_master` +## Query `sqlite_master` You can also query the `sqlite_master` table to show all tables, indexes, and the original SQL used to generate them: @@ -44,12 +55,6 @@ SELECT name, sql FROM sqlite_master } ``` -## SQLite Extensions - -D1 supports a subset of SQLite extensions for added functionality, including: - -- [FTS5 module](https://www.sqlite.org/fts5.html) for full-text search - ## Related resources - Learn [how to create indexes](/d1/build-with-d1/use-indexes/#list-indexes) in D1. diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx index ae2a26a996f4325..88e0175646428de 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/database.mdx @@ -95,13 +95,14 @@ await db.batch([ #### Parameters -- statementArray: +- statements: - An array of `db.prepare()` statements. #### Return values -- resultArray: - - An array of results of the `.db.prepare()` statements. Each result is contained in the array position corresponding to the array position of the `db.prepare()` statement within the `statementArray`. +- results: + - An array of objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. + - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object).
diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx index 9e854c642335304..30308ddcbae5d0a 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -13,7 +13,7 @@ You can modify the query results which has been obtained after executing a `.db( ## Methods -### `await stmt.run()` +### `stmt.run()` Runs the query (or queries) and returns results. @@ -29,7 +29,7 @@ const { results } = await stmt.run(); - results: - An array of objects, where each object represents a row of the query result. - - Each object is created on the `results` property of the `D1Result` type. {/*What does it return when `results` is actually empty?*/} + - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object).
```js @@ -62,7 +62,7 @@ console.log(results); - `stmt.run()` is functionally equivalent to `stmt.all()` and can be treated as an alias. - -### `await stmt.raw()` +### `stmt.raw()` Returns results as an array of arrays, with each row represented by an array. The return type is an array of arrays, and does not include query metadata. @@ -112,7 +112,7 @@ console.log(columns); - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `raw()` to return a typed result array. -### `await stmt.first()` +### `stmt.first()` Returns the first row of the query result. This does not return metadata like the other methods. Instead, it directly returns the object. diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx new file mode 100644 index 000000000000000..8c903ab0b0a9547 --- /dev/null +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -0,0 +1,42 @@ +--- +title: Return object +pcx_content_type: concept +sidebar: + order: 3 +--- + +The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object that contains the results (if applicable), the success status, and a meta object with the internal duration of the operation in milliseconds. + +```js +{ + results: array | null, // [] if empty, or null if it does not apply + success: boolean, // true if the operation was successful, false otherwise + meta: { + duration: number, // duration of the operation in milliseconds + rows_read: number, // the number of rows read (scanned) by this query + rows_written: number // the number of rows written by this query + } +} +``` + +## Example: + +```js +const { duration } = ( + await db + .prepare("INSERT INTO users (name, age) VALUES (?1, ?2)") + .bind("John", 42) + .run() +).meta; + +console.log(duration); // 0.172 +``` + +The `db.exec()` method returns a `D1ExecResult` object: + +```js +{ + count: number, // the number of queries executed + duration: number // duration of the operation in milliseconds +} +``` \ No newline at end of file diff --git a/src/content/partials/d1/use-pragma-statements.mdx b/src/content/partials/d1/use-pragma-statements.mdx index dff9cb8c6b8f224..1a522c79ab01129 100644 --- a/src/content/partials/d1/use-pragma-statements.mdx +++ b/src/content/partials/d1/use-pragma-statements.mdx @@ -48,7 +48,7 @@ D1 PRAGMA statements only apply to the current transaction. Lists the tables and views in the database. This includes the system tables maintained by D1. -**Returns:** +#### Return values One row per each table. Each row contains: @@ -114,7 +114,7 @@ One row per each table. Each row contains: Shows the schema (columns, types, null, default values) for the given `TABLE_NAME`. -**Returns:** +#### Return values One row for each column in the specified table. Each row contains: @@ -222,7 +222,7 @@ Similar to `PRAGMA table_info(TABLE_NAME)` but also includes [generated columns] Show the indexes for the given `TABLE_NAME`. -**Returns:** +#### Return values One row for each index associated with the specified table. Each row contains: @@ -255,7 +255,7 @@ One row for each index associated with the specified table. Each row contains: Show the indexed column(s) for the given `INDEX_NAME`. -**Returns:** +#### Return values One row for each key column in the specified index. Each row contains: @@ -315,7 +315,7 @@ Checks the formatting and consistency of the table, including: - Missing pages - Sections of the database which are used multiple times, or are not used at all. -Returns: +#### Return values - **If there are no errors:** a single row with the value `OK` - **If there are errors:** a string which describes the issues flagged by the check From 5aa097aa7ae584643bbd75e2a525c5894420c648 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 7 Nov 2024 16:27:52 +0000 Subject: [PATCH 09/33] Adding in more information to be complete. --- .../docs/d1/sql-api/sql-statements.mdx | 20 +++++++++++-- src/content/docs/d1/worker-api/database.mdx | 29 ++++++++++++++++++- .../docs/d1/worker-api/return-object.mdx | 6 +++- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index a665b763b731e29..8ef8978c06c5471 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -18,9 +18,9 @@ D1 supports a subset of SQLite extensions for added functionality, including: - Default SQLite extensions. - [FTS5 module](https://www.sqlite.org/fts5.html) for full-text search. -## PRAGMA statements +## Compatible PRAGMA statements -D1 supports [SQLite PRAGMA](https://www.sqlite.org/pragma.html) statements. The PRAGMA statement is an SQL extension for SQLite. PRAGMA commands can be used to: +D1 supports some [SQLite PRAGMA](https://www.sqlite.org/pragma.html) statements. The PRAGMA statement is an SQL extension for SQLite. PRAGMA commands can be used to: - Modify the behavior of certain SQLite operations. - Query the SQLite library for internal data about schemas or tables (but note that PRAGMA statements cannot query the contents of a table). @@ -55,6 +55,22 @@ SELECT name, sql FROM sqlite_master } ``` +## Search with LIKE + +You can perform a search using SQL's `LIKE` operator: + +```js +const { results } = await env.DB.prepare( + "SELECT * FROM Customers WHERE CompanyName LIKE ?", +) + .bind("%eve%") + .all(); +console.log("results: ", results); +``` +```js output +results: [...] +``` + ## Related resources - Learn [how to create indexes](/d1/build-with-d1/use-indexes/#list-indexes) in D1. diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx index 88e0175646428de..e1924350d049d16 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/database.mdx @@ -11,11 +11,38 @@ import { Type, MetaInfo, Details } from "~/components"; You can execute queries on your D1 database through SQL statements. +### TypeScript support + +D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. + +When using the [query statement methods](#query-statement-methods) `stmt.all()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. + +For example, providing an `OrderRow` type as a type parameter to `stmt.all()` will return a typed `Array` object instead of the default `Record` type: + +```ts +// Row definition +type OrderRow = { + Id: string; + CustomerName: string; + OrderDate: number; +}; + +// Elsewhere in your application +const result = await env.MY_DB.prepare( + "SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", +).all(); +``` + ## Methods ### `db.prepare()` -D1 API supports both prepared and static statements. The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. +D1 API supports both prepared and static statements. + +- Prepared statements are SQL statements where the variables are dynamically determined. When writing a prepared statement, you insert variables into placeholders within the statement string. +- Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. + +The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. Example of a prepared statement: diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index 8c903ab0b0a9547..9c85e58ccdf4a46 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -5,7 +5,11 @@ sidebar: order: 3 --- -The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object that contains the results (if applicable), the success status, and a meta object with the internal duration of the operation in milliseconds. +The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: + +- The results (if applicable) as an array +- The success status +- A meta object with the internal duration of the operation in milliseconds ```js { From 6ab8172102eb795032d3bfad26d6eb7b91196d3a Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 7 Nov 2024 17:22:33 +0000 Subject: [PATCH 10/33] Apply suggestions from code review Co-authored-by: Lambros Petrou --- src/content/docs/d1/worker-api/database.mdx | 14 ++++++++------ src/content/docs/d1/worker-api/query.mdx | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/database.mdx index e1924350d049d16..65318388d35ba94 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/database.mdx @@ -44,12 +44,14 @@ D1 API supports both prepared and static statements. The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. -Example of a prepared statement: +Example of a prepared statement with dynamically bound value: ```js +// Dynamically generate the value to use. +const someVariable = "John Doe"; const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind(someVariable); // A variable (someVariable) will replace the placeholder '?1' in the query. -// This is a prepared statement. +// `stmt` is a prepared statement. ``` Example of a static statement: @@ -57,7 +59,7 @@ Example of a static statement: ```js const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); // "John Doe" is hard-coded into the query. -// This is a static statement. +// `stmt` will also be a prepared statement. ``` #### Parameters @@ -74,7 +76,7 @@ const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); - You can pass multiple queries into a single `.prepare()` statement. Simply delineate each query with a semi-colon. - The statement only returns the results of the last query, even though all queries are executed. - - You can only pass parameters to the last query. + - You can only bind parameters to the last query. ```js const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") ``` @@ -137,7 +139,7 @@ await db.batch([ const rows = await db.batch([ db.prepare("SELECT * FROM users WHERE name = ?1").bind("John"), db.prepare("SELECT * FROM users WHERE name = ?1").bind("Anthony") - ]); +]); ``` ```js console.log(rows[0].results); @@ -163,7 +165,7 @@ console.log(rows[1].results); name: "Anthony Hopkins", age: 66, }, - ] +] ```
diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx index 30308ddcbae5d0a..922036c855f701f 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -15,7 +15,7 @@ You can modify the query results which has been obtained after executing a `.db( ### `stmt.run()` -Runs the query (or queries) and returns results. +Runs the prepared query (or queries) and returns results. ```js const { results } = await stmt.run(); From 3d5cb9988d1607f31a99330f053e1da7bb23c206 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 7 Nov 2024 17:26:50 +0000 Subject: [PATCH 11/33] Update src/content/docs/d1/worker-api/query.mdx --- src/content/docs/d1/worker-api/query.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/query.mdx index 922036c855f701f..90663aee5a4ff37 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/query.mdx @@ -1,5 +1,5 @@ --- -title: D1 query +title: D1 prepared statement pcx_content_type: concept sidebar: order: 2 From c89fc37dd2183f37c9563f051a74b9bc9aaa7942 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 8 Nov 2024 18:01:54 +0000 Subject: [PATCH 12/33] Updating the Return Object chapter. Testing more APIs. --- .../{database.mdx => prepare-a-statement.mdx} | 14 +- .../docs/d1/worker-api/return-object.mdx | 51 ++++--- .../{query.mdx => run-a-statement.mdx} | 127 ++++++++++++------ 3 files changed, 132 insertions(+), 60 deletions(-) rename src/content/docs/d1/worker-api/{database.mdx => prepare-a-statement.mdx} (96%) rename src/content/docs/d1/worker-api/{query.mdx => run-a-statement.mdx} (59%) diff --git a/src/content/docs/d1/worker-api/database.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx similarity index 96% rename from src/content/docs/d1/worker-api/database.mdx rename to src/content/docs/d1/worker-api/prepare-a-statement.mdx index 65318388d35ba94..8d3b78f9c6b27e5 100644 --- a/src/content/docs/d1/worker-api/database.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -1,5 +1,5 @@ --- -title: D1 database +title: Prepare a statement pcx_content_type: concept sidebar: order: 1 @@ -7,11 +7,13 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -## Description +You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: -You can execute queries on your D1 database through SQL statements. +1. Prepare your query statement. +2. If appliable, bind variables into your statement. +3. Execute your query. -### TypeScript support +## TypeScript support D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. @@ -37,12 +39,14 @@ const result = await env.MY_DB.prepare( ### `db.prepare()` -D1 API supports both prepared and static statements. +Prepares a query statement statement. D1 API supports both prepared and static statements. - Prepared statements are SQL statements where the variables are dynamically determined. When writing a prepared statement, you insert variables into placeholders within the statement string. - Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. +:::note The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. +::: Example of a prepared statement with dynamically bound value: diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index 9c85e58ccdf4a46..520127178108c69 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -7,40 +7,59 @@ sidebar: The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: -- The results (if applicable) as an array - The success status - A meta object with the internal duration of the operation in milliseconds +- The results (if applicable) as an array ```js { - results: array | null, // [] if empty, or null if it does not apply success: boolean, // true if the operation was successful, false otherwise meta: { - duration: number, // duration of the operation in milliseconds + served_by: string // the version of Cloudflare's backend Worker that returned the result + duration: number, // the duration of the SQL query execution only, in milliseconds + changes: number, // the number of changes made to the database + last_row_id: number, // the last inserted row ID, only applies when the table is defined without the `WITHOUT ROWID` option + changed_db: boolean, // true if something on the database was changed + size_after: number, // the size of the database after the query is successfully applied rows_read: number, // the number of rows read (scanned) by this query rows_written: number // the number of rows written by this query } + results: array | null, // [] if empty, or null if it does not apply } ``` ## Example: ```js -const { duration } = ( - await db - .prepare("INSERT INTO users (name, age) VALUES (?1, ?2)") - .bind("John", 42) - .run() -).meta; - -console.log(duration); // 0.172 +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.run(); +return Response.json(result) ``` - -The `db.exec()` method returns a `D1ExecResult` object: - ```js { - count: number, // the number of queries executed - duration: number // duration of the operation in milliseconds + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 1, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } + ] } ``` \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/query.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx similarity index 59% rename from src/content/docs/d1/worker-api/query.mdx rename to src/content/docs/d1/worker-api/run-a-statement.mdx index 90663aee5a4ff37..b9156ab702da7b0 100644 --- a/src/content/docs/d1/worker-api/query.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -1,5 +1,5 @@ --- -title: D1 prepared statement +title: Run a prepared statement pcx_content_type: concept sidebar: order: 2 @@ -9,16 +9,16 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description -You can modify the query results which has been obtained after executing a `.db()` method. +After preparing a query statement, you can run and retrieve the results of the query. ## Methods ### `stmt.run()` -Runs the prepared query (or queries) and returns results. +Runs the prepared query (or queries) and returns results. The returned results includes metadata. ```js -const { results } = await stmt.run(); +const returnValue = await stmt.run(); ``` #### Parameter @@ -27,31 +27,45 @@ const { results } = await stmt.run(); #### Return value -- results: - - An array of objects, where each object represents a row of the query result. +- returnValue: + - An object containing the success status, a meta object, and an array of objects containing the query results. - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object).
```js -const stmt = await db.prepare("SELECT name, age FROM users LIMIT 3"); -const { results } = await stmt.run(); -console.log(results); +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.run(); +``` +```js +return Response.json(returnValue); ``` ```js output -[ - { - name: "John", - age: 42, - }, - { - name: "Anthony", - age: 37, +{ + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 1, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 }, + "results": [ { - name: "Dave", - age: 29, - }, - ] + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } + ] +} ```
@@ -59,17 +73,37 @@ console.log(results); - `results` is empty for write operations such as UPDATE, DELETE, or INSERT. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. -- `stmt.run()` is functionally equivalent to `stmt.all()` and can be treated as an alias. -- +- `stmt.run()` is functionally equivalent to `stmt.all()`, and can be treated as an alias. +- You can choose to extract only the results you expect from the statement by simply returning the `results` property of the return object. + +
+```js +return Response.json(returnValue.results); +``` +```js output +[ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } +] +``` +
### `stmt.raw()` -Returns results as an array of arrays, with each row represented by an array. The return type is an array of arrays, and does not include query metadata. +Runs the prepared query (or queries), and returns the results as an array of arrays. The returned results do not include metadata. Column names are not included in the result set by default. To include column names as the first row of the result array, set `.raw({columnNames: true})`. ```js -const rows = await stmt.raw(); +const returnValue = await stmt.raw(); ``` #### Parameters @@ -80,31 +114,47 @@ const rows = await stmt.raw(); #### Return values - Array: - - An array of arrays. - - Each array represents a row. + - An array of arrays. Each sub-array represents a row.
```js -const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); -const rows = await stmt.raw(); -console.log(rows); +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.raw(); // columnName not specified +return Response.json(returnValue); ``` ```js output [ - [ "John", 42 ], - [ "Anthony", 37 ], - [ "Dave", 29 ], + [11, "Bs Beverages", + "Victoria Ashworth" + ], + [13, "Bs Beverages", + "Random Name" + ] ] ``` With parameter `columnNames: true`: ```js -const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); -const [columns, ...rows] = await stmt.raw({ columnNames: true }); -console.log(columns); +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.raw({columnNames:true}); +return Response.json(returnValue) ``` ```js output -[ "name", age ], // The first result array includes the column names +[ + [ + "CustomerId", + "CompanyName", + "ContactName" + ], + [11, "Bs Beverages", + "Victoria Ashworth" + ], + [13, "Bs Beverages", + "Random Name" + ] +] ```
@@ -114,11 +164,10 @@ console.log(columns); ### `stmt.first()` -Returns the first row of the query result. This does not return metadata like the other methods. Instead, it directly returns the object. +Runs the prepared query (or queries), and returns the first row of the query result as an object. This does not return any metadata. Instead, it directly returns the object. ```js const values = await stmt.first(); -const total = await stmt.first("columnName"); ``` #### Parameters From 4880d8fa3c3861fcedfdeccdc46d9efa4f403195 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 11 Nov 2024 14:17:38 +0000 Subject: [PATCH 13/33] Fleshing out the API docs in more detail. --- .../d1/worker-api/prepare-a-statement.mdx | 137 ++++++++++++------ .../docs/d1/worker-api/run-a-statement.mdx | 31 ++-- 2 files changed, 113 insertions(+), 55 deletions(-) diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index 8d3b78f9c6b27e5..3e3a7c48566b0da 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -9,17 +9,18 @@ import { Type, MetaInfo, Details } from "~/components"; You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: -1. Prepare your query statement. -2. If appliable, bind variables into your statement. -3. Execute your query. +1. Prepare your query statement (including binding variables into the statement). +2. Execute your query. + +This chapter documents how to prepare a statement and how to execute them. ## TypeScript support D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. -When using the [query statement methods](#query-statement-methods) `stmt.all()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. -For example, providing an `OrderRow` type as a type parameter to `stmt.all()` will return a typed `Array` object instead of the default `Record` type: +For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: ```ts // Row definition @@ -32,14 +33,16 @@ type OrderRow = { // Elsewhere in your application const result = await env.MY_DB.prepare( "SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", -).all(); +).run(); ``` ## Methods ### `db.prepare()` -Prepares a query statement statement. D1 API supports both prepared and static statements. +Prepares a query statement to be later executed. + +D1 API supports both prepared and static statements. - Prepared statements are SQL statements where the variables are dynamically determined. When writing a prepared statement, you insert variables into placeholders within the statement string. - Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. @@ -51,19 +54,18 @@ The recommended approach is to use prepared statements (which are precompiled ob Example of a prepared statement with dynamically bound value: ```js -// Dynamically generate the value to use. -const someVariable = "John Doe"; -const stmt = db.prepare("SELECT * FROM users WHERE name = ?1").bind(someVariable); -// A variable (someVariable) will replace the placeholder '?1' in the query. +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +// A variable (someVariable) will replace the placeholder '?' in the query. // `stmt` is a prepared statement. ``` Example of a static statement: ```js -const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); -// "John Doe" is hard-coded into the query. -// `stmt` will also be a prepared statement. +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beverages"); +// "Bs Beverages" is hard-coded into the query. +// `stmt` is a static statement. ``` #### Parameters @@ -73,8 +75,7 @@ const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); #### Return values -- queryResult: - - The result of the SQL query. +- None. #### Guidance @@ -96,33 +97,36 @@ const stmt = db.prepare('SELECT * FROM users WHERE name = "John Doe"'); Order and anonymous examples: ```js - const stmt = db.prepare("SELECT * FROM users WHERE name = ?").bind("John Doe"); + const stmt = db.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(""); ``` ```js const stmt = db - .prepare("SELECT * FROM users WHERE name = ? AND age = ?") - .bind("John Doe", 41); + .prepare("SELECT * FROM Customers WHERE CompanyName = ? AND CustomerId = ?") + .bind("Alfreds Futterkiste", 1); ``` ```js const stmt = db - .prepare("SELECT * FROM users WHERE name = ?2 AND age = ?1") - .bind(41, "John Doe"); + .prepare("SELECT * FROM Customers WHERE CompanyName = ?2 AND CustomerId = ?1") + .bind(1, "Alfreds Futterkiste"); ``` ### `db.batch()` -Batching sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. +Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. ```js -await db.batch([ - db.prepare("UPDATE users SET name = ?1 WHERE id = ?2").bind("John", 17), - db.prepare("UPDATE users SET age = ?1 WHERE id = ?2").bind(35, 19), +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); +const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) ]); ``` @@ -140,35 +144,73 @@ await db.batch([
```js -const rows = await db.batch([ - db.prepare("SELECT * FROM users WHERE name = ?1").bind("John"), - db.prepare("SELECT * FROM users WHERE name = ?1").bind("Anthony") +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = await env.DB.batch([ + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName1), + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName2) ]); -``` -```js -console.log(rows[0].results); +return Response.json(stmt) ``` ```js output [ { - name: "John Clemente", - age: 42, - }, - { - name: "John Davis", - age: 37, + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } + ] }, - ] + { + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } + ] + } +] ``` ```js -console.log(rows[1].results); +console.log(stmt[1].results); ``` ```js output [ { - name: "Anthony Hopkins", - age: 66, - }, + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } ] ```
@@ -178,9 +220,14 @@ console.log(rows[1].results); - You can construct batches reusing the same prepared statement: ```js - const stmt = db.prepare("SELECT * FROM users WHERE name = ?1"); - - const rows = await db.batch([stmt.bind("John"), stmt.bind("Anthony")]); + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + return Response.json(batchResult); ``` ### `db.exec()` diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index b9156ab702da7b0..b17ae43d706def2 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -9,7 +9,12 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description -After preparing a query statement, you can run and retrieve the results of the query. +You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: + +1. Prepare your query statement (including binding variables into the statement). +2. Execute your query. + +This chapter documents the various ways you can run and retrieve the results of a query after you have prepared your statement. ## Methods @@ -173,7 +178,7 @@ const values = await stmt.first(); #### Parameters - columnName: - - Specify a `columnName` to return the value from a specific column in the first row of the query result. + - Specify a `columnName` to return a value from a specific column in the first row of the query result. - None. - Do not pass a parameter to obtain all columns from the first row. @@ -190,23 +195,29 @@ const values = await stmt.first(); Get all the columns from the first row: ```js -const stmt = db.prepare("SELECT COUNT(*) AS total FROM users"); -const values = await stmt.first(); -console.log(values); +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.first(); +return Response.json(returnValue) ``` ```js output -{ total: 50 } +{ + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" +} ``` Get a specific column from the first row: ```js -const stmt = db.prepare("SELECT COUNT(*) AS total FROM users"); -const total = await stmt.first("total"); -console.log(total); +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.first(CustomerId); +return Response.json(returnValue) ``` ```js output -50 // NEED CONFIRMING +11 ```
From 66182a01111ce5ae533be108e11ff7eb43849a79 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 11 Nov 2024 15:07:11 +0000 Subject: [PATCH 14/33] Fixing broken link. --- src/content/docs/d1/sql-api/sql-statements.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index 8ef8978c06c5471..f42e5e504e0d1cd 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -9,7 +9,7 @@ import { Details, Render } from "~/components"; D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. -You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 client API](/d1/worker-api/database). +You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 client API](/d1/worker-api/prepare-a-statement). ## SQLite Extensions From a0fb41f64429855b29d633d76f0e63bde88e3dca Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 11 Nov 2024 15:08:56 +0000 Subject: [PATCH 15/33] Changing reference to mention Worker Binding APIs. --- src/content/docs/d1/sql-api/sql-statements.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index f42e5e504e0d1cd..5433b935e76cfcd 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -9,7 +9,7 @@ import { Details, Render } from "~/components"; D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. -You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 client API](/d1/worker-api/prepare-a-statement). +You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/prepare-a-statement). ## SQLite Extensions From e1c2357cfd3f04ade5e63b8e163f1f0ba8862bbd Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 12 Nov 2024 14:51:53 +0000 Subject: [PATCH 16/33] Small rename. --- src/content/docs/d1/worker-api/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 57a08eb4f5b58ba..e8326b84631c336 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: navigation -title: Worker Bindings API +title: Worker Binding API sidebar: order: 4 group: From 93f66744e36f4dab8df859a853e1bfdc1e9dc9dc Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 12 Nov 2024 14:51:53 +0000 Subject: [PATCH 17/33] Small rename. --- .../docs/d1/worker-api/api-playground.mdx | 95 ++++++++ src/content/docs/d1/worker-api/index.mdx | 2 +- .../d1/worker-api/prepare-a-statement.mdx | 220 ++---------------- .../docs/d1/worker-api/return-object.mdx | 2 +- .../docs/d1/worker-api/run-a-statement.mdx | 187 ++++++++++++++- 5 files changed, 299 insertions(+), 207 deletions(-) create mode 100644 src/content/docs/d1/worker-api/api-playground.mdx diff --git a/src/content/docs/d1/worker-api/api-playground.mdx b/src/content/docs/d1/worker-api/api-playground.mdx new file mode 100644 index 000000000000000..16d5d52f3fa2ae3 --- /dev/null +++ b/src/content/docs/d1/worker-api/api-playground.mdx @@ -0,0 +1,95 @@ +--- +title: Worker Binding API playground +pcx_content_type: concept +sidebar: + label: API playground + order: 10 +--- + +import { DirectoryListing, Details, Steps } from "~/components"; + +The Worker Binding API playground is an `index.js` file where you can test each of the documented Worker Binding APIs for D1. The file builds from the end-state of the [Get started](/d1/get-started/#write-queries-within-your-worker) code. + +Follow the steps to setup your API playground. + +## 1. Complete the Get started tutorial + +Complete the [Get started](/d1/get-started/#write-queries-within-your-worker) tutorial. Ensure you use JavaScript instead of TypeScript. + +## 2. Modify the content of `index.js` + +Replace the contents of your `index.js` file with the below to view the effect of each API. + +
+```js +export default { + async fetch(request, env) { + const { pathname } = new URL(request.url); + + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + + if (pathname === `/RUN`){ + const returnValue = await stmt.bind(companyName1).run() + return Response.json(returnValue); + + } else if (pathname === `/RAW`){ + const returnValue = await stmt.bind(companyName1).raw(); + return Response.json(returnValue); + + } else if (pathname === `/FIRST`){ + const returnValue = await stmt.bind(companyName1).first(); + return Response.json(returnValue); + + } else if (pathname === `/BATCH`) { + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + // const returnValue = await stmt.run(); + return Response.json(batchResult); + } + + return new Response( + `Welcome to the D1 API Playground! + \nChange the URL to test the methods inside your index.js file.`, + ); + }, + }; + +``` +
+ +## 3. Deploy the Worker + + +1. Navigate to your tutorial directory you created by following step 1. +2. Run `npx wrangler dev`. + ```sh + npx wrangler dev + ``` + ```sh output + ⛅️ wrangler 3.85.0 (update available 3.86.1) + ------------------------------------------------------- + + Your worker has access to the following bindings: + - D1 Databases: + - DB: (DATABASE_ID) (local) + ⎔ Starting local server... + [wrangler:inf] Ready on http://localhost:8787 + ╭───────────────────────────╮ + │ [b] open a browser │ + │ [d] open devtools │ + │ [l] turn off local mode │ + │ [c] clear console │ + │ [x] to exit │ + ╰───────────────────────────╯ + ``` +3. Open a browser at the specified address. + + +## 4. Test the APIs + +Change the URL to test the various D1 Worker Binding APIs. + diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 57a08eb4f5b58ba..e8326b84631c336 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: navigation -title: Worker Bindings API +title: Worker Binding API sidebar: order: 4 group: diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index 3e3a7c48566b0da..6e502b4d43f2b7e 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -7,34 +7,12 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: +D1 uses SQLite query semantics. You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: 1. Prepare your query statement (including binding variables into the statement). 2. Execute your query. -This chapter documents how to prepare a statement and how to execute them. - -## TypeScript support - -D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. - -When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. - -For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: - -```ts -// Row definition -type OrderRow = { - Id: string; - CustomerName: string; - OrderDate: number; -}; - -// Elsewhere in your application -const result = await env.MY_DB.prepare( - "SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", -).run(); -``` +This chapter documents how to prepare a statement. ## Methods @@ -112,186 +90,22 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beve .bind(1, "Alfreds Futterkiste"); ``` -### `db.batch()` - -Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. - -Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. - -To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. +- D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. -```js -const companyName1 = `Bs Beverages`; -const companyName2 = `Around the Horn`; -const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); -const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) -]); -``` - -#### Parameters + - When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. -- statements: - - An array of `db.prepare()` statements. - -#### Return values - -- results: - - An array of objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. - - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object). - -
- -```js -const companyName1 = `Bs Beverages`; -const companyName2 = `Around the Horn`; -const stmt = await env.DB.batch([ - env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName1), - env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName2) -]); -return Response.json(stmt) -``` -```js output -[ - { - "success": true, - "meta": { - "served_by": "miniflare.db", - "duration": 0, - "changes": 0, - "last_row_id": 0, - "changed_db": false, - "size_after": 8192, - "rows_read": 4, - "rows_written": 0 - }, - "results": [ - { - "CustomerId": 11, - "CompanyName": "Bs Beverages", - "ContactName": "Victoria Ashworth" - }, - { - "CustomerId": 13, - "CompanyName": "Bs Beverages", - "ContactName": "Random Name" - } - ] - }, - { - "success": true, - "meta": { - "served_by": "miniflare.db", - "duration": 0, - "changes": 0, - "last_row_id": 0, - "changed_db": false, - "size_after": 8192, - "rows_read": 4, - "rows_written": 0 - }, - "results": [ - { - "CustomerId": 4, - "CompanyName": "Around the Horn", - "ContactName": "Thomas Hardy" - } - ] - } -] -``` -```js -console.log(stmt[1].results); -``` -```js output -[ - { - "CustomerId": 4, - "CompanyName": "Around the Horn", - "ContactName": "Thomas Hardy" - } -] -``` -
- -#### Guidance - -- You can construct batches reusing the same prepared statement: - - ```js - const companyName1 = `Bs Beverages`; - const companyName2 = `Around the Horn`; - const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); - const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) - ]); - return Response.json(batchResult); - ``` + - For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: -### `db.exec()` - -Executes one or more queries directly without prepared statements or parameters binding. - -```js -const migration = await fetch("/migration.sql"); -const out = await db.exec(migration.text()); -``` - -#### Parameters - -- - -#### Return values - -- queryResult: - - Result of the query. - -
-```js -const migration = await fetch("/migration.sql"); -const out = await db.exec(migration.text()); -console.log(out); -``` -```js output -{ - count: 80, - duration: 76 -} -``` -
- -#### Guidance - -- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. -- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. -- Only use this method for maintenance and one-shot tasks (for example, migration jobs). -- The input can be one or multiple queries separated by `\n`. - -### `db.dump` - -:::caution -This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. -::: - -Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. - -```js -const dump = await db.dump(); -return new Response(dump, { - status: 200, - headers: { - "Content-Type": "application/octet-stream", - }, -}); -``` - -#### Parameters - -- - -#### Return values - -- + ```ts + // Row definition + type OrderRow = { + Id: string; + CustomerName: string; + OrderDate: number; + }; + // Elsewhere in your application + const result = await env.MY_DB.prepare( + "SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", + ).run(); + ``` \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index 520127178108c69..fd87251decd0610 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -5,7 +5,7 @@ sidebar: order: 3 --- -The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: +The methods `stmt.run()`, `db.exec()`, and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: - The success status - A meta object with the internal duration of the operation in milliseconds diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index b17ae43d706def2..ebefcffd15d1477 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -9,12 +9,12 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description -You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: +D1 uses SQLite query semantics. You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: 1. Prepare your query statement (including binding variables into the statement). 2. Execute your query. -This chapter documents the various ways you can run and retrieve the results of a query after you have prepared your statement. +This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/prepare-a-statement). ## Methods @@ -275,3 +275,186 @@ console.log(results); - When joining tables with identical column names, only the leftmost column will be included in the row object. Use [`stmt.raw()`](#await-stmtraw) to return all rows as an array of arrays. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `all()` to return a typed result object. */} +### `db.batch()` + +Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. + +Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. + +To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. + +```js +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); +const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) +]); +``` + +#### Parameters + +- statements: + - An array of `db.prepare()` statements. + +#### Return values + +- results: + - An array of objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. + - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object). + +
+ +```js +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = await env.DB.batch([ + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName1), + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName2) +]); +return Response.json(stmt) +``` +```js output +[ + { + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } + ] + }, + { + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } + ] + } +] +``` +```js +console.log(stmt[1].results); +``` +```js output +[ + { + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } +] +``` +
+ +#### Guidance + +- You can construct batches reusing the same prepared statement: + + ```js + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + return Response.json(batchResult); + ``` + +### `db.exec()` + +Executes one or more queries directly without prepared statements or parameters binding. + +```js +const migration = await fetch("/migration.sql"); +const out = await db.exec(migration.text()); +``` + +#### Parameters + +- + +#### Return values + +- queryResult: + - Result of the query. + +
+```js +const migration = await fetch("/migration.sql"); +const out = await db.exec(migration.text()); +console.log(out); +``` +```js output +{ + count: 80, + duration: 76 +} +``` +
+ +#### Guidance + +- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. +- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. +- Only use this method for maintenance and one-shot tasks (for example, migration jobs). +- The input can be one or multiple queries separated by `\n`. + +### `db.dump` + +:::caution +This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. +::: + +Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. + +```js +const dump = await db.dump(); +return new Response(dump, { + status: 200, + headers: { + "Content-Type": "application/octet-stream", + }, +}); +``` + +#### Parameters + +- + +#### Return values + +- + From e3741ddcb5fcb1f10d555a9e02c2bd55da017fc9 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 12 Nov 2024 17:08:19 +0000 Subject: [PATCH 18/33] Updating the chapters --- src/content/docs/d1/sql-api/sql-statements.mdx | 2 +- src/content/docs/d1/worker-api/prepare-a-statement.mdx | 2 +- src/content/docs/d1/worker-api/run-a-statement.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index 5433b935e76cfcd..fb1752d4d5bf664 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -7,7 +7,7 @@ sidebar: import { Details, Render } from "~/components"; -D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. +D1 is compatible with most SQLite's SQL convention since it leverages SQLite's query engine. D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/prepare-a-statement). diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index 6e502b4d43f2b7e..422a317a52185da 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -7,7 +7,7 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -D1 uses SQLite query semantics. You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: +You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: 1. Prepare your query statement (including binding variables into the statement). 2. Execute your query. diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index ebefcffd15d1477..206c3df9479d86b 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -9,7 +9,7 @@ import { Type, MetaInfo, Details } from "~/components"; ## Description -D1 uses SQLite query semantics. You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: +You to execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: 1. Prepare your query statement (including binding variables into the statement). 2. Execute your query. From bf9ced48add5e7ce3ef07d5177aa836f24b08921 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 12 Nov 2024 17:38:52 +0000 Subject: [PATCH 19/33] Modifying the structure to align with discussion. --- .../docs/d1/worker-api/api-playground.mdx | 95 ------------- src/content/docs/d1/worker-api/index.mdx | 126 +++++++++++++++++- .../d1/worker-api/prepare-a-statement.mdx | 61 +++------ .../docs/d1/worker-api/run-a-statement.mdx | 7 - 4 files changed, 141 insertions(+), 148 deletions(-) delete mode 100644 src/content/docs/d1/worker-api/api-playground.mdx diff --git a/src/content/docs/d1/worker-api/api-playground.mdx b/src/content/docs/d1/worker-api/api-playground.mdx deleted file mode 100644 index 16d5d52f3fa2ae3..000000000000000 --- a/src/content/docs/d1/worker-api/api-playground.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Worker Binding API playground -pcx_content_type: concept -sidebar: - label: API playground - order: 10 ---- - -import { DirectoryListing, Details, Steps } from "~/components"; - -The Worker Binding API playground is an `index.js` file where you can test each of the documented Worker Binding APIs for D1. The file builds from the end-state of the [Get started](/d1/get-started/#write-queries-within-your-worker) code. - -Follow the steps to setup your API playground. - -## 1. Complete the Get started tutorial - -Complete the [Get started](/d1/get-started/#write-queries-within-your-worker) tutorial. Ensure you use JavaScript instead of TypeScript. - -## 2. Modify the content of `index.js` - -Replace the contents of your `index.js` file with the below to view the effect of each API. - -
-```js -export default { - async fetch(request, env) { - const { pathname } = new URL(request.url); - - const companyName1 = `Bs Beverages`; - const companyName2 = `Around the Horn`; - const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); - - if (pathname === `/RUN`){ - const returnValue = await stmt.bind(companyName1).run() - return Response.json(returnValue); - - } else if (pathname === `/RAW`){ - const returnValue = await stmt.bind(companyName1).raw(); - return Response.json(returnValue); - - } else if (pathname === `/FIRST`){ - const returnValue = await stmt.bind(companyName1).first(); - return Response.json(returnValue); - - } else if (pathname === `/BATCH`) { - const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) - ]); - // const returnValue = await stmt.run(); - return Response.json(batchResult); - } - - return new Response( - `Welcome to the D1 API Playground! - \nChange the URL to test the methods inside your index.js file.`, - ); - }, - }; - -``` -
- -## 3. Deploy the Worker - - -1. Navigate to your tutorial directory you created by following step 1. -2. Run `npx wrangler dev`. - ```sh - npx wrangler dev - ``` - ```sh output - ⛅️ wrangler 3.85.0 (update available 3.86.1) - ------------------------------------------------------- - - Your worker has access to the following bindings: - - D1 Databases: - - DB: (DATABASE_ID) (local) - ⎔ Starting local server... - [wrangler:inf] Ready on http://localhost:8787 - ╭───────────────────────────╮ - │ [b] open a browser │ - │ [d] open devtools │ - │ [l] turn off local mode │ - │ [c] clear console │ - │ [x] to exit │ - ╰───────────────────────────╯ - ``` -3. Open a browser at the specified address. - - -## 4. Test the APIs - -Change the URL to test the various D1 Worker Binding APIs. - diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index e8326b84631c336..b0d93e06679730f 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -1,12 +1,128 @@ --- pcx_content_type: navigation -title: Worker Binding API +title: D1 Worker Binding API sidebar: order: 4 - group: - hideIndex: true --- -import { DirectoryListing } from "~/components"; +import { DirectoryListing, Details, Steps } from "~/components"; + +You can execute queries on your D1 database through SQL query statements. To do this, you need to perform the following steps: + +1. [Prepare a statement](/d1/worker-api/prepare-a-statement). +2. [Run the prepared statement](/d1/worker-api/run-a-statement). +3. Analyze the [return object](/d1/worker-api/return-object) (if necessary). + +Refer to the relevant sections for the API documentation. + +## Typescript support + +D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. + +When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. + +For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: + +```ts +// Row definition +type OrderRow = { +Id: string; +CustomerName: string; +OrderDate: number; +}; + +// Elsewhere in your application +const result = await env.MY_DB.prepare( +"SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", +).run(); +``` + +## API playground + +The D1 Worker Binding API playground is an `index.js` file where you can test each of the documented Worker Binding APIs for D1. The file builds from the end-state of the [Get started](/d1/get-started/#write-queries-within-your-worker) code. + +You can use this alongside the API documentation to better understand how each API works. + +Follow the steps to setup your API playground. + +### 1. Complete the Get started tutorial + +Complete the [Get started](/d1/get-started/#write-queries-within-your-worker) tutorial. Ensure you use JavaScript instead of TypeScript. + +### 2. Modify the content of `index.js` + +Replace the contents of your `index.js` file with the below to view the effect of each API. + +
+```js +export default { + async fetch(request, env) { + const { pathname } = new URL(request.url); + + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + + if (pathname === `/RUN`){ + const returnValue = await stmt.bind(companyName1).run() + return Response.json(returnValue); + + } else if (pathname === `/RAW`){ + const returnValue = await stmt.bind(companyName1).raw(); + return Response.json(returnValue); + + } else if (pathname === `/FIRST`){ + const returnValue = await stmt.bind(companyName1).first(); + return Response.json(returnValue); + + } else if (pathname === `/BATCH`) { + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + // const returnValue = await stmt.run(); + return Response.json(batchResult); + } + + return new Response( + `Welcome to the D1 API Playground! + \nChange the URL to test the methods inside your index.js file.`, + ); + }, + }; + +``` +
+ +### 3. Deploy the Worker + + +1. Navigate to your tutorial directory you created by following step 1. +2. Run `npx wrangler dev`. + ```sh + npx wrangler dev + ``` + ```sh output + ⛅️ wrangler 3.85.0 (update available 3.86.1) + ------------------------------------------------------- + + Your worker has access to the following bindings: + - D1 Databases: + - DB: (DATABASE_ID) (local) + ⎔ Starting local server... + [wrangler:inf] Ready on http://localhost:8787 + ╭───────────────────────────╮ + │ [b] open a browser │ + │ [d] open devtools │ + │ [l] turn off local mode │ + │ [c] clear console │ + │ [x] to exit │ + ╰───────────────────────────╯ + ``` +3. Open a browser at the specified address. + + +### 4. Test the APIs + +Change the URL to test the various D1 Worker Binding APIs. - diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index 422a317a52185da..e54ec702ec7b64b 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -7,11 +7,6 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -You can execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: - -1. Prepare your query statement (including binding variables into the statement). -2. Execute your query. - This chapter documents how to prepare a statement. ## Methods @@ -20,30 +15,9 @@ This chapter documents how to prepare a statement. Prepares a query statement to be later executed. -D1 API supports both prepared and static statements. - -- Prepared statements are SQL statements where the variables are dynamically determined. When writing a prepared statement, you insert variables into placeholders within the statement string. -- Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. - -:::note -The recommended approach is to use prepared statements (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. -::: - -Example of a prepared statement with dynamically bound value: - ```js const someVariable = `Bs Beverages`; const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); -// A variable (someVariable) will replace the placeholder '?' in the query. -// `stmt` is a prepared statement. -``` - -Example of a static statement: - -```js -const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beverages"); -// "Bs Beverages" is hard-coded into the query. -// `stmt` is a static statement. ``` #### Parameters @@ -90,22 +64,27 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beve .bind(1, "Alfreds Futterkiste"); ``` -- D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. +## Static statements - - When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +D1 API supports static statements. Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. - - For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: +:::note +The recommended approach is to bind parameters to create a prepared statement (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. +::: - ```ts - // Row definition - type OrderRow = { - Id: string; - CustomerName: string; - OrderDate: number; - }; +Example of a prepared statement with dynamically bound value: - // Elsewhere in your application - const result = await env.MY_DB.prepare( - "SELECT Id, CustomerName, OrderDate FROM [Order] ORDER BY ShippedDate DESC LIMIT 100", - ).run(); - ``` \ No newline at end of file +```js +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +// A variable (someVariable) will replace the placeholder '?' in the query. +// `stmt` is a prepared statement. +``` + +Example of a static statement: + +```js +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beverages"); +// "Bs Beverages" is hard-coded into the query. +// `stmt` is a static statement. +``` \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index 206c3df9479d86b..7636aaa043c2224 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -7,13 +7,6 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -## Description - -You to execute queries on your D1 database through SQL query statements. To do this, you need to follow these steps: - -1. Prepare your query statement (including binding variables into the statement). -2. Execute your query. - This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/prepare-a-statement). ## Methods From 881776159992dff46d9e1945d592d1b7e39e7b21 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 13 Nov 2024 10:25:23 +0000 Subject: [PATCH 20/33] Renaming extensions header for better clarity. --- src/content/docs/d1/sql-api/sql-statements.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index fb1752d4d5bf664..a7881c5233dbd59 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -11,7 +11,7 @@ D1 is compatible with most SQLite's SQL convention since it leverages SQLite's q You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/prepare-a-statement). -## SQLite Extensions +## Supported SQLite Extensions D1 supports a subset of SQLite extensions for added functionality, including: From 696a82a5d7b685e2a8044f49789907521a0270a4 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 13 Nov 2024 14:42:30 +0000 Subject: [PATCH 21/33] Adding changelog entry for including multiple queries in a single prepared statement. --- src/content/changelogs/d1.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/content/changelogs/d1.yaml b/src/content/changelogs/d1.yaml index 3af43dac56c0f8f..cc67b6539c84aa0 100644 --- a/src/content/changelogs/d1.yaml +++ b/src/content/changelogs/d1.yaml @@ -5,6 +5,12 @@ productLink: "/d1/" productArea: Developer platform productAreaLink: /workers/platform/changelog/platform/ entries: + - publish_date: "2024-11-18" + title: Support for multiple queries in a single prepared statement + description: |- + You can now have multiple queries in a single prepared statement when using `db.prepare`. To use this feature, separate each query with a semi-colon. Prepared statements with multiple queries only returns the results of the last query, even though all queries are executed. Additionally, you can only bind parameters to the last query in the prepared statement. + + For more information, refer to [`db.prepare` guidance](/d1/worker-api/prepare-a-statement/#guidance). - publish_date: "2024-08-23" title: D1 alpha databases have stopped accepting SQL queries description: |- From 1d3637f1b594af811d8c156837630e99119338d1 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 13 Nov 2024 15:43:38 +0000 Subject: [PATCH 22/33] Updating wording in Get started to match new folders. --- src/content/docs/d1/get-started.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index 2f95990dc57e1d0..ff3f13d0c4539e5 100644 --- a/src/content/docs/d1/get-started.mdx +++ b/src/content/docs/d1/get-started.mdx @@ -532,5 +532,5 @@ In this tutorial, you have: If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the [Cloudflare Developers community on Discord](https://discord.cloudflare.com). - See supported [Wrangler commands for D1](/workers/wrangler/commands/#d1). -- Learn how to use the [D1 client API](/d1/build-with-d1/d1-client-api/) within your Worker. +- Learn how to use the [D1 Worker Binding API](/d1/worker-api/index) within your Worker. - Explore [community projects built on D1](/d1/reference/community-projects/). From c3023abc608f65c7d8924b205713a1bbebb731c9 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 13 Nov 2024 16:04:22 +0000 Subject: [PATCH 23/33] Fixing broken link --- src/content/docs/d1/get-started.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index ff3f13d0c4539e5..5fcc24fdd3ba03c 100644 --- a/src/content/docs/d1/get-started.mdx +++ b/src/content/docs/d1/get-started.mdx @@ -532,5 +532,5 @@ In this tutorial, you have: If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the [Cloudflare Developers community on Discord](https://discord.cloudflare.com). - See supported [Wrangler commands for D1](/workers/wrangler/commands/#d1). -- Learn how to use the [D1 Worker Binding API](/d1/worker-api/index) within your Worker. +- Learn how to use the [D1 Worker Binding API](/d1/worker-api/) within your Worker. - Explore [community projects built on D1](/d1/reference/community-projects/). From 73083c0b1d537f9a65ff9c9f796536aa5179d452 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 10:51:16 +0000 Subject: [PATCH 24/33] Implementing feedback. --- src/content/changelogs/d1.yaml | 2 +- src/content/docs/d1/get-started.mdx | 2 +- src/content/docs/d1/worker-api/index.mdx | 89 +++++++++++-------- .../d1/worker-api/prepare-a-statement.mdx | 13 +-- .../docs/d1/worker-api/return-object.mdx | 42 ++++++++- .../docs/d1/worker-api/run-a-statement.mdx | 38 ++++---- 6 files changed, 119 insertions(+), 67 deletions(-) diff --git a/src/content/changelogs/d1.yaml b/src/content/changelogs/d1.yaml index cc67b6539c84aa0..08ce5e2f0e2a22a 100644 --- a/src/content/changelogs/d1.yaml +++ b/src/content/changelogs/d1.yaml @@ -5,7 +5,7 @@ productLink: "/d1/" productArea: Developer platform productAreaLink: /workers/platform/changelog/platform/ entries: - - publish_date: "2024-11-18" + - publish_date: "2024-11-01" title: Support for multiple queries in a single prepared statement description: |- You can now have multiple queries in a single prepared statement when using `db.prepare`. To use this feature, separate each query with a semi-colon. Prepared statements with multiple queries only returns the results of the last query, even though all queries are executed. Additionally, you can only bind parameters to the last query in the prepared statement. diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index 5fcc24fdd3ba03c..2bc0f690744ba12 100644 --- a/src/content/docs/d1/get-started.mdx +++ b/src/content/docs/d1/get-started.mdx @@ -532,5 +532,5 @@ In this tutorial, you have: If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the [Cloudflare Developers community on Discord](https://discord.cloudflare.com). - See supported [Wrangler commands for D1](/workers/wrangler/commands/#d1). -- Learn how to use the [D1 Worker Binding API](/d1/worker-api/) within your Worker. +- Learn how to use the [D1 Worker Binding API](/d1/worker-api/) within your Worker, and test them from the [API playground](/d1/worker-api/#api-playground). - Explore [community projects built on D1](/d1/reference/community-projects/). diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index b0d93e06679730f..60c19877e2ec64e 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -7,7 +7,7 @@ sidebar: import { DirectoryListing, Details, Steps } from "~/components"; -You can execute queries on your D1 database through SQL query statements. To do this, you need to perform the following steps: +You can execute SQL queries on your D1 database from a Worker using the Worker Binding API. To do this, you can perform the following steps: 1. [Prepare a statement](/d1/worker-api/prepare-a-statement). 2. [Run the prepared statement](/d1/worker-api/run-a-statement). @@ -17,9 +17,9 @@ Refer to the relevant sections for the API documentation. ## Typescript support -D1 Worker Bindings API is fully-typed via the `@cloudflare/workers-types` package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. +D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. -When using the [query statement methods](#query-statement-methods) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +When using the [query statement methods](/d1/worker-api/run-a-statement) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: @@ -56,40 +56,55 @@ Replace the contents of your `index.js` file with the below to view the effect o
```js export default { - async fetch(request, env) { - const { pathname } = new URL(request.url); - - const companyName1 = `Bs Beverages`; - const companyName2 = `Around the Horn`; - const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); - - if (pathname === `/RUN`){ - const returnValue = await stmt.bind(companyName1).run() - return Response.json(returnValue); - - } else if (pathname === `/RAW`){ - const returnValue = await stmt.bind(companyName1).raw(); - return Response.json(returnValue); - - } else if (pathname === `/FIRST`){ - const returnValue = await stmt.bind(companyName1).first(); - return Response.json(returnValue); - - } else if (pathname === `/BATCH`) { - const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) - ]); - // const returnValue = await stmt.run(); - return Response.json(batchResult); - } - - return new Response( - `Welcome to the D1 API Playground! - \nChange the URL to test the methods inside your index.js file.`, - ); - }, - }; + async fetch(request, env) { + const { pathname } = new URL(request.url); + + // if (pathname === "/api/beverages") { + // // If you did not use `DB` as your binding name, change it here + // const { results } = await env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?",).bind("Bs Beverages").all(); + // return Response.json(results); + // } + + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + const stmtMulti = env.DB.prepare(`SELECT * FROM Customers; SELECT * FROM Customers WHERE CompanyName = ?`); + + if (pathname === `/RUN`){ + const returnValue = await stmt.bind(companyName1).run(); + return Response.json(returnValue); + + } else if (pathname === `/RAW`){ + const returnValue = await stmt.bind(companyName1).raw(); + return Response.json(returnValue); + + } else if (pathname === `/FIRST`){ + const returnValue = await stmt.bind(companyName1).first(); + return Response.json(returnValue); + + } else if (pathname === `/BATCH`) { + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + // const returnValue = await stmt.run(); + return Response.json(batchResult); + + } else if (pathname === `/RUNMULTI`){ + const returnValue = await stmtMulti.bind(companyName1).run(); + return Response.json(returnValue); + + } else if (pathname === `/EXEC`){ + const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); + return Response.json(returnValue); + } + + return new Response( + `Welcome to the D1 API Playground! + \nChange the URL to test the various methods inside your index.js file.`, + ); + }, +}; ```
diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index e54ec702ec7b64b..d76b92b20df87d0 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -31,12 +31,6 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin #### Guidance -- You can pass multiple queries into a single `.prepare()` statement. Simply delineate each query with a semi-colon. - - The statement only returns the results of the last query, even though all queries are executed. - - You can only bind parameters to the last query. - ```js - const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") - ``` - D1 follows the [SQLite convention](https://www.sqlite.org/lang_expr.html#varparam) for prepared statements parameter binding. Currently, D1 only supports Ordered (`?NNNN`) and Anonymous (`?`) parameters. In the future, D1 will support named parameters as well. | Syntax | Type | Description | @@ -64,6 +58,13 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin .bind(1, "Alfreds Futterkiste"); ``` +- You can pass multiple queries into a single `.prepare()` statement. Simply delineate each query with a semi-colon. + - The statement only returns the results of the last query, even though all queries are executed. + - You can only bind parameters to the last query. + ```js + const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") + ``` + ## Static statements D1 API supports static statements. Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index fd87251decd0610..2d7c5c9c31fb442 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -1,11 +1,20 @@ --- -title: Return object +title: Return objects pcx_content_type: concept sidebar: order: 3 --- -The methods `stmt.run()`, `db.exec()`, and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: +Some D1 Worker Binding APIs return a typed object. + +| D1 Worker Binding API | Return object | +| ------------------------- | ------------- | +| `stmt.run()`, `db.batch()`| `D1Result` | +| `db.exec()` | `D1ExecResult`| + +## D1Result + +The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: - The success status - A meta object with the internal duration of the operation in milliseconds @@ -28,7 +37,7 @@ The methods `stmt.run()`, `db.exec()`, and `db.batch()` return a typed `D1Result } ``` -## Example: +### Example ```js const someVariable = `Bs Beverages`; @@ -62,4 +71,31 @@ return Response.json(result) } ] } +``` + +## D1ExecResult + +The method `db.exec()` returns a typed `D1ExecResult` object for each query statement. This object contains: + +- The number of executed queries +- The duration of the operation in milliseconds + +```js +{ + "count": number, // the number of executed queries + "duration": number // the duration of the operation, in milliseconds +} +``` + +### Example + +```js +const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); +return Response.json(returnValue); +``` +```js output +{ + "count": 1, + "duration": 1 +} ``` \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index 7636aaa043c2224..98a0e46f11fd54a 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -1,5 +1,5 @@ --- -title: Run a prepared statement +title: Run a statement pcx_content_type: concept sidebar: order: 2 @@ -25,9 +25,9 @@ const returnValue = await stmt.run(); #### Return value -- returnValue: +- D1Result: - An object containing the success status, a meta object, and an array of objects containing the query results. - - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object). + - For more information on the object, refer to [`D1Result`](/d1/worker-api/return-object/d1result).
```js @@ -294,8 +294,8 @@ const batchResult = await env.DB.batch([ #### Return values - results: - - An array of objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. - - For more information on the returned object, refer to [Return objects](/d1/worker-api/return-object). + - An array of `D1Result` objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. + - Refer to [`D1Result`](/d1/worker-api/return-object/d1result) for more information about this object.
@@ -388,32 +388,33 @@ console.log(stmt[1].results); ### `db.exec()` -Executes one or more queries directly without prepared statements or parameters binding. +Executes one or more queries directly without prepared statements or parameter bindings. ```js -const migration = await fetch("/migration.sql"); -const out = await db.exec(migration.text()); +const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); ``` #### Parameters -- +- queryString: + - The SQL query statement without parameter binding. #### Return values -- queryResult: - - Result of the query. +- D1ExecResult: + - The `count` property contains the number of executed queries. + - The `duration` property contains the duration of operation in milliseconds. + - Refer to [`D1ExecResult`](/d1/worker-api/return-object/#d1execresult) for more information.
```js -const migration = await fetch("/migration.sql"); -const out = await db.exec(migration.text()); -console.log(out); +const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); +return Response.json(returnValue); ``` ```js output { - count: 80, - duration: 76 + "count": 1, + "duration": 1 } ```
@@ -445,9 +446,8 @@ return new Response(dump, { #### Parameters -- +- None. #### Return values -- - +- None. From 4f2a119db0470b96feb0f6c95cb1cc935b9e959e Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 11:29:47 +0000 Subject: [PATCH 25/33] Removing references to multi-statement prepare(). --- src/content/changelogs/d1.yaml | 6 ------ src/content/docs/d1/worker-api/index.mdx | 6 ------ src/content/docs/d1/worker-api/prepare-a-statement.mdx | 7 ------- 3 files changed, 19 deletions(-) diff --git a/src/content/changelogs/d1.yaml b/src/content/changelogs/d1.yaml index 08ce5e2f0e2a22a..3af43dac56c0f8f 100644 --- a/src/content/changelogs/d1.yaml +++ b/src/content/changelogs/d1.yaml @@ -5,12 +5,6 @@ productLink: "/d1/" productArea: Developer platform productAreaLink: /workers/platform/changelog/platform/ entries: - - publish_date: "2024-11-01" - title: Support for multiple queries in a single prepared statement - description: |- - You can now have multiple queries in a single prepared statement when using `db.prepare`. To use this feature, separate each query with a semi-colon. Prepared statements with multiple queries only returns the results of the last query, even though all queries are executed. Additionally, you can only bind parameters to the last query in the prepared statement. - - For more information, refer to [`db.prepare` guidance](/d1/worker-api/prepare-a-statement/#guidance). - publish_date: "2024-08-23" title: D1 alpha databases have stopped accepting SQL queries description: |- diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 60c19877e2ec64e..8e2bce7927fea3a 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -68,7 +68,6 @@ export default { const companyName1 = `Bs Beverages`; const companyName2 = `Around the Horn`; const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); - const stmtMulti = env.DB.prepare(`SELECT * FROM Customers; SELECT * FROM Customers WHERE CompanyName = ?`); if (pathname === `/RUN`){ const returnValue = await stmt.bind(companyName1).run(); @@ -87,13 +86,8 @@ export default { stmt.bind(companyName1), stmt.bind(companyName2) ]); - // const returnValue = await stmt.run(); return Response.json(batchResult); - } else if (pathname === `/RUNMULTI`){ - const returnValue = await stmtMulti.bind(companyName1).run(); - return Response.json(returnValue); - } else if (pathname === `/EXEC`){ const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); return Response.json(returnValue); diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index d76b92b20df87d0..5ca48486f189543 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -58,13 +58,6 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin .bind(1, "Alfreds Futterkiste"); ``` -- You can pass multiple queries into a single `.prepare()` statement. Simply delineate each query with a semi-colon. - - The statement only returns the results of the last query, even though all queries are executed. - - You can only bind parameters to the last query. - ```js - const stmt = db.prepare(`SELECT * FROM users WHERE name = "Anthony"; SELECT * FROM users WHERE name = ?1`).bind("Joe") - ``` - ## Static statements D1 API supports static statements. Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. From 7dbf844f0da30dab4674edf60ce1501d84bc4b4f Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 11:49:40 +0000 Subject: [PATCH 26/33] Fixing broken links --- src/content/docs/d1/worker-api/run-a-statement.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index 98a0e46f11fd54a..07649dea440e2cc 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -27,7 +27,7 @@ const returnValue = await stmt.run(); - D1Result: - An object containing the success status, a meta object, and an array of objects containing the query results. - - For more information on the object, refer to [`D1Result`](/d1/worker-api/return-object/d1result). + - For more information on the object, refer to [`D1Result`](/d1/worker-api/return-object/#d1result).
```js @@ -295,7 +295,7 @@ const batchResult = await env.DB.batch([ - results: - An array of `D1Result` objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. - - Refer to [`D1Result`](/d1/worker-api/return-object/d1result) for more information about this object. + - Refer to [`D1Result`](/d1/worker-api/return-object/#d1result) for more information about this object.
From 9efd9e974d0609b56d5893393a7107cfc29b7a3b Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 14:55:34 +0000 Subject: [PATCH 27/33] Grammar fixes and deleting redundant comment block. --- src/content/docs/d1/get-started.mdx | 2 +- src/content/docs/d1/worker-api/index.mdx | 2 +- .../docs/d1/worker-api/run-a-statement.mdx | 48 ------------------- 3 files changed, 2 insertions(+), 50 deletions(-) diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index 2bc0f690744ba12..7be39970073ebf6 100644 --- a/src/content/docs/d1/get-started.mdx +++ b/src/content/docs/d1/get-started.mdx @@ -532,5 +532,5 @@ In this tutorial, you have: If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the [Cloudflare Developers community on Discord](https://discord.cloudflare.com). - See supported [Wrangler commands for D1](/workers/wrangler/commands/#d1). -- Learn how to use the [D1 Worker Binding API](/d1/worker-api/) within your Worker, and test them from the [API playground](/d1/worker-api/#api-playground). +- Learn how to use [D1 Worker Binding APIs](/d1/worker-api/) within your Worker, and test them from the [API playground](/d1/worker-api/#api-playground). - Explore [community projects built on D1](/d1/reference/community-projects/). diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 8e2bce7927fea3a..1c3fd920c019d28 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -17,7 +17,7 @@ Refer to the relevant sections for the API documentation. ## Typescript support -D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional _type parameter_ so that a function understands the type of the data it is handling. +D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional `type parameter` so that a function understands the type of the data it is handling. When using the [query statement methods](/d1/worker-api/run-a-statement) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index 07649dea440e2cc..2de035083f0ee3a 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -220,54 +220,6 @@ return Response.json(returnValue) - `stmt.first()` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `first()` to return a typed result object. -{/* ### `stmt.all()` - -Returns all rows as an array of objects, with each result row represented as an object on the `results` property of the `D1Result` type. - -```js -const { results } = await stmt.all(); -``` - -#### Parameters - -- None. - -#### Return values - -- Array: - - An array of objects. - - Each row represents a row. - - Each object is created on the `results` property of the `D1Result` type. - -
-```js -const stmt = db.prepare("SELECT name, age FROM users LIMIT 3"); -const { results } = await stmt.all(); -console.log(results); -``` - -```js output -[ - { - name: "John", - age: 42, - }, - { - name: "Anthony", - age: 37, - }, - { - name: "Dave", - age: 29, - }, - ] -``` -
- -#### Guidance - -- When joining tables with identical column names, only the leftmost column will be included in the row object. Use [`stmt.raw()`](#await-stmtraw) to return all rows as an array of arrays. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `all()` to return a typed result object. */} ### `db.batch()` Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. From caf3890caa8d92c7f21ca608905b520497b0cf36 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 14:57:38 +0000 Subject: [PATCH 28/33] Apply suggestions from code review Co-authored-by: marciocloudflare <83226960+marciocloudflare@users.noreply.github.com> --- src/content/docs/d1/sql-api/sql-statements.mdx | 2 +- src/content/docs/d1/worker-api/index.mdx | 4 ++-- src/content/docs/d1/worker-api/prepare-a-statement.mdx | 2 +- src/content/docs/d1/worker-api/run-a-statement.mdx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index a7881c5233dbd59..c69c390d9a3e7e8 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -11,7 +11,7 @@ D1 is compatible with most SQLite's SQL convention since it leverages SQLite's q You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/prepare-a-statement). -## Supported SQLite Extensions +## Supported SQLite extensions D1 supports a subset of SQLite extensions for added functionality, including: diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 1c3fd920c019d28..e8b88b7428d72db 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -15,7 +15,7 @@ You can execute SQL queries on your D1 database from a Worker using the Worker B Refer to the relevant sections for the API documentation. -## Typescript support +## TypeScript support D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional `type parameter` so that a function understands the type of the data it is handling. @@ -51,7 +51,7 @@ Complete the [Get started](/d1/get-started/#write-queries-within-your-worker) tu ### 2. Modify the content of `index.js` -Replace the contents of your `index.js` file with the below to view the effect of each API. +Replace the contents of your `index.js` file with the code below to view the effect of each API.
```js diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx index 5ca48486f189543..31320e955143a35 100644 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepare-a-statement.mdx @@ -36,7 +36,7 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin | Syntax | Type | Description | | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | - | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than SQLITE_MAX_VARIABLE_NUMBER, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead | + | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than `SQLITE_MAX_VARIABLE_NUMBER`, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead. | To bind a parameter, use the `stmt.bind()` method. diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/run-a-statement.mdx index 2de035083f0ee3a..e180adbfa5c1716 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/run-a-statement.mdx @@ -69,7 +69,7 @@ return Response.json(returnValue); #### Guidance -- `results` is empty for write operations such as UPDATE, DELETE, or INSERT. +- `results` is empty for write operations such as `UPDATE`, `DELETE`, or `INSERT`. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. - `stmt.run()` is functionally equivalent to `stmt.all()`, and can be treated as an alias. - You can choose to extract only the results you expect from the statement by simply returning the `results` property of the return object. From d3cdce6b3b0340618d4ab99a55fa6dff3e3485e7 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 15 Nov 2024 15:47:48 +0000 Subject: [PATCH 29/33] Minor rename of the chapter --- src/content/docs/d1/worker-api/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index e8b88b7428d72db..b9d395ae335e07f 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -1,6 +1,6 @@ --- pcx_content_type: navigation -title: D1 Worker Binding API +title: Worker Binding API sidebar: order: 4 --- From ba5fbde8eb9ca37923f8e4b378b69b26669cef1e Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 19 Nov 2024 09:58:08 +0000 Subject: [PATCH 30/33] Cleaning up the structure by method hierarchy. --- .../docs/d1/sql-api/sql-statements.mdx | 2 +- src/content/docs/d1/worker-api/d1-binding.mdx | 276 ++++++++++++++++++ src/content/docs/d1/worker-api/index.mdx | 9 +- .../d1/worker-api/prepare-a-statement.mdx | 84 ------ ...-statement.mdx => prepared-statements.mdx} | 187 +----------- 5 files changed, 284 insertions(+), 274 deletions(-) create mode 100644 src/content/docs/d1/worker-api/d1-binding.mdx delete mode 100644 src/content/docs/d1/worker-api/prepare-a-statement.mdx rename src/content/docs/d1/worker-api/{run-a-statement.mdx => prepared-statements.mdx} (52%) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index c69c390d9a3e7e8..c9f1877e7a53a7b 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -9,7 +9,7 @@ import { Details, Render } from "~/components"; D1 is compatible with most SQLite's SQL convention since it leverages SQLite's query engine. D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. -You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/prepare-a-statement). +You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/d1-binding). ## Supported SQLite extensions diff --git a/src/content/docs/d1/worker-api/d1-binding.mdx b/src/content/docs/d1/worker-api/d1-binding.mdx new file mode 100644 index 000000000000000..da827e370a556e5 --- /dev/null +++ b/src/content/docs/d1/worker-api/d1-binding.mdx @@ -0,0 +1,276 @@ +--- +title: D1 binding +pcx_content_type: concept +sidebar: + order: 1 +--- + +import { Type, MetaInfo, Details } from "~/components"; + +To interact with your D1 database from your Worker, you need to access it through the environment bindings provided to the Worker (`env`). + +```js +async fetch(request, env) { + // D1 database is 'env.DB', where "DB" is the binding name from the Wrangler.toml file. +} +``` + +A D1 binding has the type `D1Database`, and supports a number of methods, as listed below. + +## Methods + +### `db.prepare()` + +Prepares a query statement to be later executed. + +```js +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +``` + +#### Parameters + +- sqlQuery: + - The SQL query you wish to execute on the database. + +#### Return values + +- None. + +#### Guidance + +- D1 follows the [SQLite convention](https://www.sqlite.org/lang_expr.html#varparam) for prepared statements parameter binding. Currently, D1 only supports Ordered (`?NNNN`) and Anonymous (`?`) parameters. In the future, D1 will support named parameters as well. + + | Syntax | Type | Description | + | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | + | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than `SQLITE_MAX_VARIABLE_NUMBER`, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead. | + + To bind a parameter, use the `stmt.bind()` method. + + Order and anonymous examples: + + ```js + const stmt = db.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(""); + ``` + + ```js + const stmt = db + .prepare("SELECT * FROM Customers WHERE CompanyName = ? AND CustomerId = ?") + .bind("Alfreds Futterkiste", 1); + ``` + + ```js + const stmt = db + .prepare("SELECT * FROM Customers WHERE CompanyName = ?2 AND CustomerId = ?1") + .bind(1, "Alfreds Futterkiste"); + ``` + +#### Static statements + +D1 API supports static statements. Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. + +:::note +The recommended approach is to bind parameters to create a prepared statement (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. +::: + +Example of a prepared statement with dynamically bound value: + +```js +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +// A variable (someVariable) will replace the placeholder '?' in the query. +// `stmt` is a prepared statement. +``` + +Example of a static statement: + +```js +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beverages"); +// "Bs Beverages" is hard-coded into the query. +// `stmt` is a static statement. +``` + +### `db.batch()` + +Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. + +Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. + +To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. + +```js +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); +const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) +]); +``` + +#### Parameters + +- statements: + - An array of `db.prepare()` statements. + +#### Return values + +- results: + - An array of `D1Result` objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. + - Refer to [`D1Result`](/d1/worker-api/return-object/#d1result) for more information about this object. + +
+ +```js +const companyName1 = `Bs Beverages`; +const companyName2 = `Around the Horn`; +const stmt = await env.DB.batch([ + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName1), + env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName2) +]); +return Response.json(stmt) +``` +```js output +[ + { + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } + ] + }, + { + "success": true, + "meta": { + "served_by": "miniflare.db", + "duration": 0, + "changes": 0, + "last_row_id": 0, + "changed_db": false, + "size_after": 8192, + "rows_read": 4, + "rows_written": 0 + }, + "results": [ + { + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } + ] + } +] +``` +```js +console.log(stmt[1].results); +``` +```js output +[ + { + "CustomerId": 4, + "CompanyName": "Around the Horn", + "ContactName": "Thomas Hardy" + } +] +``` +
+ +#### Guidance + +- You can construct batches reusing the same prepared statement: + + ```js + const companyName1 = `Bs Beverages`; + const companyName2 = `Around the Horn`; + const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); + const batchResult = await env.DB.batch([ + stmt.bind(companyName1), + stmt.bind(companyName2) + ]); + return Response.json(batchResult); + ``` + +### `db.exec()` + +Executes one or more queries directly without prepared statements or parameter bindings. + +```js +const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); +``` + +#### Parameters + +- queryString: + - The SQL query statement without parameter binding. + +#### Return values + +- D1ExecResult: + - The `count` property contains the number of executed queries. + - The `duration` property contains the duration of operation in milliseconds. + - Refer to [`D1ExecResult`](/d1/worker-api/return-object/#d1execresult) for more information. + +
+```js +const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); +return Response.json(returnValue); +``` +```js output +{ + "count": 1, + "duration": 1 +} +``` +
+ +#### Guidance + +- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. +- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. +- Only use this method for maintenance and one-shot tasks (for example, migration jobs). +- The input can be one or multiple queries separated by `\n`. + +### `db.dump` + +:::caution +This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. +::: + +Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. + +```js +const dump = await db.dump(); +return new Response(dump, { + status: 200, + headers: { + "Content-Type": "application/octet-stream", + }, +}); +``` + +#### Parameters + +- None. + +#### Return values + +- None. \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index b9d395ae335e07f..47b248761835e92 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -9,9 +9,10 @@ import { DirectoryListing, Details, Steps } from "~/components"; You can execute SQL queries on your D1 database from a Worker using the Worker Binding API. To do this, you can perform the following steps: -1. [Prepare a statement](/d1/worker-api/prepare-a-statement). -2. [Run the prepared statement](/d1/worker-api/run-a-statement). -3. Analyze the [return object](/d1/worker-api/return-object) (if necessary). +1. [Bind the D1 Database](/d1/worker-api/d1-binding). +2. [Prepare a statement](/d1/worker-api/d1-binding/#dbprepare). +3. [Run the prepared statement](/d1/worker-api/prepared-statements). +4. Analyze the [return object](/d1/worker-api/return-object) (if necessary). Refer to the relevant sections for the API documentation. @@ -19,7 +20,7 @@ Refer to the relevant sections for the API documentation. D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional `type parameter` so that a function understands the type of the data it is handling. -When using the [query statement methods](/d1/worker-api/run-a-statement) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +When using the [query statement methods](/d1/worker-api/prepared-statements) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: diff --git a/src/content/docs/d1/worker-api/prepare-a-statement.mdx b/src/content/docs/d1/worker-api/prepare-a-statement.mdx deleted file mode 100644 index 31320e955143a35..000000000000000 --- a/src/content/docs/d1/worker-api/prepare-a-statement.mdx +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Prepare a statement -pcx_content_type: concept -sidebar: - order: 1 ---- - -import { Type, MetaInfo, Details } from "~/components"; - -This chapter documents how to prepare a statement. - -## Methods - -### `db.prepare()` - -Prepares a query statement to be later executed. - -```js -const someVariable = `Bs Beverages`; -const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); -``` - -#### Parameters - -- sqlQuery: - - The SQL query you wish to execute on the database. - -#### Return values - -- None. - -#### Guidance - -- D1 follows the [SQLite convention](https://www.sqlite.org/lang_expr.html#varparam) for prepared statements parameter binding. Currently, D1 only supports Ordered (`?NNNN`) and Anonymous (`?`) parameters. In the future, D1 will support named parameters as well. - - | Syntax | Type | Description | - | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | - | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than `SQLITE_MAX_VARIABLE_NUMBER`, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead. | - - To bind a parameter, use the `stmt.bind()` method. - - Order and anonymous examples: - - ```js - const stmt = db.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(""); - ``` - - ```js - const stmt = db - .prepare("SELECT * FROM Customers WHERE CompanyName = ? AND CustomerId = ?") - .bind("Alfreds Futterkiste", 1); - ``` - - ```js - const stmt = db - .prepare("SELECT * FROM Customers WHERE CompanyName = ?2 AND CustomerId = ?1") - .bind(1, "Alfreds Futterkiste"); - ``` - -## Static statements - -D1 API supports static statements. Static statements are SQL statements where the variables have been hard coded. When writing a static statement, you manually type the variable within the statement string. - -:::note -The recommended approach is to bind parameters to create a prepared statement (which are precompiled objects used by the database) to run the SQL. Prepared statements lead to faster overall execution and prevent SQL injection attacks. -::: - -Example of a prepared statement with dynamically bound value: - -```js -const someVariable = `Bs Beverages`; -const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); -// A variable (someVariable) will replace the placeholder '?' in the query. -// `stmt` is a prepared statement. -``` - -Example of a static statement: - -```js -const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beverages"); -// "Bs Beverages" is hard-coded into the query. -// `stmt` is a static statement. -``` \ No newline at end of file diff --git a/src/content/docs/d1/worker-api/run-a-statement.mdx b/src/content/docs/d1/worker-api/prepared-statements.mdx similarity index 52% rename from src/content/docs/d1/worker-api/run-a-statement.mdx rename to src/content/docs/d1/worker-api/prepared-statements.mdx index e180adbfa5c1716..511ce69a2726566 100644 --- a/src/content/docs/d1/worker-api/run-a-statement.mdx +++ b/src/content/docs/d1/worker-api/prepared-statements.mdx @@ -1,5 +1,5 @@ --- -title: Run a statement +title: Prepared statement methods pcx_content_type: concept sidebar: order: 2 @@ -7,7 +7,7 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/prepare-a-statement). +This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/d1-binding/#dbprepare). ## Methods @@ -220,186 +220,3 @@ return Response.json(returnValue) - `stmt.first()` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. - When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `first()` to return a typed result object. -### `db.batch()` - -Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. - -Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. - -To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. - -```js -const companyName1 = `Bs Beverages`; -const companyName2 = `Around the Horn`; -const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); -const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) -]); -``` - -#### Parameters - -- statements: - - An array of `db.prepare()` statements. - -#### Return values - -- results: - - An array of `D1Result` objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. - - Refer to [`D1Result`](/d1/worker-api/return-object/#d1result) for more information about this object. - -
- -```js -const companyName1 = `Bs Beverages`; -const companyName2 = `Around the Horn`; -const stmt = await env.DB.batch([ - env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName1), - env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`).bind(companyName2) -]); -return Response.json(stmt) -``` -```js output -[ - { - "success": true, - "meta": { - "served_by": "miniflare.db", - "duration": 0, - "changes": 0, - "last_row_id": 0, - "changed_db": false, - "size_after": 8192, - "rows_read": 4, - "rows_written": 0 - }, - "results": [ - { - "CustomerId": 11, - "CompanyName": "Bs Beverages", - "ContactName": "Victoria Ashworth" - }, - { - "CustomerId": 13, - "CompanyName": "Bs Beverages", - "ContactName": "Random Name" - } - ] - }, - { - "success": true, - "meta": { - "served_by": "miniflare.db", - "duration": 0, - "changes": 0, - "last_row_id": 0, - "changed_db": false, - "size_after": 8192, - "rows_read": 4, - "rows_written": 0 - }, - "results": [ - { - "CustomerId": 4, - "CompanyName": "Around the Horn", - "ContactName": "Thomas Hardy" - } - ] - } -] -``` -```js -console.log(stmt[1].results); -``` -```js output -[ - { - "CustomerId": 4, - "CompanyName": "Around the Horn", - "ContactName": "Thomas Hardy" - } -] -``` -
- -#### Guidance - -- You can construct batches reusing the same prepared statement: - - ```js - const companyName1 = `Bs Beverages`; - const companyName2 = `Around the Horn`; - const stmt = env.DB.prepare(`SELECT * FROM Customers WHERE CompanyName = ?`); - const batchResult = await env.DB.batch([ - stmt.bind(companyName1), - stmt.bind(companyName2) - ]); - return Response.json(batchResult); - ``` - -### `db.exec()` - -Executes one or more queries directly without prepared statements or parameter bindings. - -```js -const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); -``` - -#### Parameters - -- queryString: - - The SQL query statement without parameter binding. - -#### Return values - -- D1ExecResult: - - The `count` property contains the number of executed queries. - - The `duration` property contains the duration of operation in milliseconds. - - Refer to [`D1ExecResult`](/d1/worker-api/return-object/#d1execresult) for more information. - -
-```js -const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName = "Bs Beverages"`); -return Response.json(returnValue); -``` -```js output -{ - "count": 1, - "duration": 1 -} -``` -
- -#### Guidance - -- If an error occurs, an exception is thrown with the query and error messages, execution stops and further statements are not executed. Refer to [Errors](/d1/build-with-d1/d1-client-api/#errors) to learn more. -- This method can have poorer performance (prepared statements can be reused in some cases) and, more importantly, is less safe. -- Only use this method for maintenance and one-shot tasks (for example, migration jobs). -- The input can be one or multiple queries separated by `\n`. - -### `db.dump` - -:::caution -This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. -::: - -Dumps the entire D1 database to an SQLite compatible file inside an ArrayBuffer. - -```js -const dump = await db.dump(); -return new Response(dump, { - status: 200, - headers: { - "Content-Type": "application/octet-stream", - }, -}); -``` - -#### Parameters - -- None. - -#### Return values - -- None. From b7d850d4a4394df85bcb0c3ebccf3cf8be0b8909 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 19 Nov 2024 10:22:55 +0000 Subject: [PATCH 31/33] Adding a note for those who are following the tutorial with an existing Worker. --- src/content/docs/d1/get-started.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index 7be39970073ebf6..24c7219f52e6453 100644 --- a/src/content/docs/d1/get-started.mdx +++ b/src/content/docs/d1/get-started.mdx @@ -23,6 +23,10 @@ This guide instructs you through: You can perform these tasks through the CLI or through the Cloudflare dashboard. +:::note +If you already have an existing Worker and an existing D1 database, follow this tutorial from [3. Bind your Worker to your D1 database](/d1/get-started/#3-bind-your-worker-to-your-d1-database). +::: + ## Prerequisites From cc0de6fe32ba835668bfdb7d60d020653d4efc72 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 19 Nov 2024 16:46:42 +0000 Subject: [PATCH 32/33] Actioning PR feedback. --- .../docs/d1/sql-api/sql-statements.mdx | 2 +- .../{d1-binding.mdx => d1-database.mdx} | 22 +++++++------- src/content/docs/d1/worker-api/index.mdx | 8 ++--- .../d1/worker-api/prepared-statements.mdx | 29 ++++++++++--------- .../docs/d1/worker-api/return-object.mdx | 12 ++++---- 5 files changed, 37 insertions(+), 36 deletions(-) rename src/content/docs/d1/worker-api/{d1-binding.mdx => d1-database.mdx} (93%) diff --git a/src/content/docs/d1/sql-api/sql-statements.mdx b/src/content/docs/d1/sql-api/sql-statements.mdx index c9f1877e7a53a7b..06d3efbb51c2e3c 100644 --- a/src/content/docs/d1/sql-api/sql-statements.mdx +++ b/src/content/docs/d1/sql-api/sql-statements.mdx @@ -9,7 +9,7 @@ import { Details, Render } from "~/components"; D1 is compatible with most SQLite's SQL convention since it leverages SQLite's query engine. D1 supports a number of database-level statements that allow you to list tables, indexes, and inspect the schema for a given table or index. -You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/d1-binding). +You can execute any of these statements via the D1 console in the Cloudflare dashboard, [`wrangler d1 execute`](/workers/wrangler/commands/#d1), or with the [D1 Worker Bindings API](/d1/worker-api/d1-database). ## Supported SQLite extensions diff --git a/src/content/docs/d1/worker-api/d1-binding.mdx b/src/content/docs/d1/worker-api/d1-database.mdx similarity index 93% rename from src/content/docs/d1/worker-api/d1-binding.mdx rename to src/content/docs/d1/worker-api/d1-database.mdx index da827e370a556e5..85640817acfadbe 100644 --- a/src/content/docs/d1/worker-api/d1-binding.mdx +++ b/src/content/docs/d1/worker-api/d1-database.mdx @@ -1,5 +1,5 @@ --- -title: D1 binding +title: D1 Database pcx_content_type: concept sidebar: order: 1 @@ -19,7 +19,7 @@ A D1 binding has the type `D1Database`, and supports a number of methods, as lis ## Methods -### `db.prepare()` +### `prepare()` Prepares a query statement to be later executed. @@ -30,7 +30,7 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin #### Parameters -- sqlQuery: +- query: - The SQL query you wish to execute on the database. #### Return values @@ -46,7 +46,7 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than `SQLITE_MAX_VARIABLE_NUMBER`, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead. | - To bind a parameter, use the `stmt.bind()` method. + To bind a parameter, use the `D1PreparedStatement::bind` method. Order and anonymous examples: @@ -91,13 +91,13 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = Bs Beve // `stmt` is a static statement. ``` -### `db.batch()` +### `batch()` Sends multiple SQL statements inside a single call to the database. This can have a huge performance impact as it reduces latency from network round trips to D1. D1 operates in auto-commit. Our implementation guarantees that each statement in the list will execute and commit, sequentially, non-concurrently. Batched statements are [SQL transactions](https://www.sqlite.org/lang_transaction.html). If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence. -To send batch statements, provide `.batch()` a list of prepared statements and get the results in the same order. +To send batch statements, provide `D1Database::batch` a list of prepared statements and get the results in the same order. ```js const companyName1 = `Bs Beverages`; @@ -112,12 +112,12 @@ const batchResult = await env.DB.batch([ #### Parameters - statements: - - An array of `db.prepare()` statements. + - An array of [`D1PreparedStatement`](#prepare)s. #### Return values - results: - - An array of `D1Result` objects containing the results of the `.db.prepare()` statements. Each object is in the array position corresponding to the array position of the initial `db.prepare()` statement within the `statementArray`. + - An array of `D1Result` objects containing the results of the `D1Database::prepare` statements. Each object is in the array position corresponding to the array position of the initial `D1Database::prepare` statement within the `statements`. - Refer to [`D1Result`](/d1/worker-api/return-object/#d1result) for more information about this object.
@@ -209,7 +209,7 @@ console.log(stmt[1].results); return Response.json(batchResult); ``` -### `db.exec()` +### `exec()` Executes one or more queries directly without prepared statements or parameter bindings. @@ -219,7 +219,7 @@ const returnValue = await env.DB.exec(`SELECT * FROM Customers WHERE CompanyName #### Parameters -- queryString: +- query: - The SQL query statement without parameter binding. #### Return values @@ -249,7 +249,7 @@ return Response.json(returnValue); - Only use this method for maintenance and one-shot tasks (for example, migration jobs). - The input can be one or multiple queries separated by `\n`. -### `db.dump` +### `dump` :::caution This API only works on databases created during D1's alpha period. Check which version your database uses with `wrangler d1 info `. diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index 47b248761835e92..a215a15dadb3a46 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -9,8 +9,8 @@ import { DirectoryListing, Details, Steps } from "~/components"; You can execute SQL queries on your D1 database from a Worker using the Worker Binding API. To do this, you can perform the following steps: -1. [Bind the D1 Database](/d1/worker-api/d1-binding). -2. [Prepare a statement](/d1/worker-api/d1-binding/#dbprepare). +1. [Bind the D1 Database](/d1/worker-api/d1-database). +2. [Prepare a statement](/d1/worker-api/d1-database/#dbprepare). 3. [Run the prepared statement](/d1/worker-api/prepared-statements). 4. Analyze the [return object](/d1/worker-api/return-object) (if necessary). @@ -20,9 +20,9 @@ Refer to the relevant sections for the API documentation. D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional `type parameter` so that a function understands the type of the data it is handling. -When using the [query statement methods](/d1/worker-api/prepared-statements) `stmt.run()`, `stmt.raw()` and `stmt.first()`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +When using the [query statement methods](/d1/worker-api/prepared-statements) `D1PreparedStatement::run`, `D1PreparedStatement::raw` and `D1PreparedStatement::first`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. -For example, providing an `OrderRow` type as a type parameter to `stmt.run()` will return a typed `Array` object instead of the default `Record` type: +For example, providing an `OrderRow` type as a type parameter to `D1PreparedStatement::run` will return a typed `Array` object instead of the default `Record` type: ```ts // Row definition diff --git a/src/content/docs/d1/worker-api/prepared-statements.mdx b/src/content/docs/d1/worker-api/prepared-statements.mdx index 511ce69a2726566..087ac2bfa7c9273 100644 --- a/src/content/docs/d1/worker-api/prepared-statements.mdx +++ b/src/content/docs/d1/worker-api/prepared-statements.mdx @@ -7,11 +7,11 @@ sidebar: import { Type, MetaInfo, Details } from "~/components"; -This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/d1-binding/#dbprepare). +This chapter documents the various ways you can run and retrieve the results of a query after you have [prepared your statement](/d1/worker-api/d1-database/#dbprepare). ## Methods -### `stmt.run()` +### `run()` Runs the prepared query (or queries) and returns results. The returned results includes metadata. @@ -70,8 +70,8 @@ return Response.json(returnValue); #### Guidance - `results` is empty for write operations such as `UPDATE`, `DELETE`, or `INSERT`. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `run()` to return a typed result object. -- `stmt.run()` is functionally equivalent to `stmt.all()`, and can be treated as an alias. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::run` to return a typed result object. +- `D1PreparedStatement::run` is functionally equivalent to `D1PreparedStatement::all`, and can be treated as an alias. - You can choose to extract only the results you expect from the statement by simply returning the `results` property of the return object.
@@ -94,7 +94,7 @@ return Response.json(returnValue.results); ```
-### `stmt.raw()` +### `raw()` Runs the prepared query (or queries), and returns the results as an array of arrays. The returned results do not include metadata. @@ -106,8 +106,8 @@ const returnValue = await stmt.raw(); #### Parameters -- columnNames: - - A boolean flag which includes column names as the first row of the result array. +- columnNames: + - A boolean object which includes column names as the first row of the result array. #### Return values @@ -118,7 +118,7 @@ const returnValue = await stmt.raw(); ```js const someVariable = `Bs Beverages`; const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); -const returnValue = await stmt.raw(); // columnName not specified +const returnValue = await stmt.raw(); return Response.json(returnValue); ``` ```js output @@ -158,9 +158,9 @@ return Response.json(returnValue) #### Guidance -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `raw()` to return a typed result array. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::raw` to return a typed result array. -### `stmt.first()` +### `first()` Runs the prepared query (or queries), and returns the first row of the query result as an object. This does not return any metadata. Instead, it directly returns the object. @@ -177,8 +177,9 @@ const values = await stmt.first(); #### Return values -- firstRow: +- firstRow: - An object containing the first row of the query result. + - The return value will be further filtered to a specific attribute if `columnName` was specified. - `null`: - If the query returns no rows. @@ -216,7 +217,7 @@ return Response.json(returnValue) #### Guidance -- If the query returns rows but `column` does not exist, then `first()` throws the `D1_ERROR` exception. -- `stmt.first()` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `first()` to return a typed result object. +- If the query returns rows but `column` does not exist, then `D1PreparedStatement::first` throws the `D1_ERROR` exception. +- `D1PreparedStatement::first` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::first` to return a typed result object. diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index 2d7c5c9c31fb442..42cbcec90844d74 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -7,14 +7,14 @@ sidebar: Some D1 Worker Binding APIs return a typed object. -| D1 Worker Binding API | Return object | -| ------------------------- | ------------- | -| `stmt.run()`, `db.batch()`| `D1Result` | -| `db.exec()` | `D1ExecResult`| +| D1 Worker Binding API | Return object | +| ---------------------------------------------- | ------------- | +| `D1PreparedStatement::run`, `D1Database::batch`| `D1Result` | +| `D1Database::exec` | `D1ExecResult`| ## D1Result -The methods `stmt.run()` and `db.batch()` return a typed `D1Result` object for each query statement. This object contains: +The methods `D1PreparedStatement::run` and `D1Database::batch` return a typed `D1Result` object for each query statement. This object contains: - The success status - A meta object with the internal duration of the operation in milliseconds @@ -75,7 +75,7 @@ return Response.json(result) ## D1ExecResult -The method `db.exec()` returns a typed `D1ExecResult` object for each query statement. This object contains: +The method `D1Database::exec` returns a typed `D1ExecResult` object for each query statement. This object contains: - The number of executed queries - The duration of the operation in milliseconds From 236aad993f2871ae1c4cd908bba1524c6ff59780 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Tue, 19 Nov 2024 17:06:21 +0000 Subject: [PATCH 33/33] Turning all method names into links to the relevant header. --- src/content/docs/d1/worker-api/d1-database.mdx | 4 ++-- src/content/docs/d1/worker-api/index.mdx | 4 ++-- .../docs/d1/worker-api/prepared-statements.mdx | 12 ++++++------ src/content/docs/d1/worker-api/return-object.mdx | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/content/docs/d1/worker-api/d1-database.mdx b/src/content/docs/d1/worker-api/d1-database.mdx index 85640817acfadbe..98a3992b56582a3 100644 --- a/src/content/docs/d1/worker-api/d1-database.mdx +++ b/src/content/docs/d1/worker-api/d1-database.mdx @@ -46,7 +46,7 @@ const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bin | `?NNN` | Ordered | A question mark followed by a number `NNN` holds a spot for the `NNN`-th parameter. `NNN` must be between `1` and `SQLITE_MAX_VARIABLE_NUMBER` | | `?` | Anonymous | A question mark that is not followed by a number creates a parameter with a number one greater than the largest parameter number already assigned. If this means the parameter number is greater than `SQLITE_MAX_VARIABLE_NUMBER`, it is an error. This parameter format is provided for compatibility with other database engines. But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the `?NNN` format above instead. | - To bind a parameter, use the `D1PreparedStatement::bind` method. + To bind a parameter, use the `.bind` method. Order and anonymous examples: @@ -117,7 +117,7 @@ const batchResult = await env.DB.batch([ #### Return values - results: - - An array of `D1Result` objects containing the results of the `D1Database::prepare` statements. Each object is in the array position corresponding to the array position of the initial `D1Database::prepare` statement within the `statements`. + - An array of `D1Result` objects containing the results of the [`D1Database::prepare`](#prepare) statements. Each object is in the array position corresponding to the array position of the initial [`D1Database::prepare`](#prepare) statement within the `statements`. - Refer to [`D1Result`](/d1/worker-api/return-object/#d1result) for more information about this object.
diff --git a/src/content/docs/d1/worker-api/index.mdx b/src/content/docs/d1/worker-api/index.mdx index a215a15dadb3a46..268f4d4d1172e14 100644 --- a/src/content/docs/d1/worker-api/index.mdx +++ b/src/content/docs/d1/worker-api/index.mdx @@ -20,9 +20,9 @@ Refer to the relevant sections for the API documentation. D1 Worker Bindings API is fully-typed via the [`@cloudflare/workers-types`](/workers/languages/typescript/#typescript) package, and also supports [generic types](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types) as part of its TypeScript API. A generic type allows you to provide an optional `type parameter` so that a function understands the type of the data it is handling. -When using the [query statement methods](/d1/worker-api/prepared-statements) `D1PreparedStatement::run`, `D1PreparedStatement::raw` and `D1PreparedStatement::first`, you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. +When using the query statement methods [`D1PreparedStatement::run`](/d1/worker-api/prepared-statements/#run), [`D1PreparedStatement::raw`](/d1/worker-api/prepared-statements/#raw) and [`D1PreparedStatement::first`](/d1/worker-api/prepared-statements/#first), you can provide a type representing each database row. D1's API will [return the result object](#return-object) with the correct type. -For example, providing an `OrderRow` type as a type parameter to `D1PreparedStatement::run` will return a typed `Array` object instead of the default `Record` type: +For example, providing an `OrderRow` type as a type parameter to [`D1PreparedStatement::run`](/d1/worker-api/prepared-statements/#run) will return a typed `Array` object instead of the default `Record` type: ```ts // Row definition diff --git a/src/content/docs/d1/worker-api/prepared-statements.mdx b/src/content/docs/d1/worker-api/prepared-statements.mdx index 087ac2bfa7c9273..6eb13db7d62de8f 100644 --- a/src/content/docs/d1/worker-api/prepared-statements.mdx +++ b/src/content/docs/d1/worker-api/prepared-statements.mdx @@ -70,8 +70,8 @@ return Response.json(returnValue); #### Guidance - `results` is empty for write operations such as `UPDATE`, `DELETE`, or `INSERT`. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::run` to return a typed result object. -- `D1PreparedStatement::run` is functionally equivalent to `D1PreparedStatement::all`, and can be treated as an alias. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to [`D1PreparedStatement::run`](#run) to return a typed result object. +- [`D1PreparedStatement::run`](#run) is functionally equivalent to `D1PreparedStatement::all`, and can be treated as an alias. - You can choose to extract only the results you expect from the statement by simply returning the `results` property of the return object.
@@ -158,7 +158,7 @@ return Response.json(returnValue) #### Guidance -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::raw` to return a typed result array. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to [`D1PreparedStatement::raw`](#raw) to return a typed result array. ### `first()` @@ -217,7 +217,7 @@ return Response.json(returnValue) #### Guidance -- If the query returns rows but `column` does not exist, then `D1PreparedStatement::first` throws the `D1_ERROR` exception. -- `D1PreparedStatement::first` does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. -- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to `D1PreparedStatement::first` to return a typed result object. +- If the query returns rows but `column` does not exist, then [`D1PreparedStatement::first`](#first) throws the `D1_ERROR` exception. +- [`D1PreparedStatement::first`](#first) does not alter the SQL query. To improve performance, consider appending `LIMIT 1` to your statement. +- When using TypeScript, you can pass a [type parameter](/d1/build-with-d1/d1-client-api/#typescript-support) to [`D1PreparedStatement::first`](#first) to return a typed result object. diff --git a/src/content/docs/d1/worker-api/return-object.mdx b/src/content/docs/d1/worker-api/return-object.mdx index 42cbcec90844d74..85dd2448b365499 100644 --- a/src/content/docs/d1/worker-api/return-object.mdx +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -7,14 +7,14 @@ sidebar: Some D1 Worker Binding APIs return a typed object. -| D1 Worker Binding API | Return object | -| ---------------------------------------------- | ------------- | -| `D1PreparedStatement::run`, `D1Database::batch`| `D1Result` | -| `D1Database::exec` | `D1ExecResult`| +| D1 Worker Binding API | Return object | +| ------------------------------------------------------------------------------------------------------------------------------ | ------------- | +| [`D1PreparedStatement::run`](/d1/worker-api/prepared-statements/#run), [`D1Database::batch`](/d1/worker-api/d1-database/#batch)| `D1Result` | +| [`D1Database::exec`](/d1/worker-api/d1-database/#exec) | `D1ExecResult`| ## D1Result -The methods `D1PreparedStatement::run` and `D1Database::batch` return a typed `D1Result` object for each query statement. This object contains: +The methods [`D1PreparedStatement::run`](/d1/worker-api/prepared-statements/#run) and [`D1Database::batch`](/d1/worker-api/d1-database/#batch) return a typed [`D1Result`](#d1result) object for each query statement. This object contains: - The success status - A meta object with the internal duration of the operation in milliseconds @@ -75,7 +75,7 @@ return Response.json(result) ## D1ExecResult -The method `D1Database::exec` returns a typed `D1ExecResult` object for each query statement. This object contains: +The method [`D1Database::exec`](/d1/worker-api/d1-database/#exec) returns a typed [`D1ExecResult`](#d1execresult) object for each query statement. This object contains: - The number of executed queries - The duration of the operation in milliseconds