Skip to content

Commit 98bd239

Browse files
committed
doc: correct and expand documentation for SQLTagStore
1 parent d54e6ae commit 98bd239

File tree

2 files changed

+115
-49
lines changed

2 files changed

+115
-49
lines changed

doc/api/sqlite.md

Lines changed: 115 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -446,15 +446,68 @@ added: v24.9.0
446446
**Default:** `1000`.
447447
* Returns: {SQLTagStore} A new SQL tag store for caching prepared statements.
448448

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

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

459512
```mjs
460513
import { DatabaseSync } from 'node:sqlite';
@@ -609,23 +662,6 @@ wrapper around [`sqlite3session_patchset()`][].
609662
Closes the session. An exception is thrown if the database or the session is not open. This method is a
610663
wrapper around [`sqlite3session_delete()`][].
611664

612-
## Class: `StatementSync`
613-
614-
<!-- YAML
615-
added: v22.5.0
616-
-->
617-
618-
This class represents a single [prepared statement][]. This class cannot be
619-
instantiated via its constructor. Instead, instances are created via the
620-
`database.prepare()` method. All APIs exposed by this class execute
621-
synchronously.
622-
623-
A prepared statement is an efficient binary representation of the SQL used to
624-
create it. Prepared statements are parameterizable, and can be invoked multiple
625-
times with different bound values. Parameters also offer protection against
626-
[SQL injection][] attacks. For these reasons, prepared statements are preferred
627-
over hand-crafted SQL strings when handling user input.
628-
629665
## Class: `SQLTagStore`
630666

631667
<!-- YAML
@@ -635,65 +671,86 @@ added: v24.9.0
635671
This class represents a single LRU (Least Recently Used) cache for storing
636672
prepared statements.
637673

638-
Instances of this class are created via the database.createTagStore() method,
639-
not by using a constructor. The store caches prepared statements based on the
640-
provided SQL query string. When the same query is seen again, the store
674+
Instances of this class are created via the [`database.createTagStore()`][]
675+
method, not by using a constructor. The store caches prepared statements based
676+
on the provided SQL query string. When the same query is seen again, the store
641677
retrieves the cached statement and safely applies the new values through
642678
parameter binding, thereby preventing attacks like SQL injection.
643679

644680
The cache has a maxSize that defaults to 1000 statements, but a custom size can
645-
be provided (e.g., database.createTagStore(100)). All APIs exposed by this
681+
be provided (e.g., `database.createTagStore(100)`). All APIs exposed by this
646682
class execute synchronously.
647683

648-
### `sqlTagStore.all(sqlTemplate[, ...values])`
684+
### `sqlTagStore.all(stringElements[, ...boundParameters])`
649685

650686
<!-- YAML
651687
added: v24.9.0
652688
-->
653689

654-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
655-
* `...values` {any} Values to be interpolated into the template literal.
690+
* `stringElements` {string\[]} Template literal elements containing the SQL
691+
query.
692+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
693+
Parameter values to be bound to placeholders in the template string.
656694
* Returns: {Array} An array of objects representing the rows returned by the query.
657695

658-
Executes the given SQL query and returns all resulting rows as an array of objects.
696+
Executes the given SQL query and returns all resulting rows as an array of
697+
objects.
698+
699+
This function is intended to be used as a template literal tag, not to be
700+
called directly.
659701

660-
### `sqlTagStore.get(sqlTemplate[, ...values])`
702+
### `sqlTagStore.get(stringElements[, ...boundParameters])`
661703

662704
<!-- YAML
663705
added: v24.9.0
664706
-->
665707

666-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
667-
* `...values` {any} Values to be interpolated into the template literal.
708+
* `stringElements` {string\[]} Template literal elements containing the SQL
709+
query.
710+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
711+
Parameter values to be bound to placeholders in the template string.
668712
* Returns: {Object | undefined} An object representing the first row returned by
669713
the query, or `undefined` if no rows are returned.
670714

671715
Executes the given SQL query and returns the first resulting row as an object.
672716

673-
### `sqlTagStore.iterate(sqlTemplate[, ...values])`
717+
This function is intended to be used as a template literal tag, not to be
718+
called directly.
719+
720+
### `sqlTagStore.iterate(stringElements[, ...boundParameters])`
674721

675722
<!-- YAML
676723
added: v24.9.0
677724
-->
678725

679-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
680-
* `...values` {any} Values to be interpolated into the template literal.
726+
* `stringElements` {string\[]} Template literal elements containing the SQL
727+
query.
728+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
729+
Parameter values to be bound to placeholders in the template string.
681730
* Returns: {Iterator} An iterator that yields objects representing the rows returned by the query.
682731

683732
Executes the given SQL query and returns an iterator over the resulting rows.
684733

685-
### `sqlTagStore.run(sqlTemplate[, ...values])`
734+
This function is intended to be used as a template literal tag, not to be
735+
called directly.
736+
737+
### `sqlTagStore.run(stringElements[, ...boundParameters])`
686738

687739
<!-- YAML
688740
added: v24.9.0
689741
-->
690742

691-
* `sqlTemplate` {Template Literal} A template literal containing the SQL query.
692-
* `...values` {any} Values to be interpolated into the template literal.
743+
* `stringElements` {string\[]} Template literal elements containing the SQL
744+
query.
745+
* `...boundParameters` {null|number|bigint|string|Buffer|TypedArray|DataView}
746+
Parameter values to be bound to placeholders in the template string.
693747
* Returns: {Object} An object containing information about the execution, including `changes` and `lastInsertRowid`.
694748

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

751+
This function is intended to be used as a template literal tag, not to be
752+
called directly.
753+
697754
### `sqlTagStore.size()`
698755

699756
<!-- YAML
@@ -710,7 +767,7 @@ A read-only property that returns the number of prepared statements currently in
710767
added: v24.9.0
711768
-->
712769

713-
* Returns: {integer} The maximum number of prepared statements the cache can hold.
770+
* Type: {integer}
714771

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

@@ -720,25 +777,34 @@ A read-only property that returns the maximum number of prepared statements the
720777
added: v24.9.0
721778
-->
722779

723-
* {DatabaseSync} The `DatabaseSync` instance that created this `SQLTagStore`.
780+
* Type: {DatabaseSync}
724781

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

727-
### `sqlTagStore.reset()`
784+
### `sqlTagStore.clear()`
728785

729786
<!-- YAML
730787
added: v24.9.0
731788
-->
732789

733790
Resets the LRU cache, clearing all stored prepared statements.
734791

735-
### `sqlTagStore.clear()`
792+
## Class: `StatementSync`
736793

737794
<!-- YAML
738-
added: v24.9.0
795+
added: v22.5.0
739796
-->
740797

741-
An alias for `sqlTagStore.reset()`.
798+
This class represents a single [prepared statement][]. This class cannot be
799+
instantiated via its constructor. Instead, instances are created via the
800+
`database.prepare()` method. All APIs exposed by this class execute
801+
synchronously.
802+
803+
A prepared statement is an efficient binary representation of the SQL used to
804+
create it. Prepared statements are parameterizable, and can be invoked multiple
805+
times with different bound values. Parameters also offer protection against
806+
[SQL injection][] attacks. For these reasons, prepared statements are preferred
807+
over hand-crafted SQL strings when handling user input.
742808

743809
### `statement.all([namedParameters][, ...anonymousParameters])`
744810

@@ -1309,7 +1375,9 @@ callback function to indicate what type of operation is being authorized.
13091375
[`SQLITE_DETERMINISTIC`]: https://www.sqlite.org/c3ref/c_deterministic.html
13101376
[`SQLITE_DIRECTONLY`]: https://www.sqlite.org/c3ref/c_deterministic.html
13111377
[`SQLITE_MAX_FUNCTION_ARG`]: https://www.sqlite.org/limits.html#max_function_arg
1378+
[`SQLTagStore`]: #class-sqltagstore
13121379
[`database.applyChangeset()`]: #databaseapplychangesetchangeset-options
1380+
[`database.createTagStore()`]: #databasecreatetagstoremaxsize
13131381
[`database.setAuthorizer()`]: #databasesetauthorizercallback
13141382
[`sqlite3_backup_finish()`]: https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
13151383
[`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)