| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7aec53b commit 9a3e58a
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -351,6 +351,53 @@ added: v22.5.0 | |||
| 351 | 351 | Compiles a SQL statement into a [prepared statement][]. This method is a wrapper | |
| 352 | 352 | around [`sqlite3_prepare_v2()`][]. | |
| 353 | 353 | ||
| 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 | + const db = new DatabaseSync(':memory:'); | ||
| 378 | + const sql = 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 | + const id = 1; | ||
| 389 | + const user = 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 | + const allUsers = 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 | + | ||
| 354 | 401 | ### `database.createSession([options])` | |
| 355 | 402 | ||
| 356 | 403 | <!-- YAML | |
@@ -494,6 +541,120 @@ times with different bound values. Parameters also offer protection against | |||
| 494 | 541 | [SQL injection][] attacks. For these reasons, prepared statements are preferred | |
| 495 | 542 | over hand-crafted SQL strings when handling user input. | |
| 496 | 543 | ||
| 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 | + | ||
| 497 | 658 | ### `statement.all([namedParameters][, ...anonymousParameters])` | |
| 498 | 659 | ||
| 499 | 660 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,69 @@ | |||
| 1 | + #ifndef SRC_LRU_CACHE_INL_H_ | ||
| 2 | + #define SRC_LRU_CACHE_INL_H_ | ||
| 3 | + | ||
| 4 | + #include <list> | ||
| 5 | + #include <unordered_map> | ||
| 6 | + #include <utility> | ||
| 7 | + | ||
| 8 | + template <typename key_t, typename value_t> | ||
| 9 | + class LRUCache { | ||
| 10 | + public: | ||
| 11 | + using key_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_iterator begin() const { return lru_list_.begin(); } | ||
| 16 | + const_iterator end() const { return lru_list_.end(); } | ||
| 17 | + | ||
| 18 | + explicit LRUCache(size_t capacity) : capacity_(capacity) {} | ||
| 19 | + | ||
| 20 | + void Put(const key_t& key, const value_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(const key_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 | + void Erase(const key_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 | + bool Exists(const key_t& key) const { return lookup_map_.count(key) > 0; } | ||
| 53 | + | ||
| 54 | + size_t Size() const { return lookup_map_.size(); } | ||
| 55 | + | ||
| 56 | + size_t Capacity() const { return capacity_; } | ||
| 57 | + | ||
| 58 | + void Clear() { | ||
| 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_ | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments