@jarenjs/linq 0.73.0 → 0.83.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/types/db.d.ts CHANGED
@@ -145,6 +145,7 @@ export type Continuation<S, M extends EntityMeta> = LoadContinuation & {
145
145
  /** A page's options over this graph (the store's `PageOptions`, the
146
146
  * continuation typed by the declared ordering). */
147
147
  export interface GraphPageOptions<S, M extends EntityMeta> extends EntityCursorOptions {
148
+ lookahead?: boolean;
148
149
  limit?: number;
149
150
  after?: Continuation<S, M>;
150
151
  maxBytes?: number;
@@ -205,6 +206,7 @@ export interface Graph<E extends MetaMap<E>, M extends EntityMeta, S> {
205
206
  * exactly the many-to-many members. */
206
207
  export type EntityHandle<E extends MetaMap<E>, M extends EntityMeta> =
207
208
  TypedEntitySet<E, M> & ChainStart<M['doc']> & {
209
+ range(spec: import('@jarenjs/db').LoadSpec, options: DbRangeOptions): Promise<DbRangeProvider<M['doc']>>;
208
210
  /** Open a graph: include one relation member with an optional spec. */
209
211
  include<K extends keyof M['relations'] & string, const I extends IncludeSpec<E, TargetMeta<E, M, K>> = true>(
210
212
  pick: (u: RelationPicker<M>) => Picked<K>, spec?: I | NoInfer<IncludeSpec<E, TargetMeta<E, M, K>>>,
@@ -217,6 +219,40 @@ export type EntityHandle<E extends MetaMap<E>, M extends EntityMeta> =
217
219
  live<T = M['doc']>(source?: AsyncSequence<T, any> | object, options?: LiveOptions): Promise<TypedLiveQuery<T>>;
218
220
  };
219
221
 
222
+ export interface DbRangeOptions {
223
+ keys: readonly string[];
224
+ resident?: boolean; seekIndex?: boolean; exactTotal?: boolean;
225
+ source?: string; query?: string; schemaVersion?: string;
226
+ profile?: 'safe' | import('@jarenjs/db').ProfileSpec;
227
+ maxRows?: number; maxBytes?: number; maxPages?: number; maxInFlight?: number; maxSubscriptions?: number;
228
+ runtime?: Partial<Runtime>;
229
+ }
230
+ export interface DbRangeRequest {
231
+ generation: number; requestId: string; query: string; snapshot: string;
232
+ range?: { start: number; end: number }; continuation?: string;
233
+ credits: { pages: number; rows: number; bytes: number; work: number };
234
+ }
235
+ export interface DbRangeResponse<T = unknown> {
236
+ generation: number; requestId: string; query: string; snapshot: string;
237
+ state: 'ready' | 'loading' | 'error' | 'invalidated' | 'budget-exhausted'; reason?: string;
238
+ rows?: readonly T[]; keys?: readonly string[]; continuation?: string | null;
239
+ total?: { kind: 'known'; value: number } | { kind: 'unknown' };
240
+ used: { pages: number; rows: number; bytes: number; work: number };
241
+ }
242
+ export interface DbRangeProvider<T = unknown> {
243
+ readonly query: string; readonly snapshot: string;
244
+ readonly capabilities: Readonly<{ seekIndex: boolean; seekKey: false; continuation: true;
245
+ live: true; exactTotal: boolean; completeExport: false }>;
246
+ request(request: DbRangeRequest, signal?: AbortSignal): Promise<DbRangeResponse<T>>;
247
+ subscribe(observer: (event: { type: 'reset'; reason: string; query: string; snapshot: string; revision: number; capture: string }) => void): () => boolean;
248
+ stats(): { sourceReads: number; sourceRows: number; sourceBytes: number; pending: number;
249
+ pages: number; rows: number; bytes: number; subscriptions: number; disposed: boolean };
250
+ dispose(): Promise<void>;
251
+ }
252
+ /** Source capture is required; keyset mode is sequential unless resident is explicit. */
253
+ export declare function createDbRangeProvider<T = unknown>(store: import('@jarenjs/db').Store | TypedStore<any>,
254
+ entity: string, spec: import('@jarenjs/db').LoadSpec, options: DbRangeOptions): Promise<DbRangeProvider<T>>;
255
+
220
256
  /** Present exactly when the model declares entities, as on the store. */
221
257
  export interface EntityClientMembers {
222
258
  /** The store's unit of work, flushed. */
@@ -331,6 +367,9 @@ export type TransactionClientOf<E extends MetaMap<E>, C = Record<string, unknown
331
367
  /** The scope-bound store — the escape hatch, still inside. It carries
332
368
  * no `close`: a transaction never owns the connection's lifetime. */
333
369
  readonly store: TransactionStore;
370
+ readonly sql: TransactionStore['sql'];
371
+ readonly jobs: TransactionStore['jobs'];
372
+ readonly sync: TransactionStore['sync'];
334
373
  readonly capabilities: StoreCapabilities;
335
374
  readonly entities: { readonly [K in keyof E & string]: EntityHandle<E, E[K]> };
336
375
  readonly collections: { readonly [K in keyof C & string]: CollectionHandle<C[K]> };
@@ -364,3 +403,65 @@ export function defineReplication(header: Omit<import('@jarenjs/db').Replication
364
403
  toDocument(): import('@jarenjs/db').ReplicationEnvelope;
365
404
  toJSON(): import('@jarenjs/db').ReplicationEnvelope;
366
405
  };
406
+
407
+ /** A complete lexical membership composed with the common structural range provider. */
408
+ export declare function createLexicalRangeProvider(source: import('@jarenjs/db/search').DbSearch,
409
+ text: string, request?: Record<string, unknown>, options?: {maxMatches?:number; maxSourceBytes?:number;
410
+ maxRows?:number; maxBytes?:number; maxPages?:number; maxInFlight?:number; query?:string;
411
+ source?:string; exactTotal?:boolean; seekIndex?:boolean; disposeSource?:boolean}): Promise<any>;
412
+
413
+ /** Atomic staging and publication over application-declared collections. */
414
+ export function createDbIngestionStore(client: Client<any> | TransactionClientOf<any>, options: {
415
+ staging: string; checkpoints: string; publications: string; facts?: string;
416
+ reconcile?: (existing: any, incoming: any, evidence: any) => any;
417
+ }): {
418
+ begin(plan: any): Promise<any>;
419
+ stage(plan: any, partition: string, page: any): Promise<any>;
420
+ invalidate(plan: any, reason: string): Promise<void>;
421
+ publish(plan: any, evidence: any, context?: { signal?: AbortSignal }): Promise<any>;
422
+ current(source: string): Promise<any>;
423
+ inspect(plan: any): Promise<any>;
424
+ };
425
+
426
+ /** Lossless canonical-record mapping onto an application-declared collection. */
427
+ export type DurableRecordMapping = string | (({ collection: string; entity?: never } | { entity: string; collection?: never }) & { key?: (id: string) => any; read: (stored: any) => any; write: (record: any) => any });
428
+ export interface CommandIdentity {
429
+ tenant: string; environment: string; aggregate: string; op: string; key: string; hashVersion: string; hash: string;
430
+ }
431
+ /** Permanent business outcomes and independently expiring execution authority. */
432
+ export function createDbReceipts(client: Client<any> | TransactionClientOf<any>, options: {
433
+ receipts: DurableRecordMapping; leases?: DurableRecordMapping; runtime?: Partial<import('@jarenjs/core/runtime').Runtime>;
434
+ }): {
435
+ lookup(identity: CommandIdentity): Promise<any>;
436
+ execute(identity: CommandIdentity, work: (tx: TransactionClientOf<any>) => Promise<{ outcome: any; references?: any[] }>, context?: { lease?: any }): Promise<any>;
437
+ claim(identity: CommandIdentity, options: { leaseMs: number }): Promise<any>;
438
+ release(identity: CommandIdentity, lease: any): Promise<any>;
439
+ sweep(identities: CommandIdentity[]): Promise<{ changes: number; writes: number; revisions: number }>;
440
+ migrate(records: any[]): Promise<{ changes: number; writes: number; revisions: number }>;
441
+ compact(identity: CommandIdentity, policy: { retainReplay: true; retainReferences: true; actor: string; reason: string }): Promise<any>;
442
+ };
443
+ /** Durable preparation, job-fenced sending and explicit reconciliation. */
444
+ export function createDbEffectStore(client: Client<any> | TransactionClientOf<any>, options: {
445
+ operations: DurableRecordMapping; maxLegs?: number; maxBytes?: number;
446
+ }): {
447
+ prepare(plan: any, prepare?: (tx: TransactionClientOf<any>) => any): Promise<any>;
448
+ get(id: string): Promise<any>;
449
+ begin(id: string, legId: string, revision: number, lease: import('@jarenjs/db').JobLease): Promise<any>;
450
+ settle(id: string, legId: string, revision: number, lease: import('@jarenjs/db').JobLease, outcome: any): Promise<any>;
451
+ recover(id: string, revision: number, lease: import('@jarenjs/db').JobLease): Promise<any>;
452
+ reconcile(id: string, legId: string, revision: number, lease: import('@jarenjs/db').JobLease, decision: any): Promise<any>;
453
+ };
454
+ /** Application run/checkpoint records and bounded public revision pages. */
455
+ export function createDbRunStore(client: Client<any> | TransactionClientOf<any>, options: {
456
+ runs: DurableRecordMapping; events: DurableRecordMapping; statuses?: Record<string, string>;
457
+ summary?: (snapshot: any) => any; canReset?: (tx: TransactionClientOf<any>, record: any) => any; maxPage?: number; maxBytes?: number;
458
+ }): {
459
+ attach(identity: { id: string; jobId: string; workflow: string; schemaVersion: string }, lease: import('@jarenjs/db').JobLease): Promise<any>;
460
+ load(id: string, identity: any, lease: import('@jarenjs/db').JobLease): Promise<any>;
461
+ save(id: string, snapshot: any, expectedGeneration: number, lease: import('@jarenjs/db').JobLease): Promise<boolean>;
462
+ get(id: string): Promise<any>;
463
+ page(id: string, options?: { after?: number; limit?: number }): Promise<any>;
464
+ requestCancel(id: string, revision: number, evidence: { actor: string; reason: string }): Promise<any>;
465
+ finish(id: string, state: 'cancelled' | 'failed', lease: import('@jarenjs/db').JobLease): Promise<any>;
466
+ reset(id: string, revision: number, evidence: any, lease: import('@jarenjs/db').JobLease): Promise<any>;
467
+ };
@@ -0,0 +1,9 @@
1
+ /** Author a saved JSON Query formula without executing it. */
2
+ export declare function defineFormula(id: string, expression: unknown, options?: {
3
+ revision?: string;
4
+ bindings?: Record<string, unknown>;
5
+ inputSchema?: { id: string; version: string };
6
+ resultSchema?: { id: string; version: string };
7
+ helpers?: { name: string; version: string }[];
8
+ resultMode?: 'value' | 'outcome';
9
+ }): any;
package/types/index.d.ts CHANGED
@@ -77,6 +77,8 @@ export interface StringExpr extends ExprBase<string>, EqExpr<string>, SpatialMet
77
77
  contains(value: string | StringExpr): BoolExpr;
78
78
  /** I-Regexp (RFC 9485) full match. */
79
79
  matches(pattern: string): BoolExpr;
80
+ /** Explicit lexical provider request; preserves ranked-result completeness. */
81
+ lexical(provider: string, request?: Record<string, unknown>): UnknownExpr;
80
82
  upper(): StringExpr;
81
83
  lower(): StringExpr;
82
84
  length(): NumberExpr;
@@ -363,6 +365,8 @@ export interface UnknownExpr
363
365
  endsWith(value: unknown): BoolExpr;
364
366
  contains(value: unknown): BoolExpr;
365
367
  matches(pattern: string): BoolExpr;
368
+ /** Explicit lexical provider request; preserves ranked-result completeness. */
369
+ lexical(provider: string, request?: Record<string, unknown>): UnknownExpr;
366
370
  upper(): UnknownExpr;
367
371
  lower(): UnknownExpr;
368
372
  length(): NumberExpr;
@@ -795,15 +799,18 @@ export interface FederatedSide {
795
799
  readonly document: unknown;
796
800
  /** Whether this side is pulled row by row, or answered whole. */
797
801
  readonly streaming: 'row' | 'buffered';
802
+ readonly children?: readonly FederatedSide[];
798
803
  }
799
804
 
800
805
  /** What a federated document will do, without doing any of it (§12.1). */
801
806
  export interface FederationPlan {
802
807
  readonly strategy: 'hash';
803
808
  readonly budget: { readonly maxRows: number; readonly maxBytes: number };
809
+ readonly combinedBudget: { readonly maxTotalRows: number; readonly maxTotalBytes: number };
810
+ readonly order: readonly FederatedSide[];
804
811
  readonly build: FederatedSide;
805
812
  readonly probe: FederatedSide;
806
- /** The join itself is the engine's, over the two reduced sides. */
813
+ /** The engine evaluates the original binding order over the reduced sets. */
807
814
  readonly resident: { readonly document: unknown };
808
815
  }
809
816
 
@@ -822,13 +829,18 @@ export interface FederatedSource<T = unknown> extends AsyncProvider<T> {
822
829
  * out of that, by naming the sources and the bounds together: each
823
830
  * side's own filters and projection run at its source, the smaller side
824
831
  * fills a bounded hash table, the other is probed against it, and the
825
- * caller's own document decides over the two reduced sets. A side that
832
+ * caller's own document decides over the reduced sets. Connected N-way
833
+ * graphs and nested fluent joins share cumulative admission credits. A side that
826
834
  * reaches `maxRows` or `maxBytes` raises `JL2008` at the row that would
827
835
  * have broken the bound. */
828
836
  export function federate(spec: {
829
837
  sources: Record<string, AsyncProvider | { provider: AsyncProvider; estimatedRows?: number }>;
830
838
  maxRows: number;
831
839
  maxBytes: number;
840
+ /** Shared admission credits across source reads and intermediate sets; defaults to 2 * maxRows. */
841
+ maxTotalRows?: number;
842
+ /** Defaults to 2 * maxBytes. Buffered providers/intermediates are checked after production. */
843
+ maxTotalBytes?: number;
832
844
  strategy?: 'hash';
833
845
  }): {
834
846
  source<T = unknown>(name: string): FederatedSource<T>;
@@ -1,7 +1,7 @@
1
1
  // Derived from the English catalogs by scripts/generate-message-pen.js.
2
2
  export interface CatalogIds {
3
3
  validate: "type" | "required" | "minimum" | "maximum" | "exclusiveMinimum" | "exclusiveMaximum" | "multipleOf" | "minLength" | "maxLength" | "pattern" | "additionalProperties" | "minProperties" | "maxProperties" | "minItems" | "maxItems" | "uniqueItems" | "contains" | "items" | "allOf" | "anyOf" | "oneOf" | "not" | "format" | "if" | "then" | "else" | "false schema" | "$query" | "JQ2001" | "JQ2003";
4
- forms: "form/required" | "form/type" | "form/const" | "form/enum" | "form/minLength" | "form/maxLength" | "form/pattern" | "form/format" | "form/minimum" | "form/maximum" | "form/exclusiveMinimum" | "form/exclusiveMaximum" | "form/multipleOf" | "form/minItems" | "form/maxItems" | "form/uniqueItems" | "form/minProperties" | "form/maxProperties" | "x-form/assert" | "form/addItem" | "form/removeItem";
4
+ forms: "form/required" | "form/type" | "form/const" | "form/enum" | "form/minLength" | "form/maxLength" | "form/pattern" | "form/format" | "form/minimum" | "form/maximum" | "form/exclusiveMinimum" | "form/exclusiveMaximum" | "form/multipleOf" | "form/minItems" | "form/maxItems" | "form/uniqueItems" | "form/minProperties" | "form/maxProperties" | "x-form/assert" | "form/addItem" | "form/removeItem" | "form/jsonPlaceholder";
5
5
  contract: "contract/not-found" | "contract/method-not-allowed" | "contract/body-too-large" | "contract/unsupported-media" | "contract/malformed-json" | "contract/invalid-input" | "contract/idempotency-key-required" | "contract/handler-failed" | "contract/idempotency-conflict" | "contract/invalid-output" | "contract/malformed-path" | "contract/malformed-query" | "contract/not-implemented" | "contract/precondition-failed" | "contract/invalid-header" | "contract/handler-error" | "contract/client-invalid-input" | "contract/network" | "contract/cancelled" | "contract/invalid-response" | "contract/key-storage-failed" | "contract/undeclared-response" | "contract/not-a-contract" | "contract/incompatible" | "contract/host-failed" | "contract/local-handler-failed" | "contract/unknown-operation" | "contract/port-timeout" | "contract/malformed-frame" | "contract/channel-closed" | "contract/not-a-stream" | "contract/invalid-snapshot" | "contract/seq-regression" | "contract/stream-error" | "contract/heartbeat-missed" | "contract/slow-consumer" | "contract/reconnect-exhausted";
6
6
  }
7
7
  export interface MessageParameters {
@@ -56,6 +56,7 @@ export interface MessageParameters {
56
56
  "x-form/assert": never;
57
57
  "form/addItem": never;
58
58
  "form/removeItem": never;
59
+ "form/jsonPlaceholder": never;
59
60
  "contract/not-found": never;
60
61
  "contract/method-not-allowed": "allow";
61
62
  "contract/body-too-large": "limit" | "op";
package/types/model.d.ts CHANGED
@@ -61,6 +61,20 @@ export interface EntityBlock {
61
61
  };
62
62
  }
63
63
 
64
+ /** Explicit column-only layout for an existing SQLite object. */
65
+ export interface PhysicalLayout {
66
+ readonly table: string;
67
+ readonly kind?: 'table' | 'view';
68
+ readonly keys?: readonly string[];
69
+ readonly columns: Readonly<Record<string, {
70
+ readonly name: string;
71
+ readonly codec: 'text' | 'integer' | 'number' | 'boolean' | 'json' | 'date' | 'datetime' | 'epoch-ms' | 'bigint' | 'decimal' | 'blob-hex';
72
+ readonly null: 'null' | 'absent' | 'reject';
73
+ readonly default?: 'database';
74
+ readonly generated?: boolean;
75
+ }>>;
76
+ }
77
+
64
78
  // ————— the entity-aware builders —————
65
79
 
66
80
  /** The base every untyped kind is built from, plus the vocabulary. */
@@ -203,6 +217,10 @@ export class EntityObjectBuilder<
203
217
  P extends Props, Open extends boolean = false, PV = never, PVIn = PV,
204
218
  N extends boolean = false, F extends Flag = never,
205
219
  > extends ObjectBuilder<P, Open, PV, PVIn, N, F> {
220
+ physical(layout: PhysicalLayout): this;
221
+ invariants(rules: readonly { name: string; on: readonly ('insert' | 'update' | 'delete')[];
222
+ enforcement: 'database' | 'store'; assert: unknown;
223
+ audit?: { entity: string; values: Readonly<Record<string, unknown>> } }[]): this;
206
224
  optional(): EntityObjectBuilder<P, Open, PV, PVIn, N, F | 'optional'>;
207
225
  nullable(): EntityObjectBuilder<P, Open, PV, PVIn, true, F>;
208
226
  open(): EntityObjectBuilder<P, true, PV, PVIn, N, F>;
@@ -7,7 +7,13 @@ export type JsonInput<T> = unknown extends T ? unknown
7
7
  : T extends object ? { readonly [K in keyof T]: JsonInput<T[K]> } : never;
8
8
 
9
9
  export type FileKind = 'app' | 'jslt' | 'query' | 'state' | 'data' | 'schema' | 'fsm' | 'dag' | 'model' | 'contract';
10
- export interface ProjectFile<Name extends string = string, Kind extends FileKind = FileKind> {
10
+ export interface ProjectFileOptions {
11
+ readonly imports?: Readonly<Record<string, string>>;
12
+ readonly input?: string;
13
+ readonly model?: string;
14
+ readonly collection?: string;
15
+ }
16
+ export interface ProjectFile<Name extends string = string, Kind extends FileKind = FileKind> extends ProjectFileOptions {
11
17
  readonly name: Name;
12
18
  readonly kind: Kind;
13
19
  readonly text: string;
@@ -24,8 +30,8 @@ export interface ProjectDocument {
24
30
  readonly layout?: ProjectLayout;
25
31
  }
26
32
  export const FILE_KINDS: readonly FileKind[];
27
- export function file<const N extends string, K extends FileKind>(name: N, kind: K, text: string): ProjectFile<N, K>;
28
- export function jsonFile<const N extends string, K extends FileKind, const D>(name: N, kind: K, document: D & JsonInput<D>): ProjectFile<N, K>;
33
+ export function file<const N extends string, K extends FileKind>(name: N, kind: K, text: string, options?: ProjectFileOptions): ProjectFile<N, K>;
34
+ export function jsonFile<const N extends string, K extends FileKind, const D>(name: N, kind: K, document: D & JsonInput<D>, options?: ProjectFileOptions): ProjectFile<N, K>;
29
35
  /** Names are a phantom; the public document has no extra registry. */
30
36
  export class ProjectBuilder<Names extends string = never> {
31
37
  protected constructor();