Skip to content

Commit 1ce22dd

Browse files
authored
doc: correct and expand documentation for SQLTagStore
PR-URL: #60200 Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 478a5e6 commit 1ce22dd

File tree

2 files changed

+103
-37
lines changed

2 files changed

+103
-37
lines changed

doc/api/sqlite.md

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,68 @@ added: v24.9.0
473473
**Default:** `1000`.
474474
* Returns: {SQLTagStore} A new SQL tag store for caching prepared statements.
475475

476-
Creates a new `SQLTagStore`, which is an LRU (Least Recently Used) cache for
477-
storing prepared statements. This allows for the efficient reuse of prepared
478-
statements by tagging them with a unique identifier.
476+
Creates a new [`SQLTagStore`][], which is a Least Recently Used (LRU) cache
477+
for storing prepared statements. This allows for the efficient reuse of
478+
prepared statements by tagging them with a unique identifier.
479479

480480
When a tagged SQL literal is executed, the `SQLTagStore` checks if a prepared
481-
statement for that specific SQL string already exists in the cache. If it does,
482-
the cached statement is used. If not, a new prepared statement is created,
483-
executed, and then stored in the cache for future use. This mechanism helps to
484-
avoid the overhead of repeatedly parsing and preparing the same SQL statements.
481+
statement for the corresponding SQL query string already exists in the cache.
482+
If it does, the cached statement is used. If not, a new prepared statement is
483+
created, executed, and then stored in the cache for future use. This mechanism
484+
helps to avoid the overhead of repeatedly parsing and preparing the same SQL
485+
statements.
486+
487+
Tagged statements bind the placeholder values from the template literal as
488+
parameters to the underlying prepared statement. For example:
489+
490+
```js
491+
sqlTagStore.get`SELECT ${value}`;
492+
```
493+
494+
is equivalent to:
495+
496+
```js
497+
db.prepare('SELECT ?').get(value);
498+
```
499+
500+
However, in the first example, the tag store will cache the underlying prepared
501+
statement for future use.
502+
503+
> **Note:** The `${value}` syntax in tagged statements _binds_ a parameter to
504+
> the prepared statement. This differs from its behavior in _untagged_ template
505+
> literals, where it performs string interpolation.
506+
>
507+
> ```js
508+
> // This a safe example of binding a parameter to a tagged statement.
509+
> sqlTagStore.run`INSERT INTO t1 (id) VALUES (${id})`;
510+
>
511+
> // This is an *unsafe* example of an untagged template string.
512+
> // `id` is interpolated into the query text as a string.
513+
> // This can lead to SQL injection and data corruption.
514+
> db.run(`INSERT INTO t1 (id) VALUES (${id})`);
515+
> ```
516+
517+
The tag store will match a statement from the cache if the query strings
518+
(including the positions of any bound placeholders) are identical.
519+
520+
```js
521+
// The following statements will match in the cache:
522+
sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`;
523+
sqlTagStore.get`SELECT * FROM t1 WHERE id = ${12345} AND active = 1`;
524+
525+
// The following statements will not match, as the query strings
526+
// and bound placeholders differ:
527+
sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`;
528+
sqlTagStore.get`SELECT * FROM t1 WHERE id = 12345 AND active = 1`;
529+
530+
// The following statements will not match, as matches are case-sensitive:
531+
sqlTagStore.get`SELECT * FROM t1 WHERE id = ${id} AND active = 1`;
532+
sqlTagStore.get`select * from t1 where id = ${id} and active = 1`;
533+
```
534+
535+
The only way of binding parameters in tagged statements is with the `${value}`
536+
syntax. Do not add parameter binding placeholders (`?` etc.) to the SQL query
537+
string itself.
485538

486539
```mjs
487540
import { DatabaseSync } from 'node:sqlite';
@@ -941,65 +994,86 @@ added: v24.9.0
941994
This class represents a single LRU (Least Recently Used) cache for storing
942995
prepared statements.
943996

944-
Instances of this class are created via the database.createTagStore() method,
945-
not by using a constructor. The store caches prepared statements based on the
946-
provided SQL query string. When the same query is seen again, the store
997+
Instances of this class are created via the [`database.createTagStore()`][]
998+
method, not by using a constructor. The store caches prepared statements based
999+
on the provided SQL query string. When the same query is seen again, the store
9471000
retrieves the cached statement and safely applies the new values through
9481001
parameter binding, thereby preventing attacks like SQL injection.
9491002

9501003
The cache has a maxSize that defaults to 1000 statements, but a custom size can
951-
be provided (e.g., database.createTagStore(100)). All APIs exposed by this
1004+
be provided (e.g., `database.createTagStore(100)`). All APIs exposed by this
9521005
class execute synchronously.
9531006

954-
### `sqlTagStore.all(sqlTemplate[, ...values])`
1007+
### `sqlTagStore.all(stringElements[, ...boundParameters])`
9551008

9561009
<!-- YAML
9571010
added: v24.9.0
9581011
-->
9591012

960-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
961-
* `...values` {any} Values to be interpolated into the template literal.
1013+
* `stringElements` {string\[]} Template literal elements containing the SQL
1014+
query.
1015+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1016+
Parameter values to be bound to placeholders in the template string.
9621017
* Returns: {Array} An array of objects representing the rows returned by the query.
9631018

964-
Executes the given SQL query and returns all resulting rows as an array of objects.
1019+
Executes the given SQL query and returns all resulting rows as an array of
1020+
objects.
9651021

966-
### `sqlTagStore.get(sqlTemplate[, ...values])`
1022+
This function is intended to be used as a template literal tag, not to be
1023+
called directly.
1024+
1025+
### `sqlTagStore.get(stringElements[, ...boundParameters])`
9671026

9681027
<!-- YAML
9691028
added: v24.9.0
9701029
-->
9711030

972-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
973-
* `...values` {any} Values to be interpolated into the template literal.
1031+
* `stringElements` {string\[]} Template literal elements containing the SQL
1032+
query.
1033+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1034+
Parameter values to be bound to placeholders in the template string.
9741035
* Returns: {Object | undefined} An object representing the first row returned by
9751036
the query, or `undefined` if no rows are returned.
9761037

9771038
Executes the given SQL query and returns the first resulting row as an object.
9781039

979-
### `sqlTagStore.iterate(sqlTemplate[, ...values])`
1040+
This function is intended to be used as a template literal tag, not to be
1041+
called directly.
1042+
1043+
### `sqlTagStore.iterate(stringElements[, ...boundParameters])`
9801044

9811045
<!-- YAML
9821046
added: v24.9.0
9831047
-->
9841048

985-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
986-
* `...values` {any} Values to be interpolated into the template literal.
1049+
* `stringElements` {string\[]} Template literal elements containing the SQL
1050+
query.
1051+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1052+
Parameter values to be bound to placeholders in the template string.
9871053
* Returns: {Iterator} An iterator that yields objects representing the rows returned by the query.
9881054

9891055
Executes the given SQL query and returns an iterator over the resulting rows.
9901056

991-
### `sqlTagStore.run(sqlTemplate[, ...values])`
1057+
This function is intended to be used as a template literal tag, not to be
1058+
called directly.
1059+
1060+
### `sqlTagStore.run(stringElements[, ...boundParameters])`
9921061

9931062
<!-- YAML
9941063
added: v24.9.0
9951064
-->
9961065

997-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
998-
* `...values` {any} Values to be interpolated into the template literal.
1066+
* `stringElements` {string\[]} Template literal elements containing the SQL
1067+
query.
1068+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1069+
Parameter values to be bound to placeholders in the template string.
9991070
* Returns: {Object} An object containing information about the execution, including `changes` and `lastInsertRowid`.
10001071

10011072
Executes the given SQL query, which is expected to not return any rows (e.g., INSERT, UPDATE, DELETE).
10021073

1074+
This function is intended to be used as a template literal tag, not to be
1075+
called directly.
1076+
10031077
### `sqlTagStore.size()`
10041078

10051079
<!-- YAML
@@ -1016,7 +1090,7 @@ A read-only property that returns the number of prepared statements currently in
10161090
added: v24.9.0
10171091
-->
10181092

1019-
* Returns: {integer} The maximum number of prepared statements the cache can hold.
1093+
* Type: {integer}
10201094

10211095
A read-only property that returns the maximum number of prepared statements the cache can hold.
10221096

@@ -1026,25 +1100,17 @@ A read-only property that returns the maximum number of prepared statements the
10261100
added: v24.9.0
10271101
-->
10281102

1029-
* {DatabaseSync} The `DatabaseSync` instance that created this `SQLTagStore`.
1103+
* Type: {DatabaseSync}
10301104

10311105
A read-only property that returns the `DatabaseSync` object associated with this `SQLTagStore`.
10321106

1033-
### `sqlTagStore.reset()`
1034-
1035-
<!-- YAML
1036-
added: v24.9.0
1037-
-->
1038-
1039-
Resets the LRU cache, clearing all stored prepared statements.
1040-
10411107
### `sqlTagStore.clear()`
10421108

10431109
<!-- YAML
10441110
added: v24.9.0
10451111
-->
10461112

1047-
An alias for `sqlTagStore.reset()`.
1113+
Resets the LRU cache, clearing all stored prepared statements.
10481114

10491115
### Type conversion between JavaScript and SQLite
10501116

@@ -1386,7 +1452,9 @@ callback function to indicate what type of operation is being authorized.
13861452
[`SQLITE_DETERMINISTIC`]: https://www.sqlite.org/c3ref/c_deterministic.html
13871453
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html
13881454
[`SQLITE_MAX_FUNCTION_ARG`]: https://www.sqlite.org/limits.html#max_function_arg
1455+
[`SQLTagStore`]: #class-sqltagstore
13891456
[`database.applyChangeset()`]: #databaseapplychangesetchangeset-options
1457+
[`database.createTagStore()`]: #databasecreatetagstoremaxsize
13901458
[`database.setAuthorizer()`]: #databasesetauthorizercallback
13911459
[`sqlite3_backup_finish()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
13921460
[`sqlite3_backup_init()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit

tools/doc/type-parser.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ const customTypesMap = {
9696
'EncapsulatedBits': 'webcrypto.html#class-encapsulatedbits',
9797
'EncapsulatedKey': 'webcrypto.html#class-encapsulatedkey',
9898
'SubtleCrypto': 'webcrypto.html#class-subtlecrypto',
99-
'Template Literal':
100-
`${jsDocPrefix}Reference/Template_literals`,
10199
'RsaOaepParams': 'webcrypto.html#class-rsaoaepparams',
102100
'AesCtrParams': 'webcrypto.html#class-aesctrparams',
103101
'AesCbcParams': 'webcrypto.html#class-aescbcparams',

0 commit comments

Comments
 (0)