bun-query-builder 0.1.26 → 0.1.27
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/bin/cli.js +144 -82
- package/dist/client.d.ts +37 -7
- package/dist/orm.d.ts +14 -1
- package/dist/schema.d.ts +65 -3
- package/dist/src/index.js +138 -76
- package/dist/type-inference.d.ts +40 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -118,13 +118,22 @@ export declare interface BaseSelectQueryBuilder<DB extends DatabaseSchema<any>,
|
|
|
118
118
|
whereJsonContainsKey?: (path: string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
|
|
119
119
|
whereJsonDoesntContainKey?: (path: string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
|
|
120
120
|
whereJsonLength?: (path: string, opOrLen: WhereOperator | number, len?: number) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
|
|
121
|
-
with?: (...relations:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
121
|
+
with?: (...relations: WithRelationArg<DB, TTable>[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
122
|
+
whereHas?: (relation: TableRelationName<DB, TTable>, callback?: (qb: any) => any) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
123
|
+
whereDoesntHave?: (relation: TableRelationName<DB, TTable>, callback?: (qb: any) => any) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
124
|
+
has?: (relation: TableRelationName<DB, TTable>) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
125
|
+
doesntHave?: (relation: TableRelationName<DB, TTable>) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
126
|
+
withCount?: (...relations: TableRelationName<DB, TTable>[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
127
|
+
withSum?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
128
|
+
withAvg?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
129
|
+
withMax?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
130
|
+
withMin?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
131
|
+
withPivot?: (relation: TableRelationName<DB, TTable>, ...columns: string[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
132
|
+
wherePivot?: (relation: TableRelationName<DB, TTable>, column: string, opOrValue: any, value?: any) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
133
|
+
wherePivotIn?: (relation: TableRelationName<DB, TTable>, column: string, values: any[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
134
|
+
wherePivotNotIn?: (relation: TableRelationName<DB, TTable>, column: string, values: any[]) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
135
|
+
wherePivotNull?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
136
|
+
wherePivotNotNull?: (relation: TableRelationName<DB, TTable>, column: string) => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
128
137
|
applyPivotColumns?: () => SelectQueryBuilder<DB, TTable, TSelected, any>
|
|
129
138
|
lockForUpdate: () => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
|
|
130
139
|
sharedLock: () => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
|
|
@@ -399,6 +408,27 @@ export type SelectedRow<DB extends DatabaseSchema<any>, _TTable extends keyof DB
|
|
|
399
408
|
declare type JoinColumn<DB extends DatabaseSchema<any>, TTables extends string> = TTables extends any
|
|
400
409
|
? `${TTables}.${keyof DB[TTables]['columns'] & string}`
|
|
401
410
|
: never;
|
|
411
|
+
/**
|
|
412
|
+
* # `TableRelationName<DB, TTable>`
|
|
413
|
+
*
|
|
414
|
+
* The relation names declared for a table, read from the type-level
|
|
415
|
+
* `relations` map that `DatabaseSchema` carries. Falls back to `string`
|
|
416
|
+
* for hand-written schema types that don't declare relation metadata, so
|
|
417
|
+
* existing untyped schemas keep compiling.
|
|
418
|
+
*/
|
|
419
|
+
export type TableRelationName<DB extends DatabaseSchema<any>, TTable extends keyof DB & string> = DB[TTable] extends { relations?: infer R }
|
|
420
|
+
? [keyof NonNullable<R>] extends [never] ? string : keyof NonNullable<R> & string
|
|
421
|
+
: string;
|
|
422
|
+
/**
|
|
423
|
+
* # `WithRelationArg<DB, TTable>`
|
|
424
|
+
*
|
|
425
|
+
* Argument accepted by `.with()`: a declared relation name, a dotted nested
|
|
426
|
+
* path rooted at a declared relation (`'posts.comments'`), or a record
|
|
427
|
+
* mapping relation names to constraint callbacks.
|
|
428
|
+
*/
|
|
429
|
+
export type WithRelationArg<DB extends DatabaseSchema<any>, TTable extends keyof DB & string> = | TableRelationName<DB, TTable>
|
|
430
|
+
| `${TableRelationName<DB, TTable>}.${string}`
|
|
431
|
+
| Partial<Record<TableRelationName<DB, TTable>, (qb: any) => any>>;
|
|
402
432
|
// Convert snake_case to PascalCase at the type level (e.g. created_at -> CreatedAt)
|
|
403
433
|
declare type SnakeToPascal<S extends string> = S extends `${infer H}_${infer T}`
|
|
404
434
|
? `${Capitalize<H>}${SnakeToPascal<T>}`
|
package/dist/orm.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Database, type SQLQueryBindings } from 'bun:sqlite';
|
|
2
2
|
import type { Faker } from '@stacksjs/ts-faker';
|
|
3
|
+
import type { RelationCardinality } from './type-inference';
|
|
3
4
|
import type { SupportedDialect } from './types';
|
|
4
5
|
export type {
|
|
5
6
|
ModelInstance,
|
|
@@ -263,6 +264,18 @@ export type InferRelationNames<TDef> = | InferBelongsToNames<TDef>
|
|
|
263
264
|
| InferBelongsToManyNames<TDef>
|
|
264
265
|
| InferHasOneThroughNames<TDef>
|
|
265
266
|
| InferHasManyThroughNames<TDef>;
|
|
267
|
+
/**
|
|
268
|
+
* Cardinality-aware value of a loaded relation as returned by
|
|
269
|
+
* `ModelInstance.getRelation()`. Relations declared as to-many (hasMany,
|
|
270
|
+
* belongsToMany, hasManyThrough) yield arrays; to-one relations (hasOne,
|
|
271
|
+
* belongsTo, hasOneThrough) yield a single instance or null. `undefined`
|
|
272
|
+
* means the relation was not eager-loaded.
|
|
273
|
+
*/
|
|
274
|
+
declare type LoadedRelationValue<TDef, R extends string> = 'one' extends RelationCardinality<TDef, R>
|
|
275
|
+
? ModelInstance<any, any> | null | undefined
|
|
276
|
+
: 'many' extends RelationCardinality<TDef, R>
|
|
277
|
+
? ModelInstance<any, any>[] | undefined
|
|
278
|
+
: ModelInstance<any, any>[] | ModelInstance<any, any> | null | undefined;
|
|
266
279
|
declare type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'not like' | 'in' | 'not in';
|
|
267
280
|
// --- Dialect-aware execution layer -------------------------------------------
|
|
268
281
|
//
|
|
@@ -306,7 +319,7 @@ declare class ModelInstance<TDef extends ModelDefinition, TSelected extends Colu
|
|
|
306
319
|
set<K extends ColumnName<TDef>>(key: K, value: K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown): void;
|
|
307
320
|
only<K extends TSelected>(keys: ReadonlyArray<K>): Partial<ModelAttributes<TDef>>;
|
|
308
321
|
except<K extends TSelected>(keys: ReadonlyArray<K>): Partial<ModelAttributes<TDef>>;
|
|
309
|
-
getRelation(name:
|
|
322
|
+
getRelation<R extends InferRelationNames<TDef> & string>(name: R): LoadedRelationValue<TDef, R>;
|
|
310
323
|
setRelation(name: string, data: ModelInstance<any, any>[] | ModelInstance<any, any> | null): void;
|
|
311
324
|
getLoadedRelations(): Record<string, ModelInstance<any, any>[] | ModelInstance<any, any> | null>;
|
|
312
325
|
get attributes(): Pick<ModelAttributes<TDef>, TSelected & keyof ModelAttributes<TDef>>;
|
package/dist/schema.d.ts
CHANGED
|
@@ -258,6 +258,61 @@ export type InferTableName<M extends ModelDefinition> = M extends {
|
|
|
258
258
|
: M extends { name: infer N extends string }
|
|
259
259
|
? `${Lowercase<N>}s`
|
|
260
260
|
: string;
|
|
261
|
+
/**
|
|
262
|
+
* Resolve a models-record entry to the raw definition. `defineModel()` (and
|
|
263
|
+
* `createModel`/`createBrowserModel`) wrap definitions in an object exposing
|
|
264
|
+
* `getDefinition()` / `definition`; `buildDatabaseSchema` unwraps these at
|
|
265
|
+
* runtime, so the type level must unwrap them too or the schema degrades to
|
|
266
|
+
* an untyped index signature.
|
|
267
|
+
*/
|
|
268
|
+
declare type UnwrapModelDefinition<M> = M extends { getDefinition: () => infer D } ? D :
|
|
269
|
+
M extends { definition: infer D } ? D :
|
|
270
|
+
M;
|
|
271
|
+
/**
|
|
272
|
+
* Unwrap a relation entry to the related model's name. Entries may be a plain
|
|
273
|
+
* model-name string, a `{ model: 'X' }` config (belongsToMany Option A/B), or
|
|
274
|
+
* a `{ through, target }` through-relation descriptor.
|
|
275
|
+
*/
|
|
276
|
+
declare type RelationEntryModelName<E> = E extends string ? E :
|
|
277
|
+
E extends { model: infer M extends string } ? M :
|
|
278
|
+
E extends { target: infer T extends string } ? T :
|
|
279
|
+
never;
|
|
280
|
+
/**
|
|
281
|
+
* Normalize one relation declaration (array or record form) into a
|
|
282
|
+
* `relationName -> relatedModelName` record, mirroring `buildSchemaMeta`:
|
|
283
|
+
* array entries use the (unwrapped) model name as the relation name; record
|
|
284
|
+
* entries use the key.
|
|
285
|
+
*/
|
|
286
|
+
declare type RelationRecordOf<V> = [V] extends [never]
|
|
287
|
+
? {} // absent relation kind — must yield {} (not never) so intersections survive
|
|
288
|
+
: V extends readonly (infer E)[]
|
|
289
|
+
? { [K in RelationEntryModelName<E> & string]: K }
|
|
290
|
+
: V extends Readonly<Record<string, unknown>>
|
|
291
|
+
? { [K in keyof V & string]: RelationEntryModelName<V[K]> }
|
|
292
|
+
: {}
|
|
293
|
+
/** All relations of a model as a `relationName -> relatedModelName` record. */
|
|
294
|
+
declare type ModelRelationsRecord<M> = RelationRecordOf<M extends { hasOne: infer V } ? V : never>
|
|
295
|
+
& RelationRecordOf<M extends { hasMany: infer V } ? V : never>
|
|
296
|
+
& RelationRecordOf<M extends { belongsTo: infer V } ? V : never>
|
|
297
|
+
& RelationRecordOf<M extends { belongsToMany: infer V } ? V : never>
|
|
298
|
+
& RelationRecordOf<M extends { hasOneThrough: infer V } ? V : never>
|
|
299
|
+
& RelationRecordOf<M extends { hasManyThrough: infer V } ? V : never>
|
|
300
|
+
& RelationRecordOf<M extends { morphOne: infer V } ? V : never>
|
|
301
|
+
& RelationRecordOf<M extends { morphMany: infer V } ? V : never>
|
|
302
|
+
& RelationRecordOf<M extends { morphToMany: infer V } ? V : never>
|
|
303
|
+
& RelationRecordOf<M extends { morphedByMany: infer V } ? V : never>;
|
|
304
|
+
/** Resolve a related model name to its table name within the models record. */
|
|
305
|
+
declare type RelatedTableName<MRecord extends ModelRecord, ModelName> = ModelName extends keyof MRecord ? InferTableName<UnwrapModelDefinition<MRecord[ModelName]>> : string;
|
|
306
|
+
/**
|
|
307
|
+
* # `InferTableRelations<M, MRecord>`
|
|
308
|
+
*
|
|
309
|
+
* `relationName -> relatedTableName` record for one model, resolved against
|
|
310
|
+
* the full models record. Powers the type-level narrowing of `.with()`,
|
|
311
|
+
* `.whereHas()`, `.withCount()`, etc. on the query builder.
|
|
312
|
+
*/
|
|
313
|
+
export type InferTableRelations<M, MRecord extends ModelRecord> = {
|
|
314
|
+
[K in keyof ModelRelationsRecord<UnwrapModelDefinition<M>> & string]: RelatedTableName<MRecord, ModelRelationsRecord<UnwrapModelDefinition<M>>[K]>
|
|
315
|
+
}
|
|
261
316
|
/**
|
|
262
317
|
* # `DatabaseSchema<Models>`
|
|
263
318
|
*
|
|
@@ -265,6 +320,11 @@ export type InferTableName<M extends ModelDefinition> = M extends {
|
|
|
265
320
|
* table columns and primary key. This is the primary input for the query
|
|
266
321
|
* builder's type-safety.
|
|
267
322
|
*
|
|
323
|
+
* The `relations` field is type-level only (phantom): `buildDatabaseSchema`
|
|
324
|
+
* never materializes it at runtime. It maps relation names to related table
|
|
325
|
+
* names so builder methods like `.with()` can narrow their accepted relation
|
|
326
|
+
* names per table.
|
|
327
|
+
*
|
|
268
328
|
* @example
|
|
269
329
|
* ```ts
|
|
270
330
|
* const models = defineModels({ User, Post })
|
|
@@ -272,8 +332,10 @@ export type InferTableName<M extends ModelDefinition> = M extends {
|
|
|
272
332
|
* ```
|
|
273
333
|
*/
|
|
274
334
|
export type DatabaseSchema<MRecord extends ModelRecord> = {
|
|
275
|
-
[MName in keyof MRecord & string as InferTableName<MRecord[MName]
|
|
276
|
-
columns: InferAttributes<MRecord[MName]
|
|
277
|
-
primaryKey: InferPrimaryKey<MRecord[MName]
|
|
335
|
+
[MName in keyof MRecord & string as InferTableName<UnwrapModelDefinition<MRecord[MName]>>]: {
|
|
336
|
+
columns: InferAttributes<UnwrapModelDefinition<MRecord[MName]>>
|
|
337
|
+
primaryKey: InferPrimaryKey<UnwrapModelDefinition<MRecord[MName]>>
|
|
338
|
+
/** Phantom, type-level only: relation name -> related table name. */
|
|
339
|
+
relations?: InferTableRelations<MRecord[MName], MRecord>
|
|
278
340
|
};
|
|
279
341
|
}
|