bun-query-builder 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.d.ts CHANGED
@@ -62,11 +62,11 @@ export declare const browserAuth: {
62
62
  /**
63
63
  * Login and store token
64
64
  */
65
- async login: (credentials: { email: string, password: string }) => Promise<;
65
+ async login: (credentials: { email: string, password: string }) => Promise<BrowserAuthResponse>;
66
66
  /**
67
67
  * Register a new user
68
68
  */
69
- async register: (data: { name: string, email: string, password: string }) => Promise<;
69
+ async register: (data: { name: string, email: string, password: string }) => Promise<BrowserAuthResponse>;
70
70
  /**
71
71
  * Logout and clear token
72
72
  */
@@ -159,6 +159,18 @@ declare interface QueryState {
159
159
  selectColumns: string[]
160
160
  withRelations: string[]
161
161
  }
162
+ /**
163
+ * Response shape returned by `browserAuth.login` / `browserAuth.register`.
164
+ * Lifted to a named type so the generated `.d.ts` doesn't carry a nested
165
+ * inline object literal in the return position — bun-plugin-dtsx has a
166
+ * bug where `Promise<{ ... }>` in that position emits as `Promise<;`,
167
+ * breaking downstream typecheck for any consumer that imports from
168
+ * `bun-query-builder/browser`.
169
+ */
170
+ export declare interface BrowserAuthResponse {
171
+ user: Record<string, unknown>
172
+ token: string
173
+ }
162
174
  // Primitive type mappings
163
175
  declare type PrimitiveTypeMap = {
164
176
  string: string
@@ -247,7 +259,7 @@ declare type BrowserRelationNames<TDef> = | BrowserBelongsToNames<TDef>
247
259
  | BrowserHasOneThroughNames<TDef>
248
260
  | BrowserHasManyThroughNames<TDef>;
249
261
  // Types for query building
250
- export type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'in' | 'not in' | 'is' | 'is not';
262
+ export type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'not like' | 'in' | 'not in' | 'is' | 'is not';
251
263
  /**
252
264
  * Custom error class for browser query errors
253
265
  */
package/dist/client.d.ts CHANGED
@@ -2,6 +2,7 @@ import { config } from './config';
2
2
  import { resetConnection } from './db';
3
3
  import type { DatabaseSchema } from './schema';
4
4
  import type { SchemaMeta } from './meta';
5
+ // eslint-disable-next-line pickier/no-unused-vars
5
6
  export declare function createQueryBuilder<DB extends DatabaseSchema<any>>(state?: Partial<InternalState>): QueryBuilder<DB>;
6
7
  /**
7
8
  * # `clearQueryCache()`
@@ -119,6 +120,11 @@ export declare interface BaseSelectQueryBuilder<DB extends DatabaseSchema<any>,
119
120
  whereJsonLength?: (path: string, opOrLen: WhereOperator | number, len?: number) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
120
121
  with?: (...relations: string[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
121
122
  withPivot?: (relation: string, ...columns: string[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
123
+ wherePivot?: (relation: string, column: string, opOrValue: any, value?: any) => SelectQueryBuilder<DB, TTable, TSelected, any>
124
+ wherePivotIn?: (relation: string, column: string, values: any[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
125
+ wherePivotNotIn?: (relation: string, column: string, values: any[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
126
+ wherePivotNull?: (relation: string, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
127
+ wherePivotNotNull?: (relation: string, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
122
128
  applyPivotColumns?: () => SelectQueryBuilder<DB, TTable, TSelected, any>
123
129
  lockForUpdate: () => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
124
130
  sharedLock: () => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
package/dist/db.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { SQL } from 'bun';
3
+ /**
4
+ * Returns a Bun SQL instance configured for the current dialect and database settings.
5
+ * For SQLite, uses bun:sqlite directly for better compiled binary support.
6
+ * Handles connection errors gracefully by falling back to in-memory SQLite.
7
+ */
8
+ export declare function getBunSql(): SQL;
9
+ export declare function getOrCreateBunSql(forceNew?: boolean): SQL;
10
+ /**
11
+ * Resets the cached database connection.
12
+ * Call this after changing config via setConfig() to ensure the new config is used.
13
+ */
14
+ export declare function resetConnection(): void;
15
+ // Wrapper that catches "Connection closed" errors and retries with a fresh connection
16
+ export declare function withFreshConnection<T>(fn: (sql: SQL) => Promise<T>): Promise<T>;
17
+ // Export a lazy proxy - no connection is made until first use
18
+ export declare const bunSql: SQL;
19
+ /**
20
+ * SQLite wrapper that provides a SQL-like tagged template literal interface
21
+ * using bun:sqlite's Database class for better compiled binary support.
22
+ */
23
+ declare class SQLiteWrapper {
24
+ constructor(filename: string);
25
+ query(sql: string, params?: any[]): any[];
26
+ run(sql: string, params?: any[]): any;
27
+ close(): void;
28
+ get database(): Database;
29
+ }
30
+ // Also export the SQL class for advanced usage
31
+ export { SQL } from 'bun';
@@ -9,7 +9,6 @@ export declare function createSingleTableManager(config: SingleTableConfig): Sin
9
9
  */
10
10
  export declare function createRepository<T extends Record<string, any>>(manager: SingleTableManager, entityName: string, options: DynamoDBQueryBuilderOptions): SingleTableRepository<T>;
11
11
  /**
12
- * Common single table design patterns
13
12
  * @defaultValue
14
13
  * ```ts
15
14
  * {
@@ -17,11 +16,11 @@ export declare function createRepository<T extends Record<string, any>>(manager:
17
16
  * oneToMany: (parentEntity: string,
18
17
  * childEntity: string,
19
18
  * parentIdField?: string,
20
- * childIdField?: string,) => { parent: SingleTableEntity, child: SingleTableEntity },
19
+ * childIdField?: string,) => OneToManyPattern,
21
20
  * manyToMany: (entityName: string,
22
21
  * relationName: string,
23
22
  * idField?: string,
24
- * relatedIdField?: string,) => { entity: SingleTableEntity, relation: SingleTableEntity },
23
+ * relatedIdField?: string,) => ManyToManyPattern,
25
24
  * hierarchical: (entityName: string, rootIdField?: string, pathField?: string) => SingleTableEntity
26
25
  * }
27
26
  * ```
@@ -38,20 +37,14 @@ export declare const SingleTablePatterns: {
38
37
  * Parent: PK=PARENT#<parentId>, SK=METADATA
39
38
  * Child: PK=PARENT#<parentId>, SK=CHILD#<childId>
40
39
  */
41
- oneToMany: (parentEntity: string,
42
- childEntity: string,
43
- parentIdField?: string,
44
- childIdField?: string,) => ;
40
+ oneToMany: (parentEntity: string, childEntity: string, parentIdField?: string, childIdField?: string,) => OneToManyPattern;
45
41
  /**
46
42
  * Many-to-many relationship pattern using adjacency list
47
43
  * Entity: PK=ENTITY#<entityId>, SK=METADATA
48
44
  * Relationship: PK=ENTITY#<entityId>, SK=RELATED#<relatedId>
49
45
  * Inverse: PK=ENTITY#<relatedId>, SK=RELATED#<entityId> (via GSI)
50
46
  */
51
- manyToMany: (entityName: string,
52
- relationName: string,
53
- idField?: string,
54
- relatedIdField?: string,) => ;
47
+ manyToMany: (entityName: string, relationName: string, idField?: string, relatedIdField?: string,) => ManyToManyPattern;
55
48
  /**
56
49
  * Hierarchical data pattern (e.g., org chart, file system)
57
50
  * PK: ROOT#<rootId>
@@ -92,6 +85,33 @@ export declare interface SingleTableConfig {
92
85
  }[]
93
86
  entities: SingleTableEntity[]
94
87
  }
88
+ export declare interface OneToManyPattern {
89
+ parent: SingleTableEntity
90
+ child: SingleTableEntity
91
+ }
92
+ export declare interface ManyToManyPattern {
93
+ entity: SingleTableEntity
94
+ relation: SingleTableEntity
95
+ }
96
+ /**
97
+ * Common single table design patterns
98
+ */
99
+ /**
100
+ * Result shapes for relationship pattern helpers. Lifted to named
101
+ * interfaces so the generated `.d.ts` doesn't carry an inline object
102
+ * literal in the return position — bun-plugin-dtsx has a bug where
103
+ * `(...) => { ... }` in that position emits as `=> ;`, breaking
104
+ * downstream typecheck for any consumer importing from
105
+ * `bun-query-builder/dynamodb-single-table`.
106
+ */
107
+ export declare interface OneToManyPattern {
108
+ parent: SingleTableEntity
109
+ child: SingleTableEntity
110
+ }
111
+ export declare interface ManyToManyPattern {
112
+ entity: SingleTableEntity
113
+ relation: SingleTableEntity
114
+ }
95
115
  /**
96
116
  * Single Table Design Manager
97
117
  *
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export type {
15
15
  InferColumnNames,
16
16
  InferHiddenKeys,
17
17
  InferGuardedKeys,
18
+ InferPivotColumns,
18
19
  ModelRow,
19
20
  ModelRowLoose,
20
21
  ModelCreateData,
@@ -35,6 +36,7 @@ export * from './factory';
35
36
  export * from './loader';
36
37
  export * from './meta';
37
38
  export * from './migrations';
39
+ export * from './pivot';
38
40
  export * from './orm';
39
41
  export * from './schema';
40
42
  export * from './seeder';
package/dist/meta.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ModelRecord } from './schema';
1
+ import type { BelongsToManyConfig, ModelRecord } from './schema';
2
2
  export declare function buildSchemaMeta(models: ModelRecord): SchemaMeta;
3
3
  export declare interface SchemaMeta {
4
4
  modelToTable: Record<string, string>
@@ -8,7 +8,7 @@ export declare interface SchemaMeta {
8
8
  hasOne?: Record<string, string>
9
9
  hasMany?: Record<string, string>
10
10
  belongsTo?: Record<string, string>
11
- belongsToMany?: Record<string, string>
11
+ belongsToMany?: Record<string, string | BelongsToManyConfig>
12
12
  hasOneThrough?: Record<string, { through: string, target: string }>
13
13
  hasManyThrough?: Record<string, { through: string, target: string }>
14
14
  morphOne?: Record<string, string>
@@ -18,4 +18,5 @@ export declare interface SchemaMeta {
18
18
  morphedByMany?: Record<string, string>
19
19
  }>
20
20
  scopes?: Record<string, Record<string, (qb: any, value?: any) => any>>
21
+ models?: ModelRecord
21
22
  }
@@ -42,6 +42,7 @@ export declare interface IndexPlan {
42
42
  name: string
43
43
  columns: string[]
44
44
  type: 'index' | 'unique'
45
+ where?: string
45
46
  }
46
47
  export declare interface TablePlan {
47
48
  table: string
package/dist/orm.d.ts CHANGED
@@ -119,6 +119,31 @@ export declare interface ModelDefinition {
119
119
  readonly afterDelete?: (model: ModelHookInstance) => void | Promise<void>
120
120
  }
121
121
  }
122
+ /**
123
+ * Resolve a relation from its name and the parent model's definition.
124
+ * Uses the model registry to find the related model's definition.
125
+ *
126
+ * Supports both syntaxes:
127
+ * Array syntax: hasMany: ['Order'] → relation name is 'order', model is 'Order'
128
+ * Object syntax: hasMany: { orders: 'Order' } → relation name is 'orders', model is 'Order'
129
+ */
130
+ /**
131
+ * Resolved-relation shape returned by `resolveRelation`. Pivot fields are
132
+ * populated only for `belongsToMany` relations.
133
+ */
134
+ declare interface ResolvedRelation {
135
+ type: 'hasMany' | 'hasOne' | 'belongsTo' | 'belongsToMany'
136
+ relatedModelName: string
137
+ relatedTable: string
138
+ foreignKey: string
139
+ localKey: string
140
+ pivotTable?: string
141
+ pivotFkParent?: string
142
+ pivotFkRelated?: string
143
+ pivotColumns?: string[]
144
+ pivotModelName?: string
145
+ pivotTimestamps?: boolean
146
+ }
122
147
  // Binding helper type for SQL queries
123
148
  declare type Bindings = SQLQueryBindings[];
124
149
  // Primitive type mappings
@@ -208,7 +233,7 @@ export type InferRelationNames<TDef> = | InferBelongsToNames<TDef>
208
233
  | InferBelongsToManyNames<TDef>
209
234
  | InferHasOneThroughNames<TDef>
210
235
  | InferHasManyThroughNames<TDef>;
211
- declare type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'in' | 'not in';
236
+ declare type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'not like' | 'in' | 'not in';
212
237
  /**
213
238
  * Model instance - represents a single database record
214
239
  */
@@ -220,7 +245,6 @@ declare class ModelInstance<TDef extends ModelDefinition, TSelected extends Colu
220
245
  set<K extends ColumnName<TDef>>(key: K, value: K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown): void;
221
246
  only<K extends TSelected>(keys: ReadonlyArray<K>): Partial<ModelAttributes<TDef>>;
222
247
  except<K extends TSelected>(keys: ReadonlyArray<K>): Partial<ModelAttributes<TDef>>;
223
- toArray(): Record<string, unknown>;
224
248
  getRelation(name: string): ModelInstance<any, any>[] | ModelInstance<any, any> | null | undefined;
225
249
  setRelation(name: string, data: ModelInstance<any, any>[] | ModelInstance<any, any> | null): void;
226
250
  getLoadedRelations(): Record<string, ModelInstance<any, any>[] | ModelInstance<any, any> | null>;
@@ -238,8 +262,41 @@ declare class ModelInstance<TDef extends ModelDefinition, TSelected extends Colu
238
262
  delete(): boolean;
239
263
  refresh(): this | null;
240
264
  replicate(): ModelInstance<TDef, TSelected>;
265
+ toArray(): Record<string, unknown>;
241
266
  toJSON(): Omit<Pick<ModelAttributes<TDef>, TSelected & keyof ModelAttributes<TDef>>, HiddenKeys<TDef>>;
242
- toArray(): Omit<Pick<ModelAttributes<TDef>, TSelected & keyof ModelAttributes<TDef>>, HiddenKeys<TDef>>;
267
+ }
268
+ /**
269
+ * # `BelongsToManyRelationBuilder`
270
+ *
271
+ * Per-instance relation builder returned by callable accessors on a
272
+ * `ModelInstance`. Combines a query side (read pivot-joined related rows,
273
+ * filter by pivot columns) with a mutation side (attach/detach/sync/
274
+ * updateExistingPivot/toggle).
275
+ *
276
+ * Constructed lazily — `coach.athletes` returns a function that, when called,
277
+ * returns a fresh builder; chained methods return `this` so a single builder
278
+ * is reused per call.
279
+ */
280
+ export declare class BelongsToManyRelationBuilder<TRel extends ModelDefinition> {
281
+ constructor(parent: ModelInstance<any, any>, parentDef: ModelDefinition, resolved: ResolvedRelation, relatedDef: TRel);
282
+ where(column: string, opOrValue: unknown, value?: unknown): this;
283
+ wherePivot(column: string, opOrValue: unknown, value?: unknown): this;
284
+ wherePivotIn(column: string, values: unknown[]): this;
285
+ wherePivotNotIn(column: string, values: unknown[]): this;
286
+ wherePivotNull(column: string): this;
287
+ wherePivotNotNull(column: string): this;
288
+ orderBy(column: string, direction?: 'asc' | 'desc'): this;
289
+ limit(n: number): this;
290
+ offset(n: number): this;
291
+ get(): ModelInstance<TRel, any>[];
292
+ first(): ModelInstance<TRel, any> | undefined;
293
+ count(): number;
294
+ exists(): boolean;
295
+ attach(idOrIds: unknown | unknown[], extras?: Record<string, unknown>): number;
296
+ detach(idOrIds?: unknown | unknown[]): number;
297
+ updateExistingPivot(relatedId: unknown, extras: Record<string, unknown>): number;
298
+ sync(items: Array<unknown | { id: unknown, [key: string]: unknown }>): { attached: unknown[], detached: unknown[], updated: unknown[] };
299
+ toggle(idOrIds: unknown | unknown[]): { attached: unknown[], detached: unknown[] };
243
300
  }
244
301
  /**
245
302
  * Query builder with precise type narrowing
@@ -0,0 +1,29 @@
1
+ import type { ModelRecord, PivotColumnAttribute } from './schema';
2
+ import type { SchemaMeta } from './meta';
3
+ /**
4
+ * Resolve a `belongsToMany` relation entry to a `ResolvedPivot`. Returns null
5
+ * when the relation key is absent or not a `belongsToMany` on the parent.
6
+ */
7
+ export declare function resolvePivot(meta: SchemaMeta, parentTable: string, relationKey: string, options?: ResolvePivotOptions): ResolvedPivot | null;
8
+ /**
9
+ * Iterate every declared `belongsToMany` relation across all parent tables and
10
+ * yield each as a `ResolvedPivot`. Useful for migration emission and CLI
11
+ * introspection.
12
+ */
13
+ export declare function iterateAllPivots(meta: SchemaMeta, options?: ResolvePivotOptions): Generator<{ parentTable: string, relationKey: string, resolved: ResolvedPivot }>;
14
+ export declare interface ResolvedPivot {
15
+ pivotTable: string
16
+ fkParent: string
17
+ fkRelated: string
18
+ pivotColumns: string[]
19
+ pivotColumnDefs: Record<string, PivotColumnAttribute>
20
+ pivotModelName?: string
21
+ timestamps: boolean
22
+ relatedModelName: string
23
+ relatedTable: string
24
+ hasConfig: boolean
25
+ }
26
+ export declare interface ResolvePivotOptions {
27
+ singularize?: (s: string) => string
28
+ models?: ModelRecord
29
+ }
package/dist/schema.d.ts CHANGED
@@ -75,14 +75,59 @@ export declare interface AttributesElements {
75
75
  *
76
76
  * @example
77
77
  * ```ts
78
- * { name: 'user_email_unique', columns: ['email'] }
78
+ * { name: 'user_email_unique', columns: ['email'], unique: true }
79
+ * { name: 'one_primary_per_athlete', columns: ['athlete_id'], unique: true, where: "role = 'primary'" }
79
80
  * ```
80
81
  */
81
82
  export declare interface CompositeIndex {
82
83
  name: string
83
84
  columns: string[]
85
+ unique?: boolean
86
+ where?: string
84
87
  }
85
88
  export declare interface Base {}
89
+ /**
90
+ * # `PivotColumnAttribute`
91
+ *
92
+ * Inline declaration of an extra column on the pivot table (Option A). When the
93
+ * pivot is declared via a `through` model (Option B), columns are read from
94
+ * that model's `attributes` instead.
95
+ */
96
+ export declare interface PivotColumnAttribute {
97
+ default?: string | number | boolean | Date
98
+ nullable?: boolean
99
+ validation?: {
100
+ rule: ValidationType
101
+ message?: ValidatorMessage
102
+ }
103
+ }
104
+ /**
105
+ * # `PivotConfig`
106
+ *
107
+ * Inline pivot configuration (Option A). Used when the pivot does not have its
108
+ * own model in the registry. Migrations will auto-emit a table for this pivot.
109
+ */
110
+ export declare interface PivotConfig {
111
+ columns?: Record<string, PivotColumnAttribute>
112
+ timestamps?: boolean
113
+ uniques?: string[][]
114
+ }
115
+ /**
116
+ * # `BelongsToManyConfig<T>`
117
+ *
118
+ * Object form of a `belongsToMany` relation declaration. Either `through`
119
+ * (Option B — pivot is a registered model) or `pivot.columns` (Option A —
120
+ * inline metadata) supplies the pivot column metadata. When neither is
121
+ * supplied the relation behaves exactly like the legacy string form.
122
+ */
123
+ export declare interface BelongsToManyConfig<T extends string = string> {
124
+ model: T
125
+ through?: T
126
+ table?: string
127
+ foreignKey?: string
128
+ relatedKey?: string
129
+ pivot?: PivotConfig
130
+ }
86
131
  /**
87
132
  * # `ModelOptions`
88
133
  *
@@ -156,7 +201,7 @@ export type ModelNames = string;
156
201
  export type HasOne<T extends string> = Record<string, T>;
157
202
  export type HasMany<T extends string> = Record<string, T>;
158
203
  export type BelongsTo<T extends string> = Record<string, T>;
159
- export type BelongsToMany<T extends string> = Record<string, T>;
204
+ export type BelongsToMany<T extends string> = Record<string, T | BelongsToManyConfig<T>>;
160
205
  export type HasOneThrough<T extends string> = Record<string, { through: T, target: T }>;
161
206
  export type HasManyThrough<T extends string> = Record<string, { through: T, target: T }>;
162
207
  export type MorphOne<T extends string> = Record<string, T>;