@orkestrel/database 0.0.1
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/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/src/core/Clause.d.ts +30 -0
- package/dist/src/core/Cursor.d.ts +21 -0
- package/dist/src/core/Database.d.ts +80 -0
- package/dist/src/core/Query.d.ts +47 -0
- package/dist/src/core/Table.d.ts +69 -0
- package/dist/src/core/constants.d.ts +22 -0
- package/dist/src/core/drivers/MemoryDriver.d.ts +94 -0
- package/dist/src/core/errors.d.ts +38 -0
- package/dist/src/core/factories.d.ts +43 -0
- package/dist/src/core/helpers.d.ts +383 -0
- package/dist/src/core/index.d.ts +11 -0
- package/dist/src/core/index.js +3364 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/types.d.ts +739 -0
- package/dist/src/server/compilers.d.ts +169 -0
- package/dist/src/server/drivers/JSONDriver.d.ts +106 -0
- package/dist/src/server/factories.d.ts +31 -0
- package/dist/src/server/helpers.d.ts +222 -0
- package/dist/src/server/index.cjs +1014 -0
- package/dist/src/server/index.cjs.map +1 -0
- package/dist/src/server/index.d.ts +5 -0
- package/dist/src/server/types.d.ts +36 -0
- package/package.json +84 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import type { ContractShape, FieldPath } from '@orkestrel/contract';
|
|
2
|
+
import type { AggregateFunction, ColumnType, ConformanceFinding, Condition, Criteria, DriverInterface, Key, Migration, MigrationStep, Order, Row, TableSchema } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A total ordering over arbitrary values — the comparator behind sorting and the
|
|
5
|
+
* range operators.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Values of different types order by a fixed type rank (`undefined` < `null` <
|
|
9
|
+
* boolean < number < string < other); same-typed values compare naturally.
|
|
10
|
+
* `NaN` sorts after every other number and equal to itself, so the comparator
|
|
11
|
+
* is total and never returns `NaN`.
|
|
12
|
+
*
|
|
13
|
+
* @param left - The left value
|
|
14
|
+
* @param right - The right value
|
|
15
|
+
* @returns `-1`, `0`, or `1`
|
|
16
|
+
*/
|
|
17
|
+
export declare function compareValues(left: unknown, right: unknown): number;
|
|
18
|
+
/**
|
|
19
|
+
* Structural equality by SameValueZero leaves — the comparator behind conformance
|
|
20
|
+
* checks and any test/fixture that needs "same data", not "same reference".
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Primitives compare by SameValueZero (`NaN` equals itself; `+0` equals `-0`).
|
|
24
|
+
* Arrays compare by index (same length, every element `deepEqual`). Plain
|
|
25
|
+
* records (via `isRecord`) compare by their OWN enumerable keys: same key
|
|
26
|
+
* COUNT and, for every key in `left`, `right` has that key (`Object.hasOwn`)
|
|
27
|
+
* with a `deepEqual` value — so a key present with value `undefined` is NOT
|
|
28
|
+
* equal to that key being absent (both differ in `Object.keys` membership).
|
|
29
|
+
* Anything else (functions, class instances, mismatched shapes) falls through
|
|
30
|
+
* to `false`. There is no cycle detection — a cyclic input recurses forever;
|
|
31
|
+
* callers pass acyclic data (rows, plans, config).
|
|
32
|
+
*
|
|
33
|
+
* @param left - The left value
|
|
34
|
+
* @param right - The right value
|
|
35
|
+
* @returns Whether `left` and `right` are structurally equal
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* deepEqual(Number.NaN, Number.NaN) // true
|
|
40
|
+
* deepEqual({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] }) // true
|
|
41
|
+
* deepEqual({ a: undefined }, {}) // false — present-undefined ≠ absent
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function deepEqual(left: unknown, right: unknown): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Match a value against a wildcard pattern in LINEAR time — the shared, ReDoS-SAFE
|
|
47
|
+
* engine behind {@link likeMatch} and {@link globMatch}.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* A backtracking RegExp (`a%b%c` → `^a.*b.*c$`) is CATASTROPHIC on a hostile pattern:
|
|
51
|
+
* `.*` segments separated by literals, matched against a long non-matching input, blow
|
|
52
|
+
* up super-linearly — and JS has no atomic groups / possessive quantifiers to bound it
|
|
53
|
+
* (AGENTS §6.5, now that the authed server runs model-supplied `list` criteria over the
|
|
54
|
+
* wire). So this builds NO regex. It runs the classic GREEDY TWO-POINTER wildcard match:
|
|
55
|
+
* the `any` wildcard records its position and, on a later mismatch, backtracks ONLY to
|
|
56
|
+
* that last `any` (letting it absorb one more char) — so the work is O(value × pattern),
|
|
57
|
+
* never the exponential / polynomial backtracking a regex would do. The pattern length
|
|
58
|
+
* is capped at {@link MAX_PATTERN_LENGTH} (a `VALIDATION` {@link DatabaseError} over it),
|
|
59
|
+
* bounding the pattern factor so a match stays linear in the value length whatever the
|
|
60
|
+
* pattern.
|
|
61
|
+
*
|
|
62
|
+
* The `any` wildcard matches any run (including empty); `single` matches exactly one
|
|
63
|
+
* char; every other pattern char matches itself LITERALLY (a pattern `.` / `(` / `\` is
|
|
64
|
+
* a literal — the regex-metacharacter hazard is gone with the regex). `any` is tested
|
|
65
|
+
* BEFORE a literal match, so a value that literally contains the wildcard char never
|
|
66
|
+
* shadows the wildcard. Case folding is applied to BOTH sides when `fold` is set.
|
|
67
|
+
*
|
|
68
|
+
* @param value - The value to test
|
|
69
|
+
* @param pattern - The wildcard pattern
|
|
70
|
+
* @param any - The any-run wildcard char (`%` for `LIKE`, `*` for `GLOB`)
|
|
71
|
+
* @param single - The single-char wildcard char (`_` for `LIKE`, `?` for `GLOB`)
|
|
72
|
+
* @param fold - Whether to match case-INSENSITIVELY (`LIKE` folds; `GLOB` does not)
|
|
73
|
+
* @returns Whether `value` matches `pattern`
|
|
74
|
+
* @throws A `VALIDATION` {@link DatabaseError} when `pattern` exceeds {@link MAX_PATTERN_LENGTH}
|
|
75
|
+
*/
|
|
76
|
+
export declare function wildcardMatch(value: string, pattern: string, any: string, single: string, fold: boolean): boolean;
|
|
77
|
+
export declare function likeMatch(value: string, pattern: string): boolean;
|
|
78
|
+
export declare function globMatch(value: string, pattern: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Evaluate one {@link Condition} against a row — the per-operator predicate.
|
|
81
|
+
*
|
|
82
|
+
* @remarks
|
|
83
|
+
* Reads the condition's column — a `FieldPath`, resolved with `resolveField` (a
|
|
84
|
+
* string is one column; an array descends a nested value) — and applies the
|
|
85
|
+
* operator. Range operators use {@link compareValues}; `like` / `glob` / `starts`
|
|
86
|
+
* / `ends` match only strings; `any` / `none` test membership by value equality.
|
|
87
|
+
* Total — a type mismatch is simply a non-match.
|
|
88
|
+
*
|
|
89
|
+
* @param row - The row to test
|
|
90
|
+
* @param condition - The condition to apply
|
|
91
|
+
* @returns Whether the row satisfies the condition
|
|
92
|
+
*/
|
|
93
|
+
export declare function matchesCondition(row: Row, condition: Condition): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Fold a row through a list of conditions, joining each by its connector.
|
|
96
|
+
*
|
|
97
|
+
* @remarks
|
|
98
|
+
* Evaluated left-to-right: the first condition seeds the result, and each later
|
|
99
|
+
* condition combines with `&&` (`and`) or `||` (`or`). An empty list matches
|
|
100
|
+
* every row. There is no operator precedence — conditions combine in the order
|
|
101
|
+
* the query builder recorded them.
|
|
102
|
+
*
|
|
103
|
+
* @param row - The row to test
|
|
104
|
+
* @param conditions - The conditions to fold
|
|
105
|
+
* @returns Whether the row satisfies the combined conditions
|
|
106
|
+
*/
|
|
107
|
+
export declare function matchesCriteria(row: Row, conditions: readonly Condition[]): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Filter rows by a list of conditions — the shared basis for a table's count
|
|
110
|
+
* and aggregate paths (no sort/page, unlike {@link applyCriteria}).
|
|
111
|
+
*
|
|
112
|
+
* @remarks
|
|
113
|
+
* An empty condition list matches every row (returned as-is, no copy). Folds
|
|
114
|
+
* each row through {@link matchesCriteria}.
|
|
115
|
+
*
|
|
116
|
+
* @param rows - The rows to filter
|
|
117
|
+
* @param conditions - The conditions to apply (empty matches everything)
|
|
118
|
+
* @returns The matching rows
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* filterRows(
|
|
123
|
+
* [{ age: 30 }, { age: 12 }],
|
|
124
|
+
* [{ column: 'age', operator: 'above', values: [18], connector: 'and' }],
|
|
125
|
+
* ) // => [{ age: 30 }]
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function filterRows(rows: readonly Row[], conditions: readonly Condition[]): readonly Row[];
|
|
129
|
+
/**
|
|
130
|
+
* Sort rows by an ordering specification, leaving the input untouched.
|
|
131
|
+
*
|
|
132
|
+
* @remarks
|
|
133
|
+
* Applies the terms in priority order — the first term that distinguishes two
|
|
134
|
+
* rows decides — using {@link compareValues}, reversing for `descending`.
|
|
135
|
+
*
|
|
136
|
+
* @param rows - The rows to sort
|
|
137
|
+
* @param order - The ordering terms in priority order
|
|
138
|
+
* @returns A new, sorted array
|
|
139
|
+
*/
|
|
140
|
+
export declare function sortRows(rows: readonly Row[], order: readonly Order[]): readonly Row[];
|
|
141
|
+
/**
|
|
142
|
+
* Apply a {@link Criteria} to rows — filter, then sort, then page.
|
|
143
|
+
*
|
|
144
|
+
* @remarks
|
|
145
|
+
* The whole portable read pipeline in one place: conditions filter, `order`
|
|
146
|
+
* sorts, and `offset` / `limit` window the result. Each step is skipped when its
|
|
147
|
+
* part of the criteria is absent. The reference {@link DriverInterface} backends
|
|
148
|
+
* lean on this rather than each re-deriving it.
|
|
149
|
+
*
|
|
150
|
+
* @param rows - The rows to process (typically a table's full `scan`)
|
|
151
|
+
* @param criteria - The read specification, or `undefined` for all rows as-is
|
|
152
|
+
* @returns The filtered, sorted, paged rows
|
|
153
|
+
*/
|
|
154
|
+
export declare function applyCriteria(rows: readonly Row[], criteria?: Criteria): readonly Row[];
|
|
155
|
+
/**
|
|
156
|
+
* Compute an aggregate over a column across rows.
|
|
157
|
+
*
|
|
158
|
+
* @remarks
|
|
159
|
+
* `count` returns the row count. The numeric aggregates coerce each cell with
|
|
160
|
+
* the contracts `parseNumber` (so `'42'` counts) and ignore non-numeric cells;
|
|
161
|
+
* over zero numeric values they return `undefined` — the SQL `NULL` of an empty
|
|
162
|
+
* aggregate.
|
|
163
|
+
*
|
|
164
|
+
* @param rows - The rows to aggregate (non-record entries are ignored)
|
|
165
|
+
* @param operation - The aggregate to compute
|
|
166
|
+
* @param column - The column to aggregate
|
|
167
|
+
* @returns The aggregate value, or `undefined` when undefined for the inputs
|
|
168
|
+
*/
|
|
169
|
+
export declare function computeAggregate(rows: readonly unknown[], operation: AggregateFunction, column: FieldPath): number | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Read a row's primary key from a column, when it is a usable {@link Key}.
|
|
172
|
+
*
|
|
173
|
+
* @param row - The row to read
|
|
174
|
+
* @param column - The primary-key column name
|
|
175
|
+
* @returns The key (a string or finite number), or `undefined`
|
|
176
|
+
*/
|
|
177
|
+
export declare function extractKey(row: Row, column: string): Key | undefined;
|
|
178
|
+
/**
|
|
179
|
+
* Map a column's {@link ContractShape} to its portable {@link ColumnType} — the
|
|
180
|
+
* value a `TableSchema` carries so a native backend can declare a real column.
|
|
181
|
+
*
|
|
182
|
+
* @remarks
|
|
183
|
+
* `string` → `text`; `number` → `integer` when the shape is integer-only, else
|
|
184
|
+
* `real`; `boolean` → `boolean`. A `literal` takes the type of its values
|
|
185
|
+
* (all-boolean → `boolean`, all-integer → `integer`, mixed/fractional numbers →
|
|
186
|
+
* `real`, anything else → `text`). `optional` / `nullable` unwrap to their inner
|
|
187
|
+
* type (nullability is tracked separately). `null` / `object` / `array` / `union` /
|
|
188
|
+
* `json` / `raw` → `json`: a backend stores them as JSON text and can `json_extract`
|
|
189
|
+
* for nested `FieldPath` queries. A scan-only backend ignores the result.
|
|
190
|
+
*
|
|
191
|
+
* @param shape - The column's contract shape
|
|
192
|
+
* @returns The portable column type
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* shapeToColumnType(stringShape()) // 'text'
|
|
197
|
+
* shapeToColumnType(integerShape()) // 'integer'
|
|
198
|
+
* shapeToColumnType(optionalShape(integerShape())) // 'integer'
|
|
199
|
+
* shapeToColumnType(objectShape({ a: stringShape() })) // 'json'
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export declare function shapeToColumnType(shape: ContractShape): ColumnType;
|
|
203
|
+
/**
|
|
204
|
+
* Throw when an {@link ReadOptions.signal | AbortSignal} has fired — the shared
|
|
205
|
+
* cancellation gate checked at operation boundaries and between streamed rows.
|
|
206
|
+
*
|
|
207
|
+
* @remarks
|
|
208
|
+
* A no-op for `undefined` or a live signal, so callers thread `options?.signal`
|
|
209
|
+
* straight through. When the signal has aborted, throws an `ABORTED`
|
|
210
|
+
* {@link DatabaseError} carrying the signal's `reason` in its context — callers
|
|
211
|
+
* mint signals with whatever tool they like (`AbortSignal.timeout(ms)`,
|
|
212
|
+
* `new AbortController()`, `@orkestrel/abort`).
|
|
213
|
+
*
|
|
214
|
+
* @param signal - The signal to check, if any
|
|
215
|
+
* @returns Nothing — returns normally while the signal is live
|
|
216
|
+
* @throws An `ABORTED` {@link DatabaseError} when the signal has aborted
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import { checkAbort } from '@orkestrel/database'
|
|
221
|
+
*
|
|
222
|
+
* const controller = new AbortController()
|
|
223
|
+
* checkAbort(controller.signal) // returns
|
|
224
|
+
* controller.abort('too slow')
|
|
225
|
+
* checkAbort(controller.signal) // throws DatabaseError('ABORTED', …)
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
export declare function checkAbort(signal: AbortSignal | undefined): void;
|
|
229
|
+
/**
|
|
230
|
+
* Structurally diff a deployed and a declared table set into a {@link Migration}
|
|
231
|
+
* plan.
|
|
232
|
+
*
|
|
233
|
+
* @remarks
|
|
234
|
+
* Tables present in `declared` but not `deployed` become `table.add` steps
|
|
235
|
+
* (carrying the full declared {@link TableSchema}); tables present in
|
|
236
|
+
* `deployed` but not `declared` become `table.remove` steps. Tables present in
|
|
237
|
+
* both are diffed column-by-column (by name) and index-group-by-index-group
|
|
238
|
+
* (by deep equality of the column-name array), each producing `column.add` /
|
|
239
|
+
* `column.remove` / `index.add` / `index.remove` steps. Step order is
|
|
240
|
+
* deterministic: every `table.remove`, then every `table.add`, then each
|
|
241
|
+
* shared table's column/index changes in `declared` order. `from` / `to` are
|
|
242
|
+
* plan labels only — version tracking itself is deferred to persistent
|
|
243
|
+
* backends.
|
|
244
|
+
*
|
|
245
|
+
* @param deployed - The table schemas currently applied
|
|
246
|
+
* @param declared - The table schemas the caller wants applied
|
|
247
|
+
* @param from - The plan's source version label (defaults to `0`)
|
|
248
|
+
* @param to - The plan's target version label (defaults to `1`)
|
|
249
|
+
* @returns The migration plan moving `deployed` toward `declared`
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```ts
|
|
253
|
+
* const plan = planMigration(
|
|
254
|
+
* [{ name: 'users', primary: 'id', columns: [], indexes: [] }],
|
|
255
|
+
* [{ name: 'users', primary: 'id', columns: [{ name: 'age', type: 'integer', nullable: false }], indexes: [] }],
|
|
256
|
+
* )
|
|
257
|
+
* // plan.steps === [{ operation: 'column.add', table: 'users', column: { name: 'age', ... } }]
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export declare function planMigration(deployed: readonly TableSchema[], declared: readonly TableSchema[], from?: number, to?: number): Migration;
|
|
261
|
+
/**
|
|
262
|
+
* Apply one table's {@link MigrationStep}s to its rows — a pure row transform.
|
|
263
|
+
*
|
|
264
|
+
* @remarks
|
|
265
|
+
* `column.remove` drops that field from every row (a fresh copy — inputs are
|
|
266
|
+
* never mutated, AGENTS §11); `column.add` leaves rows as-is (an absent field
|
|
267
|
+
* reads as `undefined`, backfill is application policy). `table.add` /
|
|
268
|
+
* `table.remove` / `index.add` / `index.remove` are no-ops here (they operate
|
|
269
|
+
* on storage shape, not row shape). Steps for tables other than the one
|
|
270
|
+
* `rows` belongs to are ignored — pass only the steps relevant to this table.
|
|
271
|
+
*
|
|
272
|
+
* @param rows - The table's current rows
|
|
273
|
+
* @param steps - The migration steps to apply (typically one table's slice of a {@link Migration})
|
|
274
|
+
* @returns A new array of transformed rows; `rows` is never mutated
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```ts
|
|
278
|
+
* const rows = [{ id: 'a', name: 'Ada', legacy: true }]
|
|
279
|
+
* migrateRows(rows, [{ operation: 'column.remove', table: 'users', column: 'legacy' }])
|
|
280
|
+
* // => [{ id: 'a', name: 'Ada' }]
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
export declare function migrateRows(rows: readonly Row[], steps: readonly MigrationStep[]): readonly Row[];
|
|
284
|
+
/**
|
|
285
|
+
* Run the driver-conformance battery against a fresh {@link DriverInterface}
|
|
286
|
+
* per phase, yielding one {@link ConformanceFinding} per violated invariant —
|
|
287
|
+
* the shared invariant suite every backend (in-memory, SQLite, IndexedDB)
|
|
288
|
+
* must uphold to be a drop-in {@link DriverInterface}.
|
|
289
|
+
*
|
|
290
|
+
* @remarks
|
|
291
|
+
* Framework-agnostic: no test-runner or Node imports, only sibling core
|
|
292
|
+
* modules — so it runs equally from a unit test, a smoke script, or a new
|
|
293
|
+
* driver's own README. Opens a fixed two-table schema (`users` keyed by the
|
|
294
|
+
* default `id`, `posts` keyed by a non-id `slug`) and, calling `factory()`
|
|
295
|
+
* fresh for each phase so failures stay isolated, verifies: `open`/`close`;
|
|
296
|
+
* `read` of a missing key returns `undefined`; `write`/`read` round-trip with
|
|
297
|
+
* copy-in/copy-out isolation (mutating the caller's row after `write`, or the
|
|
298
|
+
* row `read` returns, never perturbs stored state) and upsert-overwrite;
|
|
299
|
+
* `delete` returns `true` then `false`; `keys`/`scan` yield in ascending key
|
|
300
|
+
* order; `clear` empties only its target table; `snapshot`'s rollback thunk
|
|
301
|
+
* restores pre-snapshot state; a scoped `snapshot(['users'])` rolls back only
|
|
302
|
+
* the named table, leaving a concurrent mutation to another table intact; a
|
|
303
|
+
* non-`id` primary key (`posts.slug`) round-trips; a nested-object row
|
|
304
|
+
* round-trips structurally (via {@link deepEqual}). The optional surface is
|
|
305
|
+
* presence-gated: when `migrate` exists, a `column.remove` plan strips the
|
|
306
|
+
* column from stored rows and a plan referencing an unknown table throws
|
|
307
|
+
* `DatabaseError` `MIGRATION`; when `stream` exists, it yields only
|
|
308
|
+
* condition-matching rows and honors `offset`/`limit`; when `transaction`
|
|
309
|
+
* exists, `commit` persists and `rollback` restores; when both `meta` and
|
|
310
|
+
* `stamp` exist, a fresh store's `meta()` is `undefined`, and after
|
|
311
|
+
* `stamp({ version, schema })`, `meta()` returns the exact stamped value.
|
|
312
|
+
*
|
|
313
|
+
* Each phase runs within a `try`/`catch`: an EXPECTED mismatch yields a
|
|
314
|
+
* finding built from the assertion, while an UNEXPECTED throw (a driver
|
|
315
|
+
* crash mid-phase) is caught and yielded as a finding too, naming the phase
|
|
316
|
+
* as `check` and carrying the caught error in `context.error` — a broken
|
|
317
|
+
* driver can never escape the battery as an unhandled rejection. Within a
|
|
318
|
+
* phase, the FIRST violated assertion yields and the phase stops (matching
|
|
319
|
+
* the historical fail-fast shape at phase granularity); the generator then
|
|
320
|
+
* moves on to the next phase regardless. Because this is a **generator**,
|
|
321
|
+
* consuming only the first yielded value reproduces true fail-fast (later
|
|
322
|
+
* phases never run) — that is exactly what {@link conformDriver} does.
|
|
323
|
+
*
|
|
324
|
+
* @param factory - Mints a fresh, unopened driver instance (called once per phase)
|
|
325
|
+
* @yields One {@link ConformanceFinding} per violated invariant, in phase order
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* import { createMemoryDriver, driverFindings } from '@orkestrel/database'
|
|
330
|
+
*
|
|
331
|
+
* for await (const finding of driverFindings(() => createMemoryDriver())) {
|
|
332
|
+
* console.log(finding.check, finding.message)
|
|
333
|
+
* }
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
export declare function driverFindings(factory: () => DriverInterface): AsyncGenerator<ConformanceFinding>;
|
|
337
|
+
/**
|
|
338
|
+
* Run the driver-conformance battery, throwing on the first violated
|
|
339
|
+
* invariant — the fail-fast entry point most callers (test setup, CI smoke
|
|
340
|
+
* checks) want.
|
|
341
|
+
*
|
|
342
|
+
* @remarks
|
|
343
|
+
* A thin driver over {@link driverFindings}: because that generator is
|
|
344
|
+
* lazy, consuming only its first yielded value means every LATER phase
|
|
345
|
+
* never runs — true fail-fast, not merely "report only the first". The
|
|
346
|
+
* thrown error is byte-compatible with the historical shape: a
|
|
347
|
+
* `CONFORMANCE` {@link DatabaseError} whose `message` is the finding's
|
|
348
|
+
* `message` and whose `context` is `{ check, ...finding.context }`.
|
|
349
|
+
*
|
|
350
|
+
* @param factory - Mints a fresh, unopened driver instance (called once per phase)
|
|
351
|
+
* @returns Nothing — resolves once every phase has passed
|
|
352
|
+
* @throws A `CONFORMANCE` {@link DatabaseError} on the first violated invariant
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* import { conformDriver, createMemoryDriver } from '@orkestrel/database'
|
|
357
|
+
*
|
|
358
|
+
* await conformDriver(() => createMemoryDriver()) // resolves when every invariant holds
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
export declare function conformDriver(factory: () => DriverInterface): Promise<void>;
|
|
362
|
+
/**
|
|
363
|
+
* Run the FULL driver-conformance battery and collect every violation — the
|
|
364
|
+
* audit entry point for a driver author who wants a complete report rather
|
|
365
|
+
* than a single fail-fast throw.
|
|
366
|
+
*
|
|
367
|
+
* @remarks
|
|
368
|
+
* Drains {@link driverFindings} to completion: every phase runs regardless
|
|
369
|
+
* of earlier violations, so a driver breaking two independent invariants
|
|
370
|
+
* reports both. An empty array means the driver is fully conformant.
|
|
371
|
+
*
|
|
372
|
+
* @param factory - Mints a fresh, unopened driver instance (called once per phase)
|
|
373
|
+
* @returns Every violated invariant found, in phase order (empty when fully conformant)
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```ts
|
|
377
|
+
* import { auditDriver, createMemoryDriver } from '@orkestrel/database'
|
|
378
|
+
*
|
|
379
|
+
* const findings = await auditDriver(() => createMemoryDriver())
|
|
380
|
+
* for (const finding of findings) console.log(`${finding.check}: ${finding.message}`)
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
export declare function auditDriver(factory: () => DriverInterface): Promise<readonly ConformanceFinding[]>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type * from './types.js';
|
|
2
|
+
export * from './constants.js';
|
|
3
|
+
export * from './errors.js';
|
|
4
|
+
export * from './helpers.js';
|
|
5
|
+
export * from './factories.js';
|
|
6
|
+
export * from './Database.js';
|
|
7
|
+
export * from './drivers/MemoryDriver.js';
|
|
8
|
+
export * from './Table.js';
|
|
9
|
+
export * from './Query.js';
|
|
10
|
+
export * from './Clause.js';
|
|
11
|
+
export * from './Cursor.js';
|