@voltro/database 0.81.0 → 0.83.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/dist/index.d.ts CHANGED
@@ -668,6 +668,10 @@ export declare interface CdcConfig {
668
668
  readonly username: string;
669
669
  readonly password: string;
670
670
  readonly database: string;
671
+ /** TLS for the reader's own connection — the same `ConnectionConfig.ssl`
672
+ * the app's pool resolved. A reader that dropped it connected in
673
+ * plaintext, and a server that requires TLS refused change capture. */
674
+ readonly ssl?: boolean;
671
675
  };
672
676
  /** Watchdog cadence + stall threshold (ms) for the binlog reader's
673
677
  * liveness safety net. Defaults (probe 15s / stall 25s) suit production;
@@ -767,6 +771,9 @@ export declare type ChangeEvent = {
767
771
  * re-read failed, or the row was already gone). Re-read or resync.
768
772
  */
769
773
  readonly oversized?: 'rehydrated' | 'tombstone' | 'unrecovered';
774
+ /** A net-change feed may coalesce intermediate writes and supply current
775
+ * images or delete keys only. It cannot support exact historical replay. */
776
+ readonly netChange?: true;
770
777
  /**
771
778
  * How the event reached this process. Absent/'inline' = emitted by this
772
779
  * process's own write path; 'injected' = delivered over a cross-instance
@@ -967,7 +974,7 @@ export declare const coercePredicateValue: (columnType: ColumnType | undefined,
967
974
  /** Same, for the array-valued operators (`inSet` / `notInSet`). */
968
975
  export declare const coercePredicateValues: (columnType: ColumnType | undefined, values: ReadonlyArray<unknown>) => ReadonlyArray<unknown>;
969
976
 
970
- /** The value half of {@link coercePredicateForSqlite}. */
977
+ /** Convert scalar/list predicate values to SQLite driver bindings. */
971
978
  export declare const coerceValueForSqlite: (value: unknown) => unknown;
972
979
 
973
980
  /**
@@ -992,7 +999,7 @@ export declare const collectSubqueries: (predicate: Predicate) => Generator<{
992
999
  * database.orders.where(eq('orgId', oid))
993
1000
  * .groupBy(['status'])
994
1001
  * .aggregate({ status: column<string>('status'), count: count() })
995
- * // rows: { status: string; count: number | Date | null }[]
1002
+ * // rows: { status: string; count: number }[]
996
1003
  * ```
997
1004
  */
998
1005
  export declare const column: <T = string | number | boolean | Date | null>(columnName: string, alias?: string) => AggregateColumn<T>;
@@ -1832,6 +1839,14 @@ export declare type ColumnInput = {
1832
1839
  * or is nullable. */
1833
1840
  declare type ColumnOptionalForInsert<K extends PropertyKey, D> = K extends AutoFilledColumn ? true : ColumnHasDefault<D> extends true ? true : null extends InferColumn<D> ? true : false;
1834
1841
 
1842
+ export declare const columnRef: (column: string) => ColumnReference;
1843
+
1844
+ /** An explicit, serializable reference to another column in the current row. */
1845
+ export declare interface ColumnReference {
1846
+ readonly _tag: 'ColumnReference';
1847
+ readonly column: string;
1848
+ }
1849
+
1835
1850
  /**
1836
1851
  * The per-column mapping, over a column DEFINITION — what `table.fields` holds.
1837
1852
  *
@@ -2174,6 +2189,10 @@ table?: string) => Statement.Fragment;
2174
2189
  */
2175
2190
  export declare const compileRawFragment: <Row extends object = Record<string, unknown>>(fragment: RawSqlFragment, sql: SqlConstructor) => Statement.Statement<Row>;
2176
2191
 
2192
+ /** Preserve declared bigint columns before SQLite drivers convert them to JS numbers.
2193
+ * Shared by SELECT and DML RETURNING; other dialects retain native projection. */
2194
+ export declare const compileRowProjection: (table: string, sql: SqlConstructor, projection?: ReadonlyArray<string>) => Statement.Fragment;
2195
+
2177
2196
  export declare const compileSelect: <Row extends object>(descriptor: QueryDescriptor, sql: SqlConstructor, namespace?: QueryNamespace) => Statement.Statement<Row>;
2178
2197
 
2179
2198
  /** Compose the durable identity written to `_voltro_cdcout_claims.changeKey`. */
@@ -2390,9 +2409,9 @@ export declare interface CoreTableRegistration {
2390
2409
  readonly tenants?: () => TableLike;
2391
2410
  }
2392
2411
 
2393
- export declare const count: (alias?: string) => AggregateColumn;
2412
+ export declare const count: (alias?: string) => AggregateColumn<number>;
2394
2413
 
2395
- export declare const countDistinct: (column: string, alias?: string) => AggregateColumn;
2414
+ export declare const countDistinct: (column: string, alias?: string) => AggregateColumn<number>;
2396
2415
 
2397
2416
  /**
2398
2417
  * A whole collaborative DOCUMENT as a column — rich text, nested maps/arrays,
@@ -3795,7 +3814,7 @@ export declare interface EnumValueRename {
3795
3814
  readonly to: string;
3796
3815
  }
3797
3816
 
3798
- export declare const eq: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
3817
+ export declare const eq: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
3799
3818
 
3800
3819
  /** Escape LIKE/ILIKE wildcard metacharacters (`\` `%` `_`) so a
3801
3820
  * user-supplied substring is matched literally. Paired with an
@@ -3943,6 +3962,13 @@ export declare interface FieldCipher {
3943
3962
  * feature, and the reader must not fall back to an unbound read.
3944
3963
  */
3945
3964
  readonly decrypt: (ciphertext: string, binding?: FieldBinding) => string;
3965
+ /**
3966
+ * `true` when only a PREVIOUS key opens this value — a cipher built with the
3967
+ * keys a rotation retires (`makeFieldCipher(current, previous)`). What
3968
+ * `voltro db encrypt-column` rewrites, so the previous key can go. Absent on
3969
+ * a cipher with one key.
3970
+ */
3971
+ readonly sealedWithPreviousKey?: (ciphertext: string, binding?: FieldBinding) => boolean;
3946
3972
  }
3947
3973
 
3948
3974
  /**
@@ -4284,9 +4310,9 @@ export declare const getResidencyConfig: () => ResidencyConfig | undefined;
4284
4310
 
4285
4311
  export declare const getTable: (tableName: string) => TableLike | undefined;
4286
4312
 
4287
- export declare const gt: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
4313
+ export declare const gt: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
4288
4314
 
4289
- export declare const gte: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
4315
+ export declare const gte: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
4290
4316
 
4291
4317
  /**
4292
4318
  * Convenience: detect whether a descriptor declares any eager loads.
@@ -4731,6 +4757,8 @@ export declare const isBoundCiphertext: (value: unknown) => value is string;
4731
4757
  * tenant namespace). */
4732
4758
  export declare const isBranchNamespace: (namespace: string) => boolean;
4733
4759
 
4760
+ export declare const isColumnReference: (value: unknown) => value is ColumnReference;
4761
+
4734
4762
  /** True when the key names columns rather than an id. */
4735
4763
  export declare const isCompositeRowKey: (key: RowKey) => key is Readonly<Record<string, unknown>>;
4736
4764
 
@@ -5062,9 +5090,9 @@ export declare const localFirstTables: (schema: Readonly<Record<string, LocalFir
5062
5090
  readonly tableName: string;
5063
5091
  }>>) => ReadonlyArray<string>;
5064
5092
 
5065
- export declare const lt: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
5093
+ export declare const lt: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
5066
5094
 
5067
- export declare const lte: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
5095
+ export declare const lte: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
5068
5096
 
5069
5097
  /**
5070
5098
  * Build the store-scoped fallback reporter: counts EVERY occurrence, logs a
@@ -5189,7 +5217,10 @@ export declare type MaterializedMixinFields<Input extends FieldsInput> = Resolve
5189
5217
 
5190
5218
  export declare const materializeFields: <F extends FieldsInput>(fields: F) => FieldDefinitions<F>;
5191
5219
 
5192
- export declare const max: (column: string, alias?: string) => AggregateColumn;
5220
+ export declare const max: <C extends string>(column: C, alias?: string) => AggregateColumn & {
5221
+ readonly op: "max";
5222
+ readonly column: C;
5223
+ };
5193
5224
 
5194
5225
  /** Strictest identifier length across supported dialects (Postgres). */
5195
5226
  export declare const MAX_IDENTIFIER_LENGTH = 63;
@@ -5424,7 +5455,10 @@ export declare interface MigrationStepContext {
5424
5455
  readonly progress: (done: number, total: number) => Effect.Effect<void, never, never>;
5425
5456
  }
5426
5457
 
5427
- export declare const min: (column: string, alias?: string) => AggregateColumn;
5458
+ export declare const min: <C extends string>(column: C, alias?: string) => AggregateColumn & {
5459
+ readonly op: "min";
5460
+ readonly column: C;
5461
+ };
5428
5462
 
5429
5463
  /**
5430
5464
  * The `conflictColumns` an upsert names that cannot match its conflict target.
@@ -5558,7 +5592,7 @@ export declare interface NeonBranchOptions {
5558
5592
  readonly parentBranch?: string;
5559
5593
  }
5560
5594
 
5561
- export declare const neq: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K]) => PredicateLeaf;
5595
+ export declare const neq: <RowOf = Record<string, unknown>, K extends keyof RowOf & string = keyof RowOf & string>(column: K, value: RowOf[K] | ColumnReference) => PredicateLeaf;
5562
5596
 
5563
5597
  /** Advance the branch lifecycle; throws on an illegal transition (so a
5564
5598
  * double-destroy or a provision-after-destroyed can't corrupt state). */
@@ -6120,7 +6154,7 @@ Joins extends JoinsMap = {}> {
6120
6154
  * - grouped (via Q2's `.groupBy()`): one row per group
6121
6155
  */
6122
6156
  aggregate: <Spec extends Record<string, AggregateColumn<unknown>>>(spec: Spec) => Query<{
6123
- [K in keyof Spec]: Spec[K] extends AggregateColumn<infer T> ? T : never;
6157
+ [K in keyof Spec]: ResolveAggregateResult<Spec[K], RowOf, Joins>;
6124
6158
  }, IxNames, Joins>;
6125
6159
  /**
6126
6160
  * Add `GROUP BY` columns. Composes with `.aggregate({...})` to
@@ -6152,8 +6186,16 @@ Joins extends JoinsMap = {}> {
6152
6186
  *
6153
6187
  * Multiple `.matching()` calls override the predicate (FTS is a
6154
6188
  * single-string concept; no AND-merge).
6189
+ *
6190
+ * `{ prefix: true }` matches each query word as a word beginning and
6191
+ * requires every word — `tomato` finds `tomatoes` — on postgres
6192
+ * (`to_tsquery` with `:*`), mysql/mariadb (BOOLEAN MODE `+word*`) and
6193
+ * sqlite (FTS5 `"word"*`); mssql's LIKE and the in-memory store already
6194
+ * match that way.
6155
6195
  */
6156
- matching: (indexName: string, query: string) => Query<RowOf, IxNames, Joins>;
6196
+ matching: (indexName: string, query: string, options?: {
6197
+ readonly prefix?: boolean;
6198
+ }) => Query<RowOf, IxNames, Joins>;
6157
6199
  /**
6158
6200
  * Request a relevance-ranking column for the active `.matching(...)`
6159
6201
  * search and (by default) order results best-match-first. Must be
@@ -6259,7 +6301,7 @@ Joins extends JoinsMap = {}> {
6259
6301
  * const rootId = '...'
6260
6302
  * const anchor = queryFor(orgs).where(eq('id', rootId))
6261
6303
  * const recursion = queryFor(orgs).as('child')
6262
- * .innerJoin('descendants', 'parent', eq('parent.id', 'child.parentId'))
6304
+ * .innerJoin('descendants', 'parent', eq('parent.id', columnRef('child.parentId')))
6263
6305
  * const tree = queryFor(orgs)
6264
6306
  * .recursiveCte('descendants', union(anchor, recursion).descriptor)
6265
6307
  * .where(eq('id', rootId))
@@ -6298,7 +6340,7 @@ Joins extends JoinsMap = {}> {
6298
6340
  *
6299
6341
  * ```ts
6300
6342
  * queryFor(posts).as('children')
6301
- * .innerJoin('posts', 'parents', eq('parents.id', 'children.parentId'))
6343
+ * .innerJoin('posts', 'parents', eq('parents.id', columnRef('children.parentId')))
6302
6344
  * ```
6303
6345
  */
6304
6346
  innerJoin: {
@@ -6330,7 +6372,7 @@ Joins extends JoinsMap = {}> {
6330
6372
  * ```ts
6331
6373
  * const rows = await store.query(
6332
6374
  * queryFor(posts).as('children')
6333
- * .innerJoin('posts', 'parents', eq('parents.id', 'children.parentId'))
6375
+ * .innerJoin('posts', 'parents', eq('parents.id', columnRef('children.parentId')))
6334
6376
  * .selectJoined({
6335
6377
  * childId: 'children.id',
6336
6378
  * childTitle: 'children.title',
@@ -6523,6 +6565,16 @@ export declare interface QueryDescriptor<R = Row> {
6523
6565
  readonly alias: string;
6524
6566
  readonly order: boolean;
6525
6567
  };
6568
+ /** Each query word matches as a word BEGINNING (`tomato` finds
6569
+ * `tomatoes`), every word required — `.matching(…, { prefix: true })`. */
6570
+ readonly prefix?: boolean;
6571
+ /**
6572
+ * Set by a store whose engine keeps no full-text index (Turso's MVCC mode
6573
+ * has no FTS5): the match compiles to a case-insensitive LIKE over the
6574
+ * covered columns, ranked by how many of them hit — the same fallback as
6575
+ * mssql. Never set by the query builder.
6576
+ */
6577
+ readonly fallback?: 'like';
6526
6578
  };
6527
6579
  /**
6528
6580
  * Common-Table-Expression definitions (Q4) — `WITH <name> AS (...)`.
@@ -6581,6 +6633,8 @@ export declare interface QueryDescriptor<R = Row> {
6581
6633
  readonly joins?: ReadonlyArray<{
6582
6634
  readonly kind: 'inner' | 'left';
6583
6635
  readonly table: string;
6636
+ /** Declared shape for typed joins; name-only joins use the table registry. */
6637
+ readonly sourceTable?: TableLike;
6584
6638
  readonly alias: string;
6585
6639
  readonly on: Predicate;
6586
6640
  }>;
@@ -7129,6 +7183,12 @@ declare type Resolve<T> = {
7129
7183
  */
7130
7184
  export declare const resolveActorSnapshot: (store: ActorLookupStore, subjectId: string | null | undefined, subjectType: string) => Promise<AuditActor | undefined>;
7131
7185
 
7186
+ /** Resolve extrema from the source column while retaining explicit projection types. */
7187
+ export declare type ResolveAggregateResult<A, RowOf, Joins extends JoinsMap> = A extends {
7188
+ readonly op: 'min' | 'max';
7189
+ readonly column: infer C extends string;
7190
+ } ? ResolveJoinedSource<C, RowOf, Joins> | null : A extends AggregateColumn<infer T> ? T : never;
7191
+
7132
7192
  /**
7133
7193
  * Pick the branch mechanism. Prioritises the Neon copy-on-write fast-path when
7134
7194
  * the owned DB is Neon AND the branch snapshots parent data (`seed: 'copy'`);
@@ -7236,6 +7296,9 @@ export declare interface RetentionSpec {
7236
7296
  readonly table: string;
7237
7297
  /** Timestamp column compared against the cutoff (rows strictly older are purged). */
7238
7298
  readonly timeColumn: string;
7299
+ /** Additional timestamps that keep a row while any is within the TTL.
7300
+ * Null timestamps do not protect a row. All columns use the same cutoff. */
7301
+ readonly activityColumns?: ReadonlyArray<string>;
7239
7302
  /** Rows whose `timeColumn` is older than `now - ttlMs` are eligible for purge. */
7240
7303
  readonly ttlMs: number;
7241
7304
  /**
@@ -7912,6 +7975,11 @@ export declare type SqlConstructor = Statement.Constructor;
7912
7975
  * SQLite extended code).
7913
7976
  */
7914
7977
  export declare interface SqlDialect {
7978
+ /** Runner storage supported by this resolved connection. Local/embedded
7979
+ * stores must not advertise shared ownership of a remote workflow journal.
7980
+ * Omission retains the dialect family's default.
7981
+ */
7982
+ readonly workflowRunnerStorage?: (connection: ConnectionConfig) => 'memory' | 'sql';
7915
7983
  readonly id: DialectId;
7916
7984
  readonly makeSqlLayer: (conn: ConnectionConfig) => Layer.Layer<SqlClient.SqlClient, ConfigError.ConfigError | SqlError.SqlError, never>;
7917
7985
  readonly makeStore: (options: MakeStoreOptions) => Promise<DataStore>;
@@ -8022,12 +8090,12 @@ export declare const stampGeneratedId: <T extends Record<string, unknown>>(table
8022
8090
  export declare const stampGeneratedIds: <T extends Record<string, unknown>>(table: string, rows: ReadonlyArray<T>) => ReadonlyArray<T>;
8023
8091
 
8024
8092
  /**
8025
- * Prefix match on a text column — `startsWith('key', 'awb_')`.
8093
+ * Prefix match on a text column — `startsWith('key', 'acme_')`.
8026
8094
  *
8027
8095
  * **Case-SENSITIVE**, unlike {@link contains}, and the asymmetry is deliberate
8028
8096
  * rather than an oversight. `contains` is a search primitive (a human typing
8029
8097
  * into a box), so folding case is what they mean. A prefix is a NAMESPACE — a
8030
- * key prefix, a path segment, a tenant-scoped id — where `awb_` and `AWB_` are
8098
+ * key prefix, a path segment, a tenant-scoped id — where `acme_` and `ACME_` are
8031
8099
  * two different namespaces and quietly merging them is a bug. It also matches
8032
8100
  * the semantics of the JS method it is named after.
8033
8101
  *
@@ -9593,6 +9661,18 @@ export declare const _voltroMigrationsTable: SchemaTable;
9593
9661
 
9594
9662
  export declare const _voltroMssqlCdcOffsetsTable: TableLike;
9595
9663
 
9664
+ /**
9665
+ * `_voltro_plugin_migrations` — which plugin `extendSchema.migrations` steps ran.
9666
+ *
9667
+ * It was created by a hand-written `id TEXT PRIMARY KEY`, which MariaDB and
9668
+ * MySQL refuse (errno 1170), so a plugin that shipped a migration could not run
9669
+ * it on the MySQL family at all. Declared here, it goes through the same
9670
+ * per-dialect bootstrap as the migration ledgers — and the declared store
9671
+ * charset with them. The snake_case column names are the ones existing ledgers
9672
+ * already carry on postgres and sqlite.
9673
+ */
9674
+ export declare const _voltroPluginMigrationsTable: SchemaTable;
9675
+
9596
9676
  /**
9597
9677
  * The one row a destructive import leaves behind while it is destructive.
9598
9678
  *