@stacksjs/orm 0.70.23 → 0.70.31

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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Per-tick batched load against a Stacks model. The model object is the
3
+ * batch identity — one queue per `model`. Ids posted in the same
4
+ * microtask are merged into a single `findMany([...])` call.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { batchLoad } from '@stacksjs/orm'
9
+ * import User from '~/app/Models/User'
10
+ *
11
+ * // Without batching: 100 SELECTs
12
+ * for (const id of orderUserIds) await User.find(id)
13
+ *
14
+ * // With batching: 1 SELECT (`WHERE id IN (1, 2, … 100)`)
15
+ * await Promise.all(orderUserIds.map(id => batchLoad(User, id)))
16
+ * ```
17
+ */
18
+ // eslint-disable-next-line pickier/no-unused-vars
19
+ export declare function batchLoad<T extends { findMany?: (ids: any[]) => Promise<any[]>, find?: (id: any) => Promise<any> }, K = number | string>(model: T, key: K): Promise<unknown>;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Database access re-export
3
+ *
4
+ * This module re-exports the db instance from @stacksjs/database
5
+ * for convenience within the ORM package.
6
+ */
7
+ export { db } from '@stacksjs/database';
@@ -0,0 +1,116 @@
1
+ import type { InferRelationNames } from 'bun-query-builder';
2
+ import { createBillableMethods } from './traits/billable';
3
+ import { createCategorizableMethods } from './traits/categorizable';
4
+ import { createCommentableMethods } from './traits/commentable';
5
+ import { createLikeableMethods } from './traits/likeable';
6
+ import { createSoftDeleteMethods } from './traits/soft-deletes';
7
+ import { createTaggableMethods } from './traits/taggable';
8
+ import { createTwoFactorMethods } from './traits/two-factor';
9
+ // Re-export types from bun-query-builder for convenience
10
+ export type { ModelDefinition, InferRelationNames, ModelAttributes, InferModelAttributes, SystemFields, ColumnName, AttributeKeys, FillableKeys, HiddenKeys, ModelInstance, ModelQueryBuilder } from 'bun-query-builder';
11
+ /**
12
+ * Stacks-enhanced model definition.
13
+ *
14
+ * Wraps bun-query-builder's `createModel()` with:
15
+ * - Event dispatching via `traits.observe`
16
+ * - Trait methods (billable, taggable, categorizable, commentable, likeable, 2FA)
17
+ * - Full backward compatibility with generators (migration, routes, dashboard)
18
+ *
19
+ * ### Relationships
20
+ * Each entry in `belongsTo`, `hasMany`, `hasOne`, `belongsToMany`,
21
+ * `hasOneThrough`, and `hasManyThrough` declares a typed relation
22
+ * usable via `.with('relationName')`:
23
+ *
24
+ * ```ts
25
+ * defineModel({
26
+ * belongsTo: ['Author'], // ↪ post.author
27
+ * hasMany: ['Comment'], // ↪ post.comments (lowercase + pluralized)
28
+ * hasOne: ['Cover'], // ↪ post.cover
29
+ * })
30
+ * ```
31
+ *
32
+ * After eager loading the related row(s) are reachable as a property
33
+ * on the instance — `(await Post.with('author').first()).author`.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { defineModel } from '@stacksjs/orm'
38
+ * import { schema } from '@stacksjs/validation'
39
+ *
40
+ * export default defineModel({
41
+ * name: 'Post',
42
+ * table: 'posts',
43
+ * attributes: {
44
+ * title: { type: 'string', fillable: true, validation: { rule: schema.string() } },
45
+ * views: { type: 'number', fillable: true, validation: { rule: schema.number() } },
46
+ * },
47
+ * belongsTo: ['Author'],
48
+ * hasMany: ['Tag', 'Category', 'Comment'],
49
+ * traits: { useTimestamps: true, useUuid: true },
50
+ * } as const)
51
+ *
52
+ * // Result: Post.where('title', 'test') — 'title' narrowed to valid columns
53
+ * // Result: Post.with('author') — 'author' narrowed to valid relations
54
+ * ```
55
+ */
56
+ export declare function defineModel<const TDef extends ModelDefinition>(definition: TDef): void;
57
+ /**
58
+ * Normalize a ModelInstance (or array of them, or already-plain row) into
59
+ * a serialization-ready plain object.
60
+ *
61
+ * Resolves the three shapes a Stacks model query can return:
62
+ * - ModelInstance (find/first/get) → calls toJSON() → strips `hidden` attrs
63
+ * - Bare attribute bag with `_attributes` → returns _attributes as-is
64
+ * - Plain row (already normalized) → returns it unchanged
65
+ *
66
+ * Use `toAttrs(inst)` in actions instead of `inst._attributes ?? inst` —
67
+ * the latter pattern silently leaks `hidden: true` fields (e.g. license_plate,
68
+ * vin, password hashes) into responses.
69
+ */
70
+ export declare function toAttrs<T = any>(value: any): T;
71
+ /**
72
+ * Custom caster interface for user-defined attribute transformations.
73
+ */
74
+ export declare interface CasterInterface {
75
+ get(value: unknown): unknown
76
+ set(value: unknown): unknown
77
+ }
78
+ declare interface StacksModelDefinition {
79
+ name: string
80
+ table: string
81
+ primaryKey?: string
82
+ autoIncrement?: boolean
83
+ traits?: Record<string, unknown>
84
+ indexes?: Array<{ name: string, columns: string[] }>
85
+ casts?: Record<string, CastType | CasterInterface>
86
+ attributes: {
87
+ [key: string]: {
88
+ factory?: (faker: any) => any
89
+ [key: string]: any
90
+ }
91
+ }
92
+ [key: string]: any
93
+ }
94
+ export declare interface TraitMethods {
95
+ _taggable?: ReturnType<typeof createTaggableMethods>
96
+ _categorizable?: ReturnType<typeof createCategorizableMethods>
97
+ _commentable?: ReturnType<typeof createCommentableMethods>
98
+ _billable?: ReturnType<typeof createBillableMethods>
99
+ _likeable?: ReturnType<typeof createLikeableMethods>
100
+ _twoFactor?: ReturnType<typeof createTwoFactorMethods>
101
+ _softDeletes?: ReturnType<typeof createSoftDeleteMethods>
102
+ }
103
+ /**
104
+ * Built-in cast types for model attributes.
105
+ */
106
+ export type CastType = 'string' | 'number' | 'boolean' | 'json' | 'datetime' | 'date' | 'array' | 'integer' | 'float';
107
+ declare type ModelDefinition = StacksModelDefinition;
108
+ /**
109
+ * Thrown by `Model.findOrFail(id)` (and other strict lookups) when no row matches.
110
+ * Callers can `instanceof` against this to distinguish "missing" from other errors.
111
+ */
112
+ export declare class ModelNotFoundError extends Error {
113
+ readonly model: string;
114
+ readonly id: number | string | undefined;
115
+ constructor(model: string, id?: number | string);
116
+ }
@@ -0,0 +1,157 @@
1
+ import '@stacksjs/validation';
2
+ export type { PrunableOptions } from './utils/prunable';
3
+ export type { AuditHelpers } from './traits/audit';
4
+ // Re-export soft-delete option types so user code can `satisfies SoftDeleteOptions`.
5
+ export type { SoftDeleteOptions, SoftDeleteHelpers } from './traits/soft-deletes';
6
+ // Re-export type utilities from bun-query-builder so consumers can infer
7
+ // model types directly from defineModel() definitions
8
+ export type {
9
+ InferAttributes,
10
+ InferPrimaryKey,
11
+ InferRelationNames,
12
+ InferTableName,
13
+ ModelDefinition,
14
+ } from 'bun-query-builder';
15
+ export declare const User: unknown;
16
+ // Same lazy-export pattern for the two queue framework models. The CLI
17
+ // commands `buddy queue:status`, `queue:failed`, `queue:flush`,
18
+ // `queue:inspect`, `queue:monitor`, `queue:clear` import them as
19
+ // `import { Job, FailedJob } from '@stacksjs/orm'`. Prefer the userland
20
+ // publication (`app/Models/Job.ts`, dropped in by `buddy publish:model
21
+ // Job`) so projects that customize the queue model — renamed columns,
22
+ // extra observers, custom traits — see their version.
23
+ export declare const Job: unknown;
24
+ export declare const FailedJob: unknown;
25
+ export declare const Activity: unknown;
26
+ export declare const Author: unknown;
27
+ export declare const Campaign: unknown;
28
+ export declare const Cart: unknown;
29
+ export declare const CartItem: unknown;
30
+ export declare const Category: unknown;
31
+ export declare const Comment: unknown;
32
+ export declare const Coupon: unknown;
33
+ export declare const Customer: unknown;
34
+ export declare const DeliveryRoute: unknown;
35
+ export declare const Deployment: unknown;
36
+ export declare const DigitalDelivery: unknown;
37
+ export declare const Driver: unknown;
38
+ export declare const CampaignSend: unknown;
39
+ export declare const EmailList: unknown;
40
+ export declare const EmailListSubscriber: unknown;
41
+ export declare const ErrorModel: unknown;
42
+ export declare const GiftCard: unknown;
43
+ export declare const LicenseKey: unknown;
44
+ export declare const Log: unknown;
45
+ export declare const LoyaltyPoint: unknown;
46
+ export declare const LoyaltyReward: unknown;
47
+ export declare const Manufacturer: unknown;
48
+ export declare const Notification: unknown;
49
+ export declare const Order: unknown;
50
+ export declare const OrderItem: unknown;
51
+ export declare const Page: unknown;
52
+ export declare const Payment: unknown;
53
+ export declare const PaymentMethod: unknown;
54
+ export declare const PaymentProduct: unknown;
55
+ export declare const PaymentTransaction: unknown;
56
+ export declare const Post: unknown;
57
+ export declare const PrintDevice: unknown;
58
+ export declare const Product: unknown;
59
+ export declare const ProductUnit: unknown;
60
+ export declare const ProductVariant: unknown;
61
+ export declare const Receipt: unknown;
62
+ export declare const Release: unknown;
63
+ export declare const Request: unknown;
64
+ export declare const Review: unknown;
65
+ export declare const ShippingMethod: unknown;
66
+ export declare const ShippingRate: unknown;
67
+ export declare const ShippingZone: unknown;
68
+ export declare const SocialPost: unknown;
69
+ export declare const Subscriber: unknown;
70
+ export declare const SubscriberEmail: unknown;
71
+ export declare const Subscription: unknown;
72
+ export declare const Tag: unknown;
73
+ export declare const TaxRate: unknown;
74
+ export declare const Team: unknown;
75
+ export declare const Transaction: unknown;
76
+ export declare const WaitlistProduct: unknown;
77
+ export declare const WaitlistRestaurant: unknown;
78
+ export declare const Websocket: unknown;
79
+ /** Row type for the polymorphic categories table (categorizable trait). */
80
+ export declare interface CategorizableTable {
81
+ id?: number
82
+ name: string
83
+ slug: string
84
+ description?: string
85
+ is_active: boolean
86
+ categorizable_type: string
87
+ created_at?: string
88
+ updated_at?: string
89
+ }
90
+ /** Row type for the category-model pivot table (categorizable trait). */
91
+ export declare interface CategorizableModelsTable {
92
+ id?: number
93
+ category_id: number
94
+ categorizable_type: string
95
+ categorizable_id: number
96
+ created_at?: string
97
+ updated_at?: string
98
+ }
99
+ /** Row type for the polymorphic comments table (commentable trait). */
100
+ export declare interface CommentablesTable {
101
+ id?: number
102
+ title: string
103
+ body: string
104
+ status: string
105
+ approved_at: number | null
106
+ rejected_at: number | null
107
+ commentables_id: number
108
+ commentables_type: string
109
+ user_id: number | null
110
+ created_at?: string
111
+ updated_at?: string | null
112
+ }
113
+ /** Row type for the polymorphic tags table (taggable trait). */
114
+ export declare interface TaggableTable {
115
+ id?: number
116
+ name: string
117
+ slug: string
118
+ description?: string
119
+ is_active: boolean
120
+ taggable_type: string
121
+ created_at?: string
122
+ updated_at?: string
123
+ }
124
+ // The following type utilities are referenced by the framework but are not
125
+ // yet exported by the installed `bun-query-builder` version. Until upstream
126
+ // catches up we ship structural stubs so consumer code still type-checks.
127
+ // These intentionally fall back to `any` to avoid spurious narrowing errors;
128
+ // once `bun-query-builder` exports the real shapes, remove these stubs.
129
+ export type InferFillableAttributes<_M> = any;
130
+ export type InferNumericColumns<_M> = string;
131
+ export type InferColumnNames<_M> = string;
132
+ export type ModelRow<_M> = any;
133
+ export type ModelRowLoose<_M> = any;
134
+ export type ModelCreateData<_M> = any;
135
+ export type ModelCreateDataLoose<_M> = any;
136
+ /** User model row type — inferred from the User model definition. */
137
+ export type UserModel = ModelRowLoose<unknown>;
138
+ /** Data required to create a new User — inferred fillable attributes. */
139
+ export type NewUser = ModelCreateDataLoose<unknown>;
140
+ export * from './utils/prunable';
141
+ export {
142
+ collectEncryptedAttributes,
143
+ decryptValue,
144
+ encryptValue,
145
+ isEncrypted,
146
+ } from './utils/encrypted';
147
+ // Audit trait public API: setAuditUser is the queue/cron escape hatch for
148
+ // attributing audit rows to a user when there's no current HTTP request.
149
+ export { setAuditUser, createAuditMethods } from './traits/audit';
150
+ export * from './batch-loader';
151
+ export * from './db';
152
+ export * from './subquery';
153
+ export * from './transaction';
154
+ export * from './model-types';
155
+ export * from './types';
156
+ export * from './utils';
157
+ export * from './define-model';
@@ -0,0 +1,40 @@
1
+ import type { InferModelAttributes, ModelAttributes, ModelDefinition } from 'bun-query-builder';
2
+ /**
3
+ * Extract the raw ModelDefinition from a defineModel() return value.
4
+ * Uses the getDefinition() accessor that defineModel() provides.
5
+ */
6
+ export type Def<T> = T extends { getDefinition: () => infer D extends ModelDefinition } ? D : never;
7
+ /**
8
+ * Extract foreign key columns from belongsTo relations.
9
+ * e.g., belongsTo: ['Customer', 'Coupon'] → { customer_id: number, coupon_id: number }
10
+ */
11
+ export type BelongsToForeignKeys<TDef> = TDef extends { readonly belongsTo: readonly (infer R extends string)[] }
12
+ ? { [K in R as `${Lowercase<K>}_id`]: number }
13
+ : {}
14
+ /**
15
+ * Full database row type: model attributes + system fields (id, uuid, timestamps) + FK columns.
16
+ *
17
+ * @example
18
+ * import type { ModelRow } from '@stacksjs/orm'
19
+ * import type Post from '../models/Post'
20
+ * type PostJsonResponse = ModelRow<Post>
21
+ */
22
+ export type ModelRow<T> = ModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>;
23
+ /**
24
+ * Insertable data type: model attributes + FK columns, all optional.
25
+ *
26
+ * @example
27
+ * import type { NewModelData } from '@stacksjs/orm'
28
+ * import type Post from '../models/Post'
29
+ * type NewPost = NewModelData<Post>
30
+ */
31
+ export type NewModelData<T> = Partial<InferModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>>;
32
+ /**
33
+ * Updateable data type: model attributes + FK columns, all optional.
34
+ *
35
+ * @example
36
+ * import type { UpdateModelData } from '@stacksjs/orm'
37
+ * import type Post from '../models/Post'
38
+ * type PostUpdate = UpdateModelData<Post>
39
+ */
40
+ export type UpdateModelData<T> = Partial<InferModelAttributes<Def<T>> & BelongsToForeignKeys<Def<T>>>;
@@ -0,0 +1,22 @@
1
+ declare interface WhereCondition<T, V = any> {
2
+ type: 'and' | 'or'
3
+ method: 'where' | 'whereIn' | 'whereNull' | 'whereNotNull' | 'whereBetween' | 'whereExists'
4
+ column: keyof T
5
+ operator?: Operator
6
+ value?: V
7
+ values?: V[] | [V, V]
8
+ range?: [V, V]
9
+ callback?: (query: SubqueryBuilder<T>) => void
10
+ }
11
+ export type Operator = '=' | '<' | '>' | '<=' | '>=' | '<>' | '!=' | 'like' | 'not like' | 'in' | 'not in' | 'between' | 'not between' | 'is' | 'is not';
12
+ export declare class SubqueryBuilder<T> {
13
+ where<V>(column: keyof T, ...args: [V] | [Operator, V]): void;
14
+ orWhere<V>(column: keyof T, ...args: [V] | [Operator, V]): void;
15
+ whereIn<V>(column: keyof T, values: V[]): void;
16
+ whereNotIn<V>(column: keyof T, values: V[]): void;
17
+ whereNull(column: keyof T): void;
18
+ whereNotNull(column: keyof T): void;
19
+ whereBetween<V>(column: keyof T, range: [V, V]): void;
20
+ whereExists(callback: (query: SubqueryBuilder<T>) => void): void;
21
+ getConditions(): WhereCondition<T>[];
22
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Override the user id attached to subsequent audit rows. Useful in queue
3
+ * workers, scheduled jobs, and CLI commands where there is no current HTTP
4
+ * request to extract the user from. Pass `null` to clear the override and
5
+ * fall back to the request-derived id.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { setAuditUser } from '@stacksjs/orm'
10
+ *
11
+ * // In a queue job that's running on behalf of user 42:
12
+ * setAuditUser(42)
13
+ * try { await processOrder(orderId) } finally { setAuditUser(null) }
14
+ * ```
15
+ */
16
+ export declare function setAuditUser(id: number | string | null): void;
17
+ /**
18
+ * Build the public-facing audit helper(s). Right now that's just
19
+ * `audits(id)` — the rest is wired up via `applyAudit()` which intercepts
20
+ * the model's write methods.
21
+ */
22
+ export declare function createAuditMethods(modelName: string): AuditHelpers;
23
+ /**
24
+ * Wire the audit trait into a model's static surface. Wraps `create`,
25
+ * `update`, and `delete` so each one writes a `model_audits` row after a
26
+ * successful operation. Idempotent against the proxy machinery — relies on
27
+ * the same wrapping pattern used by `applySoftDeletes`.
28
+ *
29
+ * Must run AFTER the static-helpers / cast / soft-delete wrappers have
30
+ * installed their own versions of `create` / `update` / `delete`, so that
31
+ * we wrap the final composed function rather than something that gets
32
+ * shadowed later.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Inside defineModel():
37
+ * if (definition.traits?.useAudit) {
38
+ * applyAudit(baseModel, definition)
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function applyAudit(baseModel: Record<string, unknown>, modelName: string, primaryKey?: string): void;
43
+ export declare interface AuditHelpers {
44
+ audits: (id: number | string) => Promise<Array<Record<string, unknown>>>
45
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Build the runtime methods backing the soft-delete trait. The trait is
3
+ * applied via `applySoftDeletes()` in `define-model.ts`.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * const helpers = createSoftDeleteMethods(model, 'id')
8
+ * await helpers.softDelete(42)
9
+ * ```
10
+ */
11
+ export declare function createSoftDeleteMethods(model: SoftDeleteCapableModel, primaryKey?: string): SoftDeleteHelpers;
12
+ /**
13
+ * Convert `traits.useSoftDeletes` into a normalized options object. The
14
+ * trait accepts either `true` (legacy) or `{ cascade: [...] }` (new), so
15
+ * downstream code should always go through this resolver.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * resolveSoftDeleteOptions(true) // → {}
20
+ * resolveSoftDeleteOptions({ cascade: ['posts'] }) // → { cascade: ['posts'] }
21
+ * ```
22
+ */
23
+ export declare function resolveSoftDeleteOptions(value: unknown): SoftDeleteOptions;
24
+ /**
25
+ * Run cascade soft-delete (or restore) for every relation listed in
26
+ * `options.cascade`. Called by `define-model.ts` immediately after the
27
+ * parent's own soft-delete or restore succeeds.
28
+ *
29
+ * IMPORTANT: cascade is fire-and-forget on the audit/observer side — this
30
+ * function awaits each child to ensure ordering (parent before children
31
+ * for delete, vice versa for restore) but does not propagate child
32
+ * failures up to the caller. The parent operation has already committed.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * await cascadeSoftDelete(parentDefinition, options, parentId, 'softDelete')
37
+ * ```
38
+ */
39
+ export declare function cascadeSoftDelete(parentDefinition: { name: string, hasMany?: ReadonlyArray<string>, hasOne?: ReadonlyArray<string> }, options: SoftDeleteOptions, parentId: number | string, action: 'softDelete' | 'restore'): Promise<void>;
40
+ declare interface SoftDeleteCapableModel {
41
+ where: (...args: unknown[]) => any
42
+ query?: () => any
43
+ delete?: (...args: unknown[]) => unknown
44
+ }
45
+ /**
46
+ * Object-form options for `traits.useSoftDeletes`.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * traits: {
51
+ * useSoftDeletes: {
52
+ * // Names of relations declared on this model (hasMany / hasOne)
53
+ * // that should be soft-deleted alongside the parent.
54
+ * cascade: ['posts', 'comments'],
55
+ * },
56
+ * }
57
+ * ```
58
+ */
59
+ export declare interface SoftDeleteOptions {
60
+ cascade?: ReadonlyArray<string>
61
+ }
62
+ export declare interface SoftDeleteHelpers {
63
+ softDelete: (id: number | string) => Promise<boolean>
64
+ restore: (id: number | string) => Promise<boolean>
65
+ forceDelete: (id: number | string) => Promise<boolean>
66
+ withTrashed: () => any
67
+ onlyTrashed: () => any
68
+ }
@@ -0,0 +1,67 @@
1
+ import { db } from '@stacksjs/database';
2
+ /**
3
+ * Execute a callback within a database transaction.
4
+ *
5
+ * The transaction will automatically commit if the callback succeeds,
6
+ * or rollback if an error is thrown.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * await transaction(async (tx) => {
11
+ * await tx.insertInto('users').values({ name: 'Alice' }).execute()
12
+ * await tx.insertInto('profiles').values({ user_id: 1 }).execute()
13
+ * })
14
+ * ```
15
+ */
16
+ export declare function transaction<T>(callback: (tx: TransactionHandle) => Promise<T>, options?: TransactionOptions): Promise<T>;
17
+ /**
18
+ * Legacy alias for transaction()
19
+ * @deprecated Use transaction() instead
20
+ */
21
+ export declare function transactionBuilder(callback: () => Promise<void>): Promise<void>;
22
+ /**
23
+ * Create a savepoint within a transaction for nested rollback support.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * await transaction(async (tx) => {
28
+ * await tx.insertInto('users').values({ name: 'Bob' }).execute()
29
+ *
30
+ * await savepoint(async (sp) => {
31
+ * await sp.insertInto('logs').values({ action: 'created' }).execute()
32
+ * // If this fails, only this savepoint rolls back
33
+ * })
34
+ * })
35
+ * ```
36
+ */
37
+ export declare function savepoint<T>(callback: (sp: TransactionHandle) => Promise<T>): Promise<T>;
38
+ /**
39
+ * Wrap a function to automatically run within a transaction when called.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const createUserWithProfile = transactional(async (tx, name: string, bio: string) => {
44
+ * const user = await tx.insertInto('users').values({ name }).returningAll().executeTakeFirst()
45
+ * await tx.insertInto('profiles').values({ user_id: user.id, bio }).execute()
46
+ * return user
47
+ * })
48
+ *
49
+ * // Usage - automatically wrapped in transaction
50
+ * const user = await createUserWithProfile('Alice', 'Hello world')
51
+ * ```
52
+ */
53
+ export declare function transactional<TArgs extends any[], R>(fn: (tx: TransactionHandle, ...args: TArgs) => Promise<R>, options?: TransactionOptions): (...args: TArgs) => Promise<R>;
54
+ export declare interface TransactionOptions {
55
+ retries?: number
56
+ isolation?: 'read committed' | 'repeatable read' | 'serializable'
57
+ readOnly?: boolean
58
+ onRollback?: (error: any) => void
59
+ afterRollback?: () => void
60
+ }
61
+ /**
62
+ * Transaction handle. Aliases the project's `db` type so callers get
63
+ * the same fluent query API inside the callback as outside, without
64
+ * the previous untyped `(tx: any)` signature that erased intellisense
65
+ * and let typo'd column names slip through to runtime.
66
+ */
67
+ export type TransactionHandle = typeof db;
@@ -0,0 +1,55 @@
1
+ import type { Operator } from './subquery';
2
+ export declare interface OrmDriver<T = unknown> {
3
+ find: (id: number) => Promise<T | undefined>
4
+ create: (data: Partial<T>) => Promise<T>
5
+ update: (id: number, data: Partial<T>) => Promise<T | undefined>
6
+ delete: (id: number) => Promise<boolean>
7
+ all: () => Promise<T[]>
8
+ where: (column: string, value: unknown) => Promise<T[]>
9
+ }
10
+ export declare interface SelectedQuery<TTable, TJson, K extends string> {
11
+ where<V = string>(column: keyof TTable, ...args: [V] | [Operator, V]): SelectedQuery<TTable, TJson, K>
12
+ orWhere(...conditions: [keyof TTable, any][]): SelectedQuery<TTable, TJson, K>
13
+ whereIn<V = number>(column: keyof TTable, values: V[]): SelectedQuery<TTable, TJson, K>
14
+ whereNotIn<V = number>(column: keyof TTable, values: V[]): SelectedQuery<TTable, TJson, K>
15
+ whereBetween<V = number>(column: keyof TTable, range: [V, V]): SelectedQuery<TTable, TJson, K>
16
+ whereRef(column: keyof TTable, ...args: string[]): SelectedQuery<TTable, TJson, K>
17
+ when(condition: boolean, callback: (query: SelectedQuery<TTable, TJson, K>) => SelectedQuery<TTable, TJson, K>): SelectedQuery<TTable, TJson, K>
18
+ whereNull(column: keyof TTable): SelectedQuery<TTable, TJson, K>
19
+ whereNotNull(column: keyof TTable): SelectedQuery<TTable, TJson, K>
20
+ whereLike(column: keyof TTable, value: string): SelectedQuery<TTable, TJson, K>
21
+ orderBy(column: keyof TTable, order: 'asc' | 'desc'): SelectedQuery<TTable, TJson, K>
22
+ orderByAsc(column: keyof TTable): SelectedQuery<TTable, TJson, K>
23
+ orderByDesc(column: keyof TTable): SelectedQuery<TTable, TJson, K>
24
+ groupBy(column: keyof TTable): SelectedQuery<TTable, TJson, K>
25
+ having<V = string>(column: keyof TTable, operator: Operator, value: V): SelectedQuery<TTable, TJson, K>
26
+ inRandomOrder(): SelectedQuery<TTable, TJson, K>
27
+ whereColumn(first: keyof TTable, operator: Operator, second: keyof TTable): SelectedQuery<TTable, TJson, K>
28
+ skip(count: number): SelectedQuery<TTable, TJson, K>
29
+ take(count: number): SelectedQuery<TTable, TJson, K>
30
+ distinct(column: keyof TJson): SelectedQuery<TTable, TJson, K>
31
+ join(table: string, firstCol: string, secondCol: string): SelectedQuery<TTable, TJson, K>
32
+ first(): Promise<SelectedResult<TJson, K> | undefined>
33
+ last(): Promise<SelectedResult<TJson, K> | undefined>
34
+ firstOrFail(): Promise<SelectedResult<TJson, K>>
35
+ find(id: number): Promise<SelectedResult<TJson, K> | undefined>
36
+ findOrFail(id: number): Promise<SelectedResult<TJson, K>>
37
+ findMany(ids: number[]): Promise<SelectedResult<TJson, K>[]>
38
+ all(): Promise<SelectedResult<TJson, K>[]>
39
+ get(): Promise<SelectedResult<TJson, K>[]>
40
+ latest(column?: keyof TTable): Promise<SelectedResult<TJson, K> | undefined>
41
+ oldest(column?: keyof TTable): Promise<SelectedResult<TJson, K> | undefined>
42
+ paginate(options?: { limit?: number, offset?: number, page?: number }): Promise<{
43
+ data: SelectedResult<TJson, K>[]
44
+ paging: { total_records: number, page: number, total_pages: number }
45
+ next_cursor: number | null
46
+ }>
47
+ chunk(size: number, callback: (models: SelectedResult<TJson, K>[]) => Promise<void>): Promise<void>
48
+ pluck<PK extends Extract<K | 'id', keyof TJson>>(field: PK): Promise<TJson[PK][]>
49
+ max(field: keyof TTable): Promise<number>
50
+ min(field: keyof TTable): Promise<number>
51
+ avg(field: keyof TTable): Promise<number>
52
+ sum(field: keyof TTable): Promise<number>
53
+ count(): Promise<number>
54
+ }
55
+ export type SelectedResult<TJson, K extends string> = Pick<TJson, Extract<K | 'id', keyof TJson>> & { id: number }