bun-query-builder 0.1.9 → 0.1.11

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,27 @@
1
+ export type { BrowserModelDefinition as ModelDefinition };
2
+ /**
3
+ * Define an isomorphic model that works in both server and browser.
4
+ *
5
+ * In the browser, this creates a model that uses fetch() to call your API.
6
+ * On the server, this returns the definition for ORM generation AND provides
7
+ * query methods that work directly with the database.
8
+ *
9
+ * @param definition - The model definition
10
+ * @returns An isomorphic model with query methods
11
+ */
12
+ export declare function defineModel<const TDef extends BrowserModelDefinition>(definition: TDef): void;
13
+ /**
14
+ * Register models on the global window.StacksBrowser object.
15
+ * Call this in your app's entry point to make models available for STX auto-imports.
16
+ *
17
+ * @param models - Object mapping model names to model instances
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import Trail from './Models/Trail'
22
+ * import Activity from './Models/Activity'
23
+ *
24
+ * registerBrowserModels({ Trail, Activity })
25
+ * ```
26
+ */
27
+ export declare function registerBrowserModels(models: Record<string, unknown>): void;
package/dist/orm.d.ts ADDED
@@ -0,0 +1,172 @@
1
+ import { Database } from 'bun:sqlite';
2
+ export type { ModelInstance, ModelQueryBuilder };
3
+ export declare function configureOrm(options: { database?: string | Database; verbose?: boolean }): void;
4
+ export declare function getDatabase(): Database;
5
+ /**
6
+ * Create a model class from a definition with full type inference
7
+ */
8
+ export declare function createModel<const TDef extends ModelDefinition>(definition: TDef): void;
9
+ export declare function createTableFromModel(definition: ModelDefinition): void;
10
+ export declare function seedModel(definition: ModelDefinition, count?: number, faker?: any): Promise<void>;
11
+ // Attribute definition with explicit type
12
+ export declare interface TypedAttribute<T = unknown> {
13
+ type?: T
14
+ order?: number
15
+ fillable?: boolean
16
+ unique?: boolean
17
+ hidden?: boolean
18
+ guarded?: boolean
19
+ nullable?: boolean
20
+ default?: InferType<T>
21
+ validation?: {
22
+ rule: unknown
23
+ message?: Record<string, string>
24
+ }
25
+ factory?: (faker: unknown) => InferType<T>
26
+ }
27
+ // Base model definition
28
+ export declare interface ModelDefinition {
29
+ name: string
30
+ table: string
31
+ primaryKey?: string
32
+ autoIncrement?: boolean
33
+ connection?: string
34
+ traits?: {
35
+ readonly useUuid?: boolean
36
+ readonly useTimestamps?: boolean
37
+ readonly useSoftDeletes?: boolean
38
+ readonly useSearch?: {
39
+ readonly displayable?: readonly string[]
40
+ readonly searchable?: readonly string[]
41
+ readonly sortable?: readonly string[]
42
+ readonly filterable?: readonly string[]
43
+ }
44
+ readonly useSeeder?: {
45
+ readonly count: number
46
+ }
47
+ readonly useApi?: {
48
+ readonly uri: string
49
+ readonly routes: readonly string[]
50
+ }
51
+ }
52
+ belongsTo?: readonly string[]
53
+ hasMany?: readonly string[]
54
+ hasOne?: readonly string[]
55
+ attributes: {
56
+ readonly [key: string]: TypedAttribute<unknown>
57
+ }
58
+ get?: Record<string, (attributes: Record<string, unknown>) => unknown>
59
+ set?: Record<string, (attributes: Record<string, unknown>) => unknown>
60
+ }
61
+ // Binding helper type for SQL queries
62
+ declare type Bindings = SQLQueryBindings[]
63
+ // Primitive type mappings
64
+ declare type PrimitiveTypeMap = {
65
+ string: string
66
+ number: number
67
+ boolean: boolean
68
+ date: Date
69
+ json: Record<string, unknown>
70
+ }
71
+ // Infer the actual TS type from attribute type definition
72
+ declare type InferType<T> = T extends keyof PrimitiveTypeMap ? PrimitiveTypeMap[T] :
73
+ T extends readonly (infer U)[] ? U :
74
+ T extends (infer U)[] ? U :
75
+ unknown
76
+ // Extract attribute keys from definition
77
+ declare type AttributeKeys<TDef extends ModelDefinition> = keyof TDef['attributes'] & string
78
+ // Infer single attribute type
79
+ declare type InferAttributeType<TAttr> = TAttr extends { type: infer T } ? InferType<T> :
80
+ TAttr extends { factory: (faker: unknown) => infer R } ? R :
81
+ unknown
82
+ // Build the full attributes type from definition
83
+ declare type InferModelAttributes<TDef extends ModelDefinition> = {
84
+ [K in AttributeKeys<TDef>]: InferAttributeType<TDef['attributes'][K]>
85
+ }
86
+ // System fields added by traits
87
+ declare type SystemFields<TDef extends ModelDefinition> = { id: number } &
88
+ (TDef['traits'] extends { useUuid: true } ? { uuid: string } : {}) &
89
+ (TDef['traits'] extends { useTimestamps: true } ? { created_at: string; updated_at: string } : {}) &
90
+ (TDef['traits'] extends { useSoftDeletes: true } ? { deleted_at: string | null } : {})
91
+ // Complete model type
92
+ declare type ModelAttributes<TDef extends ModelDefinition> = InferModelAttributes<TDef> & SystemFields<TDef>
93
+ // All valid column names
94
+ declare type ColumnName<TDef extends ModelDefinition> = | AttributeKeys<TDef>
95
+ | 'id'
96
+ | (TDef['traits'] extends { useUuid: true } ? 'uuid' : never)
97
+ | (TDef['traits'] extends { useTimestamps: true } ? 'created_at' | 'updated_at' : never)
98
+ | (TDef['traits'] extends { useSoftDeletes: true } ? 'deleted_at' : never)
99
+ // Hidden fields
100
+ declare type HiddenKeys<TDef extends ModelDefinition> = {
101
+ [K in AttributeKeys<TDef>]: TDef['attributes'][K] extends { hidden: true } ? K : never
102
+ }[AttributeKeys<TDef>]
103
+ // Fillable fields
104
+ declare type FillableKeys<TDef extends ModelDefinition> = {
105
+ [K in AttributeKeys<TDef>]: TDef['attributes'][K] extends { fillable: true } ? K : never
106
+ }[AttributeKeys<TDef>]
107
+ declare type WhereOperator = '=' | '!=' | '<' | '>' | '<=' | '>=' | 'like' | 'in' | 'not in'
108
+ /**
109
+ * Model instance - represents a single database record
110
+ */
111
+ declare class ModelInstance<TDef extends ModelDefinition, TSelected extends ColumnName<TDef> = ColumnName<TDef>> {
112
+ private _attributes: Record<string, unknown>;
113
+ private _original: Record<string, unknown>;
114
+ private _definition: TDef;
115
+ private _hasSaved: any;
116
+ constructor(definition: TDef, attributes?: Partial<ModelAttributes<TDef>>);
117
+ get<K extends TSelected>(key: K): K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : never;
118
+ set<K extends AttributeKeys<TDef>>(key: K, value: ModelAttributes<TDef>[K]): void;
119
+ isDirty<K extends AttributeKeys<TDef>>(column?: K): boolean;
120
+ isClean<K extends AttributeKeys<TDef>>(column?: K): boolean;
121
+ getOriginal<K extends AttributeKeys<TDef>>(column: K): ModelAttributes<TDef>[K];
122
+ getChanges(): Partial<InferModelAttributes<TDef>>;
123
+ fill(data: Partial<Pick<InferModelAttributes<TDef>, FillableKeys<TDef>>>): this;
124
+ forceFill(data: Partial<InferModelAttributes<TDef>>): this;
125
+ save(): this;
126
+ update(data: Partial<Pick<InferModelAttributes<TDef>, FillableKeys<TDef>>>): this;
127
+ delete(): boolean;
128
+ refresh(): this;
129
+ toJSON(): Omit<Pick<ModelAttributes<TDef>, TSelected & keyof ModelAttributes<TDef>>, HiddenKeys<TDef>>;
130
+ }
131
+ /**
132
+ * Query builder with precise type narrowing
133
+ */
134
+ declare class ModelQueryBuilder<TDef extends ModelDefinition, TSelected extends ColumnName<TDef> = ColumnName<TDef>> {
135
+ private _definition: TDef;
136
+ private _wheres: { column: string; operator: WhereOperator; value: unknown; boolean: 'and' | 'or' }[];
137
+ private _orderBy: { column: string; direction: 'asc' | 'desc' }[];
138
+ private _limit?: number;
139
+ private _offset?: number;
140
+ private _select: string[];
141
+ constructor(definition: TDef);
142
+ where<K extends ColumnName<TDef>>(column: K, operatorOrValue: WhereOperator | (K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown), value?: K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown): ModelQueryBuilder<TDef, TSelected>;
143
+ orWhere<K extends ColumnName<TDef>>(column: K, operatorOrValue: WhereOperator | (K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown), value?: K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown): ModelQueryBuilder<TDef, TSelected>;
144
+ whereIn<K extends ColumnName<TDef>>(column: K, values: (K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown)[]): ModelQueryBuilder<TDef, TSelected>;
145
+ whereNotIn<K extends ColumnName<TDef>>(column: K, values: (K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown)[]): ModelQueryBuilder<TDef, TSelected>;
146
+ whereNull<K extends ColumnName<TDef>>(column: K): ModelQueryBuilder<TDef, TSelected>;
147
+ whereNotNull<K extends ColumnName<TDef>>(column: K): ModelQueryBuilder<TDef, TSelected>;
148
+ whereLike<K extends ColumnName<TDef>>(column: K, pattern: string): ModelQueryBuilder<TDef, TSelected>;
149
+ orderBy<K extends ColumnName<TDef>>(column: K, direction?: 'asc' | 'desc'): ModelQueryBuilder<TDef, TSelected>;
150
+ orderByDesc<K extends ColumnName<TDef>>(column: K): ModelQueryBuilder<TDef, TSelected>;
151
+ orderByAsc<K extends ColumnName<TDef>>(column: K): ModelQueryBuilder<TDef, TSelected>;
152
+ limit(count: number): ModelQueryBuilder<TDef, TSelected>;
153
+ take(count: number): ModelQueryBuilder<TDef, TSelected>;
154
+ offset(count: number): ModelQueryBuilder<TDef, TSelected>;
155
+ skip(count: number): ModelQueryBuilder<TDef, TSelected>;
156
+ select<K extends ColumnName<TDef>>(columns: K[]): ModelQueryBuilder<TDef, K>;
157
+ private buildQuery(): { sql: string; params: unknown[] };
158
+ get(): ModelInstance<TDef, TSelected>[];
159
+ first(): ModelInstance<TDef, TSelected> | undefined;
160
+ firstOrFail(): ModelInstance<TDef, TSelected>;
161
+ last(): ModelInstance<TDef, TSelected> | undefined;
162
+ count(): number;
163
+ exists(): boolean;
164
+ paginate(page?: any, perPage?: any): void;
165
+ pluck<K extends ColumnName<TDef>>(column: K): (K extends keyof ModelAttributes<TDef> ? ModelAttributes<TDef>[K] : unknown)[];
166
+ max<K extends AttributeKeys<TDef>>(column: K): number;
167
+ min<K extends AttributeKeys<TDef>>(column: K): number;
168
+ avg<K extends AttributeKeys<TDef>>(column: K): number;
169
+ sum<K extends AttributeKeys<TDef>>(column: K): number;
170
+ delete(): number;
171
+ update(data: Partial<Pick<InferModelAttributes<TDef>, FillableKeys<TDef>>>): number;
172
+ }
package/dist/types.d.ts CHANGED
@@ -151,6 +151,21 @@ export declare interface DatabaseConfig {
151
151
  url?: string
152
152
  port: number
153
153
  }
154
+ /**
155
+ * # `BrowserConfig`
156
+ *
157
+ * Configuration for browser mode that uses fetch() API instead of direct database connections.
158
+ * This enables the query builder to work in browser environments by translating queries to REST API calls.
159
+ */
160
+ export declare interface BrowserConfig {
161
+ baseUrl: string
162
+ getToken?: () => string | null | Promise<string | null>
163
+ onUnauthorized?: () => void
164
+ headers?: Record<string, string>
165
+ timeout?: number
166
+ transformResponse?: <T>(response: any) => T
167
+ transformRequest?: <T>(data: T) => any
168
+ }
154
169
  /**
155
170
  * # `QueryBuilderConfig`
156
171
  *
@@ -171,6 +186,7 @@ export declare interface QueryBuilderConfig {
171
186
  verbose: boolean
172
187
  dialect: SupportedDialect
173
188
  database: DatabaseConfig
189
+ browser?: BrowserConfig
174
190
  timestamps: TimestampConfig
175
191
  pagination: PaginationConfig
176
192
  aliasing: AliasingConfig
@@ -230,5 +246,6 @@ export declare interface UnsafeOptions {
230
246
  * - 'postgres': Uses `RANDOM()`, supports JSON operators (e.g. `@>`), `FOR SHARE`, `FOR UPDATE`, CTEs
231
247
  * - 'mysql': Uses `RAND()`, shared locks via `LOCK IN SHARE MODE`
232
248
  * - 'sqlite': Lightweight engine; some features are limited or emulated
249
+ * - 'browser': Browser-compatible mode that uses fetch() API calls instead of direct database connections
233
250
  */
234
- export type SupportedDialect = 'postgres' | 'mysql' | 'sqlite'
251
+ 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.9",
4
+ "version": "0.1.11",
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",
@@ -21,10 +21,22 @@
21
21
  ],
22
22
  "exports": {
23
23
  ".": {
24
+ "bun": "./src/index.ts",
24
25
  "types": "./dist/index.d.ts",
25
26
  "import": "./dist/index.js"
26
27
  },
28
+ "./browser": {
29
+ "bun": "./src/browser.ts",
30
+ "types": "./dist/browser.d.ts",
31
+ "import": "./dist/browser.js"
32
+ },
33
+ "./dynamodb": {
34
+ "bun": "./src/dynamodb/index.ts",
35
+ "types": "./dist/dynamodb/index.d.ts",
36
+ "import": "./dist/dynamodb/index.js"
37
+ },
27
38
  "./*": {
39
+ "bun": "./src/*",
28
40
  "import": "./dist/*"
29
41
  }
30
42
  },
@@ -58,8 +70,8 @@
58
70
  "fresh": "bunx rimraf node_modules/ bun.lock && bun i",
59
71
  "prepublishOnly": "bun --bun run build && bun run compile:all && bun run zip",
60
72
  "test": "bun test",
61
- "lint": "bunx --bun eslint .",
62
- "lint:fix": "bunx --bun eslint . --fix",
73
+ "lint": "bunx --bun pickier lint .",
74
+ "lint:fix": "bunx --bun pickier lint . --fix",
63
75
  "changelog": "bunx logsmith --verbose",
64
76
  "changelog:generate": "bunx logsmith --output CHANGELOG.md",
65
77
  "release": "bun --bun run changelog:generate && bunx --bun bumpx prompt --recursive",
@@ -70,7 +82,8 @@
70
82
  },
71
83
  "dependencies": {
72
84
  "@stacksjs/clapp": "^0.2.0",
73
- "@stacksjs/ts-validation": "^0.4.7",
85
+ "@stacksjs/ts-validation": "^0.4.9",
86
+ "dynamodb-tooling": "^0.3.2",
74
87
  "ts-mocker": "^0.1.5"
75
88
  },
76
89
  "devDependencies": {
@@ -82,7 +95,7 @@
82
95
  "git-hooks": {
83
96
  "pre-commit": {
84
97
  "staged-lint": {
85
- "*.{js,ts,json,yaml,yml,md}": "bunx --bun eslint --fix"
98
+ "*.{js,ts,json,yaml,yml,md}": "bunx --bun pickier lint --fix"
86
99
  }
87
100
  },
88
101
  "commit-msg": "bunx gitlint --edit .git/COMMIT_EDITMSG"