@dokebi/search 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js CHANGED
@@ -5,7 +5,7 @@ import { SearchError } from './errors.js';
5
5
  import { indexesOf } from './indexes.js';
6
6
  import { DEFAULT_SECRETS_ENV, MIN_SECRET_LENGTH, options } from './options.js';
7
7
  import { detectDriver, isMissingTable, isQueryable, isRetryable, serverDialect, session, } from './sql.js';
8
- import { COUNTS_TABLE, INDEXES_TABLE, Store, TERMS_TABLE, } from './store.js';
8
+ import { COUNT_BATCH, COUNTS_TABLE, INDEXES_TABLE, Store, TERMS_TABLE, } from './store.js';
9
9
  import { MAX_QUERY_WORDS, queryTerms, terms } from './terms.js';
10
10
  const db = providerDependency({
11
11
  name: 'dokebi-db',
@@ -398,8 +398,8 @@ class SearchRuntime {
398
398
  this.#flushSoon();
399
399
  }
400
400
  /**
401
- * Adds the buffered count changes to the table, one autocommit statement per index on the
402
- * plugin's pool, words in sorted order. A failure is logged and the changes are kept for the
401
+ * Adds the buffered count changes to the table, in autocommit statements of up to COUNT_BATCH
402
+ * words per index on the plugin's pool, words in sorted order. A failure is logged and the changes are kept for the
403
403
  * next flush. Never rejects.
404
404
  */
405
405
  #flush() {
@@ -432,14 +432,23 @@ class SearchRuntime {
432
432
  }
433
433
  for (const [index, deltas] of byIndex) {
434
434
  deltas.sort((a, b) => byKey(a.field, b.field) || byKey(a.term, b.term));
435
+ // One autocommit statement per COUNT_BATCH words: `written` words are in the table.
436
+ let written = 0;
435
437
  try {
436
- await live.store.addCounts(live.pool, index, deltas);
438
+ for (; written < deltas.length; written += COUNT_BATCH)
439
+ await live.store.addCounts(live.pool, index, deltas.slice(written, written + COUNT_BATCH));
437
440
  }
438
441
  catch (error) {
439
- // Kept for the next flush: the counts are late, never lost while the process runs.
440
- for (const row of deltas) {
442
+ // Kept for the next flush: the counts are late, never lost while the process runs. Only
443
+ // the words from the failed statement on: the statements before it are committed, and
444
+ // keeping their words too would add them twice (R9-g14-3).
445
+ for (const row of deltas.slice(written)) {
441
446
  const key = `${index}${SEP}${row.field}${SEP}${row.term}`;
442
- this.#pending.set(key, (this.#pending.get(key) ?? 0) + row.delta);
447
+ const value = (this.#pending.get(key) ?? 0) + row.delta;
448
+ if (value === 0)
449
+ this.#pending.delete(key);
450
+ else
451
+ this.#pending.set(key, value);
443
452
  }
444
453
  this.#repeats?.log('error', 'Search word counts could not be written; they are kept for the next flush.', 'SEARCH_COUNTS_FAILED', error);
445
454
  }
@@ -697,7 +706,7 @@ class SearchRuntime {
697
706
  /** Factory input: `{ app, options?, entry }`: `entry` is the module of src/infra/search/indexes.ts. */
698
707
  export const createPlugin = definePlugin({
699
708
  name: 'dokebi-search',
700
- version: '0.1.1',
709
+ version: '0.1.2',
701
710
  core: '^0.4.2',
702
711
  options,
703
712
  dependencies: () => [db],
package/dist/store.d.ts CHANGED
@@ -3,6 +3,8 @@ import type { Dialect, Session } from './sql.js';
3
3
  export declare const TERMS_TABLE = "dokebi_search_terms";
4
4
  export declare const COUNTS_TABLE = "dokebi_search_counts";
5
5
  export declare const INDEXES_TABLE = "dokebi_search_indexes";
6
+ /** Words of one count statement: a flush hands `addCounts` this many at a time. */
7
+ export declare const COUNT_BATCH = 500;
6
8
  export interface TermRow {
7
9
  readonly field: string;
8
10
  readonly term: string;
@@ -47,7 +49,10 @@ export declare class Store {
47
49
  insertRows(db: Session, index: string, id: string, sortKey: number, rows: readonly TermRow[]): Promise<void>;
48
50
  /**
49
51
  * Moves the item counts of words by their deltas, in one slot chosen at random, in the order
50
- * given (the caller sorts them, so two writers lock the same rows in the same order).
52
+ * given (the caller sorts them, so two writers lock the same rows in the same order). One
53
+ * statement for up to COUNT_BATCH deltas: all of them are written or none. More are several
54
+ * statements, and a failure then leaves the earlier ones written, so a caller that keeps what
55
+ * failed hands over COUNT_BATCH at a time.
51
56
  */
52
57
  addCounts(db: Session, index: string, deltas: readonly CountDelta[]): Promise<void>;
53
58
  /** The item count of each word (its slots summed); a word without rows is absent. */
package/dist/store.js CHANGED
@@ -10,6 +10,8 @@ export const COUNTS_TABLE = 'dokebi_search_counts';
10
10
  export const INDEXES_TABLE = 'dokebi_search_indexes';
11
11
  /** Rows of one multi-row INSERT or DELETE (parameters stay far below every driver's limit). */
12
12
  const BATCH = 500;
13
+ /** Words of one count statement: a flush hands `addCounts` this many at a time. */
14
+ export const COUNT_BATCH = BATCH;
13
15
  export class Store {
14
16
  #dialect;
15
17
  /** MySQL and MariaDB read an older snapshot in a REPEATABLE READ transaction. */
@@ -98,7 +100,10 @@ export class Store {
98
100
  }
99
101
  /**
100
102
  * Moves the item counts of words by their deltas, in one slot chosen at random, in the order
101
- * given (the caller sorts them, so two writers lock the same rows in the same order).
103
+ * given (the caller sorts them, so two writers lock the same rows in the same order). One
104
+ * statement for up to COUNT_BATCH deltas: all of them are written or none. More are several
105
+ * statements, and a failure then leaves the earlier ones written, so a caller that keeps what
106
+ * failed hands over COUNT_BATCH at a time.
102
107
  */
103
108
  async addCounts(db, index, deltas) {
104
109
  const slot = Math.floor(Math.random() * this.#slots);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dokebi/search",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Search in an application's lists for Dokebi by @dokebi/db AI.md 6.10: a term table in display order written in the text's transaction, Korean word prefixes, the rarest word leads, bounded requests and searches with a signed cursor.",
5
5
  "keywords": [
6
6
  "dokebi",