@orkestrel/database 0.0.6 → 0.0.8

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/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # @orkestrel/database
2
2
 
3
- A typed database abstraction for the `@orkestrel` line — a single
4
- environment-agnostic core engine (`Database`, `Table`, `Query`, `Cursor`,
5
- `Clause`) over pluggable storage drivers at the seams. Built to sit beside
3
+ A typed database abstraction for the `@orkestrel` line — one public
4
+ `Database` over internal table/query engines and pluggable storage drivers at
5
+ the seams. Consumers use `TableInterface` and `QueryInterface`. Built to sit beside
6
6
  `@orkestrel/contract` (validation) and `@orkestrel/emitter` (observable
7
- lifecycle), reusing both as it takes shape.
7
+ lifecycle), reusing both directly. `TableInterface.cursor()` exposes the
8
+ `CursorInterface` contract for serial bulk mutation.
8
9
 
9
10
  ## Install
10
11
 
@@ -14,14 +15,15 @@ npm install @orkestrel/database
14
15
 
15
16
  ## Requirements
16
17
 
17
- - Node.js >= 24 (`node:sqlite`, used by the `./server` SQLite driver, emits an
18
- `ExperimentalWarning` on Node's current stable line)
18
+ - Node.js >= 22.12.0, matching the package engine declaration
19
+ - The `./server` SQLite driver additionally requires a Node.js release that
20
+ provides `node:sqlite`
19
21
  - Core is ESM; the `./server` subpath ships dual ESM+CJS builds; `./browser`
20
22
  is ESM-only
21
23
 
22
24
  ## Status
23
25
 
24
- Pre-release (`0.0.2`): the core engine, and the memory, JSON file, SQLite,
26
+ Pre-release (`0.0.7`): the core engine and the memory, JSON file, SQLite,
25
27
  and IndexedDB drivers are all implemented and tested, but the public API is
26
28
  still unstable and may change without notice. See
27
29
  [guides/src/database.md](./guides/src/database.md) for the full documented
@@ -35,34 +37,10 @@ the in-memory driver), `./server` (adds the JSON file and SQLite drivers),
35
37
  and `./browser` (adds the IndexedDB driver). Core and `./server` ship dual
36
38
  ESM+CJS builds; `./browser` is ESM-only.
37
39
 
38
- ### Release order
39
-
40
- Everything currently on the npm registry is at `0.0.1` the wrapper repos'
41
- `0.0.2`s were never published, so `0.0.2` is the next version for all three
42
- packages and absorbs every change on this line.
43
-
44
- This package's SQLite and IndexedDB drivers are built against the wrapper
45
- surfaces documented by the mirrored guides in this repo — that is,
46
- `@orkestrel/sqlite@0.0.2` and `@orkestrel/indexeddb@0.0.2` — and the
47
- dependency ranges pin exactly those versions (`^0.0.2`; on a `0.0.x` version
48
- a caret means exactly that patch: `>=0.0.2 <0.0.3`). Publish in this order:
49
-
50
- 1. Publish `@orkestrel/sqlite@0.0.2` and `@orkestrel/indexeddb@0.0.2` — they
51
- are independent of each other (either order; both depend only on the
52
- already-published `@orkestrel/contract`).
53
- 2. In this repo, run `npm install` to re-resolve `package-lock.json` against
54
- the newly published wrappers and commit the refreshed lockfile.
55
- 3. Run the `prepublishOnly` gates and publish `@orkestrel/database@0.0.2`.
56
-
57
- Until step 1 happens, a fresh `npm ci` in this repo fails to resolve
58
- `^0.0.2` — deliberately. The exact pin makes it impossible to install or
59
- publish this package against the older `0.0.1` wrappers, which lack driver
60
- fixes this package's behavior relies on (the SQLite wrapper's mid-stream
61
- `iterate` fault mapping, the IndexedDB wrapper's abnormal-close recovery and
62
- `READONLY` fault code) and whose surfaces the mirrored guides here no longer
63
- describe. The same discipline applies to every future wrapper release: bump
64
- the pinned range, re-mirror the wrapper guides, and republish this package
65
- deliberately — wrapper changes never flow in silently.
40
+ The server and browser drivers use the declared `@orkestrel/sqlite` and
41
+ `@orkestrel/indexeddb` package ranges. Wrapper upgrades are deliberate:
42
+ update the declared range, refresh the lockfile, run the full package gates,
43
+ and publish Database only after its wrapper dependencies are available.
66
44
 
67
45
  ## License
68
46
 
@@ -1,21 +1,24 @@
1
- import { ColumnType } from '../core/index.ts';
1
+ import { ColumnStorage } from '../core/index.ts';
2
2
  import { Condition } from '../core/index.ts';
3
- import { Criteria } from '../core/index.ts';
4
- import { Criteria as Criteria_2 } from '../../core/index.ts';
5
3
  import { DatabaseError } from '../core/index.ts';
6
4
  import { DriverInterface } from '../../core/index.ts';
7
5
  import { DriverInterface as DriverInterface_2 } from '../core/index.ts';
8
- import { DriverMeta } from '../../core/index.ts';
6
+ import { DriverMetadata } from '../../core/index.ts';
9
7
  import { IndexedDBError } from '@orkestrel/indexeddb';
10
8
  import { Key } from '../../core/index.ts';
11
- import { Migration } from '../../core/index.ts';
9
+ import { MigrationInput } from '../../core/index.ts';
10
+ import { OperationOptions } from '../../core/index.ts';
11
+ import { QueryInput } from '../core/index.ts';
12
+ import { QueryInput as QueryInput_2 } from '../../core/index.ts';
12
13
  import { Row } from '../../core/index.ts';
14
+ import { StoreDefinition } from '@orkestrel/indexeddb';
13
15
  import { TableSchema } from '../core/index.ts';
14
16
  import { TableSchema as TableSchema_2 } from '../../core/index.ts';
15
17
 
16
18
  /**
17
19
  * The `IDBKeyRange` a single {@link Condition} maps to, when its operator is one
18
- * of the six exact key comparisons over scalar operands — else `null`.
20
+ * of the six exact key comparisons over scalar operands; otherwise
21
+ * `undefined`.
19
22
  *
20
23
  * @remarks
21
24
  * Only the comparison operators (`equals`/`above`/`below`/`from`/`to`/`between`)
@@ -30,7 +33,7 @@ import { TableSchema as TableSchema_2 } from '../../core/index.ts';
30
33
  * boolean) that is not a usable key. `between` additionally guards against a
31
34
  * REVERSED pair (`first > second`): native `IDBKeyRange.bound` throws a raw
32
35
  * `DataError` `DOMException` for a lower bound above the upper bound, so a
33
- * reversed pair returns `null` here (falls back to a full scan, which the
36
+ * reversed pair returns `undefined` here (falls back to a full scan, which the
34
37
  * engine then correctly resolves to an empty result) rather than letting a
35
38
  * native exception escape untyped — the same defensive posture as every other
36
39
  * backend, which returns empty for a reversed/empty range instead of throwing.
@@ -39,17 +42,17 @@ import { TableSchema as TableSchema_2 } from '../../core/index.ts';
39
42
  * to a (possibly lossy) range.
40
43
  *
41
44
  * @param condition - The condition to translate
42
- * @returns Its exact key range, or `null` when the operator/operands cannot push
45
+ * @returns Its exact key range, or `undefined` when the operator/operands cannot push
43
46
  */
44
- export declare function conditionRange(condition: Condition): IDBKeyRange | null;
47
+ export declare function conditionToRange(condition: Condition): IDBKeyRange | undefined;
45
48
 
46
49
  /**
47
50
  * Create a persistent IndexedDB {@link DriverInterface} for the core database layer.
48
51
  *
49
52
  * @remarks
50
- * Pass it to `createDatabase` from `@orkestrel/database` to run the whole typed database +
51
- * relations stack against IndexedDB instead of memory — the `Database` / `Table` /
52
- * `Query` / relations API is unchanged; only where the bytes live changes. The
53
+ * Pass it to `createDatabase` from `@orkestrel/database` to run the typed database
54
+ * layer against IndexedDB instead of memory — the `Database` / `Table` / `Query`
55
+ * API is unchanged; only where the bytes live changes. The
53
56
  * driver is built on the published `@orkestrel/indexeddb` wrapper in auto-managed
54
57
  * mode, so a table added to the `tables` map is created on the next open with no
55
58
  * version bump. This unit omits `transaction` / `aggregate` (see
@@ -97,13 +100,13 @@ export declare function createIndexedDBDriver(name: string): DriverInterface_2;
97
100
  *
98
101
  * @example
99
102
  * ```ts
100
- * deriveIndexName(['age']) // 'age'
101
- * deriveIndexName(['a', 'b']) // '2#1:a1:b'
103
+ * deriveIndexedDBIndexName(['age']) // 'age'
104
+ * deriveIndexedDBIndexName(['a', 'b']) // '2#1:a1:b'
102
105
  * ```
103
106
  */
104
- export declare function deriveIndexName(columns: readonly string[]): string;
107
+ export declare function deriveIndexedDBIndexName(columns: readonly string[]): string;
105
108
 
106
- export declare const INDEXABLE_TYPES: ReadonlySet<ColumnType>;
109
+ export declare const INDEXABLE_STORAGE: ReadonlySet<ColumnStorage>;
107
110
 
108
111
  /**
109
112
  * The IndexedDB {@link DriverInterface} — the persistent browser backend, built on
@@ -115,25 +118,27 @@ export declare const INDEXABLE_TYPES: ReadonlySet<ColumnType>;
115
118
  * / `snapshot`) by delegating to the wrapper's typed store operations — it never
116
119
  * touches raw IndexedDB. Rows are stored with **out-of-line keys** (the database
117
120
  * passes the key explicitly, `store.set(row, key)`), so each table is declared as a
118
- * key-path-less store. The wrapper opens in **auto-managed** mode (no fixed
119
- * version), creating any missing store on demand, so a table added to the schema is
120
- * created on the next open with no manual version bump. The driver's bulk reads
121
- * (`scan` / `keys`) use the wrapper's native `getAll` / `getAllKeys`, and `snapshot`
122
- * rolls back through one atomic wrapper transaction.
121
+ * key-path-less store. A fresh database opens in **auto-managed** mode (no fixed
122
+ * version), creating missing declared stores on demand. Once metadata is persisted,
123
+ * bootstrap captures the live stores and version, rejects a missing persisted store,
124
+ * and pins the final open to that version so a competing versionchange cannot
125
+ * silently recreate lost storage. The driver's bulk reads (`scan` / `keys`) use the
126
+ * wrapper's native `getAll` / `getAllKeys`, and `snapshot` rolls back through one
127
+ * atomic wrapper transaction.
123
128
  *
124
- * It also implements the optional native `records` / `count` / `stream` hooks
125
- * (AGENTS §21): `selectPlan` ({@link selectPlan}) turns the {@link Criteria} into a
129
+ * It also implements the optional native `records` / `stream` hooks
130
+ * (AGENTS §21): `selectPlan` ({@link selectPlan}) turns the {@link QueryInput} into a
126
131
  * key-range pushdown over the primary key or a single-column secondary index,
127
- * fetching a candidate **superset** that the core engine (`applyCriteria` /
128
- * `matchesCriteria`) then refines — so a native read is byte-identical to a full
132
+ * fetching a candidate **superset** that the core engine (`applyQuery` /
133
+ * `matchesQuery`) then refines — so a native read is byte-identical to a full
129
134
  * scan, just cheaper. Pushdown is conservative: only the exact-comparison
130
135
  * operators over orderable columns narrow to a range; everything else falls back
131
136
  * to a full scan + the engine.
132
137
  *
133
138
  * @remarks
134
- * This driver also implements `migrate` / `meta` / `stamp`. `meta` / `stamp`
135
- * persist the {@link DriverMeta} in a reserved out-of-line store,
136
- * {@link META_STORE} (`__meta__`) — excluded from a whole-store `snapshot`
139
+ * This driver also implements `migrate` / `metadata` / `stamp`. `metadata` / `stamp`
140
+ * persist the {@link DriverMetadata} in a reserved out-of-line store,
141
+ * {@link METADATA_STORE} (`__metadata__`) — excluded from a whole-store `snapshot`
137
142
  * capture, since it is driver bookkeeping, not caller data. `migrate` applies a
138
143
  * {@link Migration} plan natively: IndexedDB schema DDL (creating/dropping a
139
144
  * store, creating/dropping an index) is legal only inside a versionchange
@@ -150,9 +155,9 @@ export declare const INDEXABLE_TYPES: ReadonlySet<ColumnType>;
150
155
  * This unit deliberately OMITS `aggregate` / `transaction`. There is no native
151
156
  * `aggregate` (IndexedDB has no native SUM/AVG); the engine over the narrowed
152
157
  * `records` covers it. `transaction` is impossible here: the wrapper auto-commits
153
- * an `IDBTransaction` the moment control yields to a non-IDB `await`, so a
154
- * BEGIN-now / commit-or-rollback-later handle spanning arbitrary caller code
155
- * cannot be built on top of it — every atomic multi-op sequence in this driver
158
+ * an `IDBTransaction` when control yields outside its request chain, so arbitrary
159
+ * callback awaits cannot remain inside one native transaction. Every atomic
160
+ * multi-operation sequence in this driver
156
161
  * (`snapshot`'s rollback) instead runs entirely inside ONE `db.write(...)` scope.
157
162
  */
158
163
  export declare class IndexedDBDriver implements DriverInterface {
@@ -161,34 +166,34 @@ export declare class IndexedDBDriver implements DriverInterface {
161
166
  open(schema: readonly TableSchema_2[]): Promise<void>;
162
167
  close(): Promise<void>;
163
168
  read(table: string, key: Key): Promise<Row | undefined>;
164
- write(table: string, key: Key, row: Row): Promise<void>;
165
- delete(table: string, key: Key): Promise<boolean>;
169
+ write(table: string, key: Key, row: Row, options?: OperationOptions): Promise<void>;
170
+ insert(table: string, key: Key, row: Row, options?: OperationOptions): Promise<void>;
171
+ delete(table: string, key: Key, options?: OperationOptions): Promise<boolean>;
166
172
  keys(table: string): Promise<readonly Key[]>;
167
173
  scan(table: string): AsyncIterable<Row>;
168
174
  clear(table: string): Promise<void>;
169
- records(table: string, criteria: Criteria_2): Promise<readonly Row[]>;
170
- count(table: string, criteria: Criteria_2): Promise<number>;
171
- stream(table: string, criteria: Criteria_2): AsyncIterable<Row>;
175
+ records(table: string, input: QueryInput_2): Promise<readonly Row[]>;
176
+ stream(table: string, input: QueryInput_2): AsyncIterable<Row>;
172
177
  snapshot(tables?: readonly string[]): Promise<() => Promise<void>>;
173
178
  /**
174
- * Return the persisted {@link DriverMeta}, or `undefined` when the store has
179
+ * Return the persisted {@link DriverMetadata}, or `undefined` when the store has
175
180
  * never been stamped.
176
181
  *
177
182
  * @remarks
178
- * Reads `'meta'` from the reserved {@link META_STORE}, narrowing the
179
- * structured-clone value with the core {@link isDriverMeta} guard (never
180
- * asserted, AGENTS §14) a missing or malformed record returns `undefined`,
181
- * exactly like a fresh, never-stamped store.
183
+ * Reads `'metadata'` from the reserved {@link METADATA_STORE} in one readonly
184
+ * transaction that distinguishes key absence from a present `undefined`
185
+ * value. Only absence returns `undefined`; present malformed state fails
186
+ * closed with a payload-safe `DRIVER` error.
182
187
  *
183
- * @returns The last-stamped {@link DriverMeta}, or `undefined`
188
+ * @returns The last-stamped {@link DriverMetadata}, or `undefined`
184
189
  */
185
- meta(): Promise<DriverMeta | undefined>;
190
+ metadata(): Promise<DriverMetadata | undefined>;
186
191
  /**
187
- * Persist `meta` verbatim for a later `meta()` to return.
192
+ * Persist an owned metadata snapshot for a later `metadata()` to return.
188
193
  *
189
- * @param meta - The {@link DriverMeta} to persist
194
+ * @param metadata - The {@link DriverMetadata} to persist
190
195
  */
191
- stamp(meta: DriverMeta): Promise<void>;
196
+ stamp(metadata: DriverMetadata): Promise<void>;
192
197
  /**
193
198
  * Apply a {@link Migration} plan by reconnecting at a bumped version and
194
199
  * running the plan's steps inside the wrapper's `upgrade` hook.
@@ -196,7 +201,7 @@ export declare class IndexedDBDriver implements DriverInterface {
196
201
  * @remarks
197
202
  * IndexedDB schema DDL is legal only inside `onupgradeneeded`, so this closes
198
203
  * the current connection and opens a FRESH one at `version + 1`, declaring
199
- * every currently-known store (plus {@link META_STORE}) so nothing is lost,
204
+ * every currently-known store (plus {@link METADATA_STORE}) so nothing is lost,
200
205
  * and applying `table.remove` / `index.add` / `index.remove` /
201
206
  * `column.remove` inside `upgrade`. Every step's `table` is validated against
202
207
  * the driver's own `#schema` BEFORE the reconnect — an unknown-table step
@@ -209,13 +214,11 @@ export declare class IndexedDBDriver implements DriverInterface {
209
214
  * `open` tracks, so subsequent pushdown planning and a later `migrate` /
210
215
  * `open` see the new shape.
211
216
  *
212
- * @param plan - The migration plan to apply
217
+ * @param input - The migration plan and optional metadata stamp to apply atomically
213
218
  */
214
- migrate(plan: Migration): Promise<void>;
219
+ migrate(input: MigrationInput): Promise<void>;
215
220
  }
216
221
 
217
- export declare function isKey(value: unknown): value is string | number;
218
-
219
222
  /**
220
223
  * Map a backend {@link IndexedDBError} to the portable `DatabaseError` taxonomy
221
224
  * — the default mapping used everywhere except inside `migrate()`.
@@ -225,17 +228,17 @@ export declare function isKey(value: unknown): value is string | number;
225
228
  * `CONSTRAINT` (a unique-key violation) is a `CONFLICT` — the same code every
226
229
  * other backend uses for a duplicate key. `CLOSED`/`NOT_OPEN`/`INVALID` (the
227
230
  * connection is gone, never opened, or the native handle is stale) collapse to
228
- * `CLOSED`. `QUOTA` and `BLOCKED` are genuine infrastructure faults (`DRIVER`),
229
- * carrying a machine-readable `context.code` (`'QUOTA'` / `'BLOCKED'`) so a
230
- * caller can branch without parsing the message; `BLOCKED` additionally marks
231
- * `context.retryable: true` a concurrent connection holding the database open
232
- * is a transient condition, not a permanent one. Every other code (`UPGRADE`
233
- * here — see {@link mapMigrationError} for the `migrate()`-only remapping to
234
- * `MIGRATION` — `ABORTED`, `NOT_FOUND`, `DATA`, `OPEN`, `INACTIVE`, `READONLY`,
235
- * `UNKNOWN`) is an unexpected infrastructure fault and maps to `DRIVER` — the
236
- * driver opens its own readwrite transactions, so a `READONLY` fault can only
237
- * mean the backend behaved unexpectedly. The original error is always
238
- * preserved as `context.cause` for diagnostics.
231
+ * `CLOSED`. `QUOTA` is a genuine infrastructure fault (`DRIVER`) carrying a
232
+ * machine-readable `context.code` so a caller can branch without parsing the
233
+ * message. A blocked open or versionchange is nonterminal in the backend and
234
+ * remains pending until the competing connection closes, so it never reaches
235
+ * this error mapper. Every other code (`UPGRADE` here — see
236
+ * {@link mapMigrationError} for the `migrate()`-only remapping to `MIGRATION` —
237
+ * `ABORTED`, `NOT_FOUND`, `DATA`, `OPEN`, `INACTIVE`, `READONLY`, `UNKNOWN`) is
238
+ * an unexpected infrastructure fault and maps to `DRIVER` — the driver opens
239
+ * its own readwrite transactions, so a `READONLY` fault can only mean the
240
+ * backend behaved unexpectedly. The original error is always preserved as
241
+ * `context.cause` for diagnostics.
239
242
  *
240
243
  * @param error - The backend error to translate
241
244
  * @returns The portable `DatabaseError`
@@ -260,20 +263,30 @@ export declare function mapIndexedDBError(error: IndexedDBError): DatabaseError;
260
263
  */
261
264
  export declare function mapMigrationError(error: IndexedDBError): DatabaseError;
262
265
 
263
- export declare const META_STORE = "__meta__";
266
+ export declare const METADATA_STORE = "__metadata__";
264
267
 
265
268
  /**
266
- * A pushdown plan — which index (or the primary store, `null`) to read and the
267
- * `IDBKeyRange` to narrow by (`null` = full scan). Always a SUPERSET of the
268
- * matching rows; the core engine refines it to the exact result.
269
+ * A pushdown plan — an optional index and optional `IDBKeyRange` used to narrow
270
+ * a read. An omitted `index` selects the primary store; an omitted `range`
271
+ * performs a full scan. The plan is always a superset of the matching rows;
272
+ * the core engine refines it to the exact result. An empty plan (`{}`) is a
273
+ * primary-store full scan.
269
274
  */
270
275
  export declare interface QueryPlan {
271
- readonly index: string | null;
272
- readonly range: IDBKeyRange | null;
276
+ readonly index?: string;
277
+ readonly range?: IDBKeyRange;
273
278
  }
274
279
 
275
280
  /**
276
- * Plan an IndexedDB read for a {@link Criteria} pick the index (or the primary
281
+ * Project a table schema into the IndexedDB wrapper's store definition.
282
+ *
283
+ * @param schema - Portable table schema
284
+ * @returns Store definition with declared indexes
285
+ */
286
+ export declare function schemaToStore(schema: TableSchema): StoreDefinition;
287
+
288
+ /**
289
+ * Plan an IndexedDB read for a {@link QueryInput} — pick the index (or the primary
277
290
  * store) and {@link IDBKeyRange} to narrow by, falling back to a full scan.
278
291
  *
279
292
  * @remarks
@@ -283,9 +296,9 @@ export declare interface QueryPlan {
283
296
  * (a row can match through a later condition the range would exclude), so any `or`
284
297
  * forces a full scan. Otherwise it scans the conditions in order and selects the
285
298
  * **first** one that is provably range-exact and backed by a key: a comparison
286
- * operator (`conditionRange`) over a single, orderable (`text`/`integer`/`real`)
287
- * column that is either the table's primary key (read the store directly, `index:
288
- * null`) or has a single-column secondary index (named exactly the column — read
299
+ * operator (`conditionToRange`) over a single, orderable (`text`/`integer`/`real`)
300
+ * column that is either the table's primary key (read the store directly with
301
+ * `index` omitted) or has a single-column secondary index (named exactly the column — read
289
302
  * that index). A condition whose column is a nested {@link FieldPath} array
290
303
  * (descends a json value, not a key), is absent from the schema, is a non-orderable
291
304
  * type (`boolean`/`json`/`blob`), uses a non-comparison operator, or has a
@@ -311,19 +324,19 @@ export declare interface QueryPlan {
311
324
  * in the total order, so an absent/null-valued row can never satisfy them — the
312
325
  * index's silence on such a row is harmless (it was never going to match).
313
326
  * **Declared-type trust caveat:** this reasoning holds under the contract that
314
- * an {@link INDEXABLE_TYPES} column, once contract-validated at write time,
327
+ * an {@link INDEXABLE_STORAGE} column, once contract-validated at write time,
315
328
  * holds only `string | number | null` (or is absent) — never some other
316
329
  * runtime value that could rank differently; a driver bypassing the write
317
330
  * contract (writing raw rows directly to the store) could defeat this
318
331
  * argument, but that is out of scope for a planner reading validated schema
319
332
  * metadata.
320
333
  *
321
- * When no condition qualifies the plan is a full scan (`{ index: null, range:
322
- * null }`) and the engine does everything. The plan is always a SUPERSET of the
334
+ * When no condition qualifies the plan is a full scan (`{}`) and the engine
335
+ * does everything. The plan is always a SUPERSET of the
323
336
  * matching rows — the only correctness contract — so the driver may safely run
324
337
  * the exact engine over it.
325
338
  *
326
- * @param criteria - The read specification (its `conditions` drive the plan), or
339
+ * @param input - The read specification (its `conditions` drive the plan), or
327
340
  * `undefined` for an unconditional read
328
341
  * @param schema - The table's schema — its `primary` key and column types
329
342
  * @param available - The secondary-index names that physically exist on the store
@@ -332,11 +345,11 @@ export declare interface QueryPlan {
332
345
  *
333
346
  * @example
334
347
  * ```ts
335
- * selectPlan({ conditions: [eq('id', 'u1')] }, schema, []) // { index: null, range: only('u1') }
348
+ * selectPlan({ conditions: [eq('id', 'u1')] }, schema, []) // { range: only('u1') }
336
349
  * selectPlan({ conditions: [from('age', 18)] }, schema, ['age']) // { index: 'age', range: from(18) }
337
- * selectPlan({ conditions: [contains('name', 'a')] }, schema, []) // { index: null, range: null }
350
+ * selectPlan({ conditions: [contains('name', 'a')] }, schema, []) // {}
338
351
  * ```
339
352
  */
340
- export declare function selectPlan(criteria: Criteria | undefined, schema: TableSchema, available: readonly string[]): QueryPlan;
353
+ export declare function selectPlan(input: QueryInput | undefined, schema: TableSchema, available: readonly string[]): QueryPlan;
341
354
 
342
355
  export { }