Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9a3e58a

Browse files
0hmXtargos
authored andcommitted
sqlite: add tagged template
This pr introduces the support for tagged templatesAnd an LRU to cache the templates. We introduced anew object called SqlTagStore that holds the refto Lru. This acts as the main object that allowsus to use tagged templates.PR-URL:#58748Reviewed-By: Matteo Collina <matteo.collina@gmail.com>Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com>
1 parent7aec53b commit9a3e58a

File tree

7 files changed

+1065
-116
lines changed

7 files changed

+1065
-116
lines changed

‎doc/api/sqlite.md‎

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,53 @@ added: v22.5.0
351351
Compiles a SQL statement into a[prepared statement][]. This method is a wrapper
352352
around[`sqlite3_prepare_v2()`][].
353353

354+
###`database.createSQLTagStore([maxSize])`
355+
356+
<!-- YAML
357+
added: REPLACEME
358+
-->
359+
360+
*`maxSize` {integer} The maximum number of prepared statements to cache.
361+
**Default:**`1000`.
362+
* Returns: {SQLTagStore} A new SQL tag store for caching prepared statements.
363+
364+
Creates a new`SQLTagStore`, which is an LRU (Least Recently Used) cache for
365+
storing prepared statements. This allows for the efficient reuse of prepared
366+
statements by tagging them with a unique identifier.
367+
368+
When a tagged SQL literal is executed, the`SQLTagStore` checks if a prepared
369+
statement for that specific SQL string already exists in the cache. If it does,
370+
the cached statement is used. If not, a new prepared statement is created,
371+
executed, and then stored in the cache for future use. This mechanism helps to
372+
avoid the overhead of repeatedly parsing and preparing the same SQL statements.
373+
374+
```mjs
375+
import {DatabaseSync }from'node:sqlite';
376+
377+
constdb=newDatabaseSync(':memory:');
378+
constsql=db.createSQLTagStore();
379+
380+
db.exec('CREATE TABLE users (id INT, name TEXT)');
381+
382+
// Using the 'run' method to insert data.
383+
// The tagged literal is used to identify the prepared statement.
384+
sql.run`INSERT INTO users VALUES (1, 'Alice')`;
385+
sql.run`INSERT INTO users VALUES (2, 'Bob')`;
386+
387+
// Using the 'get' method to retrieve a single row.
388+
constid=1;
389+
constuser=sql.get`SELECT * FROM users WHERE id =${id}`;
390+
console.log(user);// { id: 1, name: 'Alice' }
391+
392+
// Using the 'all' method to retrieve all rows.
393+
constallUsers=sql.all`SELECT * FROM users ORDER BY id`;
394+
console.log(allUsers);
395+
// [
396+
// { id: 1, name: 'Alice' },
397+
// { id: 2, name: 'Bob' }
398+
// ]
399+
```
400+
354401
###`database.createSession([options])`
355402

356403
<!-- YAML
@@ -494,6 +541,120 @@ times with different bound values. Parameters also offer protection against
494541
[SQL injection][] attacks. For these reasons, prepared statements are preferred
495542
over hand-crafted SQL strings when handling user input.
496543

544+
##Class:`SQLTagStore`
545+
546+
<!-- YAML
547+
added: REPLACEME
548+
-->
549+
550+
This class represents a single LRU (Least Recently Used) cache for storing
551+
prepared statements.
552+
553+
Instances of this class are created via the database.createSQLTagStore() method,
554+
not by using a constructor. The store caches prepared statements based on the
555+
provided SQL query string. When the same query is seen again, the store
556+
retrieves the cached statement and safely applies the new values through
557+
parameter binding, thereby preventing attacks like SQL injection.
558+
559+
The cache has a maxSize that defaults to 1000 statements, but a custom size can
560+
be provided (e.g., database.createSQLTagStore(100)). All APIs exposed by this
561+
class execute synchronously.
562+
563+
###`sqlTagStore.all(sqlTemplate[, ...values])`
564+
565+
<!-- YAML
566+
added: REPLACEME
567+
-->
568+
569+
*`sqlTemplate` {Template Literal} A template literal containing the SQL query.
570+
*`...values` {any} Values to be interpolated into the template literal.
571+
* Returns: {Array} An array of objects representing the rows returned by the query.
572+
573+
Executes the given SQL query and returns all resulting rows as an array of objects.
574+
575+
###`sqlTagStore.get(sqlTemplate[, ...values])`
576+
577+
<!-- YAML
578+
added: REPLACEME
579+
-->
580+
581+
*`sqlTemplate` {Template Literal} A template literal containing the SQL query.
582+
*`...values` {any} Values to be interpolated into the template literal.
583+
* Returns: {Object | undefined} An object representing the first row returned by
584+
the query, or`undefined` if no rows are returned.
585+
586+
Executes the given SQL query and returns the first resulting row as an object.
587+
588+
###`sqlTagStore.iterate(sqlTemplate[, ...values])`
589+
590+
<!-- YAML
591+
added: REPLACEME
592+
-->
593+
594+
*`sqlTemplate` {Template Literal} A template literal containing the SQL query.
595+
*`...values` {any} Values to be interpolated into the template literal.
596+
* Returns: {Iterator} An iterator that yields objects representing the rows returned by the query.
597+
598+
Executes the given SQL query and returns an iterator over the resulting rows.
599+
600+
###`sqlTagStore.run(sqlTemplate[, ...values])`
601+
602+
<!-- YAML
603+
added: REPLACEME
604+
-->
605+
606+
*`sqlTemplate` {Template Literal} A template literal containing the SQL query.
607+
*`...values` {any} Values to be interpolated into the template literal.
608+
* Returns: {Object} An object containing information about the execution, including`changes` and`lastInsertRowid`.
609+
610+
Executes the given SQL query, which is expected to not return any rows (e.g., INSERT, UPDATE, DELETE).
611+
612+
###`sqlTagStore.size()`
613+
614+
<!-- YAML
615+
added: REPLACEME
616+
-->
617+
618+
* Returns: {integer} The number of prepared statements currently in the cache.
619+
620+
A read-only property that returns the number of prepared statements currently in the cache.
621+
622+
###`sqlTagStore.capacity`
623+
624+
<!-- YAML
625+
added: REPLACEME
626+
-->
627+
628+
* Returns: {integer} The maximum number of prepared statements the cache can hold.
629+
630+
A read-only property that returns the maximum number of prepared statements the cache can hold.
631+
632+
###`sqlTagStore.db`
633+
634+
<!-- YAML
635+
added: REPLACEME
636+
-->
637+
638+
* {DatabaseSync} The`DatabaseSync` instance that created this`SQLTagStore`.
639+
640+
A read-only property that returns the`DatabaseSync` object associated with this`SQLTagStore`.
641+
642+
###`sqlTagStore.reset()`
643+
644+
<!-- YAML
645+
added: REPLACEME
646+
-->
647+
648+
Resets the LRU cache, clearing all stored prepared statements.
649+
650+
###`sqlTagStore.clear()`
651+
652+
<!-- YAML
653+
added: REPLACEME
654+
-->
655+
656+
An alias for`sqlTagStore.reset()`.
657+
497658
###`statement.all([namedParameters][, ...anonymousParameters])`
498659

499660
<!-- YAML

‎src/lru_cache-inl.h‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#ifndef SRC_LRU_CACHE_INL_H_
2+
#defineSRC_LRU_CACHE_INL_H_
3+
4+
#include<list>
5+
#include<unordered_map>
6+
#include<utility>
7+
8+
template<typenamekey_t,typenamevalue_t>
9+
classLRUCache {
10+
public:
11+
usingkey_value_pair_t =typename std::pair<key_t,value_t>;
12+
using iterator =typename std::list<key_value_pair_t>::iterator;
13+
using const_iterator =typename std::list<key_value_pair_t>::const_iterator;
14+
15+
const_iteratorbegin()const {return lru_list_.begin(); }
16+
const_iteratorend()const {return lru_list_.end(); }
17+
18+
explicitLRUCache(size_t capacity) : capacity_(capacity) {}
19+
20+
voidPut(constkey_t& key,constvalue_t& value) {
21+
auto it = lookup_map_.find(key);
22+
if (it != lookup_map_.end()) {
23+
lru_list_.erase(it->second);
24+
lookup_map_.erase(it);
25+
}
26+
27+
lru_list_.push_front(std::make_pair(key, value));
28+
lookup_map_[key] = lru_list_.begin();
29+
30+
if (lookup_map_.size() > capacity_) {
31+
auto last = lru_list_.end();
32+
last--;
33+
lookup_map_.erase(last->first);
34+
lru_list_.pop_back();
35+
}
36+
}
37+
38+
value_t&Get(constkey_t& key) {
39+
auto it = lookup_map_.find(key);
40+
lru_list_.splice(lru_list_.begin(), lru_list_, it->second);
41+
return it->second->second;
42+
}
43+
44+
voidErase(constkey_t& key) {
45+
auto it = lookup_map_.find(key);
46+
if (it != lookup_map_.end()) {
47+
lru_list_.erase(it->second);
48+
lookup_map_.erase(it);
49+
}
50+
}
51+
52+
boolExists(constkey_t& key)const {return lookup_map_.count(key) >0; }
53+
54+
size_tSize()const {return lookup_map_.size(); }
55+
56+
size_tCapacity()const {return capacity_; }
57+
58+
voidClear() {
59+
lru_list_.clear();
60+
lookup_map_.clear();
61+
}
62+
63+
private:
64+
std::list<key_value_pair_t> lru_list_;
65+
std::unordered_map<key_t, iterator> lookup_map_;
66+
size_t capacity_;
67+
};
68+
69+
#endif// SRC_LRU_CACHE_INL_H_

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp