bun-query-builder 0.1.13 → 0.1.15

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 (63) hide show
  1. package/README.md +45 -468
  2. package/dist/__tests__/type-narrowing-compile.d.ts +1 -0
  3. package/dist/__tests__/type-narrowing.test.d.ts +1 -0
  4. package/dist/actions/benchmark.d.ts +1 -1
  5. package/dist/actions/cache.d.ts +1 -1
  6. package/dist/actions/console.d.ts +1 -1
  7. package/dist/actions/data.d.ts +2 -1
  8. package/dist/actions/db-info.d.ts +1 -1
  9. package/dist/actions/db-optimize.d.ts +1 -1
  10. package/dist/actions/db-wipe.d.ts +1 -1
  11. package/dist/actions/explain.d.ts +1 -1
  12. package/dist/actions/file.d.ts +1 -1
  13. package/dist/actions/index.d.ts +1 -1
  14. package/dist/actions/inspect.d.ts +1 -1
  15. package/dist/actions/introspect.d.ts +1 -1
  16. package/dist/actions/make-model.d.ts +1 -1
  17. package/dist/actions/migrate-generate.d.ts +1 -1
  18. package/dist/actions/migrate-rollback.d.ts +1 -1
  19. package/dist/actions/migrate-status.d.ts +1 -1
  20. package/dist/actions/migrate.d.ts +1 -1
  21. package/dist/actions/model-show.d.ts +1 -1
  22. package/dist/actions/ping.d.ts +1 -1
  23. package/dist/actions/query-explain-all.d.ts +1 -1
  24. package/dist/actions/relation-diagram.d.ts +1 -1
  25. package/dist/actions/seed.d.ts +1 -1
  26. package/dist/actions/sql.d.ts +1 -1
  27. package/dist/actions/unsafe.d.ts +1 -1
  28. package/dist/actions/validate.d.ts +1 -1
  29. package/dist/actions/wait-ready.d.ts +1 -1
  30. package/dist/bin/cli.js +25785 -0
  31. package/dist/browser.d.ts +118 -44
  32. package/dist/client.d.ts +22 -56
  33. package/dist/config.d.ts +16 -3
  34. package/dist/db.d.ts +5 -4
  35. package/dist/drivers/dynamodb.d.ts +3 -13
  36. package/dist/drivers/index.d.ts +2 -1
  37. package/dist/drivers/mysql.d.ts +3 -9
  38. package/dist/drivers/postgres.d.ts +3 -9
  39. package/dist/drivers/sqlite.d.ts +3 -9
  40. package/dist/dynamodb/client.d.ts +1 -5
  41. package/dist/dynamodb/index.d.ts +7 -28
  42. package/dist/dynamodb/migration-driver.d.ts +2 -23
  43. package/dist/dynamodb/migration-tracker.d.ts +4 -6
  44. package/dist/dynamodb/migrations.d.ts +4 -1
  45. package/dist/dynamodb/model.d.ts +5 -13
  46. package/dist/dynamodb-client.d.ts +3 -23
  47. package/dist/dynamodb-single-table.d.ts +22 -26
  48. package/dist/dynamodb-tooling-adapter.d.ts +2 -33
  49. package/dist/factory.d.ts +3 -3
  50. package/dist/index.d.ts +24 -1
  51. package/dist/loader.d.ts +1 -1
  52. package/dist/meta.d.ts +1 -1
  53. package/dist/migrations.d.ts +4 -4
  54. package/dist/model.d.ts +61 -3
  55. package/dist/orm.d.ts +130 -82
  56. package/dist/schema.d.ts +32 -25
  57. package/dist/seeder.d.ts +3 -1
  58. package/dist/{browser.js → src/browser.js} +32 -5
  59. package/dist/{dynamodb → src/dynamodb}/index.js +29 -2
  60. package/dist/{index.js → src/index.js} +8253 -7498
  61. package/dist/type-inference.d.ts +326 -0
  62. package/dist/types.d.ts +1 -5
  63. package/package.json +3 -3
@@ -0,0 +1,326 @@
1
+ import type { Faker } from 'ts-mocker';
2
+ /** Minimal attribute definition for type inference */
3
+ declare interface InferableAttribute<T = unknown> {
4
+ type?: T
5
+ fillable?: boolean
6
+ unique?: boolean
7
+ hidden?: boolean
8
+ guarded?: boolean
9
+ nullable?: boolean
10
+ default?: InferType<T>
11
+ factory?: (faker: Faker) => InferType<T>
12
+ }
13
+ /** Minimal model definition shape for type inference */
14
+ declare interface InferableModelDefinition {
15
+ readonly name: string
16
+ readonly table: string
17
+ readonly primaryKey?: string
18
+ readonly traits?: {
19
+ readonly useUuid?: boolean
20
+ readonly useTimestamps?: boolean | object
21
+ readonly timestampable?: boolean | object
22
+ readonly useSoftDeletes?: boolean | object
23
+ readonly softDeletable?: boolean | object
24
+ readonly useAuth?: boolean | object
25
+ readonly billable?: boolean | object
26
+ }
27
+ readonly belongsTo?: readonly string[] | Readonly<Record<string, string>>
28
+ readonly hasMany?: readonly string[] | Readonly<Record<string, string>>
29
+ readonly hasOne?: readonly string[] | Readonly<Record<string, string>>
30
+ readonly belongsToMany?: readonly (string | object)[] | Readonly<Record<string, string | object>>
31
+ readonly hasOneThrough?: readonly (string | object)[] | Readonly<Record<string, string | object>>
32
+ readonly hasManyThrough?: readonly (string | object)[] | Readonly<Record<string, string | object>>
33
+ readonly morphOne?: string | object | Readonly<Record<string, string>>
34
+ readonly morphMany?: readonly (string | object)[] | Readonly<Record<string, string | object>>
35
+ readonly morphTo?: object
36
+ readonly morphToMany?: readonly string[]
37
+ readonly morphedByMany?: readonly string[]
38
+ readonly attributes: {
39
+ readonly [key: string]: InferableAttribute<unknown>
40
+ }
41
+ }
42
+ // ============================================================================
43
+ // Primitive type mappings (shared with orm.ts and browser.ts)
44
+ // ============================================================================
45
+ declare type PrimitiveTypeMap = {
46
+ string: string
47
+ number: number
48
+ boolean: boolean
49
+ date: Date
50
+ json: Record<string, unknown>
51
+ }
52
+ declare type InferType<T> = T extends keyof PrimitiveTypeMap ? PrimitiveTypeMap[T] :
53
+ T extends readonly (infer U)[] ? U :
54
+ T extends (infer U)[] ? U :
55
+ unknown;
56
+ /**
57
+ * Resolves TModel to the underlying definition type.
58
+ * Handles both raw definitions and wrapped models (from defineModel / createModel / createBrowserModel)
59
+ * that expose a `getDefinition()` method or `definition` property.
60
+ */
61
+ declare type ResolveDefinition<TModel> = TModel extends { getDefinition: () => infer D } ? D :
62
+ TModel extends { definition: infer D } ? D :
63
+ TModel extends InferableModelDefinition ? TModel :
64
+ never;
65
+ /** Extract user-defined attribute keys from a model definition */
66
+ declare type DefinitionAttributeKeys<TDef extends InferableModelDefinition> = keyof TDef['attributes'] & string;
67
+ // ============================================================================
68
+ // Single attribute type inference
69
+ // ============================================================================
70
+ declare type InferSingleAttributeType<TAttr> = TAttr extends { type: infer T } ? InferType<T> :
71
+ TAttr extends { factory: (faker: Faker) => infer R } ? R :
72
+ unknown;
73
+ /**
74
+ * Infer the full attributes type from a model definition or wrapped model.
75
+ * Includes user-defined attributes plus system fields (id, uuid, timestamps, soft deletes).
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * type UserAttrs = InferAttributes<typeof UserModel>
80
+ * // { name: string; email: string; age: number } & { id: number; created_at: string; updated_at: string }
81
+ * ```
82
+ */
83
+ export type InferAttributes<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
84
+ ? {
85
+ [K in DefinitionAttributeKeys<TDef>]: TDef['attributes'][K] extends { nullable: true }
86
+ ? InferSingleAttributeType<TDef['attributes'][K]> | null
87
+ : InferSingleAttributeType<TDef['attributes'][K]>
88
+ } & { [K in TDef extends { primaryKey: infer PK extends string } ? PK : 'id']: number }
89
+ & (TDef['traits'] extends { useUuid: true } ? { uuid: string } : {})
90
+ & (TDef['traits'] extends { useTimestamps: true } ? { created_at: string; updated_at: string | null } : {})
91
+ & (TDef['traits'] extends { timestampable: true | object } ? { created_at: string; updated_at: string | null } : {})
92
+ & (TDef['traits'] extends { useSoftDeletes: true } ? { deleted_at: string | null } : {})
93
+ & (TDef['traits'] extends { softDeletable: true | object } ? { deleted_at: string | null } : {})
94
+ & (TDef['traits'] extends { useAuth: true | object } ? { two_factor_secret: string | null; public_key: string | null } : {})
95
+ & (TDef['traits'] extends { billable: true | object } ? { stripe_id: string | null } : {})
96
+ : never;
97
+ /**
98
+ * The full row type for a model, including an index signature for trait-added
99
+ * or dynamic fields that cannot be statically inferred. Use this as the type
100
+ * for function parameters that receive a model instance or row object.
101
+ *
102
+ * Replaces hand-written interfaces like `UserModel` or `OrderModel`.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import type { ModelRow } from 'bun-query-builder'
107
+ * type UserModel = ModelRow<typeof User>
108
+ * function greet(user: UserModel) { console.log(user.name) }
109
+ * ```
110
+ */
111
+ export type ModelRow<TModel> = InferAttributes<TModel>;
112
+ /**
113
+ * Loose variant of ModelRow that includes an index signature for dynamic fields.
114
+ * Use when consumers may access trait-added or dynamic fields that cannot be statically inferred.
115
+ */
116
+ export type ModelRowLoose<TModel> = InferAttributes<TModel> & { [key: string]: unknown }
117
+ /**
118
+ * The create/update data type for a model — only fillable attributes.
119
+ * Use this for function parameters that accept new record data.
120
+ *
121
+ * Replaces hand-written interfaces like `NewUser`.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * import type { ModelCreateData } from 'bun-query-builder'
126
+ * type NewUser = ModelCreateData<typeof User>
127
+ * ```
128
+ */
129
+ export type ModelCreateData<TModel> = InferFillableAttributes<TModel>;
130
+ /**
131
+ * Loose variant of ModelCreateData that includes an index signature for dynamic fields.
132
+ * Use when consumers may pass trait-added or dynamic fields that cannot be statically inferred.
133
+ */
134
+ export type ModelCreateDataLoose<TModel> = InferFillableAttributes<TModel> & { [key: string]: unknown }
135
+ /**
136
+ * Infer only the fillable fields from a model definition or wrapped model.
137
+ * This is the type accepted by `create()`, `update()`, and `fill()`.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * type UserFillable = InferFillableAttributes<typeof UserModel>
142
+ * // { name: string; email: string; age: number; role: 'admin' | 'user' }
143
+ * ```
144
+ */
145
+ export type InferFillableAttributes<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
146
+ ? {
147
+ [K in DefinitionAttributeKeys<TDef> as TDef['attributes'][K] extends { fillable: true } ? K : never]:
148
+ InferSingleAttributeType<TDef['attributes'][K]>
149
+ }
150
+ : never;
151
+ /**
152
+ * Infer the primary key type from a model definition or wrapped model.
153
+ * Returns the literal string type of the primary key column name.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * type UserPK = InferPrimaryKey<typeof UserModel>
158
+ * // 'id' (or whatever the model's primaryKey is set to)
159
+ * ```
160
+ */
161
+ export type InferPrimaryKey<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
162
+ ? TDef extends { primaryKey: infer PK extends string } ? PK : 'id'
163
+ : never;
164
+ /**
165
+ * Infer the table name literal from a model definition or wrapped model.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * type UserTable = InferTableName<typeof UserModel>
170
+ * // 'users'
171
+ * ```
172
+ */
173
+ export type InferTableName<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
174
+ ? TDef['table']
175
+ : never;
176
+ /**
177
+ * Infer all valid relation names from a model definition or wrapped model.
178
+ * Combines belongsTo, hasMany, hasOne, belongsToMany, hasOneThrough, and hasManyThrough.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * type UserRelations = InferRelationNames<typeof UserModel>
183
+ * // 'team' | 'post' (lowercased from belongsTo: ['Team'], hasMany: ['Post'])
184
+ * ```
185
+ */
186
+ export type InferRelationNames<TModel> = ResolveDefinition<TModel> extends infer TDef
187
+ ? InferBelongsToNames<TDef>
188
+ | InferHasManyNames<TDef>
189
+ | InferHasOneNames<TDef>
190
+ | InferBelongsToManyNames<TDef>
191
+ | InferHasOneThroughNames<TDef>
192
+ | InferHasManyThroughNames<TDef>
193
+ : never;
194
+ /**
195
+ * Infer column names that have numeric types from a model definition or wrapped model.
196
+ * Useful for constraining aggregate methods (sum, avg, etc.) to numeric columns only.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * type UserNumeric = InferNumericColumns<typeof UserModel>
201
+ * // 'age'
202
+ * ```
203
+ */
204
+ export type InferNumericColumns<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
205
+ ? {
206
+ [K in DefinitionAttributeKeys<TDef>]:
207
+ TDef['attributes'][K] extends { type: 'number' } ? K : never
208
+ }[DefinitionAttributeKeys<TDef>]
209
+ : never;
210
+ /**
211
+ * Infer all valid column names (attributes + system fields) from a model definition.
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * type UserCols = InferColumnNames<typeof UserModel>
216
+ * // 'name' | 'email' | 'age' | 'role' | 'id' | 'uuid' | 'created_at' | 'updated_at'
217
+ * ```
218
+ */
219
+ export type InferColumnNames<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
220
+ ? DefinitionAttributeKeys<TDef>
221
+ | 'id'
222
+ | (TDef['traits'] extends { useUuid: true } ? 'uuid' : never)
223
+ | (TDef['traits'] extends { useTimestamps: true } ? 'created_at' | 'updated_at' : never)
224
+ | (TDef['traits'] extends { timestampable: true | object } ? 'created_at' | 'updated_at' : never)
225
+ | (TDef['traits'] extends { useSoftDeletes: true } ? 'deleted_at' : never)
226
+ | (TDef['traits'] extends { softDeletable: true | object } ? 'deleted_at' : never)
227
+ | (TDef['traits'] extends { useAuth: true | object } ? 'two_factor_secret' | 'public_key' : never)
228
+ | (TDef['traits'] extends { billable: true | object } ? 'stripe_id' : never)
229
+ : never;
230
+ /**
231
+ * Infer hidden field keys from a model definition or wrapped model.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * type UserHidden = InferHiddenKeys<typeof UserModel>
236
+ * // 'password'
237
+ * ```
238
+ */
239
+ export type InferHiddenKeys<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
240
+ ? {
241
+ [K in DefinitionAttributeKeys<TDef>]: TDef['attributes'][K] extends { hidden: true } ? K : never
242
+ }[DefinitionAttributeKeys<TDef>]
243
+ : never;
244
+ /**
245
+ * Infer guarded field keys from a model definition or wrapped model.
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * type UserGuarded = InferGuardedKeys<typeof UserModel>
250
+ * // 'bio'
251
+ * ```
252
+ */
253
+ export type InferGuardedKeys<TModel> = ResolveDefinition<TModel> extends infer TDef extends InferableModelDefinition
254
+ ? {
255
+ [K in DefinitionAttributeKeys<TDef>]: TDef['attributes'][K] extends { guarded: true } ? K : never
256
+ }[DefinitionAttributeKeys<TDef>]
257
+ : never;
258
+ // ============================================================================
259
+ // Internal relation name inference helpers
260
+ // ============================================================================
261
+ declare type InferBelongsToNames<TDef> = (TDef extends { belongsTo: readonly (infer R)[] }
262
+ ? R extends string ? Lowercase<R> : never : never)
263
+ | (TDef extends { belongsTo: Readonly<Record<infer K, unknown>> }
264
+ ? K extends string ? K : never : never);
265
+ declare type InferHasManyNames<TDef> = (TDef extends { hasMany: readonly (infer R)[] }
266
+ ? R extends string ? Lowercase<R> : never : never)
267
+ | (TDef extends { hasMany: Readonly<Record<infer K, unknown>> }
268
+ ? K extends string ? K : never : never);
269
+ declare type InferHasOneNames<TDef> = (TDef extends { hasOne: readonly (infer R)[] }
270
+ ? R extends string ? Lowercase<R> : never : never)
271
+ | (TDef extends { hasOne: Readonly<Record<infer K, unknown>> }
272
+ ? K extends string ? K : never : never);
273
+ declare type InferBelongsToManyNames<TDef> = (TDef extends { belongsToMany: readonly (infer R)[] }
274
+ ? R extends string ? Lowercase<R> : R extends { model: infer M extends string } ? Lowercase<M> : never : never)
275
+ | (TDef extends { belongsToMany: Readonly<Record<infer K, unknown>> }
276
+ ? K extends string ? K : never : never);
277
+ declare type InferHasOneThroughNames<TDef> = (TDef extends { hasOneThrough: readonly (infer R)[] }
278
+ ? R extends string ? Lowercase<R> : R extends { model: infer M extends string } ? Lowercase<M> : never : never)
279
+ | (TDef extends { hasOneThrough: Readonly<Record<infer K, unknown>> }
280
+ ? K extends string ? K : never : never);
281
+ declare type InferHasManyThroughNames<TDef> = (TDef extends { hasManyThrough: readonly (infer R)[] }
282
+ ? R extends string ? Lowercase<R> : R extends { model: infer M extends string } ? Lowercase<M> : never : never)
283
+ | (TDef extends { hasManyThrough: Readonly<Record<infer K, unknown>> }
284
+ ? K extends string ? K : never : never);
285
+ /**
286
+ * Determine the cardinality of a relation on a model.
287
+ * hasMany → 'many', hasOne/belongsTo → 'one'
288
+ */
289
+ export type RelationCardinality<TModel, R extends string> = ResolveDefinition<TModel> extends infer TDef
290
+ ? // hasMany array syntax
291
+ (TDef extends { hasMany: readonly (infer M)[] }
292
+ ? Lowercase<M & string> extends R ? 'many' : never
293
+ : never)
294
+ // hasMany object syntax
295
+ | (TDef extends { hasMany: Readonly<Record<infer K, unknown>> }
296
+ ? K extends string ? K extends R ? 'many' : never : never
297
+ : never)
298
+ // hasOne array syntax
299
+ | (TDef extends { hasOne: readonly (infer M)[] }
300
+ ? Lowercase<M & string> extends R ? 'one' : never
301
+ : never)
302
+ // hasOne object syntax
303
+ | (TDef extends { hasOne: Readonly<Record<infer K, unknown>> }
304
+ ? K extends string ? K extends R ? 'one' : never : never
305
+ : never)
306
+ // belongsTo array syntax
307
+ | (TDef extends { belongsTo: readonly (infer M)[] }
308
+ ? Lowercase<M & string> extends R ? 'one' : never
309
+ : never)
310
+ // belongsTo object syntax
311
+ | (TDef extends { belongsTo: Readonly<Record<infer K, unknown>> }
312
+ ? K extends string ? K extends R ? 'one' : never : never
313
+ : never)
314
+ // belongsToMany array syntax
315
+ | (TDef extends { belongsToMany: readonly (infer M)[] }
316
+ ? M extends string
317
+ ? Lowercase<M> extends R ? 'many' : never
318
+ : M extends { model: infer N extends string }
319
+ ? Lowercase<N> extends R ? 'many' : never
320
+ : never
321
+ : never)
322
+ // belongsToMany object syntax
323
+ | (TDef extends { belongsToMany: Readonly<Record<infer K, unknown>> }
324
+ ? K extends string ? K extends R ? 'many' : never : never
325
+ : never)
326
+ : never;
package/dist/types.d.ts CHANGED
@@ -195,16 +195,12 @@ export declare interface QueryBuilderConfig {
195
195
  sql: SqlConfig
196
196
  features: FeatureToggles
197
197
  debug?: {
198
- /** When true, capture query text for debugging via `toText()`. */
199
198
  captureText: boolean
200
199
  }
201
200
  hooks?: QueryHooks
202
201
  softDeletes?: {
203
- /** When true, apply a default `WHERE deleted_at IS NULL` filter. */
204
202
  enabled: boolean
205
- /** Column name used for soft delete flag/timestamp. */
206
203
  column: string
207
- /** When true, default filter is applied unless `.withTrashed()` is called. */
208
204
  defaultFilter: boolean
209
205
  }
210
206
  }
@@ -248,4 +244,4 @@ export declare interface UnsafeOptions {
248
244
  * - 'sqlite': Lightweight engine; some features are limited or emulated
249
245
  * - 'browser': Browser-compatible mode that uses fetch() API calls instead of direct database connections
250
246
  */
251
- export type SupportedDialect = 'postgres' | 'mysql' | 'sqlite' | 'browser'
247
+ export type SupportedDialect = 'postgres' | 'mysql' | 'sqlite' | 'browser';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-query-builder",
3
3
  "type": "module",
4
- "version": "0.1.13",
4
+ "version": "0.1.15",
5
5
  "description": "A simple yet performant query builder for TypeScript. Built with Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -78,9 +78,9 @@
78
78
  },
79
79
  "dependencies": {
80
80
  "@stacksjs/clapp": "^0.2.0",
81
- "@stacksjs/ts-validation": "^0.4.9",
81
+ "@stacksjs/ts-validation": "^0.4.10",
82
82
  "dynamodb-tooling": "^0.3.2",
83
- "ts-mocker": "^0.1.5"
83
+ "ts-mocker": "^0.1.7"
84
84
  },
85
85
  "devDependencies": {
86
86
  "bunfig": "^0.15.6"