@holo-js/db 0.1.9 → 0.2.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +236 -174
  2. package/dist/index.mjs +260 -35
  3. package/package.json +7 -7
package/dist/index.d.ts CHANGED
@@ -1,3 +1,27 @@
1
+ /**
2
+ * Capability flags exposed by a driver+dialect pair.
3
+ *
4
+ * The new architecture uses explicit capabilities instead of branching on
5
+ * driver names throughout the ORM.
6
+ */
7
+ interface DatabaseCapabilities {
8
+ returning: boolean;
9
+ savepoints: boolean;
10
+ concurrentQueries: boolean;
11
+ workerThreadExecution: boolean;
12
+ lockForUpdate: boolean;
13
+ sharedLock: boolean;
14
+ jsonValueQuery: boolean;
15
+ jsonContains: boolean;
16
+ jsonLength: boolean;
17
+ schemaQualifiedIdentifiers: boolean;
18
+ nativeUpsert: boolean;
19
+ ddlAlterSupport: boolean;
20
+ introspection: boolean;
21
+ }
22
+ declare const DEFAULT_CAPABILITIES: DatabaseCapabilities;
23
+ declare function createCapabilities(overrides?: Partial<DatabaseCapabilities>): DatabaseCapabilities;
24
+
1
25
  type LogicalColumnKind = 'id' | 'integer' | 'bigInteger' | 'string' | 'text' | 'boolean' | 'real' | 'decimal' | 'date' | 'datetime' | 'timestamp' | 'json' | 'blob' | 'uuid' | 'ulid' | 'snowflake' | 'vector' | 'enum';
2
26
  type ColumnDefaultKind = 'value' | 'now';
3
27
  type IdGenerationStrategy = 'autoIncrement' | 'uuid' | 'ulid' | 'snowflake';
@@ -168,171 +192,6 @@ declare function renderGeneratedSchemaPlaceholder(): string;
168
192
  declare function renderGeneratedSchemaModule(tables: readonly TableDefinition[]): string;
169
193
  declare function renderGeneratedSchemaRuntimeModule(tables: readonly TableDefinition[]): string;
170
194
 
171
- type EntityConstructor = {
172
- new <TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap>(repository: unknown, attributes: Partial<ModelRecord<TTable>>, exists?: boolean): Entity<TTable, TRelations>;
173
- prototype: Entity<TableDefinition, RelationMap>;
174
- };
175
-
176
- declare class EntityBase<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> {
177
- private readonly repository;
178
- private attributes;
179
- private original;
180
- private changes;
181
- private persisted;
182
- private relations;
183
- private relationLoads;
184
- private peerCollection?;
185
- private hiddenOverrides;
186
- private visibleOverrides;
187
- private visibleOnly;
188
- private appendedOverrides;
189
- constructor(repository: ModelRepositoryLike<TTable, EmptyScopeMap, TRelations>, attributes: Partial<ModelRecord<TTable>>, exists?: boolean);
190
- getRepository(): ModelRepositoryLike<TTable>;
191
- private getRepositoryRuntime;
192
- is(other: unknown): boolean;
193
- isNot(other: unknown): boolean;
194
- exists(): boolean;
195
- trashed(): boolean;
196
- get<TKey extends Extract<keyof ModelRecord<TTable>, string>>(key: TKey): ModelRecord<TTable>[TKey];
197
- set<TKey extends Extract<keyof ModelRecord<TTable>, string>>(key: TKey, value: ModelRecord<TTable>[TKey]): this;
198
- fill(values: Partial<ModelRecord<TTable>>): this;
199
- update(values: ModelUpdatePayload<TTable>): Promise<this>;
200
- forceFill(values: Partial<ModelRecord<TTable>>): this;
201
- isDirty(key?: Extract<keyof ModelRecord<TTable>, string>): boolean;
202
- isClean(): boolean;
203
- getDirty(): Partial<ModelUpdatePayload<TTable>>;
204
- getChanges(): Partial<ModelUpdatePayload<TTable>>;
205
- wasChanged(key?: Extract<keyof ModelRecord<TTable>, string>): boolean;
206
- syncOriginal(): this;
207
- syncChanges(): this;
208
- syncPersisted(entity: EntityBase<TTable>, changes?: Record<string, unknown>): this;
209
- bindPeerCollection(peers: readonly EntityBase<TTable, TRelations>[]): this;
210
- getPeerCollection(): readonly EntityBase<TTable, TRelations>[] | undefined;
211
- getPendingRelationLoad(name: string): Promise<unknown> | undefined;
212
- setPendingRelationLoad(name: string, load: Promise<unknown>): this;
213
- clearPendingRelationLoad(name: string): this;
214
- toAttributes(): ModelRecord<TTable>;
215
- setRelation(name: string, value: unknown): this;
216
- setComputed(name: string, value: unknown): this;
217
- makeHidden(...keys: readonly string[]): this;
218
- makeVisible(...keys: readonly string[]): this;
219
- setHidden(keys: readonly string[]): this;
220
- setVisible(keys: readonly string[]): this;
221
- append(...keys: readonly string[]): this;
222
- setAppends(keys: readonly string[]): this;
223
- withoutAppends(): this;
224
- getRelation<TRelation = unknown>(name: string): TRelation;
225
- hasRelation(name: string): boolean;
226
- getLoadedRelations(): Readonly<Record<string, unknown>>;
227
- getSerializationConfig(): {
228
- readonly hidden: ReadonlySet<string>;
229
- readonly visible: ReadonlySet<string>;
230
- readonly visibleOnly: readonly string[] | null;
231
- readonly appended: readonly string[] | null;
232
- };
233
- forgetRelation(name: string): this;
234
- relation<K extends ModelRelationName<TRelations>>(name: K): RelationMethodsOf<TRelations[K]>;
235
- toJSON(): ModelRecord<TTable>;
236
- private applyPersistedEntity;
237
- private persistEntity;
238
- private deletePersistedEntity;
239
- private restoreEntity;
240
- private forceDeletePersistedEntity;
241
- private loadAggregateDefinitions;
242
- save(): Promise<this>;
243
- push(): Promise<this>;
244
- saveQuietly(): Promise<this>;
245
- delete(): Promise<void>;
246
- deleteQuietly(): Promise<void>;
247
- restore(): Promise<this>;
248
- restoreQuietly(): Promise<this>;
249
- forceDelete(): Promise<void>;
250
- forceDeleteQuietly(): Promise<void>;
251
- fresh(): Promise<Entity<TTable, TRelations> | undefined>;
252
- refresh(): Promise<this>;
253
- replicate(except?: readonly string[]): Entity<TTable, TRelations>;
254
- load<TPaths extends readonly ModelRelationPath<TRelations>[]>(...relations: TPaths): Promise<Omit<this, keyof ResolveEagerLoads<TRelations, TPaths>> & ResolveEagerLoads<TRelations, TPaths> & (this extends {
255
- toJSON(): infer R;
256
- } ? {
257
- toJSON(): R & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
258
- } : {
259
- toJSON(): ModelRecord<TTable> & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
260
- })>;
261
- loadMissing<TPaths extends readonly ModelRelationPath<TRelations>[]>(...relations: TPaths): Promise<Omit<this, keyof ResolveEagerLoads<TRelations, TPaths>> & ResolveEagerLoads<TRelations, TPaths> & (this extends {
262
- toJSON(): infer R;
263
- } ? {
264
- toJSON(): R & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
265
- } : {
266
- toJSON(): ModelRecord<TTable> & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
267
- })>;
268
- loadMorph(relation: ModelRelationName<TRelations>, mapping: ModelMorphLoadMap): Promise<this>;
269
- loadCount(...relations: readonly ModelRelationName<TRelations>[]): Promise<this>;
270
- loadExists(...relations: readonly ModelRelationName<TRelations>[]): Promise<this>;
271
- loadSum<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
272
- loadAvg<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
273
- loadMin<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
274
- loadMax<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
275
- associate<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated> | null): this;
276
- dissociate(relation: string): this;
277
- saveRelated<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated>): Promise<Entity<TRelated>>;
278
- saveManyRelated<TRelated extends TableDefinition>(relation: string, related: readonly Entity<TRelated>[]): Promise<Entity<TRelated>[]>;
279
- saveRelatedQuietly<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated>): Promise<Entity<TRelated>>;
280
- saveManyRelatedQuietly<TRelated extends TableDefinition>(relation: string, related: readonly Entity<TRelated>[]): Promise<Entity<TRelated>[]>;
281
- createRelated(relation: string, values: Record<string, unknown>): Promise<Entity<TableDefinition>>;
282
- createManyRelated(relation: string, values: readonly Record<string, unknown>[]): Promise<Entity<TableDefinition>[]>;
283
- createRelatedQuietly(relation: string, values: Record<string, unknown>): Promise<Entity<TableDefinition>>;
284
- createManyRelatedQuietly(relation: string, values: readonly Record<string, unknown>[]): Promise<Entity<TableDefinition>[]>;
285
- attach(relation: string, ids: unknown, attributes?: Record<string, unknown>): Promise<void>;
286
- detach(relation: string, ids?: unknown): Promise<number>;
287
- sync(relation: string, ids: unknown): Promise<{
288
- attached: unknown[];
289
- detached: unknown[];
290
- updated: unknown[];
291
- }>;
292
- syncWithoutDetaching(relation: string, ids: unknown): Promise<{
293
- attached: unknown[];
294
- detached: unknown[];
295
- updated: unknown[];
296
- }>;
297
- updateExistingPivot(relation: string, id: unknown, attributes: Record<string, unknown>): Promise<number>;
298
- toggle(relation: string, ids: unknown): Promise<{
299
- attached: unknown[];
300
- detached: unknown[];
301
- }>;
302
- }
303
- type ModelRelationMethods<TRelations extends RelationMap> = string extends ModelRelationName<TRelations> ? Record<never, never> : {
304
- [K in ModelRelationName<TRelations>]: () => RelationMethodsOf<TRelations[K]>;
305
- };
306
- type ModelBase<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> = EntityBase<TTable, TRelations> & ModelRecord<TTable> & {
307
- relation<K extends ModelRelationName<TRelations>>(name: K): RelationMethodsOf<TRelations[K]>;
308
- };
309
- type Entity<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> = ModelBase<TTable, TRelations> & ModelRelationMethods<TRelations>;
310
- declare const Entity: EntityConstructor;
311
-
312
- /**
313
- * Capability flags exposed by a driver+dialect pair.
314
- *
315
- * The new architecture uses explicit capabilities instead of branching on
316
- * driver names throughout the ORM.
317
- */
318
- interface DatabaseCapabilities {
319
- returning: boolean;
320
- savepoints: boolean;
321
- concurrentQueries: boolean;
322
- workerThreadExecution: boolean;
323
- lockForUpdate: boolean;
324
- sharedLock: boolean;
325
- jsonValueQuery: boolean;
326
- jsonContains: boolean;
327
- jsonLength: boolean;
328
- schemaQualifiedIdentifiers: boolean;
329
- nativeUpsert: boolean;
330
- ddlAlterSupport: boolean;
331
- introspection: boolean;
332
- }
333
- declare const DEFAULT_CAPABILITIES: DatabaseCapabilities;
334
- declare function createCapabilities(overrides?: Partial<DatabaseCapabilities>): DatabaseCapabilities;
335
-
336
195
  interface SecurityPolicy {
337
196
  allowUnsafeRawSql: boolean;
338
197
  debugSqlInLogs: boolean;
@@ -413,6 +272,10 @@ interface DatabaseOperationOptions {
413
272
  signal?: AbortSignal;
414
273
  timeoutMs?: number;
415
274
  }
275
+ type TransactionMode = 'deferred' | 'immediate' | 'exclusive';
276
+ interface DatabaseTransactionOptions extends DatabaseOperationOptions {
277
+ mode?: TransactionMode;
278
+ }
416
279
  type TransactionCallback = () => void | Promise<void>;
417
280
  interface UnsafeStatement {
418
281
  unsafe: true;
@@ -474,11 +337,13 @@ interface DriverAdapter {
474
337
  initialize(): Promise<void>;
475
338
  disconnect(): Promise<void>;
476
339
  isConnected(): boolean;
340
+ isDatabaseMissingError?(error: unknown): boolean;
341
+ ensureDatabaseExists?(): Promise<void>;
477
342
  runWithTransactionScope?<T>(callback: () => Promise<T>): Promise<T>;
478
343
  introspect?<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
479
344
  query<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
480
345
  execute(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverExecutionResult>;
481
- beginTransaction(options?: DatabaseOperationOptions): Promise<void>;
346
+ beginTransaction(options?: DatabaseTransactionOptions): Promise<void>;
482
347
  commit(options?: DatabaseOperationOptions): Promise<void>;
483
348
  rollback(options?: DatabaseOperationOptions): Promise<void>;
484
349
  createSavepoint?(name: string, options?: DatabaseOperationOptions): Promise<void>;
@@ -808,12 +673,27 @@ interface DatabaseQueryCacheBridge {
808
673
  readonly driver?: string;
809
674
  }): Promise<void>;
810
675
  }
676
+ interface DatabaseDependencyInvalidationEvent {
677
+ readonly connectionName: string;
678
+ readonly dependencies: readonly string[];
679
+ }
680
+ type DatabaseDependencyInvalidationListener = (event: DatabaseDependencyInvalidationEvent) => void | Promise<void>;
681
+ interface DatabaseDependencyCollectionResult<TValue> {
682
+ readonly value: TValue;
683
+ readonly dependencies: readonly string[];
684
+ }
811
685
  declare function getQueryCacheBridgeState(): {
812
686
  bridge?: DatabaseQueryCacheBridge;
687
+ dependencyInvalidationListeners?: Set<DatabaseDependencyInvalidationListener>;
813
688
  };
814
689
  declare function configureDatabaseQueryCacheBridge(bridge?: DatabaseQueryCacheBridge): void;
815
690
  declare function getDatabaseQueryCacheBridge(): DatabaseQueryCacheBridge | undefined;
816
691
  declare function resetDatabaseQueryCacheBridge(): void;
692
+ declare function onDatabaseDependencyInvalidated(listener: DatabaseDependencyInvalidationListener): () => void;
693
+ declare function resetDatabaseDependencyInvalidationListeners(): void;
694
+ declare function collectDatabaseQueryDependencies<TValue>(callback: () => TValue | Promise<TValue>): Promise<DatabaseDependencyCollectionResult<TValue>>;
695
+ declare function recordDatabaseQueryDependencies(dependencies: readonly string[] | undefined): void;
696
+ declare function notifyDatabaseDependencyInvalidationListeners(event: DatabaseDependencyInvalidationEvent): Promise<void>;
817
697
  declare function normalizeQueryCacheConfig(input: QueryCacheTtlInput | QueryCacheConfig): NormalizedQueryCacheConfig;
818
698
  declare function createDeterministicQueryCacheKey(statement: CompiledStatement, connectionName: string): string;
819
699
  declare function resolveQueryCacheKey(statement: CompiledStatement, connectionName: string, config: NormalizedQueryCacheConfig): string;
@@ -824,6 +704,7 @@ declare function supportsAutomaticQueryCacheInvalidation(plan: SelectQueryPlan):
824
704
  declare function inferAutomaticQueryCacheDependencies(plan: SelectQueryPlan, connectionName: string): readonly string[] | undefined;
825
705
  declare function resolveQueryCacheDependencies(plan: SelectQueryPlan, connectionName: string, explicit?: readonly string[]): readonly string[] | undefined;
826
706
  declare const queryCacheInternals: {
707
+ collectDatabaseQueryDependencies: typeof collectDatabaseQueryDependencies;
827
708
  configureDatabaseQueryCacheBridge: typeof configureDatabaseQueryCacheBridge;
828
709
  createDeterministicQueryCacheKey: typeof createDeterministicQueryCacheKey;
829
710
  createTableCacheDependency: typeof createTableCacheDependency;
@@ -831,8 +712,12 @@ declare const queryCacheInternals: {
831
712
  inferAutomaticQueryCacheDependencies: typeof inferAutomaticQueryCacheDependencies;
832
713
  normalizeQueryCacheConfig: typeof normalizeQueryCacheConfig;
833
714
  normalizeQueryCacheDependencies: typeof normalizeQueryCacheDependencies;
715
+ notifyDatabaseDependencyInvalidationListeners: typeof notifyDatabaseDependencyInvalidationListeners;
716
+ onDatabaseDependencyInvalidated: typeof onDatabaseDependencyInvalidated;
717
+ recordDatabaseQueryDependencies: typeof recordDatabaseQueryDependencies;
834
718
  resolveQueryCacheDependencies: typeof resolveQueryCacheDependencies;
835
719
  resolveQueryCacheKey: typeof resolveQueryCacheKey;
720
+ resetDatabaseDependencyInvalidationListeners: typeof resetDatabaseDependencyInvalidationListeners;
836
721
  supportsAutomaticPredicateInvalidation: typeof supportsAutomaticPredicateInvalidation;
837
722
  supportsAutomaticQueryCacheInvalidation: typeof supportsAutomaticQueryCacheInvalidation;
838
723
  };
@@ -1142,6 +1027,8 @@ declare class TableQueryBuilder<TTableOrName extends TableReference = string, TS
1142
1027
  private whereFullTextWithBoolean;
1143
1028
  private whereVectorSimilarToWithBoolean;
1144
1029
  private prepareCursorPaginationQuery;
1030
+ private resolveCursorOrders;
1031
+ private readCursorColumnValue;
1145
1032
  private aggregateNumeric;
1146
1033
  private extractNumericValues;
1147
1034
  private normalizeUpdateValues;
@@ -1711,6 +1598,8 @@ declare class ModelQueryBuilder<TTable extends TableDefinition = TableDefinition
1711
1598
  private extractNumericValues;
1712
1599
  private getUnpaginatedEntities;
1713
1600
  private prepareCursorPaginationQuery;
1601
+ private resolveCursorOrders;
1602
+ private readCursorColumnValue;
1714
1603
  }
1715
1604
 
1716
1605
  type ModelInsertPayload<TTable extends TableDefinition> = Partial<InferInsert<TTable>>;
@@ -2066,7 +1955,9 @@ type ResolveEagerLoadUnion<TRelations extends RelationMap, TPaths extends string
2066
1955
  * - `Entity<T> | null` → `ModelRecord<T> | null`
2067
1956
  * - `Entity<T> & { r: Entity<U>[] }` → `ModelRecord<T> & { r: ModelRecord<U>[] }`
2068
1957
  */
2069
- type SerializeLoadedValue<TValue> = TValue extends readonly (infer TItem)[] ? SerializeLoadedValue<TItem>[] : TValue extends null ? null : TValue extends Entity<infer TTable, infer _TRelations> ? ModelRecord<TTable> & SerializeLoaded<Omit<TValue, keyof Entity<TTable, _TRelations>>> : TValue;
1958
+ type SerializeLoadedValue<TValue> = TValue extends readonly (infer TItem)[] ? SerializeLoadedValue<TItem>[] : TValue extends null ? null : TValue extends {
1959
+ toJSON(): infer TSerialized;
1960
+ } ? TSerialized : TValue extends Entity<infer TTable, infer _TRelations> ? ModelRecord<TTable> & SerializeLoaded<Omit<TValue, keyof Entity<TTable, _TRelations>>> : TValue;
2070
1961
  type SerializeLoaded<TLoaded> = unknown extends TLoaded ? unknown : {
2071
1962
  readonly [K in keyof TLoaded]: SerializeLoadedValue<TLoaded[K]>;
2072
1963
  };
@@ -2215,6 +2106,147 @@ interface ModelRepositoryLike<TTable extends TableDefinition = TableDefinition,
2215
2106
  getConnection(): DatabaseContext;
2216
2107
  }
2217
2108
 
2109
+ type EntityConstructor = {
2110
+ new <TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap>(repository: unknown, attributes: Partial<ModelRecord<TTable>>, exists?: boolean): Entity<TTable, TRelations>;
2111
+ prototype: Entity<TableDefinition, RelationMap>;
2112
+ };
2113
+
2114
+ declare class EntityBase<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> {
2115
+ private readonly repository;
2116
+ private attributes;
2117
+ private original;
2118
+ private changes;
2119
+ private persisted;
2120
+ private relations;
2121
+ private relationLoads;
2122
+ private peerCollection?;
2123
+ private hiddenOverrides;
2124
+ private visibleOverrides;
2125
+ private visibleOnly;
2126
+ private appendedOverrides;
2127
+ constructor(repository: ModelRepositoryLike<TTable, EmptyScopeMap, TRelations>, attributes: Partial<ModelRecord<TTable>>, exists?: boolean);
2128
+ getRepository(): ModelRepositoryLike<TTable>;
2129
+ private getRepositoryRuntime;
2130
+ is(other: unknown): boolean;
2131
+ isNot(other: unknown): boolean;
2132
+ exists(): boolean;
2133
+ trashed(): boolean;
2134
+ get<TKey extends Extract<keyof ModelRecord<TTable>, string>>(key: TKey): ModelRecord<TTable>[TKey];
2135
+ set<TKey extends Extract<keyof ModelRecord<TTable>, string>>(key: TKey, value: ModelRecord<TTable>[TKey]): this;
2136
+ fill(values: Partial<ModelRecord<TTable>>): this;
2137
+ update(values: ModelUpdatePayload<TTable>): Promise<this>;
2138
+ forceFill(values: Partial<ModelRecord<TTable>>): this;
2139
+ isDirty(key?: Extract<keyof ModelRecord<TTable>, string>): boolean;
2140
+ isClean(): boolean;
2141
+ getDirty(): Partial<ModelUpdatePayload<TTable>>;
2142
+ getChanges(): Partial<ModelUpdatePayload<TTable>>;
2143
+ wasChanged(key?: Extract<keyof ModelRecord<TTable>, string>): boolean;
2144
+ syncOriginal(): this;
2145
+ syncChanges(): this;
2146
+ syncPersisted(entity: EntityBase<TTable>, changes?: Record<string, unknown>): this;
2147
+ bindPeerCollection(peers: readonly EntityBase<TTable, TRelations>[]): this;
2148
+ getPeerCollection(): readonly EntityBase<TTable, TRelations>[] | undefined;
2149
+ getPendingRelationLoad(name: string): Promise<unknown> | undefined;
2150
+ setPendingRelationLoad(name: string, load: Promise<unknown>): this;
2151
+ clearPendingRelationLoad(name: string): this;
2152
+ toAttributes(): ModelRecord<TTable>;
2153
+ setRelation(name: string, value: unknown): this;
2154
+ setComputed(name: string, value: unknown): this;
2155
+ makeHidden(...keys: readonly string[]): this;
2156
+ makeVisible(...keys: readonly string[]): this;
2157
+ setHidden(keys: readonly string[]): this;
2158
+ setVisible(keys: readonly string[]): this;
2159
+ append(...keys: readonly string[]): this;
2160
+ setAppends(keys: readonly string[]): this;
2161
+ withoutAppends(): this;
2162
+ getRelation<TRelation = unknown>(name: string): TRelation;
2163
+ hasRelation(name: string): boolean;
2164
+ getLoadedRelations(): Readonly<Record<string, unknown>>;
2165
+ getSerializationConfig(): {
2166
+ readonly hidden: ReadonlySet<string>;
2167
+ readonly visible: ReadonlySet<string>;
2168
+ readonly visibleOnly: readonly string[] | null;
2169
+ readonly appended: readonly string[] | null;
2170
+ };
2171
+ forgetRelation(name: string): this;
2172
+ relation<K extends ModelRelationName<TRelations>>(name: K): RelationMethodsOf<TRelations[K]>;
2173
+ toJSON(): ModelRecord<TTable>;
2174
+ private applyPersistedEntity;
2175
+ private persistEntity;
2176
+ private deletePersistedEntity;
2177
+ private restoreEntity;
2178
+ private forceDeletePersistedEntity;
2179
+ private loadAggregateDefinitions;
2180
+ save(): Promise<this>;
2181
+ push(): Promise<this>;
2182
+ saveQuietly(): Promise<this>;
2183
+ delete(): Promise<void>;
2184
+ deleteQuietly(): Promise<void>;
2185
+ restore(): Promise<this>;
2186
+ restoreQuietly(): Promise<this>;
2187
+ forceDelete(): Promise<void>;
2188
+ forceDeleteQuietly(): Promise<void>;
2189
+ fresh(): Promise<Entity<TTable, TRelations> | undefined>;
2190
+ refresh(): Promise<this>;
2191
+ replicate(except?: readonly string[]): Entity<TTable, TRelations>;
2192
+ load<TPaths extends readonly ModelRelationPath<TRelations>[]>(...relations: TPaths): Promise<Omit<this, keyof ResolveEagerLoads<TRelations, TPaths>> & ResolveEagerLoads<TRelations, TPaths> & (this extends {
2193
+ toJSON(): infer R;
2194
+ } ? {
2195
+ toJSON(): R & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
2196
+ } : {
2197
+ toJSON(): ModelRecord<TTable> & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
2198
+ })>;
2199
+ loadMissing<TPaths extends readonly ModelRelationPath<TRelations>[]>(...relations: TPaths): Promise<Omit<this, keyof ResolveEagerLoads<TRelations, TPaths>> & ResolveEagerLoads<TRelations, TPaths> & (this extends {
2200
+ toJSON(): infer R;
2201
+ } ? {
2202
+ toJSON(): R & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
2203
+ } : {
2204
+ toJSON(): ModelRecord<TTable> & SerializeLoaded<ResolveEagerLoads<TRelations, TPaths>>;
2205
+ })>;
2206
+ loadMorph(relation: ModelRelationName<TRelations>, mapping: ModelMorphLoadMap): Promise<this>;
2207
+ loadCount(...relations: readonly ModelRelationName<TRelations>[]): Promise<this>;
2208
+ loadExists(...relations: readonly ModelRelationName<TRelations>[]): Promise<this>;
2209
+ loadSum<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
2210
+ loadAvg<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
2211
+ loadMin<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
2212
+ loadMax<TRelationName extends ModelRelationName<TRelations>>(relation: TRelationName, column: RelatedColumnNameOfRelation<TRelations[TRelationName]>): Promise<this>;
2213
+ associate<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated> | null): this;
2214
+ dissociate(relation: string): this;
2215
+ saveRelated<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated>): Promise<Entity<TRelated>>;
2216
+ saveManyRelated<TRelated extends TableDefinition>(relation: string, related: readonly Entity<TRelated>[]): Promise<Entity<TRelated>[]>;
2217
+ saveRelatedQuietly<TRelated extends TableDefinition>(relation: string, related: Entity<TRelated>): Promise<Entity<TRelated>>;
2218
+ saveManyRelatedQuietly<TRelated extends TableDefinition>(relation: string, related: readonly Entity<TRelated>[]): Promise<Entity<TRelated>[]>;
2219
+ createRelated(relation: string, values: Record<string, unknown>): Promise<Entity<TableDefinition>>;
2220
+ createManyRelated(relation: string, values: readonly Record<string, unknown>[]): Promise<Entity<TableDefinition>[]>;
2221
+ createRelatedQuietly(relation: string, values: Record<string, unknown>): Promise<Entity<TableDefinition>>;
2222
+ createManyRelatedQuietly(relation: string, values: readonly Record<string, unknown>[]): Promise<Entity<TableDefinition>[]>;
2223
+ attach(relation: string, ids: unknown, attributes?: Record<string, unknown>): Promise<void>;
2224
+ detach(relation: string, ids?: unknown): Promise<number>;
2225
+ sync(relation: string, ids: unknown): Promise<{
2226
+ attached: unknown[];
2227
+ detached: unknown[];
2228
+ updated: unknown[];
2229
+ }>;
2230
+ syncWithoutDetaching(relation: string, ids: unknown): Promise<{
2231
+ attached: unknown[];
2232
+ detached: unknown[];
2233
+ updated: unknown[];
2234
+ }>;
2235
+ updateExistingPivot(relation: string, id: unknown, attributes: Record<string, unknown>): Promise<number>;
2236
+ toggle(relation: string, ids: unknown): Promise<{
2237
+ attached: unknown[];
2238
+ detached: unknown[];
2239
+ }>;
2240
+ }
2241
+ type ModelRelationMethods<TRelations extends RelationMap> = string extends ModelRelationName<TRelations> ? Record<never, never> : {
2242
+ [K in ModelRelationName<TRelations>]: () => RelationMethodsOf<TRelations[K]>;
2243
+ };
2244
+ type ModelBase<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> = EntityBase<TTable, TRelations> & ModelRecord<TTable> & {
2245
+ relation<K extends ModelRelationName<TRelations>>(name: K): RelationMethodsOf<TRelations[K]>;
2246
+ };
2247
+ type Entity<TTable extends TableDefinition = TableDefinition, TRelations extends RelationMap = RelationMap> = ModelBase<TTable, TRelations> & ModelRelationMethods<TRelations>;
2248
+ declare const Entity: EntityConstructor;
2249
+
2218
2250
  interface FactoryEntityReference<TTable extends TableDefinition = TableDefinition> {
2219
2251
  attach(relation: string, ids: unknown, attributes?: Record<string, unknown>): Promise<void>;
2220
2252
  exists(): boolean;
@@ -2825,12 +2857,15 @@ declare class MigrationService {
2825
2857
  status(): Promise<MigrationStatus[]>;
2826
2858
  planSquash(archiveName?: string): Promise<MigrationSquashPlan>;
2827
2859
  migrate(options?: MigrateOptions): Promise<RegisteredMigrationDefinition[]>;
2860
+ private ensureTrackingTableForMigration;
2828
2861
  rollback(options?: RollbackOptions): Promise<RegisteredMigrationDefinition[]>;
2829
2862
  getExecutionPolicy(): MigrationExecutionPolicy;
2830
2863
  private ensureTrackingTable;
2831
2864
  private getRanRecords;
2832
2865
  private createContext;
2833
2866
  private runMigrationLifecycle;
2867
+ private isDatabaseMissingError;
2868
+ private disconnectFailedConnection;
2834
2869
  private normalizeMigratedAt;
2835
2870
  private createMigrationLog;
2836
2871
  private runExclusively;
@@ -2923,7 +2958,8 @@ declare class DatabaseContext {
2923
2958
  queryCompiled<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: CompiledStatement, options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
2924
2959
  introspectCompiled<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: CompiledStatement, options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
2925
2960
  executeCompiled(statement: CompiledStatement, options?: DatabaseOperationOptions): Promise<DriverExecutionResult>;
2926
- transaction<T>(callback: (tx: DatabaseContext) => Promise<T>, options?: DatabaseOperationOptions): Promise<T>;
2961
+ transaction<T>(callback: (tx: DatabaseContext) => Promise<T>, options?: DatabaseTransactionOptions): Promise<T>;
2962
+ writeTransaction<T>(callback: (tx: DatabaseContext) => Promise<T>, options?: DatabaseTransactionOptions): Promise<T>;
2927
2963
  private _runRootTransaction;
2928
2964
  private _runSerializedRootTransaction;
2929
2965
  private _runNestedTransaction;
@@ -2941,6 +2977,8 @@ declare class DatabaseContext {
2941
2977
  private _callTransactionHook;
2942
2978
  private _guardOperation;
2943
2979
  private _assertValidOperationOptions;
2980
+ private _assertValidTransactionOptions;
2981
+ private _resolveWriteTransactionOptions;
2944
2982
  private _throwIfAborted;
2945
2983
  private _createGuardError;
2946
2984
  }
@@ -3002,7 +3040,8 @@ declare class ConnectionManager {
3002
3040
  connection(name?: string): DatabaseContext;
3003
3041
  initializeAll(): Promise<void>;
3004
3042
  disconnectAll(): Promise<void>;
3005
- transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName?: string): Promise<T>;
3043
+ transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName?: string, options?: DatabaseTransactionOptions): Promise<T>;
3044
+ writeTransaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName?: string, options?: DatabaseTransactionOptions): Promise<T>;
3006
3045
  }
3007
3046
  declare function createConnectionManager(options: ConnectionManagerOptions): ConnectionManager;
3008
3047
 
@@ -3014,7 +3053,12 @@ declare class DatabaseFacade {
3014
3053
  table<TTable extends TableDefinition>(table: TTable, connectionName?: string): TableQueryBuilder<TTable>;
3015
3054
  table(name: string, connectionName?: string): TableQueryBuilder<string>;
3016
3055
  raw(sql: string, bindings?: readonly unknown[], source?: string): UnsafeStatement;
3017
- transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName?: string, options?: DatabaseOperationOptions): Promise<T>;
3056
+ transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, options?: DatabaseTransactionOptions): Promise<T>;
3057
+ transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName: string, options?: DatabaseTransactionOptions): Promise<T>;
3058
+ transaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName: undefined, options?: DatabaseTransactionOptions): Promise<T>;
3059
+ writeTransaction<T>(callback: (connection: DatabaseContext) => Promise<T>, options?: DatabaseTransactionOptions): Promise<T>;
3060
+ writeTransaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName: string, options?: DatabaseTransactionOptions): Promise<T>;
3061
+ writeTransaction<T>(callback: (connection: DatabaseContext) => Promise<T>, connectionName: undefined, options?: DatabaseTransactionOptions): Promise<T>;
3018
3062
  afterCommit(callback: () => void | Promise<void>, connectionName?: string): void;
3019
3063
  afterRollback(callback: () => void | Promise<void>, connectionName?: string): void;
3020
3064
  unsafeQuery<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: UnsafeStatement, connectionName?: string, options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
@@ -3044,11 +3088,13 @@ declare abstract class LazyDriverAdapter implements DriverAdapter {
3044
3088
  initialize(): Promise<void>;
3045
3089
  disconnect(): Promise<void>;
3046
3090
  isConnected(): boolean;
3091
+ ensureDatabaseExists(): Promise<void>;
3092
+ isDatabaseMissingError(error: unknown): boolean;
3047
3093
  runWithTransactionScope<T>(callback: () => Promise<T>): Promise<T>;
3048
3094
  introspect<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
3049
3095
  query<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverQueryResult<TRow>>;
3050
3096
  execute(sql: string, bindings?: readonly unknown[], options?: DatabaseOperationOptions): Promise<DriverExecutionResult>;
3051
- beginTransaction(options?: DatabaseOperationOptions): Promise<void>;
3097
+ beginTransaction(options?: DatabaseTransactionOptions): Promise<void>;
3052
3098
  commit(options?: DatabaseOperationOptions): Promise<void>;
3053
3099
  rollback(options?: DatabaseOperationOptions): Promise<void>;
3054
3100
  createSavepoint(name: string, options?: DatabaseOperationOptions): Promise<void>;
@@ -3718,7 +3764,10 @@ declare function resetMorphRegistry(): void;
3718
3764
  type SerializableModel = {
3719
3765
  toJSON(): unknown;
3720
3766
  };
3721
- type SerializeModels<TValue> = TValue extends Date ? Date : TValue extends SerializableModel ? ReturnType<TValue['toJSON']> : TValue extends readonly (infer TItem)[] ? SerializeModels<TItem>[] : TValue extends object ? {
3767
+ type MaterializeSerializedValue<TValue> = TValue extends Date ? Date : TValue extends readonly (infer TItem)[] ? MaterializeSerializedValue<TItem>[] : TValue extends (...args: never[]) => unknown ? TValue : TValue extends object ? {
3768
+ [K in keyof TValue]: MaterializeSerializedValue<TValue[K]>;
3769
+ } : TValue;
3770
+ type SerializeModels<TValue> = TValue extends Date ? Date : TValue extends SerializableModel ? MaterializeSerializedValue<ReturnType<TValue['toJSON']>> : TValue extends readonly (infer TItem)[] ? SerializeModels<TItem>[] : TValue extends object ? {
3722
3771
  [K in keyof TValue]: SerializeModels<TValue[K]>;
3723
3772
  } : TValue;
3724
3773
  declare function serializeModels<TValue>(value: TValue): SerializeModels<TValue>;
@@ -3738,7 +3787,20 @@ interface UniqueSlugOptions<TTable extends TableDefinition, TColumn extends Stri
3738
3787
  readonly separator?: string;
3739
3788
  readonly fallback?: string;
3740
3789
  }
3741
- type UniqueSlugModel<TTable extends TableDefinition, TScopes extends ModelScopesDefinition, TRelations extends RelationMap> = StaticModelApi<TTable, TScopes, TRelations>;
3790
+ type UniqueSlugModel<TTable extends TableDefinition, _TScopes extends ModelScopesDefinition, _TRelations extends RelationMap> = {
3791
+ readonly definition: {
3792
+ readonly connectionName?: string;
3793
+ readonly name: string;
3794
+ readonly primaryKey: string;
3795
+ };
3796
+ whereLike(column: ModelColumnName<TTable>, value: string): {
3797
+ when(condition: boolean, callback: (query: {
3798
+ where(column: string, operator: string, value: unknown): unknown;
3799
+ }) => unknown): {
3800
+ pluck<TColumn extends ModelAttributeKey<TTable>>(column: TColumn): Promise<Array<ModelRecord<TTable>[TColumn]>>;
3801
+ };
3802
+ };
3803
+ };
3742
3804
  declare function uniqueSlug<TTable extends TableDefinition, TScopes extends ModelScopesDefinition, TRelations extends RelationMap, TColumn extends StringModelAttributeKey<TTable> = Extract<'slug', StringModelAttributeKey<TTable>>>(model: UniqueSlugModel<TTable, TScopes, TRelations>, value: string, options?: UniqueSlugOptions<TTable, TColumn>): Promise<string>;
3743
3805
 
3744
3806
  declare function belongsTo<const TName extends RegisteredModelName>(related: TName, foreignKeyOrOptions: string | {
@@ -3855,4 +3917,4 @@ interface NormalizedHoloProjectConfig {
3855
3917
  declare function normalizeHoloProjectConfig(config?: HoloProjectConfig): NormalizedHoloProjectConfig;
3856
3918
  declare function defineHoloProject<TConfig extends HoloProjectConfig>(config: TConfig): NormalizedHoloProjectConfig & TConfig;
3857
3919
 
3858
- export { type AddColumnOperation, type AlterColumnOperation, type AnyColumnDefinition, AsyncConnectionContext, type BelongsToManyRelationDefinition, type BelongsToRelationDefinition, type BoundTableDefinition, type BuiltInCastName, type BuiltInCastString, CapabilityError, type CastableDefinition, ColumnBuilder, type ColumnDefinition, type CompiledStatement, CompilerError, type ConcurrencyOptions, ConfigurationError, ConnectionManager, type ConnectionManagerOptions, type CreateForeignKeyOperation, type CreateIndexOperation, type CreateTableOperation, type CursorPaginatedResult, type CursorPaginationOptions, DB, type DDLOperation, type DDLStatement, DEFAULT_CAPABILITIES, DEFAULT_HOLO_PROJECT_PATHS, DEFAULT_SECURITY_POLICY, DIALECT_ID_STRATEGY_MAP, DIALECT_LOGICAL_TYPE_MAP, DIALECT_VECTOR_SUPPORT, type DatabaseCapabilities, DatabaseContext, type DatabaseContextOptions, type DatabaseDriverName, DatabaseError, type DatabaseLogger, type DatabaseOperationOptions, type DatabaseQueryCacheBridge, type DefineModelOptions, type DefineTableOptions, type DeleteQueryPlan, type Dialect, type DriverAdapter, type DriverExecutionResult, type DriverQueryResult, type DropColumnOperation, type DropForeignKeyOperation, type DropIndexOperation, type DropTableOperation, type DynamicRelationResolver, type EmptyScopeMap, Entity, type EntityWithLoaded, type EnumCastDefinition, Factory, type FactoryAttributes, type FactoryContext, type FactoryDefinition, type FactoryHook, type FactoryModelReference, FactoryService, type FactoryStateDefinition, type ForeignKeyReference, type GeneratedMigrationTemplate, type GeneratedSchemaTable, type GeneratedSchemaTableName, type GeneratedSchemaTables, type HasManyRelationDefinition, type HasOneRelationDefinition, HasSnowflakes, HasUlids, HasUniqueIds, HasUuids, type HoloProjectConfig, type HoloProjectConnectionConfig, type HoloProjectDatabaseConfig, type HoloProjectPaths, HydrationError, type IdGenerationStrategy, type InferInsert, type InferSelect, type InferUpdate, type InsertQueryPlan, type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedIndex, type LogicalColumnKind, type MigrateOptions, type MigrationContext, type MigrationDefinition, type MigrationErrorLog, type MigrationExecutionPolicy, MigrationService, type MigrationSquashPlan, type MigrationStartLog, type MigrationStatus, type MigrationSuccessLog, type MigrationTemplateKind, type MigrationTemplateOptions, type ModelAttributeKey, type ModelCastDefinition, type ModelCollection, type ModelDefinition, ModelEventService, type ModelInsertPayload, ModelNotFoundException, ModelQueryBuilder, type ModelRecord, type ModelReference, ModelRegistry, ModelRepository, type ModelScopeArgs, type ModelScopeMap, type ModelTrait, type ModelUpdatePayload, MySQLAdapter, type MySQLAdapterOptions, type MySQLClientLike, type MySQLPoolLike, MySQLQueryCompiler, type MySQLQueryableLike, MySQLSchemaCompiler, type NormalizedHoloProjectConfig, type PaginatedResult, type PaginationMeta, type PaginationOptions, type PivotRelationMethods, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientLike, type PostgresPoolLike, PostgresQueryCompiler, type PostgresQueryableLike, PostgresSchemaCompiler, type QueryCacheConfig, type QueryCacheFlexibleTtlInput, type QueryCacheTtlInput, type QueryDirection, type QueryOperator, type QueryOrderBy, type QueryPlan, type QueryPredicate, QueryScheduler, type QuerySelection, type QuerySource, type RegisteredModelName, type RegisteredModelReference, type RegisteredModels, type RelationDefinition, RelationError, type RelationMap, type RenameColumnOperation, type RenameIndexOperation, type RenameTableOperation, type ResolveEagerLoadPath, type ResolveEagerLoadUnion, type ResolveEagerLoads, type RollbackOptions, type RuntimeConfigInput, type RuntimeConnectionConfig, type RuntimeDatabaseConfig, type RuntimeHoloConfig, SQLQueryCompiler, SQLSchemaCompiler, SQLiteAdapter, type SQLiteAdapterOptions, type SQLiteDatabaseLike, SQLiteQueryCompiler, SQLiteSchemaCompiler, type SQLiteStatementLike, type SchemaColumnMismatch, type SchemaDefaultDialectName, type SchemaDialectName, type SchemaDiff, SchemaError, type SchemaForeignKeyMismatch, type SchemaIndexMismatch, SchemaRegistry, SchemaService, type SchemaSyncPlan, SecurityError, type SecurityPolicy, type SeedOptions, type SeederContext, type SeederDefinition, type SeederErrorLog, SeederService, type SeederStartLog, type SeederSuccessLog, type SelectQueryPlan, SerializationError, type SerializeLoaded, type SerializeModels, type SerializedEntityWithLoaded, type SimplePaginatedResult, type SimplePaginationMeta, type StaticModelApi, type SupportedDatabaseDriver, type TableColumnsShape, type TableDefinition, TableDefinitionBuilder, type TableIndexDefinition, TableMutationBuilder, TableQueryBuilder, type TableSchemaDiff, type TransactionCallback, TransactionError, type UniqueIdRuntimeConfig, type UniqueIdTrait, type UniqueIdTraitKind, type UnsafeStatement, type UpdateQueryPlan, type VectorValue, addColumnOperation, alterColumnOperation, belongsTo, belongsToMany, binaryCast, clearGeneratedTables, column, compileDialectDefaultLiteral, configureDB, configureDatabaseQueryCacheBridge, connectionAsyncContext, createAdapter, createCapabilities, createConnectionManager, createCursorPaginator, createDatabase, createDeleteQueryPlan, createDialect, createFactoryService, createForeignKeyOperation, createIndexOperation, createInsertQueryPlan, createMigrationFileName, createMigrationService, createMigrationTimestamp, createModelCollection, createModelEventService, createModelRegistry, createMySQLAdapter, createPaginator, createPostgresAdapter, createQueryScheduler, createRuntimeConnectionOptions, createRuntimeLogger, createSQLiteAdapter, diffSchema as createSchemaDiff, createSchemaRegistry, createSchemaService, createSecurityPolicy, createSeederService, createSelectQueryPlan, createSimplePaginator, createTableOperation, createTableSource, createUpdateQueryPlan, defineFactory, defineGeneratedTable, defineHoloProject, defineMigration, defineModel, defineSeeder, diffSchema, dropColumnOperation, dropForeignKeyOperation, dropIndexOperation, dropTableOperation, encryptedCast, enumCast, generateMigrationTemplate, generateSnowflake, generateUlid, generateUuidV7, getDatabaseQueryCacheBridge, getGeneratedTableDefinition, getModelDefinition, hasMany, hasManyThrough, hasOne, hasOneThrough, inferMigrationTableName, inferMigrationTemplateKind, isSupportedDatabaseDriver, latestMorphOne, latestOfMany, listGeneratedTableDefinitions, morphMany, morphOfMany, morphOne, morphTo, morphToMany, morphedByMany, normalizeDialectReadValue, normalizeDialectWriteValue, normalizeHoloProjectConfig, normalizeMigrationSlug, ofMany, oldestMorphOne, oldestOfMany, parseDatabaseDriver, queryCacheInternals, redactBindings, redactSql, registerGeneratedTables, renameColumnOperation, renameIndexOperation, renameTableOperation, renderGeneratedSchemaModule, renderGeneratedSchemaPlaceholder, renderGeneratedSchemaRuntimeModule, resetDB, resetDatabaseQueryCacheBridge, resetGlobalModelRegistry, resetMorphRegistry, resolveDialectColumnType, resolveDialectIdStrategyType, resolveGeneratedTableDefinition, resolveMorphModel, resolveRuntimeConnectionManagerOptions, scopeRelation, serializeModels, uniqueSlug, unsafeSql, validateQueryPlan, withLimit, withOffset, withOrderBy, withPredicate, withSelections };
3920
+ export { type AddColumnOperation, type AlterColumnOperation, type AnyColumnDefinition, type AnyModelDefinition, AsyncConnectionContext, type BelongsToManyRelationDefinition, type BelongsToManyRelationMethods, type BelongsToRelationDefinition, type BelongsToRelationMethods, type BoundTableDefinition, type BuiltInCastName, type BuiltInCastString, CapabilityError, type CastableDefinition, ColumnBuilder, type ColumnDefinition, type CompiledStatement, CompilerError, type ConcurrencyOptions, ConfigurationError, ConnectionManager, type ConnectionManagerOptions, type CreateForeignKeyOperation, type CreateIndexOperation, type CreateTableOperation, type CursorPaginatedResult, type CursorPaginationOptions, DB, type DDLOperation, type DDLStatement, DEFAULT_CAPABILITIES, DEFAULT_HOLO_PROJECT_PATHS, DEFAULT_SECURITY_POLICY, DIALECT_ID_STRATEGY_MAP, DIALECT_LOGICAL_TYPE_MAP, DIALECT_VECTOR_SUPPORT, type DatabaseCapabilities, DatabaseContext, type DatabaseContextOptions, type DatabaseDependencyCollectionResult, type DatabaseDependencyInvalidationEvent, type DatabaseDependencyInvalidationListener, type DatabaseDriverName, DatabaseError, type DatabaseLogger, type DatabaseOperationOptions, type DatabaseQueryCacheBridge, type DatabaseTransactionOptions, type DefineModelOptions, type DefineTableOptions, type DeleteQueryPlan, type Dialect, type DriverAdapter, type DriverExecutionResult, type DriverQueryResult, type DropColumnOperation, type DropForeignKeyOperation, type DropIndexOperation, type DropTableOperation, type DynamicRelationResolver, type EmptyScopeMap, Entity, type EntityWithLoaded, type EnumCastDefinition, Factory, type FactoryAttributes, type FactoryContext, type FactoryDefinition, type FactoryHook, type FactoryModelReference, FactoryService, type FactoryStateDefinition, type ForeignKeyReference, type GeneratedMigrationTemplate, type GeneratedSchemaTable, type GeneratedSchemaTableName, type GeneratedSchemaTables, type HasManyRelationDefinition, type HasManyRelationMethods, type HasManyThroughRelationDefinition, type HasOneOfManyRelationDefinition, type HasOneRelationDefinition, type HasOneRelationMethods, type HasOneThroughRelationDefinition, HasSnowflakes, HasUlids, HasUniqueIds, HasUuids, type HoloProjectConfig, type HoloProjectConnectionConfig, type HoloProjectDatabaseConfig, type HoloProjectPaths, HydrationError, type IdGenerationStrategy, type InferInsert, type InferSelect, type InferUpdate, type InsertQueryPlan, type IntrospectedColumn, type IntrospectedForeignKey, type IntrospectedIndex, type LogicalColumnKind, type MigrateOptions, type MigrationContext, type MigrationDefinition, type MigrationErrorLog, type MigrationExecutionPolicy, MigrationService, type MigrationSquashPlan, type MigrationStartLog, type MigrationStatus, type MigrationSuccessLog, type MigrationTemplateKind, type MigrationTemplateOptions, type ModelAttributeKey, type ModelCastDefinition, type ModelCollection, type ModelDefinition, type ModelDefinitionLike, ModelEventService, type ModelInsertPayload, ModelNotFoundException, ModelQueryBuilder, type ModelRecord, type ModelReference, ModelRegistry, type ModelRelationPath, ModelRepository, type ModelRepositoryLike, type ModelScopeArgs, type ModelScopeMap, type ModelTrait, type ModelUpdatePayload, type MorphManyRelationDefinition, type MorphOneOfManyRelationDefinition, type MorphOneRelationDefinition, type MorphToManyRelationDefinition, type MorphToRelationDefinition, type MorphedByManyRelationDefinition, MySQLAdapter, type MySQLAdapterOptions, type MySQLClientLike, type MySQLPoolLike, MySQLQueryCompiler, type MySQLQueryableLike, MySQLSchemaCompiler, type NormalizedHoloProjectConfig, type PaginatedResult, type PaginationMeta, type PaginationOptions, type PivotRelationMethods, PostgresAdapter, type PostgresAdapterOptions, type PostgresClientLike, type PostgresPoolLike, PostgresQueryCompiler, type PostgresQueryableLike, PostgresSchemaCompiler, type QueryCacheConfig, type QueryCacheFlexibleTtlInput, type QueryCacheTtlInput, type QueryDirection, type QueryOperator, type QueryOrderBy, type QueryPlan, type QueryPredicate, QueryScheduler, type QuerySelection, type QuerySource, type RegisteredModelName, type RegisteredModelReference, type RegisteredModels, type RelatedColumnNameForRelationPath, type RelationConstraintDefinition, type RelationDefinition, RelationError, type RelationMap, type RenameColumnOperation, type RenameIndexOperation, type RenameTableOperation, type ResolveEagerLoadPath, type ResolveEagerLoadUnion, type ResolveEagerLoads, type RollbackOptions, type RuntimeConfigInput, type RuntimeConnectionConfig, type RuntimeDatabaseConfig, type RuntimeHoloConfig, SQLQueryCompiler, SQLSchemaCompiler, SQLiteAdapter, type SQLiteAdapterOptions, type SQLiteDatabaseLike, SQLiteQueryCompiler, SQLiteSchemaCompiler, type SQLiteStatementLike, type SchemaColumnMismatch, type SchemaDefaultDialectName, type SchemaDialectName, type SchemaDiff, SchemaError, type SchemaForeignKeyMismatch, type SchemaIndexMismatch, SchemaRegistry, SchemaService, type SchemaSyncPlan, SecurityError, type SecurityPolicy, type SeedOptions, type SeederContext, type SeederDefinition, type SeederErrorLog, SeederService, type SeederStartLog, type SeederSuccessLog, type SelectQueryPlan, SerializationError, type SerializeLoaded, type SerializeModels, type SerializedEntityWithLoaded, type SimplePaginatedResult, type SimplePaginationMeta, type StaticModelApi, type SupportedDatabaseDriver, type TableColumnsShape, type TableDefinition, TableDefinitionBuilder, type TableIndexDefinition, TableMutationBuilder, TableQueryBuilder, type TableSchemaDiff, type TransactionCallback, TransactionError, type TransactionMode, type UniqueIdRuntimeConfig, type UniqueIdTrait, type UniqueIdTraitKind, type UnsafeStatement, type UpdateQueryPlan, type VectorValue, addColumnOperation, alterColumnOperation, belongsTo, belongsToMany, binaryCast, clearGeneratedTables, collectDatabaseQueryDependencies, column, compileDialectDefaultLiteral, configureDB, configureDatabaseQueryCacheBridge, connectionAsyncContext, createAdapter, createCapabilities, createConnectionManager, createCursorPaginator, createDatabase, createDeleteQueryPlan, createDialect, createFactoryService, createForeignKeyOperation, createIndexOperation, createInsertQueryPlan, createMigrationFileName, createMigrationService, createMigrationTimestamp, createModelCollection, createModelEventService, createModelRegistry, createMySQLAdapter, createPaginator, createPostgresAdapter, createQueryScheduler, createRuntimeConnectionOptions, createRuntimeLogger, createSQLiteAdapter, diffSchema as createSchemaDiff, createSchemaRegistry, createSchemaService, createSecurityPolicy, createSeederService, createSelectQueryPlan, createSimplePaginator, createTableOperation, createTableSource, createUpdateQueryPlan, defineFactory, defineGeneratedTable, defineHoloProject, defineMigration, defineModel, defineSeeder, diffSchema, dropColumnOperation, dropForeignKeyOperation, dropIndexOperation, dropTableOperation, encryptedCast, enumCast, generateMigrationTemplate, generateSnowflake, generateUlid, generateUuidV7, getDatabaseQueryCacheBridge, getGeneratedTableDefinition, getModelDefinition, hasMany, hasManyThrough, hasOne, hasOneThrough, inferMigrationTableName, inferMigrationTemplateKind, isSupportedDatabaseDriver, latestMorphOne, latestOfMany, listGeneratedTableDefinitions, morphMany, morphOfMany, morphOne, morphTo, morphToMany, morphedByMany, normalizeDialectReadValue, normalizeDialectWriteValue, normalizeHoloProjectConfig, normalizeMigrationSlug, ofMany, oldestMorphOne, oldestOfMany, onDatabaseDependencyInvalidated, parseDatabaseDriver, queryCacheInternals, recordDatabaseQueryDependencies, redactBindings, redactSql, registerGeneratedTables, renameColumnOperation, renameIndexOperation, renameTableOperation, renderGeneratedSchemaModule, renderGeneratedSchemaPlaceholder, renderGeneratedSchemaRuntimeModule, resetDB, resetDatabaseDependencyInvalidationListeners, resetDatabaseQueryCacheBridge, resetGlobalModelRegistry, resetMorphRegistry, resolveDialectColumnType, resolveDialectIdStrategyType, resolveGeneratedTableDefinition, resolveMorphModel, resolveRuntimeConnectionManagerOptions, scopeRelation, serializeModels, uniqueSlug, unsafeSql, validateQueryPlan, withLimit, withOffset, withOrderBy, withPredicate, withSelections };
package/dist/index.mjs CHANGED
@@ -121,6 +121,8 @@ function redactSql(sql, policy) {
121
121
 
122
122
  // src/cache.ts
123
123
  import { createHash } from "crypto";
124
+ import { AsyncLocalStorage } from "async_hooks";
125
+ var databaseDependencyCollector = new AsyncLocalStorage();
124
126
  function getQueryCacheBridgeState() {
125
127
  const runtime = globalThis;
126
128
  runtime.__holoDbQueryCacheBridge__ ??= {};
@@ -135,6 +137,50 @@ function getDatabaseQueryCacheBridge() {
135
137
  function resetDatabaseQueryCacheBridge() {
136
138
  getQueryCacheBridgeState().bridge = void 0;
137
139
  }
140
+ function onDatabaseDependencyInvalidated(listener) {
141
+ const state = getQueryCacheBridgeState();
142
+ state.dependencyInvalidationListeners ??= /* @__PURE__ */ new Set();
143
+ state.dependencyInvalidationListeners.add(listener);
144
+ return () => {
145
+ state.dependencyInvalidationListeners?.delete(listener);
146
+ };
147
+ }
148
+ function resetDatabaseDependencyInvalidationListeners() {
149
+ getQueryCacheBridgeState().dependencyInvalidationListeners = void 0;
150
+ }
151
+ async function collectDatabaseQueryDependencies(callback) {
152
+ const dependencies = /* @__PURE__ */ new Set();
153
+ const value = await databaseDependencyCollector.run(dependencies, callback);
154
+ return Object.freeze({
155
+ value,
156
+ dependencies: Object.freeze([...dependencies])
157
+ });
158
+ }
159
+ function recordDatabaseQueryDependencies(dependencies) {
160
+ if (!dependencies || dependencies.length === 0) {
161
+ return;
162
+ }
163
+ const active = databaseDependencyCollector.getStore();
164
+ if (!active) {
165
+ return;
166
+ }
167
+ for (const dependency of dependencies) {
168
+ active.add(dependency);
169
+ }
170
+ }
171
+ async function notifyDatabaseDependencyInvalidationListeners(event) {
172
+ const listeners = getQueryCacheBridgeState().dependencyInvalidationListeners;
173
+ if (!listeners || listeners.size === 0) {
174
+ return;
175
+ }
176
+ await Promise.all([...listeners].map(async (listener) => {
177
+ try {
178
+ await listener(event);
179
+ } catch (error) {
180
+ console.error("[@holo-js/db] Database dependency invalidation listener failed.", error);
181
+ }
182
+ }));
183
+ }
138
184
  function normalizeQueryCacheConfig(input) {
139
185
  if (typeof input === "number" || input instanceof Date) {
140
186
  return Object.freeze({
@@ -238,19 +284,25 @@ function resolveQueryCacheDependencies(plan, connectionName, explicit) {
238
284
  return inferAutomaticQueryCacheDependencies(plan, connectionName);
239
285
  }
240
286
  async function invalidateQueryCacheDependencies(connection, dependencies) {
241
- const bridge = getDatabaseQueryCacheBridge();
242
- if (!bridge || dependencies.length === 0) {
287
+ if (dependencies.length === 0) {
243
288
  return;
244
289
  }
290
+ const invalidate = async () => {
291
+ const bridge = getDatabaseQueryCacheBridge();
292
+ await bridge?.invalidateDependencies(dependencies);
293
+ await notifyDatabaseDependencyInvalidationListeners({
294
+ connectionName: connection.getConnectionName(),
295
+ dependencies
296
+ });
297
+ };
245
298
  if (connection.getScope().kind === "root") {
246
- await bridge.invalidateDependencies(dependencies);
299
+ await invalidate();
247
300
  return;
248
301
  }
249
- connection.afterCommit(async () => {
250
- await bridge.invalidateDependencies(dependencies);
251
- });
302
+ connection.afterCommit(invalidate);
252
303
  }
253
304
  var queryCacheInternals = {
305
+ collectDatabaseQueryDependencies,
254
306
  configureDatabaseQueryCacheBridge,
255
307
  createDeterministicQueryCacheKey,
256
308
  createTableCacheDependency,
@@ -258,8 +310,12 @@ var queryCacheInternals = {
258
310
  inferAutomaticQueryCacheDependencies,
259
311
  normalizeQueryCacheConfig,
260
312
  normalizeQueryCacheDependencies,
313
+ notifyDatabaseDependencyInvalidationListeners,
314
+ onDatabaseDependencyInvalidated,
315
+ recordDatabaseQueryDependencies,
261
316
  resolveQueryCacheDependencies,
262
317
  resolveQueryCacheKey,
318
+ resetDatabaseDependencyInvalidationListeners,
263
319
  supportsAutomaticPredicateInvalidation,
264
320
  supportsAutomaticQueryCacheInvalidation
265
321
  };
@@ -296,24 +352,56 @@ function normalizePaginationParameterName(value, fallback, createError) {
296
352
  }
297
353
  return trimmed;
298
354
  }
299
- function encodeOffsetCursor(offset) {
300
- return Buffer.from(JSON.stringify({ offset }), "utf8").toString("base64url");
355
+ function encodeValueCursor(values) {
356
+ return Buffer.from(JSON.stringify({ values }), "utf8").toString("base64url");
301
357
  }
302
- function decodeOffsetCursor(cursor, createError) {
358
+ function decodeValueCursor(cursor, createError) {
303
359
  if (cursor === null) {
304
- return 0;
360
+ return null;
305
361
  }
306
362
  try {
307
363
  const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
308
- const offset = decoded.offset;
309
- if (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0) {
310
- throw new Error("invalid offset");
364
+ if (!Array.isArray(decoded.values)) {
365
+ throw new Error("invalid cursor values");
311
366
  }
312
- return offset;
367
+ return { values: decoded.values };
313
368
  } catch {
314
369
  throw createError("Cursor is malformed.");
315
370
  }
316
371
  }
372
+ function normalizeComparableValue(value) {
373
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
374
+ return value;
375
+ }
376
+ if (value instanceof Date) {
377
+ return value.getTime();
378
+ }
379
+ return String(value);
380
+ }
381
+ function compareCursorValues(left, right) {
382
+ const normalizedLeft = normalizeComparableValue(left);
383
+ const normalizedRight = normalizeComparableValue(right);
384
+ if (normalizedLeft === normalizedRight) {
385
+ return 0;
386
+ }
387
+ if (normalizedLeft === null) {
388
+ return -1;
389
+ }
390
+ if (normalizedRight === null) {
391
+ return 1;
392
+ }
393
+ return normalizedLeft < normalizedRight ? -1 : 1;
394
+ }
395
+ function isRowAfterCursor(rowValues, cursorValues, orders) {
396
+ for (const [index, order] of orders.entries()) {
397
+ const comparison = compareCursorValues(rowValues[index], cursorValues[index]);
398
+ if (comparison === 0) {
399
+ continue;
400
+ }
401
+ return order.direction === "asc" ? comparison > 0 : comparison < 0;
402
+ }
403
+ return false;
404
+ }
317
405
 
318
406
  // src/query/paginator.ts
319
407
  function createPaginator(data, meta) {
@@ -2721,6 +2809,12 @@ var TableQueryBuilder = class _TableQueryBuilder {
2721
2809
  async get() {
2722
2810
  const statement = this.toSQL();
2723
2811
  const cacheConfig = this.queryCacheConfig;
2812
+ const dependencies = this.plan.lockMode ? void 0 : resolveQueryCacheDependencies(
2813
+ this.plan,
2814
+ this.connection.getConnectionName(),
2815
+ cacheConfig?.invalidate
2816
+ );
2817
+ recordDatabaseQueryDependencies(dependencies);
2724
2818
  if (!cacheConfig || this.plan.lockMode) {
2725
2819
  const result = await this.connection.queryCompiled(statement);
2726
2820
  return result.rows;
@@ -2730,11 +2824,6 @@ var TableQueryBuilder = class _TableQueryBuilder {
2730
2824
  throw new ConfigurationError("[@holo-js/db] Query caching requires @holo-js/cache to be installed and configured.");
2731
2825
  }
2732
2826
  const cacheKey = resolveQueryCacheKey(statement, this.connection.getConnectionName(), cacheConfig);
2733
- const dependencies = resolveQueryCacheDependencies(
2734
- this.plan,
2735
- this.connection.getConnectionName(),
2736
- cacheConfig.invalidate
2737
- );
2738
2827
  if (cacheConfig.flexible) {
2739
2828
  return bridge.flexible(
2740
2829
  cacheKey,
@@ -2820,16 +2909,23 @@ var TableQueryBuilder = class _TableQueryBuilder {
2820
2909
  async cursorPaginate(perPage = 15, cursor = null, options = {}) {
2821
2910
  assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
2822
2911
  const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new SecurityError(message));
2823
- const offset = decodeOffsetCursor(cursor, (message) => new SecurityError(message));
2912
+ const decodedCursor = decodeValueCursor(cursor, (message) => new SecurityError(message));
2824
2913
  const orderedQuery = this.prepareCursorPaginationQuery();
2914
+ const cursorOrders = orderedQuery.resolveCursorOrders();
2825
2915
  const rows = await orderedQuery.getUnpaginatedRows();
2826
- const pageRows = rows.slice(offset, offset + perPage + 1);
2916
+ const filteredRows = decodedCursor ? rows.filter((row) => isRowAfterCursor(
2917
+ cursorOrders.map((order) => orderedQuery.readCursorColumnValue(row, order.column)),
2918
+ decodedCursor.values,
2919
+ cursorOrders
2920
+ )) : rows;
2921
+ const pageRows = filteredRows.slice(0, perPage + 1);
2827
2922
  const hasMorePages = pageRows.length > perPage;
2828
2923
  const data = hasMorePages ? pageRows.slice(0, perPage) : pageRows;
2924
+ const lastRow = data.at(-1);
2829
2925
  return createCursorPaginator(data, {
2830
2926
  perPage,
2831
2927
  cursorName,
2832
- nextCursor: hasMorePages ? encodeOffsetCursor(offset + perPage) : null,
2928
+ nextCursor: hasMorePages && lastRow ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastRow, order.column))) : null,
2833
2929
  prevCursor: cursor
2834
2930
  });
2835
2931
  }
@@ -3154,6 +3250,24 @@ var TableQueryBuilder = class _TableQueryBuilder {
3154
3250
  }
3155
3251
  return this;
3156
3252
  }
3253
+ resolveCursorOrders() {
3254
+ return this.plan.orderBy.map((orderBy) => {
3255
+ if (orderBy.kind !== "column") {
3256
+ throw new SecurityError("Cursor pagination requires column orderBy clauses.");
3257
+ }
3258
+ return {
3259
+ column: orderBy.column,
3260
+ direction: orderBy.direction
3261
+ };
3262
+ });
3263
+ }
3264
+ readCursorColumnValue(row, column2) {
3265
+ if (column2 in row) {
3266
+ return row[column2];
3267
+ }
3268
+ const unqualifiedColumn = column2.split(".").at(-1);
3269
+ return unqualifiedColumn ? row[unqualifiedColumn] : void 0;
3270
+ }
3157
3271
  async aggregateNumeric(column2, kind) {
3158
3272
  const rows = await this.get();
3159
3273
  if (rows.length === 0) {
@@ -6230,7 +6344,7 @@ var MigrationService = class {
6230
6344
  }
6231
6345
  async migrate(options = {}) {
6232
6346
  return this.runExclusively(async () => {
6233
- await this.ensureTrackingTable();
6347
+ await this.ensureTrackingTableForMigration();
6234
6348
  const step = options.step ?? Number.POSITIVE_INFINITY;
6235
6349
  const ran = await this.getRanRecords();
6236
6350
  const ranNames = new Set(ran.map((record) => record.name));
@@ -6255,6 +6369,22 @@ var MigrationService = class {
6255
6369
  return executed;
6256
6370
  });
6257
6371
  }
6372
+ async ensureTrackingTableForMigration() {
6373
+ try {
6374
+ await this.ensureTrackingTable();
6375
+ } catch (error) {
6376
+ if (!this.isDatabaseMissingError(error)) {
6377
+ throw error;
6378
+ }
6379
+ const adapter = this.connection.getAdapter();
6380
+ if (typeof adapter.ensureDatabaseExists !== "function") {
6381
+ throw error;
6382
+ }
6383
+ await this.disconnectFailedConnection();
6384
+ await adapter.ensureDatabaseExists();
6385
+ await this.ensureTrackingTable();
6386
+ }
6387
+ }
6258
6388
  async rollback(options = {}) {
6259
6389
  return this.runExclusively(async () => {
6260
6390
  await this.ensureTrackingTable();
@@ -6338,6 +6468,22 @@ var MigrationService = class {
6338
6468
  throw error;
6339
6469
  }
6340
6470
  }
6471
+ isDatabaseMissingError(error) {
6472
+ const adapter = this.connection.getAdapter();
6473
+ if (typeof adapter.isDatabaseMissingError !== "function") {
6474
+ return false;
6475
+ }
6476
+ if (adapter.isDatabaseMissingError(error)) {
6477
+ return true;
6478
+ }
6479
+ return error instanceof DatabaseError && typeof error.cause !== "undefined" && adapter.isDatabaseMissingError(error.cause);
6480
+ }
6481
+ async disconnectFailedConnection() {
6482
+ if (!this.connection.isConnected()) {
6483
+ return;
6484
+ }
6485
+ await this.connection.disconnect();
6486
+ }
6341
6487
  normalizeMigratedAt(value) {
6342
6488
  const normalized = value instanceof Date ? value : new Date(value);
6343
6489
  if (Number.isNaN(normalized.getTime())) {
@@ -6374,9 +6520,9 @@ function createMigrationService(connection, migrations = []) {
6374
6520
  }
6375
6521
 
6376
6522
  // src/model/eventState.ts
6377
- import { AsyncLocalStorage } from "async_hooks";
6378
- var eventMuteStorage = new AsyncLocalStorage();
6379
- var guardBypassStorage = new AsyncLocalStorage();
6523
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
6524
+ var eventMuteStorage = new AsyncLocalStorage2();
6525
+ var guardBypassStorage = new AsyncLocalStorage2();
6380
6526
  function areModelEventsMuted() {
6381
6527
  return (eventMuteStorage.getStore() ?? 0) > 0;
6382
6528
  }
@@ -6412,10 +6558,10 @@ function createModelEventService() {
6412
6558
  }
6413
6559
 
6414
6560
  // src/concurrency/AsyncConnectionContext.ts
6415
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
6561
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
6416
6562
  function getAsyncConnectionStorage() {
6417
6563
  const runtime = globalThis;
6418
- runtime.__holoAsyncConnectionStorage__ ??= new AsyncLocalStorage2();
6564
+ runtime.__holoAsyncConnectionStorage__ ??= new AsyncLocalStorage3();
6419
6565
  return runtime.__holoAsyncConnectionStorage__;
6420
6566
  }
6421
6567
  var AsyncConnectionContext = class {
@@ -6603,12 +6749,23 @@ var DatabaseFacade = class {
6603
6749
  raw(sql, bindings = [], source) {
6604
6750
  return unsafeSql(sql, bindings, source);
6605
6751
  }
6606
- async transaction(callback, connectionName, options) {
6752
+ async transaction(callback, connectionNameOrOptions, options) {
6753
+ const connectionName = typeof connectionNameOrOptions === "string" ? connectionNameOrOptions : void 0;
6754
+ const transactionOptions = typeof connectionNameOrOptions === "string" ? options : options ?? connectionNameOrOptions;
6607
6755
  const target = this.connection(connectionName);
6608
6756
  return target.transaction((tx) => connectionAsyncContext.run({
6609
6757
  connectionName: tx.getConnectionName(),
6610
6758
  connection: tx
6611
- }, () => callback(tx)), options);
6759
+ }, () => callback(tx)), transactionOptions);
6760
+ }
6761
+ async writeTransaction(callback, connectionNameOrOptions, options) {
6762
+ const connectionName = typeof connectionNameOrOptions === "string" ? connectionNameOrOptions : void 0;
6763
+ const transactionOptions = typeof connectionNameOrOptions === "string" ? options : options ?? connectionNameOrOptions;
6764
+ const target = this.connection(connectionName);
6765
+ return target.writeTransaction((tx) => connectionAsyncContext.run({
6766
+ connectionName: tx.getConnectionName(),
6767
+ connection: tx
6768
+ }, () => callback(tx)), transactionOptions);
6612
6769
  }
6613
6770
  afterCommit(callback, connectionName) {
6614
6771
  this.connection(connectionName).afterCommit(callback);
@@ -8015,16 +8172,23 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
8015
8172
  async cursorPaginate(perPage = 15, cursor = null, options = {}) {
8016
8173
  assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
8017
8174
  const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new HydrationError(message));
8018
- const offset = decodeOffsetCursor(cursor, (message) => new HydrationError(message));
8175
+ const decodedCursor = decodeValueCursor(cursor, (message) => new HydrationError(message));
8019
8176
  const orderedQuery = this.prepareCursorPaginationQuery();
8177
+ const cursorOrders = orderedQuery.resolveCursorOrders();
8020
8178
  const entities = await orderedQuery.getUnpaginatedEntities();
8021
- const pageEntities = entities.slice(offset, offset + perPage + 1);
8179
+ const filteredEntities = decodedCursor ? entities.filter((entity) => isRowAfterCursor(
8180
+ cursorOrders.map((order) => orderedQuery.readCursorColumnValue(entity, order.column)),
8181
+ decodedCursor.values,
8182
+ cursorOrders
8183
+ )) : entities;
8184
+ const pageEntities = filteredEntities.slice(0, perPage + 1);
8022
8185
  const hasMorePages = pageEntities.length > perPage;
8023
8186
  const data = hasMorePages ? pageEntities.slice(0, perPage) : pageEntities;
8187
+ const lastEntity = data.at(-1);
8024
8188
  return createCursorPaginator(this.repository.createCollection(data), {
8025
8189
  perPage,
8026
8190
  cursorName,
8027
- nextCursor: hasMorePages ? encodeOffsetCursor(offset + perPage) : null,
8191
+ nextCursor: hasMorePages && lastEntity ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastEntity, order.column))) : null,
8028
8192
  prevCursor: cursor
8029
8193
  });
8030
8194
  }
@@ -8501,6 +8665,22 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
8501
8665
  }
8502
8666
  return this;
8503
8667
  }
8668
+ resolveCursorOrders() {
8669
+ const plan = this.tableQuery.getPlan();
8670
+ return plan.orderBy.map((orderBy) => {
8671
+ if (orderBy.kind !== "column") {
8672
+ throw new HydrationError("Cursor pagination requires column orderBy clauses.");
8673
+ }
8674
+ return {
8675
+ column: orderBy.column,
8676
+ direction: orderBy.direction
8677
+ };
8678
+ });
8679
+ }
8680
+ readCursorColumnValue(entity, column2) {
8681
+ const unqualifiedColumn = column2.split(".").at(-1) ?? column2;
8682
+ return entity.get(unqualifiedColumn);
8683
+ }
8504
8684
  };
8505
8685
 
8506
8686
  // src/model/runtimeSettings.ts
@@ -11577,12 +11757,16 @@ var DatabaseContext = class _DatabaseContext {
11577
11757
  async transaction(callback, options) {
11578
11758
  await this.initialize();
11579
11759
  this._assertValidOperationOptions(options);
11760
+ this._assertValidTransactionOptions(options);
11580
11761
  this._throwIfAborted(options?.signal, "transaction");
11581
11762
  if (this._scope.kind === "root") {
11582
11763
  return this._runRootTransaction(callback, options);
11583
11764
  }
11584
11765
  return this._runNestedTransaction(callback, options);
11585
11766
  }
11767
+ async writeTransaction(callback, options) {
11768
+ return this.transaction(callback, this._resolveWriteTransactionOptions(options));
11769
+ }
11586
11770
  async _runRootTransaction(callback, options) {
11587
11771
  const runWithinScope = this._adapter.runWithTransactionScope?.bind(this._adapter) ?? (async (runner) => runner());
11588
11772
  const entry = {
@@ -11931,6 +12115,29 @@ var DatabaseContext = class _DatabaseContext {
11931
12115
  throw new ConfigurationError("Database operation timeouts must be positive integers in milliseconds.");
11932
12116
  }
11933
12117
  }
12118
+ _assertValidTransactionOptions(options) {
12119
+ if (typeof options?.mode === "undefined") {
12120
+ return;
12121
+ }
12122
+ if (options.mode !== "deferred" && options.mode !== "immediate" && options.mode !== "exclusive") {
12123
+ throw new ConfigurationError("Database transaction mode must be one of deferred, immediate, or exclusive.");
12124
+ }
12125
+ if (!this._dialect.name.startsWith("sqlite")) {
12126
+ throw new CapabilityError(`Transaction mode "${options.mode}" is only supported for SQLite connections.`);
12127
+ }
12128
+ if (this._scope.kind !== "root") {
12129
+ throw new TransactionError("Transaction mode can only be set when starting a root transaction.");
12130
+ }
12131
+ }
12132
+ _resolveWriteTransactionOptions(options) {
12133
+ if (this._scope.kind !== "root" || !this._dialect.name.startsWith("sqlite")) {
12134
+ return options;
12135
+ }
12136
+ return {
12137
+ ...options,
12138
+ mode: options?.mode ?? "immediate"
12139
+ };
12140
+ }
11934
12141
  _throwIfAborted(signal, action) {
11935
12142
  if (!signal?.aborted) {
11936
12143
  return;
@@ -12000,8 +12207,11 @@ var ConnectionManager = class {
12000
12207
  await connection.disconnect();
12001
12208
  }
12002
12209
  }
12003
- async transaction(callback, connectionName = this.defaultConnection) {
12004
- return this.connection(connectionName).transaction(callback);
12210
+ async transaction(callback, connectionName = this.defaultConnection, options) {
12211
+ return this.connection(connectionName).transaction(callback, options);
12212
+ }
12213
+ async writeTransaction(callback, connectionName = this.defaultConnection, options) {
12214
+ return this.connection(connectionName).writeTransaction(callback, options);
12005
12215
  }
12006
12216
  };
12007
12217
  function createConnectionManager(options) {
@@ -12024,6 +12234,7 @@ function isModuleNotFoundError(error) {
12024
12234
  function dynamicImport(specifier) {
12025
12235
  return import(
12026
12236
  /* webpackIgnore: true */
12237
+ /* @vite-ignore */
12027
12238
  specifier
12028
12239
  );
12029
12240
  }
@@ -12074,6 +12285,16 @@ var LazyDriverAdapter = class {
12074
12285
  isConnected() {
12075
12286
  return this.adapter?.isConnected() ?? this.connected;
12076
12287
  }
12288
+ async ensureDatabaseExists() {
12289
+ const adapter = await this.resolveAdapter();
12290
+ if (typeof adapter.ensureDatabaseExists !== "function") {
12291
+ return;
12292
+ }
12293
+ await adapter.ensureDatabaseExists();
12294
+ }
12295
+ isDatabaseMissingError(error) {
12296
+ return this.adapter?.isDatabaseMissingError?.(error) ?? false;
12297
+ }
12077
12298
  async runWithTransactionScope(callback) {
12078
12299
  const adapter = await this.resolveAdapter();
12079
12300
  if (typeof adapter.runWithTransactionScope !== "function") {
@@ -14491,6 +14712,7 @@ export {
14491
14712
  belongsToMany,
14492
14713
  binaryCast,
14493
14714
  clearGeneratedTables,
14715
+ collectDatabaseQueryDependencies,
14494
14716
  column,
14495
14717
  compileDialectDefaultLiteral,
14496
14718
  configureDB,
@@ -14573,8 +14795,10 @@ export {
14573
14795
  ofMany,
14574
14796
  oldestMorphOne,
14575
14797
  oldestOfMany,
14798
+ onDatabaseDependencyInvalidated,
14576
14799
  parseDatabaseDriver,
14577
14800
  queryCacheInternals,
14801
+ recordDatabaseQueryDependencies,
14578
14802
  redactBindings,
14579
14803
  redactSql,
14580
14804
  registerGeneratedTables,
@@ -14585,6 +14809,7 @@ export {
14585
14809
  renderGeneratedSchemaPlaceholder,
14586
14810
  renderGeneratedSchemaRuntimeModule,
14587
14811
  resetDB,
14812
+ resetDatabaseDependencyInvalidationListeners,
14588
14813
  resetDatabaseQueryCacheBridge,
14589
14814
  resetGlobalModelRegistry,
14590
14815
  resetMorphRegistry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/db",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "Holo-JS Framework - portable database, ORM, migrations, factories, and seeders",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,9 +28,9 @@
28
28
  "uuid": "^12.0.0"
29
29
  },
30
30
  "peerDependencies": {
31
- "@holo-js/db-mysql": "^0.1.9",
32
- "@holo-js/db-postgres": "^0.1.9",
33
- "@holo-js/db-sqlite": "^0.1.9"
31
+ "@holo-js/db-mysql": "^0.2.0",
32
+ "@holo-js/db-postgres": "^0.2.0",
33
+ "@holo-js/db-sqlite": "^0.2.0"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@holo-js/db-mysql": {
@@ -44,9 +44,9 @@
44
44
  }
45
45
  },
46
46
  "devDependencies": {
47
- "@holo-js/db-mysql": "^0.1.9",
48
- "@holo-js/db-postgres": "^0.1.9",
49
- "@holo-js/db-sqlite": "^0.1.9",
47
+ "@holo-js/db-mysql": "^0.2.0",
48
+ "@holo-js/db-postgres": "^0.2.0",
49
+ "@holo-js/db-sqlite": "^0.2.0",
50
50
  "tsup": "^8.3.5",
51
51
  "typescript": "^5.7.2"
52
52
  }