bun-query-builder 0.2.27 → 0.2.29

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
@@ -1,5 +1,5 @@
1
1
  import type { BrowserConfig } from './types';
2
- import type { Faker } from '@stacksjs/ts-faker';
2
+ import type { FactoryFaker } from './faker-compat';
3
3
  // Export types for external use
4
4
  export type { BrowserModelInstance, BrowserModelQueryBuilder };
5
5
  /**
@@ -115,7 +115,7 @@ export declare interface BrowserTypedAttribute<T = unknown> {
115
115
  rule: unknown
116
116
  message?: Record<string, string>
117
117
  }
118
- factory?: (faker: Faker) => InferType<T>
118
+ factory?: (faker: FactoryFaker) => InferType<T>
119
119
  }
120
120
  // Base model definition for browser
121
121
  export declare interface BrowserModelDefinition {
package/dist/client.d.ts CHANGED
@@ -86,6 +86,13 @@ export declare interface BaseSelectQueryBuilder<DB extends DatabaseSchema<any>,
86
86
  whereNotILike?: (column: keyof DB[TTable]['columns'] & string, pattern: string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
87
87
  orWhereNotLike: (column: keyof DB[TTable]['columns'] & string, pattern: string, caseSensitive?: boolean) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
88
88
  orWhereNotILike?: (column: keyof DB[TTable]['columns'] & string, pattern: string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
89
+ whereGroup: (callback: (builder: SelectQueryBuilder<DB, TTable, TSelected, TJoined>) => unknown) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
90
+ orWhereGroup: (callback: (builder: SelectQueryBuilder<DB, TTable, TSelected, TJoined>) => unknown) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
91
+ orWhereNull: (column: keyof DB[TTable]['columns'] & string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
92
+ orWhereNotNull: (column: keyof DB[TTable]['columns'] & string) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
93
+ orWhereBetween: (column: keyof DB[TTable]['columns'] & string, start: any, end: any) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
94
+ orWhereExists: (subquery: { toSQL: () => any }) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
95
+ orWhereRaw: (fragment: SqlFragment) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
89
96
  whereAny: <K extends keyof DB[TTable]['columns'] & string>(columns: K[], op: WhereOperator, value: DB[TTable]['columns'][K]) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
90
97
  whereAll: <K extends keyof DB[TTable]['columns'] & string>(columns: K[], op: WhereOperator, value: DB[TTable]['columns'][K]) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
91
98
  whereNone: <K extends keyof DB[TTable]['columns'] & string>(columns: K[], op: WhereOperator, value: DB[TTable]['columns'][K]) => SelectQueryBuilder<DB, TTable, TSelected, TJoined>
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Wrap a ts-faker instance in the surface factories are written against.
3
+ *
4
+ * Returned as `FactoryFaker` rather than as the underlying type, because the
5
+ * point of the wrapper is that it is a different shape - a caller typed against
6
+ * ts-faker would be told `helpers.arrayElement` does not exist, which is the
7
+ * error this module exists to remove.
8
+ */
9
+ export declare function createFakerCompatLayer(underlying: Record<string, any>): FactoryFaker;
10
+ /**
11
+ * The faker a factory is actually handed.
12
+ *
13
+ * Model factories in this ecosystem are written in the faker-js dialect - it is
14
+ * what every example, every scaffolded model and a decade of muscle memory
15
+ * produce:
16
+ *
17
+ * ```ts
18
+ * factory: faker => faker.helpers.arrayElement(['draft', 'published']),
19
+ * factory: faker => faker.string.alphanumeric(12),
20
+ * factory: faker => faker.datatype.number({ min: 1, max: 10 }),
21
+ * ```
22
+ *
23
+ * `@stacksjs/ts-faker` is a different, smaller surface: no `helpers.arrayElement`,
24
+ * no `datatype`, `address` rather than `location`, `catchphrase` rather than
25
+ * `catchPhrase`, and options objects where faker-js takes a bare number. Handing
26
+ * a factory the raw instance means `arrayElement is not a function` at seed
27
+ * time - and it is a *runtime* failure in the one code path nobody runs until
28
+ * they are setting up a new environment.
29
+ *
30
+ * So this module adapts one to the other, and exports the adapted shape as a
31
+ * type. Both halves matter: without the proxy the calls throw, and without the
32
+ * type every one of those factories is a type error in a codebase that
33
+ * typechecks.
34
+ *
35
+ * **Everything here is a translation, never an invention.** Where ts-faker has
36
+ * no equivalent at all the method is built from what it does have (a slug from
37
+ * `lorem.slug`, a registration from `vehicle.registration`), because a factory
38
+ * that returns a plausible wrong-shaped string is better than a seeder that
39
+ * stops.
40
+ */
41
+ /** What faker-js calls a string generator's options, and what ts-faker wants. */
42
+ export declare interface CompatStringOptions {
43
+ length?: number
44
+ casing?: 'upper' | 'lower' | 'mixed'
45
+ }
46
+ /** What faker-js passes to a number generator. */
47
+ export declare interface CompatNumberOptions {
48
+ min?: number
49
+ max?: number
50
+ fractionDigits?: number
51
+ multipleOf?: number
52
+ }
53
+ /**
54
+ * The faker-js-shaped surface a factory receives.
55
+ *
56
+ * Deliberately loose on the modules this file does not translate: they are
57
+ * forwarded to ts-faker untouched, and describing them here would be a second
58
+ * copy of ts-faker's own types that goes stale on its next release. What is
59
+ * spelled out is exactly what the compat layer adds or changes.
60
+ */
61
+ export declare interface FactoryFaker {
62
+ [module: string]: any
63
+ location: Record<string, (...args: any[]) => any>
64
+ datatype: {
65
+ boolean: (options?: number | { probability?: number }) => boolean
66
+ number: (options?: number | CompatNumberOptions) => number
67
+ float: (options?: CompatNumberOptions) => number
68
+ uuid: () => string
69
+ string: (length?: number) => string
70
+ hexadecimal: (options?: number | CompatStringOptions) => string
71
+ array: (length?: number) => unknown[]
72
+ json: () => string
73
+ }
74
+ helpers: {
75
+ arrayElement: <T>(items: readonly T[]) => T
76
+ arrayElements: <T>(items: readonly T[], count?: number) => T[]
77
+ shuffle: <T>(items: readonly T[]) => T[]
78
+ maybe: <T>(produce: () => T, options?: { probability?: number }) => T | undefined
79
+ slugify: (text: string) => string
80
+ replaceSymbols: (pattern: string) => string
81
+ [method: string]: any
82
+ }
83
+ }
package/dist/index.d.ts CHANGED
@@ -35,6 +35,7 @@ export * from './dynamodb-single-table';
35
35
  export * from './dynamodb-tooling-adapter';
36
36
  export * from './dynamodb/index';
37
37
  export * from './factory';
38
+ export * from './faker-compat';
38
39
  export * from './inflect';
39
40
  export * from './loader';
40
41
  export * from './meta';
package/dist/orm.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Database, type SQLQueryBindings } from 'bun:sqlite';
2
- import type { Faker } from '@stacksjs/ts-faker';
2
+ import type { FactoryFaker } from './faker-compat';
3
3
  import type { RelationCardinality } from './type-inference';
4
4
  import type { SupportedDialect } from './types';
5
5
  export type {
@@ -56,7 +56,7 @@ export declare interface TypedAttribute<T = unknown> {
56
56
  rule: unknown
57
57
  message?: Record<string, string>
58
58
  }
59
- factory?: (faker: Faker) => InferType<T>
59
+ factory?: (faker: FactoryFaker) => InferType<T>
60
60
  }
61
61
  /** Structural type for model instances passed to lifecycle hooks. */
62
62
  // eslint-disable-next-line ts/no-empty-object-type
@@ -228,14 +228,16 @@ declare type PrimitiveTypeMap = {
228
228
  declare type InferType<T> = T extends keyof PrimitiveTypeMap ? PrimitiveTypeMap[T] :
229
229
  T extends readonly (infer U)[] ? U :
230
230
  T extends (infer U)[] ? U :
231
- T extends { validate: (value: infer U) => unknown } ? U :
232
- T extends { test: (value: infer U) => unknown } ? U :
233
- unknown;
231
+ T extends { getShape: () => infer TShape extends Readonly<Record<string, unknown>> }
232
+ ? { -readonly [TKey in keyof TShape]: InferType<TShape[TKey]> }
233
+ : T extends { test: (value: infer U) => unknown } ? U :
234
+ T extends { validate: (value: infer U) => unknown } ? U :
235
+ unknown;
234
236
  // Extract attribute keys from definition
235
237
  declare type AttributeKeys<TDef extends ModelDefinition> = keyof TDef['attributes'] & string;
236
238
  // Infer single attribute type
237
239
  declare type InferAttributeType<TAttr> = TAttr extends { type: infer T } ? InferType<T> :
238
- TAttr extends { factory: (faker: Faker) => infer R }
240
+ TAttr extends { factory: (faker: FactoryFaker) => infer R }
239
241
  ? [Exclude<R, null | undefined>] extends [never]
240
242
  ? TAttr extends { validation: { rule: infer V } } ? InferType<V> | Extract<R, null | undefined> : R
241
243
  : R
@@ -370,25 +372,35 @@ declare type NumericColumns<TDef extends ModelDefinition> = {
370
372
  * and would otherwise leak its own keys ('length', indices, ...) into the
371
373
  * relation-name union.
372
374
  */
373
- declare type RelationKeyOf<V> = V extends readonly (infer E)[]
374
- ? E extends string ? Lowercase<E>
375
- : E extends { model: infer M extends string } ? Lowercase<M>
376
- : never
377
- : V extends Readonly<Record<infer K, unknown>>
378
- ? K & string
379
- : never;
375
+ declare type RelationKeyOf<V> = V extends string
376
+ ? Lowercase<V>
377
+ : V extends readonly (infer E)[]
378
+ ? E extends string ? Lowercase<E>
379
+ : E extends { model: infer M extends string } ? Lowercase<M>
380
+ : never
381
+ : V extends Readonly<Record<infer K, unknown>>
382
+ ? K & string
383
+ : never;
380
384
  declare type InferBelongsToNames<TDef> = TDef extends { belongsTo: infer V } ? RelationKeyOf<V> : never;
381
385
  declare type InferHasManyNames<TDef> = TDef extends { hasMany: infer V } ? RelationKeyOf<V> : never;
382
386
  declare type InferHasOneNames<TDef> = TDef extends { hasOne: infer V } ? RelationKeyOf<V> : never;
383
387
  declare type InferBelongsToManyNames<TDef> = TDef extends { belongsToMany: infer V } ? RelationKeyOf<V> : never;
384
388
  declare type InferHasOneThroughNames<TDef> = TDef extends { hasOneThrough: infer V } ? RelationKeyOf<V> : never;
385
389
  declare type InferHasManyThroughNames<TDef> = TDef extends { hasManyThrough: infer V } ? RelationKeyOf<V> : never;
390
+ declare type InferMorphOneNames<TDef> = TDef extends { morphOne: infer V } ? RelationKeyOf<V> : never;
391
+ declare type InferMorphManyNames<TDef> = TDef extends { morphMany: infer V } ? RelationKeyOf<V> : never;
392
+ declare type InferMorphToManyNames<TDef> = TDef extends { morphToMany: infer V } ? RelationKeyOf<V> : never;
393
+ declare type InferMorphedByManyNames<TDef> = TDef extends { morphedByMany: infer V } ? RelationKeyOf<V> : never;
386
394
  export type InferRelationNames<TDef> = | InferBelongsToNames<TDef>
387
395
  | InferHasManyNames<TDef>
388
396
  | InferHasOneNames<TDef>
389
397
  | InferBelongsToManyNames<TDef>
390
398
  | InferHasOneThroughNames<TDef>
391
- | InferHasManyThroughNames<TDef>;
399
+ | InferHasManyThroughNames<TDef>
400
+ | InferMorphOneNames<TDef>
401
+ | InferMorphManyNames<TDef>
402
+ | InferMorphToManyNames<TDef>
403
+ | InferMorphedByManyNames<TDef>;
392
404
  /**
393
405
  * Cardinality-aware value of a loaded relation as returned by
394
406
  * `ModelInstance.getRelation()`. Relations declared as to-many (hasMany,
package/dist/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Faker } from '@stacksjs/ts-faker';
1
+ import type { FactoryFaker } from './faker-compat';
2
2
  /**
3
3
  * # `defineModel(model)`
4
4
  *
@@ -62,7 +62,7 @@ export declare interface Attribute {
62
62
  fillable?: boolean
63
63
  guarded?: boolean
64
64
  foreignKey?: boolean | ForeignKeyConfig
65
- factory?: (faker: Faker) => unknown
65
+ factory?: (faker: FactoryFaker) => unknown
66
66
  validation: {
67
67
  rule: ValidationType
68
68
  message?: ValidatorMessage
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Render a WHERE body (without the `WHERE` keyword) from an ordered term list.
3
+ *
4
+ * Each MAXIMAL RUN of `OR` terms is bracketed together with the term that opens
5
+ * it, so a chain groups the way it reads:
6
+ *
7
+ * .where(a).where(b).orWhere(c) -> a AND (b OR c)
8
+ * .where(a).orWhere(b).where(c) -> (a OR b) AND c
9
+ *
10
+ * In effect `OR` binds TIGHTER than `AND` in chain order — the inverse of raw
11
+ * SQL. That is a deliberate choice for a fluent builder, and it is already what
12
+ * `whereAny`/`whereAll`/`whereNone` and the ORM's `whereGroup` do; `orWhere`
13
+ * was the odd one out. Previously the terms were concatenated as flat text and
14
+ * SQL's precedence re-associated `a AND b OR c` to `(a AND b) OR c`, so the
15
+ * first filter stopped applying to any row the `OR` matched — silently, and in
16
+ * the direction that returns MORE rows.
17
+ *
18
+ * The brackets are omitted when the body has a single top-level piece, so a
19
+ * plain two-term `.where(a).orWhere(b)` and any all-`AND` chain still render
20
+ * byte-for-byte as before. The escape hatch for the one shape this rule can no
21
+ * longer express directly — `(a AND b) OR c` — is `whereGroup(cb)`.
22
+ */
23
+ export declare function renderWhereTerms(terms: readonly WhereTerm[]): string;
24
+ /**
25
+ * Render `col IN (…)` / `col NOT IN (…)`, including the empty case.
26
+ *
27
+ * An empty `IN` is FALSE (nothing is a member of the empty set) and an empty
28
+ * `NOT IN` is TRUE (everything is a non-member). Those constants are not
29
+ * interchangeable and the mirror is easy to get backwards: writing FALSE for
30
+ * `NOT IN` would silently drop every row from any query whose exclusion list
31
+ * happened to come back empty — the same shape of silent, widening-or-narrowing
32
+ * failure as the `IN ()` bug itself.
33
+ */
34
+ export declare function renderInPredicate(column: string, values: any[], negated: boolean, placeholders: string): string;
35
+ /**
36
+ * Constant predicates, for the cases where a collection is empty.
37
+ *
38
+ * `1 = 0` and `1 = 1` take no parameters and parse identically on SQLite,
39
+ * Postgres and MySQL, which is the point: the alternatives are engine-specific.
40
+ * `IN ()` is the example that motivated these — SQLite parses it and matches
41
+ * nothing, while Postgres and MySQL reject it as a syntax error, so the same
42
+ * call site behaved differently depending on where it ran.
43
+ */
44
+ export declare const FALSE_PREDICATE: '1 = 0';
45
+ export declare const TRUE_PREDICATE: '1 = 1';
46
+ /**
47
+ * SQL fragment renderers shared by the select builder (`client.ts`) and the ORM
48
+ * query builder (`orm.ts`).
49
+ *
50
+ * They live here rather than in either builder because the two had independent
51
+ * copies of the same defect: both joined their WHERE terms as flat text, so
52
+ * `orWhere` produced an ungrouped `OR` and SQL's native precedence silently
53
+ * re-associated the chain. Two implementations of one rule is how they drifted;
54
+ * one implementation is how they stop.
55
+ *
56
+ * See stacksjs/bun-query-builder#1083.
57
+ */
58
+ /**
59
+ * A single WHERE predicate plus the connector the CALLER asked for.
60
+ *
61
+ * The connector belongs to the term rather than sitting between terms because
62
+ * the first term's connector is meaningless — nothing precedes it — and
63
+ * carrying it anyway is what lets a leading `.orWhere(x)` render as `WHERE x`
64
+ * instead of the `FROM t OR x` syntax error it used to emit.
65
+ */
66
+ export declare interface WhereTerm {
67
+ conn: 'AND' | 'OR'
68
+ sql: string
69
+ }