Skip to content

Commit f080721

Browse files
Renegade334aduh95
authored andcommitted
doc: correct and expand documentation for SQLTagStore
PR-URL: #60200 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent be3d267 commit f080721

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
@@ -463,15 +463,68 @@ added: v24.9.0
463463
**Default:** `1000`.
464464
* Returns: {SQLTagStore} A new SQL tag store for caching prepared statements.
465465

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

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

476529
```mjs
477530
import { DatabaseSync } from 'node:sqlite';
@@ -927,65 +980,86 @@ added: v24.9.0
927980
This class represents a single LRU (Least Recently Used) cache for storing
928981
prepared statements.
929982

930-
Instances of this class are created via the database.createTagStore() method,
931-
not by using a constructor. The store caches prepared statements based on the
932-
provided SQL query string. When the same query is seen again, the store
983+
Instances of this class are created via the [`database.createTagStore()`][]
984+
method, not by using a constructor. The store caches prepared statements based
985+
on the provided SQL query string. When the same query is seen again, the store
933986
retrieves the cached statement and safely applies the new values through
934987
parameter binding, thereby preventing attacks like SQL injection.
935988

936989
The cache has a maxSize that defaults to 1000 statements, but a custom size can
937-
be provided (e.g., database.createTagStore(100)). All APIs exposed by this
990+
be provided (e.g., `database.createTagStore(100)`). All APIs exposed by this
938991
class execute synchronously.
939992

940-
### `sqlTagStore.all(sqlTemplate[, ...values])`
993+
### `sqlTagStore.all(stringElements[, ...boundParameters])`
941994

942995
<!-- YAML
943996
added: v24.9.0
944997
-->
945998

946-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
947-
* `...values` {any} Values to be interpolated into the template literal.
999+
* `stringElements` {string\[]} Template literal elements containing the SQL
1000+
query.
1001+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1002+
Parameter values to be bound to placeholders in the template string.
9481003
* Returns: {Array} An array of objects representing the rows returned by the query.
9491004

950-
Executes the given SQL query and returns all resulting rows as an array of objects.
1005+
Executes the given SQL query and returns all resulting rows as an array of
1006+
objects.
9511007

952-
### `sqlTagStore.get(sqlTemplate[, ...values])`
1008+
This function is intended to be used as a template literal tag, not to be
1009+
called directly.
1010+
1011+
### `sqlTagStore.get(stringElements[, ...boundParameters])`
9531012

9541013
<!-- YAML
9551014
added: v24.9.0
9561015
-->
9571016

958-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
959-
* `...values` {any} Values to be interpolated into the template literal.
1017+
* `stringElements` {string\[]} Template literal elements containing the SQL
1018+
query.
1019+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1020+
Parameter values to be bound to placeholders in the template string.
9601021
* Returns: {Object | undefined} An object representing the first row returned by
9611022
the query, or `undefined` if no rows are returned.
9621023

9631024
Executes the given SQL query and returns the first resulting row as an object.
9641025

965-
### `sqlTagStore.iterate(sqlTemplate[, ...values])`
1026+
This function is intended to be used as a template literal tag, not to be
1027+
called directly.
1028+
1029+
### `sqlTagStore.iterate(stringElements[, ...boundParameters])`
9661030

9671031
<!-- YAML
9681032
added: v24.9.0
9691033
-->
9701034

971-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
972-
* `...values` {any} Values to be interpolated into the template literal.
1035+
* `stringElements` {string\[]} Template literal elements containing the SQL
1036+
query.
1037+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1038+
Parameter values to be bound to placeholders in the template string.
9731039
* Returns: {Iterator} An iterator that yields objects representing the rows returned by the query.
9741040

9751041
Executes the given SQL query and returns an iterator over the resulting rows.
9761042

977-
### `sqlTagStore.run(sqlTemplate[, ...values])`
1043+
This function is intended to be used as a template literal tag, not to be
1044+
called directly.
1045+
1046+
### `sqlTagStore.run(stringElements[, ...boundParameters])`
9781047

9791048
<!-- YAML
9801049
added: v24.9.0
9811050
-->
9821051

983-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
984-
* `...values` {any} Values to be interpolated into the template literal.
1052+
* `stringElements` {string\[]} Template literal elements containing the SQL
1053+
query.
1054+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
1055+
Parameter values to be bound to placeholders in the template string.
9851056
* Returns: {Object} An object containing information about the execution, including `changes` and `lastInsertRowid`.
9861057

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

1060+
This function is intended to be used as a template literal tag, not to be
1061+
called directly.
1062+
9891063
### `sqlTagStore.size()`
9901064

9911065
<!-- YAML
@@ -1002,7 +1076,7 @@ A read-only property that returns the number of prepared statements currently in
10021076
added: v24.9.0
10031077
-->
10041078

1005-
* Returns: {integer} The maximum number of prepared statements the cache can hold.
1079+
* Type: {integer}
10061080

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

@@ -1012,25 +1086,17 @@ A read-only property that returns the maximum number of prepared statements the
10121086
added: v24.9.0
10131087
-->
10141088

1015-
* {DatabaseSync} The `DatabaseSync` instance that created this `SQLTagStore`.
1089+
* Type: {DatabaseSync}
10161090

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

1019-
### `sqlTagStore.reset()`
1020-
1021-
<!-- YAML
1022-
added: v24.9.0
1023-
-->
1024-
1025-
Resets the LRU cache, clearing all stored prepared statements.
1026-
10271093
### `sqlTagStore.clear()`
10281094

10291095
<!-- YAML
10301096
added: v24.9.0
10311097
-->
10321098

1033-
An alias for `sqlTagStore.reset()`.
1099+
Resets the LRU cache, clearing all stored prepared statements.
10341100

10351101
### Type conversion between JavaScript and SQLite
10361102

@@ -1370,7 +1436,9 @@ callback function to indicate what type of operation is being authorized.
13701436
[`SQLITE_DETERMINISTIC`]: https://www.sqlite.org/c3ref/c_deterministic.html
13711437
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html
13721438
[`SQLITE_MAX_FUNCTION_ARG`]: https://www.sqlite.org/limits.html#max_function_arg
1439+
[`SQLTagStore`]: #class-sqltagstore
13731440
[`database.applyChangeset()`]: #databaseapplychangesetchangeset-options
1441+
[`database.createTagStore()`]: #databasecreatetagstoremaxsize
13741442
[`database.setAuthorizer()`]: #databasesetauthorizercallback
13751443
[`sqlite3_backup_finish()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
13761444
[`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)