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/configuration/index.mdx b/src/content/docs/d1/configuration/index.mdx index 92b68dab0bdd2de..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: 4 + 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 49a368c3b69d2bc..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: 8 + order: 10 --- diff --git a/src/content/docs/d1/examples/index.mdx b/src/content/docs/d1/examples/index.mdx index 2e23581cbb5b6f5..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: 6 + order: 8 group: hideIndex: true --- diff --git a/src/content/docs/d1/get-started.mdx b/src/content/docs/d1/get-started.mdx index 2f95990dc57e1d0..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 @@ -532,5 +536,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 [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/observability/index.mdx b/src/content/docs/d1/observability/index.mdx index 7bc6b5bc6c2436f..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: 5 + order: 7 group: hideIndex: true --- diff --git a/src/content/docs/d1/platform/index.mdx b/src/content/docs/d1/platform/index.mdx index fe7a16eca104db5..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: 8 + order: 10 group: hideIndex: true --- diff --git a/src/content/docs/d1/reference/index.mdx b/src/content/docs/d1/reference/index.mdx index 3daad7052a171b2..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: 9 + order: 11 group: hideIndex: true --- 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 66% rename from src/content/docs/d1/reference/sql-statements.mdx rename to src/content/docs/d1/sql-api/sql-statements.mdx index c7dc8e8c331b64d..06d3efbb51c2e3c 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 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. -## 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 Worker Bindings API](/d1/worker-api/d1-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. +## Supported SQLite extensions -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 a subset of SQLite extensions for added functionality, including: + +- Default SQLite extensions. +- [FTS5 module](https://www.sqlite.org/fts5.html) for full-text search. + +## Compatible PRAGMA statements + +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). +- 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,11 +55,21 @@ SELECT name, sql FROM sqlite_master } ``` -## SQLite Extensions +## Search with LIKE -D1 supports a subset of SQLite extensions for added functionality, including: +You can perform a search using SQL's `LIKE` operator: -- [FTS5 module](https://www.sqlite.org/fts5.html) for full-text search +```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 diff --git a/src/content/docs/d1/tutorials/index.mdx b/src/content/docs/d1/tutorials/index.mdx index 40b4db6dc9ddf3f..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: 7 + order: 9 --- diff --git a/src/content/docs/d1/worker-api/d1-database.mdx b/src/content/docs/d1/worker-api/d1-database.mdx new file mode 100644 index 000000000000000..98a3992b56582a3 --- /dev/null +++ b/src/content/docs/d1/worker-api/d1-database.mdx @@ -0,0 +1,276 @@ +--- +title: D1 Database +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 + +### `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 + +- query: + - 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 `.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. +``` + +### `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 `D1Database::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 [`D1PreparedStatement`](#prepare)s. + +#### Return values + +- results: + - 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. + +
+ +```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); + ``` + +### `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 + +- query: + - 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`. + +### `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 new file mode 100644 index 000000000000000..268f4d4d1172e14 --- /dev/null +++ b/src/content/docs/d1/worker-api/index.mdx @@ -0,0 +1,138 @@ +--- +pcx_content_type: navigation +title: Worker Binding API +sidebar: + order: 4 +--- + +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-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). + +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. + +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`](/d1/worker-api/prepared-statements/#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 code below to view the effect of each API. + +
+```js +export default { + 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 = ?`); + + 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) + ]); + return Response.json(batchResult); + + } 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.`, + ); + }, +}; + +``` +
+ +### 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/prepared-statements.mdx b/src/content/docs/d1/worker-api/prepared-statements.mdx new file mode 100644 index 000000000000000..6eb13db7d62de8f --- /dev/null +++ b/src/content/docs/d1/worker-api/prepared-statements.mdx @@ -0,0 +1,223 @@ +--- +title: Prepared statement methods +pcx_content_type: concept +sidebar: + order: 2 +--- + +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-database/#dbprepare). + +## Methods + +### `run()` + +Runs the prepared query (or queries) and returns results. The returned results includes metadata. + +```js +const returnValue = await stmt.run(); +``` + +#### Parameter + +- None. + +#### Return value + +- 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). + +
+```js +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 +{ + "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" + } + ] +} +``` +
+ +#### 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`](#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. + +
+```js +return Response.json(returnValue.results); +``` +```js output +[ + { + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" + }, + { + "CustomerId": 13, + "CompanyName": "Bs Beverages", + "ContactName": "Random Name" + } +] +``` +
+ +### `raw()` + +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 returnValue = await stmt.raw(); +``` + +#### Parameters + +- columnNames: + - A boolean object which includes column names as the first row of the result array. + +#### Return values + +- Array: + - An array of arrays. Each sub-array represents a row. + +
+```js +const someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.raw(); +return Response.json(returnValue); +``` +```js output +[ + [11, "Bs Beverages", + "Victoria Ashworth" + ], + [13, "Bs Beverages", + "Random Name" + ] +] +``` + +With parameter `columnNames: true`: +```js +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 +[ + [ + "CustomerId", + "CompanyName", + "ContactName" + ], + [11, "Bs Beverages", + "Victoria Ashworth" + ], + [13, "Bs Beverages", + "Random Name" + ] +] +``` +
+ +#### Guidance + +- 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()` + +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(); +``` + +#### Parameters + +- columnName: + - 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. + +#### Return values + +- 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. + +
+ +Get all the columns from the first row: + +```js +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 +{ + "CustomerId": 11, + "CompanyName": "Bs Beverages", + "ContactName": "Victoria Ashworth" +} +``` + +Get a specific column from the first row: + +```js +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 +11 +``` +
+ +#### Guidance + +- 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 new file mode 100644 index 000000000000000..85dd2448b365499 --- /dev/null +++ b/src/content/docs/d1/worker-api/return-object.mdx @@ -0,0 +1,101 @@ +--- +title: Return objects +pcx_content_type: concept +sidebar: + order: 3 +--- + +Some D1 Worker Binding APIs return a typed object. + +| 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`](/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 +- The results (if applicable) as an array + +```js +{ + success: boolean, // true if the operation was successful, false otherwise + meta: { + 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 someVariable = `Bs Beverages`; +const stmt = env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind(someVariable); +const returnValue = await stmt.run(); +return Response.json(result) +``` +```js +{ + "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" + } + ] +} +``` + +## D1ExecResult + +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 + +```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/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