@monlite/core 0.2.0 → 0.5.0
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 +87 -0
- package/dist/index.cjs +689 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +219 -7
- package/dist/index.d.ts +219 -7
- package/dist/index.js +686 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -16,6 +16,39 @@ interface SystemFields {
|
|
|
16
16
|
}
|
|
17
17
|
/** A stored document: the user's shape plus monlite's system fields. */
|
|
18
18
|
type WithId<T> = T & SystemFields;
|
|
19
|
+
/** SQLite column affinity for a structured-collection field. */
|
|
20
|
+
type ColumnType = "TEXT" | "INTEGER" | "REAL" | "BLOB" | "JSON";
|
|
21
|
+
/** Rich column definition for a structured collection. */
|
|
22
|
+
interface ColumnDef {
|
|
23
|
+
type: ColumnType;
|
|
24
|
+
/** Create a secondary index on this column. */
|
|
25
|
+
index?: boolean;
|
|
26
|
+
unique?: boolean;
|
|
27
|
+
notNull?: boolean;
|
|
28
|
+
/** Default value (string/number literal, or null). */
|
|
29
|
+
default?: string | number | null;
|
|
30
|
+
/** Foreign-key target, e.g. `"users(_id)"` or `"users"`. */
|
|
31
|
+
references?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Map of field name to column type (or full definition). */
|
|
34
|
+
type CollectionSchema = Record<string, ColumnType | ColumnDef>;
|
|
35
|
+
interface CollectionOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Declare native SQL columns ("structured" mode). Listed fields become real
|
|
38
|
+
* typed columns — fast, indexable, joinable — and any other fields overflow
|
|
39
|
+
* into a JSON column. Omit for schema-free document mode. The CRUD/query API
|
|
40
|
+
* is identical either way.
|
|
41
|
+
*/
|
|
42
|
+
schema?: CollectionSchema;
|
|
43
|
+
}
|
|
44
|
+
type CollectionMode = "document" | "structured";
|
|
45
|
+
/** A column as reported by {@link Monlite.$schema}. */
|
|
46
|
+
interface ColumnInfo {
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
notNull: boolean;
|
|
50
|
+
primaryKey: boolean;
|
|
51
|
+
}
|
|
19
52
|
/** Per-field operators, Prisma-style (no `$` prefix). */
|
|
20
53
|
interface FieldFilter<V = any> {
|
|
21
54
|
equals?: V | null;
|
|
@@ -130,9 +163,27 @@ interface AggregateResult {
|
|
|
130
163
|
_min?: Record<string, any>;
|
|
131
164
|
_max?: Record<string, any>;
|
|
132
165
|
}
|
|
166
|
+
/** Numeric comparison used by `groupBy` having-filters. */
|
|
167
|
+
interface HavingComparison {
|
|
168
|
+
equals?: number;
|
|
169
|
+
not?: number;
|
|
170
|
+
gt?: number;
|
|
171
|
+
gte?: number;
|
|
172
|
+
lt?: number;
|
|
173
|
+
lte?: number;
|
|
174
|
+
}
|
|
175
|
+
/** Post-aggregation filter (SQL `HAVING`) for `groupBy`. */
|
|
176
|
+
interface HavingInput {
|
|
177
|
+
_count?: HavingComparison;
|
|
178
|
+
_sum?: Record<string, HavingComparison>;
|
|
179
|
+
_avg?: Record<string, HavingComparison>;
|
|
180
|
+
_min?: Record<string, HavingComparison>;
|
|
181
|
+
_max?: Record<string, HavingComparison>;
|
|
182
|
+
}
|
|
133
183
|
interface GroupByArgs<T = Doc> {
|
|
134
184
|
by: string[];
|
|
135
185
|
where?: WhereInput<T>;
|
|
186
|
+
having?: HavingInput;
|
|
136
187
|
_count?: boolean;
|
|
137
188
|
_sum?: FieldSelection;
|
|
138
189
|
_avg?: FieldSelection;
|
|
@@ -150,6 +201,17 @@ interface MonliteOptions {
|
|
|
150
201
|
* when installed, otherwise the built-in `node:sqlite` (Node >= 22.5).
|
|
151
202
|
*/
|
|
152
203
|
driver?: DriverName;
|
|
204
|
+
/**
|
|
205
|
+
* Enable sync metadata (change feed, tombstones, version tracking) so the
|
|
206
|
+
* database can replicate via `@monlite/sync`. Off by default — adds zero
|
|
207
|
+
* overhead when disabled.
|
|
208
|
+
*/
|
|
209
|
+
sync?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Stable node identity used for last-write-wins tie-breaking. Auto-generated
|
|
212
|
+
* and persisted in the database on first sync-enabled open if omitted.
|
|
213
|
+
*/
|
|
214
|
+
nodeId?: string;
|
|
153
215
|
/** Auto-create indexes on frequently-queried JSON paths. Default `true`. */
|
|
154
216
|
autoIndex?: boolean;
|
|
155
217
|
/** Number of times a path must be queried before an index is created. Default `10`. */
|
|
@@ -163,19 +225,39 @@ interface MonliteOptions {
|
|
|
163
225
|
}
|
|
164
226
|
|
|
165
227
|
/**
|
|
166
|
-
* A
|
|
167
|
-
*
|
|
228
|
+
* A collection. In **document** mode (default) every document is stored as JSON
|
|
229
|
+
* in a `data` column — schema-free. In **structured** mode (when a `schema` is
|
|
230
|
+
* given) the listed fields become real, typed SQL columns (fast, indexable,
|
|
231
|
+
* joinable) while any other fields overflow into a JSON `data` column. The CRUD
|
|
232
|
+
* and query API is identical in both modes.
|
|
168
233
|
*/
|
|
169
234
|
declare class Collection<T = Doc> {
|
|
170
235
|
private readonly mon;
|
|
171
236
|
readonly name: string;
|
|
237
|
+
readonly mode: CollectionMode;
|
|
172
238
|
private initialized;
|
|
239
|
+
private readonly columnDefs;
|
|
240
|
+
private readonly columnOrder;
|
|
241
|
+
/** Declared native columns (empty in document mode). */
|
|
242
|
+
private readonly columns;
|
|
243
|
+
private readonly jsonColumns;
|
|
244
|
+
private insertSqlCache?;
|
|
173
245
|
private readonly trackPath;
|
|
174
|
-
constructor(mon: Monlite, name: string);
|
|
246
|
+
constructor(mon: Monlite, name: string, options?: CollectionOptions);
|
|
175
247
|
private get db();
|
|
248
|
+
/** Native column names declared for this collection (structured mode). */
|
|
249
|
+
get columnNames(): string[];
|
|
176
250
|
private ensureTable;
|
|
177
251
|
private rowToDoc;
|
|
178
|
-
private
|
|
252
|
+
private encodeColumn;
|
|
253
|
+
private insertColumns;
|
|
254
|
+
private insertSql;
|
|
255
|
+
/** Split an input document into a row aligned with `insertColumns()`. */
|
|
256
|
+
private buildInsert;
|
|
257
|
+
/** Build the `SET` clause + values to persist an updated document. */
|
|
258
|
+
private buildUpdateSet;
|
|
259
|
+
/** Sync store, but only for document collections (structured sync is future work). */
|
|
260
|
+
private get recorder();
|
|
179
261
|
create(args: CreateArgs<T>): Promise<WithId<T>>;
|
|
180
262
|
createMany(args: CreateManyArgs<T>): Promise<{
|
|
181
263
|
count: number;
|
|
@@ -184,6 +266,11 @@ declare class Collection<T = Doc> {
|
|
|
184
266
|
findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
|
|
185
267
|
findById(id: string): Promise<WithId<T> | null>;
|
|
186
268
|
count(args?: CountArgs<T>): Promise<number>;
|
|
269
|
+
/**
|
|
270
|
+
* Return the distinct values of a field. Array fields stored in JSON are
|
|
271
|
+
* unwound (each element counts as a value), matching MongoDB's `distinct`.
|
|
272
|
+
*/
|
|
273
|
+
distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
|
|
187
274
|
private runUpdate;
|
|
188
275
|
update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
|
|
189
276
|
updateMany(args: UpdateArgs<T>): Promise<{
|
|
@@ -242,6 +329,121 @@ declare class AutoIndexer {
|
|
|
242
329
|
reset(collection?: string): void;
|
|
243
330
|
}
|
|
244
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Versions are LWW (last-write-wins) tokens of the form
|
|
334
|
+
* `<zero-padded-ms>:<nodeId>` so that plain string comparison yields the
|
|
335
|
+
* correct ordering: newer wall-clock time wins, ties broken by node id.
|
|
336
|
+
*
|
|
337
|
+
* (The design reserves room to swap this for a hybrid logical clock later;
|
|
338
|
+
* the on-disk column is a plain string, so the format can evolve.)
|
|
339
|
+
*/
|
|
340
|
+
type Version = string;
|
|
341
|
+
declare function makeVersion(ts: number, nodeId: string): Version;
|
|
342
|
+
declare function compareVersions(a: Version, b: Version): number;
|
|
343
|
+
declare function versionTs(v: Version): number;
|
|
344
|
+
|
|
345
|
+
type SyncOp = "upsert" | "delete";
|
|
346
|
+
/** A locally-originated change ready to be pushed to a remote. */
|
|
347
|
+
interface LocalChange {
|
|
348
|
+
seq: number;
|
|
349
|
+
collection: string;
|
|
350
|
+
_id: string;
|
|
351
|
+
op: SyncOp;
|
|
352
|
+
version: Version;
|
|
353
|
+
ts: number;
|
|
354
|
+
/** Full document (with system fields) for `upsert`; absent for `delete`. */
|
|
355
|
+
doc?: Record<string, any>;
|
|
356
|
+
}
|
|
357
|
+
/** A change received from a remote, to be applied locally. */
|
|
358
|
+
interface RemoteChange {
|
|
359
|
+
collection: string;
|
|
360
|
+
_id: string;
|
|
361
|
+
op: SyncOp;
|
|
362
|
+
version: Version;
|
|
363
|
+
doc?: Record<string, any>;
|
|
364
|
+
}
|
|
365
|
+
type ConflictResolver = (ctx: {
|
|
366
|
+
collection: string;
|
|
367
|
+
_id: string;
|
|
368
|
+
local: {
|
|
369
|
+
version: Version;
|
|
370
|
+
};
|
|
371
|
+
remote: {
|
|
372
|
+
version: Version;
|
|
373
|
+
doc?: Record<string, any>;
|
|
374
|
+
};
|
|
375
|
+
}) => "local" | "remote";
|
|
376
|
+
interface ApplyResult {
|
|
377
|
+
applied: boolean;
|
|
378
|
+
conflict: boolean;
|
|
379
|
+
winner: "local" | "remote" | "none";
|
|
380
|
+
}
|
|
381
|
+
interface SyncStateRow {
|
|
382
|
+
remote: string;
|
|
383
|
+
cursor: string | null;
|
|
384
|
+
lastPullAt: number | null;
|
|
385
|
+
lastPushSeq: number | null;
|
|
386
|
+
lastPushAt: number | null;
|
|
387
|
+
}
|
|
388
|
+
interface ConflictRow {
|
|
389
|
+
collection: string;
|
|
390
|
+
_id: string;
|
|
391
|
+
localVersion: Version;
|
|
392
|
+
remoteVersion: Version;
|
|
393
|
+
winner: "local" | "remote";
|
|
394
|
+
ts: number;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Low-level sync primitives stored alongside the data in the same `.db` file:
|
|
398
|
+
* an append-only change feed, tombstones, per-remote cursors and a conflict
|
|
399
|
+
* log. Created only when a database is opened with `{ sync: true }`. The
|
|
400
|
+
* `@monlite/sync` engine drives this; apps rarely touch it directly.
|
|
401
|
+
*/
|
|
402
|
+
declare class SyncStore {
|
|
403
|
+
private readonly db;
|
|
404
|
+
readonly nodeId: string;
|
|
405
|
+
constructor(db: Driver, nodeId?: string);
|
|
406
|
+
private init;
|
|
407
|
+
private resolveNodeId;
|
|
408
|
+
/** True if this database tracks sync metadata (always, once constructed). */
|
|
409
|
+
get enabled(): boolean;
|
|
410
|
+
/** Append a locally-originated change to the feed. Call inside a write txn. */
|
|
411
|
+
recordLocal(collection: string, id: string, op: SyncOp, ts: number): Version;
|
|
412
|
+
/** Current (latest) version of a document, or null if never recorded. */
|
|
413
|
+
currentVersion(collection: string, id: string): Version | null;
|
|
414
|
+
/** Latest unpushed local change per document (the push queue). */
|
|
415
|
+
pending(collections?: string[]): LocalChange[];
|
|
416
|
+
/** Mark the given changes (and any earlier local rows per doc) as pushed. */
|
|
417
|
+
markPushed(changes: LocalChange[]): void;
|
|
418
|
+
/**
|
|
419
|
+
* Apply a remote change, resolving conflicts against the local version.
|
|
420
|
+
* Remote-applied changes are recorded with `source='remote'` so they are
|
|
421
|
+
* never pushed back (echo prevention).
|
|
422
|
+
*/
|
|
423
|
+
applyRemote(change: RemoteChange, resolver?: ConflictResolver): ApplyResult;
|
|
424
|
+
private applyData;
|
|
425
|
+
/**
|
|
426
|
+
* Latest change per document with `seq` greater than the given watermark,
|
|
427
|
+
* as RemoteChanges (used when this database acts as a sync *source*, e.g. the
|
|
428
|
+
* monlite-as-remote adapter). Returns the new watermark to resume from.
|
|
429
|
+
*/
|
|
430
|
+
changesSince(seq: number, collections?: string[]): {
|
|
431
|
+
changes: RemoteChange[];
|
|
432
|
+
maxSeq: number;
|
|
433
|
+
};
|
|
434
|
+
/**
|
|
435
|
+
* Enqueue existing documents (created before sync was enabled, or never
|
|
436
|
+
* recorded) as local upserts so they can be pushed. Idempotent.
|
|
437
|
+
*/
|
|
438
|
+
seed(collections: string[]): number;
|
|
439
|
+
getState(remote: string): SyncStateRow;
|
|
440
|
+
setState(remote: string, patch: Partial<Omit<SyncStateRow, "remote">>): void;
|
|
441
|
+
private recordConflict;
|
|
442
|
+
conflicts(): ConflictRow[];
|
|
443
|
+
private readDoc;
|
|
444
|
+
private ensureCollTable;
|
|
445
|
+
}
|
|
446
|
+
|
|
245
447
|
/**
|
|
246
448
|
* A monlite database — a thin document layer over a single SQLite file.
|
|
247
449
|
* Create one with {@link createDb}.
|
|
@@ -251,15 +453,25 @@ declare class Monlite {
|
|
|
251
453
|
readonly driver: Driver;
|
|
252
454
|
/** @internal */
|
|
253
455
|
readonly autoIndexer: AutoIndexer;
|
|
456
|
+
/** @internal Sync metadata store; present only when `{ sync: true }`. */
|
|
457
|
+
readonly $sync?: SyncStore;
|
|
254
458
|
private readonly collections;
|
|
255
459
|
private closed;
|
|
256
460
|
constructor(filename: string, options?: MonliteOptions);
|
|
461
|
+
/** Stable node id for LWW tie-breaking (only when sync is enabled). */
|
|
462
|
+
get nodeId(): string | undefined;
|
|
257
463
|
/** The underlying native database handle (escape hatch). */
|
|
258
464
|
get sqlite(): any;
|
|
259
465
|
/** Name of the active backend: `"better-sqlite3"` or `"node:sqlite"`. */
|
|
260
466
|
get driverName(): string;
|
|
261
|
-
/**
|
|
262
|
-
|
|
467
|
+
/**
|
|
468
|
+
* Get (or lazily create) a typed collection handle. Pass `{ schema }` to make
|
|
469
|
+
* it a structured collection backed by native SQL columns; omit for the
|
|
470
|
+
* default schema-free document mode. Options apply only on first access.
|
|
471
|
+
*/
|
|
472
|
+
collection<T = Doc>(name: string, options?: CollectionOptions): Collection<T>;
|
|
473
|
+
/** Inspect a collection's physical columns (PRAGMA table_info). */
|
|
474
|
+
$schema(name: string): Promise<ColumnInfo[]>;
|
|
263
475
|
/** Tagged-template SQL query returning rows. Values are safely parameterized. */
|
|
264
476
|
$queryRaw<R = any>(strings: TemplateStringsArray, ...values: any[]): Promise<R[]>;
|
|
265
477
|
/** Like {@link $queryRaw} but takes a raw SQL string and positional params. */
|
|
@@ -302,4 +514,4 @@ declare function objectId(): string;
|
|
|
302
514
|
/** True when a value looks like a monlite/ObjectId id (24 hex chars). */
|
|
303
515
|
declare function isObjectId(value: unknown): value is string;
|
|
304
516
|
|
|
305
|
-
export { type AggregateArgs, type AggregateResult, Collection, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, Monlite, MonliteError, type MonliteOptions, MonliteQueryError, type OrderBy, type PreparedStatement, type Select, type SortOrder, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type WhereInput as WhereClause, type WhereInput, type WithId, createDb, isObjectId, objectId };
|
|
517
|
+
export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LocalChange, Monlite, MonliteError, type MonliteOptions, MonliteQueryError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, objectId, versionTs };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,39 @@ interface SystemFields {
|
|
|
16
16
|
}
|
|
17
17
|
/** A stored document: the user's shape plus monlite's system fields. */
|
|
18
18
|
type WithId<T> = T & SystemFields;
|
|
19
|
+
/** SQLite column affinity for a structured-collection field. */
|
|
20
|
+
type ColumnType = "TEXT" | "INTEGER" | "REAL" | "BLOB" | "JSON";
|
|
21
|
+
/** Rich column definition for a structured collection. */
|
|
22
|
+
interface ColumnDef {
|
|
23
|
+
type: ColumnType;
|
|
24
|
+
/** Create a secondary index on this column. */
|
|
25
|
+
index?: boolean;
|
|
26
|
+
unique?: boolean;
|
|
27
|
+
notNull?: boolean;
|
|
28
|
+
/** Default value (string/number literal, or null). */
|
|
29
|
+
default?: string | number | null;
|
|
30
|
+
/** Foreign-key target, e.g. `"users(_id)"` or `"users"`. */
|
|
31
|
+
references?: string;
|
|
32
|
+
}
|
|
33
|
+
/** Map of field name to column type (or full definition). */
|
|
34
|
+
type CollectionSchema = Record<string, ColumnType | ColumnDef>;
|
|
35
|
+
interface CollectionOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Declare native SQL columns ("structured" mode). Listed fields become real
|
|
38
|
+
* typed columns — fast, indexable, joinable — and any other fields overflow
|
|
39
|
+
* into a JSON column. Omit for schema-free document mode. The CRUD/query API
|
|
40
|
+
* is identical either way.
|
|
41
|
+
*/
|
|
42
|
+
schema?: CollectionSchema;
|
|
43
|
+
}
|
|
44
|
+
type CollectionMode = "document" | "structured";
|
|
45
|
+
/** A column as reported by {@link Monlite.$schema}. */
|
|
46
|
+
interface ColumnInfo {
|
|
47
|
+
name: string;
|
|
48
|
+
type: string;
|
|
49
|
+
notNull: boolean;
|
|
50
|
+
primaryKey: boolean;
|
|
51
|
+
}
|
|
19
52
|
/** Per-field operators, Prisma-style (no `$` prefix). */
|
|
20
53
|
interface FieldFilter<V = any> {
|
|
21
54
|
equals?: V | null;
|
|
@@ -130,9 +163,27 @@ interface AggregateResult {
|
|
|
130
163
|
_min?: Record<string, any>;
|
|
131
164
|
_max?: Record<string, any>;
|
|
132
165
|
}
|
|
166
|
+
/** Numeric comparison used by `groupBy` having-filters. */
|
|
167
|
+
interface HavingComparison {
|
|
168
|
+
equals?: number;
|
|
169
|
+
not?: number;
|
|
170
|
+
gt?: number;
|
|
171
|
+
gte?: number;
|
|
172
|
+
lt?: number;
|
|
173
|
+
lte?: number;
|
|
174
|
+
}
|
|
175
|
+
/** Post-aggregation filter (SQL `HAVING`) for `groupBy`. */
|
|
176
|
+
interface HavingInput {
|
|
177
|
+
_count?: HavingComparison;
|
|
178
|
+
_sum?: Record<string, HavingComparison>;
|
|
179
|
+
_avg?: Record<string, HavingComparison>;
|
|
180
|
+
_min?: Record<string, HavingComparison>;
|
|
181
|
+
_max?: Record<string, HavingComparison>;
|
|
182
|
+
}
|
|
133
183
|
interface GroupByArgs<T = Doc> {
|
|
134
184
|
by: string[];
|
|
135
185
|
where?: WhereInput<T>;
|
|
186
|
+
having?: HavingInput;
|
|
136
187
|
_count?: boolean;
|
|
137
188
|
_sum?: FieldSelection;
|
|
138
189
|
_avg?: FieldSelection;
|
|
@@ -150,6 +201,17 @@ interface MonliteOptions {
|
|
|
150
201
|
* when installed, otherwise the built-in `node:sqlite` (Node >= 22.5).
|
|
151
202
|
*/
|
|
152
203
|
driver?: DriverName;
|
|
204
|
+
/**
|
|
205
|
+
* Enable sync metadata (change feed, tombstones, version tracking) so the
|
|
206
|
+
* database can replicate via `@monlite/sync`. Off by default — adds zero
|
|
207
|
+
* overhead when disabled.
|
|
208
|
+
*/
|
|
209
|
+
sync?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Stable node identity used for last-write-wins tie-breaking. Auto-generated
|
|
212
|
+
* and persisted in the database on first sync-enabled open if omitted.
|
|
213
|
+
*/
|
|
214
|
+
nodeId?: string;
|
|
153
215
|
/** Auto-create indexes on frequently-queried JSON paths. Default `true`. */
|
|
154
216
|
autoIndex?: boolean;
|
|
155
217
|
/** Number of times a path must be queried before an index is created. Default `10`. */
|
|
@@ -163,19 +225,39 @@ interface MonliteOptions {
|
|
|
163
225
|
}
|
|
164
226
|
|
|
165
227
|
/**
|
|
166
|
-
* A
|
|
167
|
-
*
|
|
228
|
+
* A collection. In **document** mode (default) every document is stored as JSON
|
|
229
|
+
* in a `data` column — schema-free. In **structured** mode (when a `schema` is
|
|
230
|
+
* given) the listed fields become real, typed SQL columns (fast, indexable,
|
|
231
|
+
* joinable) while any other fields overflow into a JSON `data` column. The CRUD
|
|
232
|
+
* and query API is identical in both modes.
|
|
168
233
|
*/
|
|
169
234
|
declare class Collection<T = Doc> {
|
|
170
235
|
private readonly mon;
|
|
171
236
|
readonly name: string;
|
|
237
|
+
readonly mode: CollectionMode;
|
|
172
238
|
private initialized;
|
|
239
|
+
private readonly columnDefs;
|
|
240
|
+
private readonly columnOrder;
|
|
241
|
+
/** Declared native columns (empty in document mode). */
|
|
242
|
+
private readonly columns;
|
|
243
|
+
private readonly jsonColumns;
|
|
244
|
+
private insertSqlCache?;
|
|
173
245
|
private readonly trackPath;
|
|
174
|
-
constructor(mon: Monlite, name: string);
|
|
246
|
+
constructor(mon: Monlite, name: string, options?: CollectionOptions);
|
|
175
247
|
private get db();
|
|
248
|
+
/** Native column names declared for this collection (structured mode). */
|
|
249
|
+
get columnNames(): string[];
|
|
176
250
|
private ensureTable;
|
|
177
251
|
private rowToDoc;
|
|
178
|
-
private
|
|
252
|
+
private encodeColumn;
|
|
253
|
+
private insertColumns;
|
|
254
|
+
private insertSql;
|
|
255
|
+
/** Split an input document into a row aligned with `insertColumns()`. */
|
|
256
|
+
private buildInsert;
|
|
257
|
+
/** Build the `SET` clause + values to persist an updated document. */
|
|
258
|
+
private buildUpdateSet;
|
|
259
|
+
/** Sync store, but only for document collections (structured sync is future work). */
|
|
260
|
+
private get recorder();
|
|
179
261
|
create(args: CreateArgs<T>): Promise<WithId<T>>;
|
|
180
262
|
createMany(args: CreateManyArgs<T>): Promise<{
|
|
181
263
|
count: number;
|
|
@@ -184,6 +266,11 @@ declare class Collection<T = Doc> {
|
|
|
184
266
|
findFirst(args?: FindFirstArgs<T>): Promise<WithId<T> | null>;
|
|
185
267
|
findById(id: string): Promise<WithId<T> | null>;
|
|
186
268
|
count(args?: CountArgs<T>): Promise<number>;
|
|
269
|
+
/**
|
|
270
|
+
* Return the distinct values of a field. Array fields stored in JSON are
|
|
271
|
+
* unwound (each element counts as a value), matching MongoDB's `distinct`.
|
|
272
|
+
*/
|
|
273
|
+
distinct(field: string, where?: WhereInput<T>): Promise<any[]>;
|
|
187
274
|
private runUpdate;
|
|
188
275
|
update(args: UpdateArgs<T>): Promise<WithId<T> | null>;
|
|
189
276
|
updateMany(args: UpdateArgs<T>): Promise<{
|
|
@@ -242,6 +329,121 @@ declare class AutoIndexer {
|
|
|
242
329
|
reset(collection?: string): void;
|
|
243
330
|
}
|
|
244
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Versions are LWW (last-write-wins) tokens of the form
|
|
334
|
+
* `<zero-padded-ms>:<nodeId>` so that plain string comparison yields the
|
|
335
|
+
* correct ordering: newer wall-clock time wins, ties broken by node id.
|
|
336
|
+
*
|
|
337
|
+
* (The design reserves room to swap this for a hybrid logical clock later;
|
|
338
|
+
* the on-disk column is a plain string, so the format can evolve.)
|
|
339
|
+
*/
|
|
340
|
+
type Version = string;
|
|
341
|
+
declare function makeVersion(ts: number, nodeId: string): Version;
|
|
342
|
+
declare function compareVersions(a: Version, b: Version): number;
|
|
343
|
+
declare function versionTs(v: Version): number;
|
|
344
|
+
|
|
345
|
+
type SyncOp = "upsert" | "delete";
|
|
346
|
+
/** A locally-originated change ready to be pushed to a remote. */
|
|
347
|
+
interface LocalChange {
|
|
348
|
+
seq: number;
|
|
349
|
+
collection: string;
|
|
350
|
+
_id: string;
|
|
351
|
+
op: SyncOp;
|
|
352
|
+
version: Version;
|
|
353
|
+
ts: number;
|
|
354
|
+
/** Full document (with system fields) for `upsert`; absent for `delete`. */
|
|
355
|
+
doc?: Record<string, any>;
|
|
356
|
+
}
|
|
357
|
+
/** A change received from a remote, to be applied locally. */
|
|
358
|
+
interface RemoteChange {
|
|
359
|
+
collection: string;
|
|
360
|
+
_id: string;
|
|
361
|
+
op: SyncOp;
|
|
362
|
+
version: Version;
|
|
363
|
+
doc?: Record<string, any>;
|
|
364
|
+
}
|
|
365
|
+
type ConflictResolver = (ctx: {
|
|
366
|
+
collection: string;
|
|
367
|
+
_id: string;
|
|
368
|
+
local: {
|
|
369
|
+
version: Version;
|
|
370
|
+
};
|
|
371
|
+
remote: {
|
|
372
|
+
version: Version;
|
|
373
|
+
doc?: Record<string, any>;
|
|
374
|
+
};
|
|
375
|
+
}) => "local" | "remote";
|
|
376
|
+
interface ApplyResult {
|
|
377
|
+
applied: boolean;
|
|
378
|
+
conflict: boolean;
|
|
379
|
+
winner: "local" | "remote" | "none";
|
|
380
|
+
}
|
|
381
|
+
interface SyncStateRow {
|
|
382
|
+
remote: string;
|
|
383
|
+
cursor: string | null;
|
|
384
|
+
lastPullAt: number | null;
|
|
385
|
+
lastPushSeq: number | null;
|
|
386
|
+
lastPushAt: number | null;
|
|
387
|
+
}
|
|
388
|
+
interface ConflictRow {
|
|
389
|
+
collection: string;
|
|
390
|
+
_id: string;
|
|
391
|
+
localVersion: Version;
|
|
392
|
+
remoteVersion: Version;
|
|
393
|
+
winner: "local" | "remote";
|
|
394
|
+
ts: number;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Low-level sync primitives stored alongside the data in the same `.db` file:
|
|
398
|
+
* an append-only change feed, tombstones, per-remote cursors and a conflict
|
|
399
|
+
* log. Created only when a database is opened with `{ sync: true }`. The
|
|
400
|
+
* `@monlite/sync` engine drives this; apps rarely touch it directly.
|
|
401
|
+
*/
|
|
402
|
+
declare class SyncStore {
|
|
403
|
+
private readonly db;
|
|
404
|
+
readonly nodeId: string;
|
|
405
|
+
constructor(db: Driver, nodeId?: string);
|
|
406
|
+
private init;
|
|
407
|
+
private resolveNodeId;
|
|
408
|
+
/** True if this database tracks sync metadata (always, once constructed). */
|
|
409
|
+
get enabled(): boolean;
|
|
410
|
+
/** Append a locally-originated change to the feed. Call inside a write txn. */
|
|
411
|
+
recordLocal(collection: string, id: string, op: SyncOp, ts: number): Version;
|
|
412
|
+
/** Current (latest) version of a document, or null if never recorded. */
|
|
413
|
+
currentVersion(collection: string, id: string): Version | null;
|
|
414
|
+
/** Latest unpushed local change per document (the push queue). */
|
|
415
|
+
pending(collections?: string[]): LocalChange[];
|
|
416
|
+
/** Mark the given changes (and any earlier local rows per doc) as pushed. */
|
|
417
|
+
markPushed(changes: LocalChange[]): void;
|
|
418
|
+
/**
|
|
419
|
+
* Apply a remote change, resolving conflicts against the local version.
|
|
420
|
+
* Remote-applied changes are recorded with `source='remote'` so they are
|
|
421
|
+
* never pushed back (echo prevention).
|
|
422
|
+
*/
|
|
423
|
+
applyRemote(change: RemoteChange, resolver?: ConflictResolver): ApplyResult;
|
|
424
|
+
private applyData;
|
|
425
|
+
/**
|
|
426
|
+
* Latest change per document with `seq` greater than the given watermark,
|
|
427
|
+
* as RemoteChanges (used when this database acts as a sync *source*, e.g. the
|
|
428
|
+
* monlite-as-remote adapter). Returns the new watermark to resume from.
|
|
429
|
+
*/
|
|
430
|
+
changesSince(seq: number, collections?: string[]): {
|
|
431
|
+
changes: RemoteChange[];
|
|
432
|
+
maxSeq: number;
|
|
433
|
+
};
|
|
434
|
+
/**
|
|
435
|
+
* Enqueue existing documents (created before sync was enabled, or never
|
|
436
|
+
* recorded) as local upserts so they can be pushed. Idempotent.
|
|
437
|
+
*/
|
|
438
|
+
seed(collections: string[]): number;
|
|
439
|
+
getState(remote: string): SyncStateRow;
|
|
440
|
+
setState(remote: string, patch: Partial<Omit<SyncStateRow, "remote">>): void;
|
|
441
|
+
private recordConflict;
|
|
442
|
+
conflicts(): ConflictRow[];
|
|
443
|
+
private readDoc;
|
|
444
|
+
private ensureCollTable;
|
|
445
|
+
}
|
|
446
|
+
|
|
245
447
|
/**
|
|
246
448
|
* A monlite database — a thin document layer over a single SQLite file.
|
|
247
449
|
* Create one with {@link createDb}.
|
|
@@ -251,15 +453,25 @@ declare class Monlite {
|
|
|
251
453
|
readonly driver: Driver;
|
|
252
454
|
/** @internal */
|
|
253
455
|
readonly autoIndexer: AutoIndexer;
|
|
456
|
+
/** @internal Sync metadata store; present only when `{ sync: true }`. */
|
|
457
|
+
readonly $sync?: SyncStore;
|
|
254
458
|
private readonly collections;
|
|
255
459
|
private closed;
|
|
256
460
|
constructor(filename: string, options?: MonliteOptions);
|
|
461
|
+
/** Stable node id for LWW tie-breaking (only when sync is enabled). */
|
|
462
|
+
get nodeId(): string | undefined;
|
|
257
463
|
/** The underlying native database handle (escape hatch). */
|
|
258
464
|
get sqlite(): any;
|
|
259
465
|
/** Name of the active backend: `"better-sqlite3"` or `"node:sqlite"`. */
|
|
260
466
|
get driverName(): string;
|
|
261
|
-
/**
|
|
262
|
-
|
|
467
|
+
/**
|
|
468
|
+
* Get (or lazily create) a typed collection handle. Pass `{ schema }` to make
|
|
469
|
+
* it a structured collection backed by native SQL columns; omit for the
|
|
470
|
+
* default schema-free document mode. Options apply only on first access.
|
|
471
|
+
*/
|
|
472
|
+
collection<T = Doc>(name: string, options?: CollectionOptions): Collection<T>;
|
|
473
|
+
/** Inspect a collection's physical columns (PRAGMA table_info). */
|
|
474
|
+
$schema(name: string): Promise<ColumnInfo[]>;
|
|
263
475
|
/** Tagged-template SQL query returning rows. Values are safely parameterized. */
|
|
264
476
|
$queryRaw<R = any>(strings: TemplateStringsArray, ...values: any[]): Promise<R[]>;
|
|
265
477
|
/** Like {@link $queryRaw} but takes a raw SQL string and positional params. */
|
|
@@ -302,4 +514,4 @@ declare function objectId(): string;
|
|
|
302
514
|
/** True when a value looks like a monlite/ObjectId id (24 hex chars). */
|
|
303
515
|
declare function isObjectId(value: unknown): value is string;
|
|
304
516
|
|
|
305
|
-
export { type AggregateArgs, type AggregateResult, Collection, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, Monlite, MonliteError, type MonliteOptions, MonliteQueryError, type OrderBy, type PreparedStatement, type Select, type SortOrder, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type WhereInput as WhereClause, type WhereInput, type WithId, createDb, isObjectId, objectId };
|
|
517
|
+
export { type AggregateArgs, type AggregateResult, type ApplyResult, Collection, type CollectionMode, type CollectionOptions, type CollectionSchema, type ColumnDef, type ColumnInfo, type ColumnType, type ConflictResolver, type ConflictRow, type CountArgs, type CreateArgs, type CreateManyArgs, Monlite as Db, type DeleteArgs, type Doc, type Driver, type DriverName, type FieldFilter, type FieldSelection, type FilterInput, type FindFirstArgs, type FindManyArgs, type GroupByArgs, type GroupByResult, type HavingComparison, type HavingInput, type LocalChange, Monlite, MonliteError, type MonliteOptions, MonliteQueryError, type OrderBy, type PreparedStatement, type RemoteChange, type Select, type SortOrder, type SyncOp, type SyncStateRow, SyncStore, type SystemFields, type UpdateArgs, type UpdateData, type UpdateOperators, type UpsertArgs, type Version, type WhereInput as WhereClause, type WhereInput, type WithId, compareVersions, createDb, isObjectId, makeVersion, objectId, versionTs };
|