@stacksjs/query-builder 0.70.166 → 0.70.167

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 (2) hide show
  1. package/dist/index.d.ts +132 -0
  2. package/package.json +4 -4
@@ -0,0 +1,132 @@
1
+ import { createQueryBuilder as createBunQueryBuilder } from 'bun-query-builder';
2
+ import * as bunQueryBuilder from 'bun-query-builder';
3
+ import type { DatabaseSchema } from 'bun-query-builder';
4
+ /**
5
+ * Apply the bootstrap pragmas to the connection of the CURRENT process-wide
6
+ * config. bun-query-builder's `qb.unsafe()` routes through its global
7
+ * lazily-resolved connection — NOT the instance's captured one — so this
8
+ * only targets `instance`'s connection when called in the same synchronous
9
+ * tick as `createQueryBuilder()`, before any intervening `setConfig()` can
10
+ * swap the signature-keyed singleton. The wrapped `createQueryBuilder`
11
+ * below guarantees that ordering structurally; standalone callers must
12
+ * preserve it themselves.
13
+ */
14
+ export declare function applySqlitePragmas(instance: { unsafe: (query: string, params?: any[]) => any }): void;
15
+ /**
16
+ * Bootstrap the MODEL-EXECUTOR connection — the raw `bun:sqlite` `Database`
17
+ * that `Model.create()/save()/delete()` (createModel → getExecutor) write
18
+ * through. Upstream creates it with `new Database(path)` and applies no
19
+ * pragmas whatsoever, so without this the ORM write path runs with
20
+ * `foreign_keys = OFF` (silent orphan rows) and default WAL checkpointing
21
+ * regardless of what the query-builder connection was bootstrapped with.
22
+ *
23
+ * `getDatabase()` returns the executor's live handle for the sqlite dialect
24
+ * (creating the executor if needed) and throws for mysql/postgres — where
25
+ * there is nothing to bootstrap, hence the silent catch. Safe to call
26
+ * repeatedly: the WeakSet makes it a no-op after the first hit per
27
+ * connection, and a config change that swaps the executor's Database
28
+ * produces a fresh (unseen) handle that gets bootstrapped on the next call.
29
+ */
30
+ export declare function bootstrapModelExecutorPragmas(): void;
31
+ /**
32
+ * Drop-in replacement for bun-query-builder's `configureOrm` that
33
+ * bootstraps the model-executor connection it (re)creates.
34
+ *
35
+ * This is the exact entry point `@stacksjs/orm` calls at import time
36
+ * (`autoConfigureOrm()`), which in production builds the raw `Database`
37
+ * every model write goes through — pre-fix, with no pragmas at all.
38
+ */
39
+ export declare function configureOrm(options: Parameters<typeof bunQueryBuilder.configureOrm>[0]): void;
40
+ /**
41
+ * Drop-in replacement for bun-query-builder's `createQueryBuilder` that
42
+ * bootstraps every fresh SQLite connection with the pragmas above.
43
+ *
44
+ * The upstream builder captures its connection eagerly at creation
45
+ * (`state?.sql ?? getOrCreateBunSql()`) and its `SQLiteWrapper` only sets
46
+ * `journal_mode = WAL` — never `foreign_keys` — so any instance created
47
+ * outside this wrapper runs with FK enforcement off. Applying in the same
48
+ * synchronous tick as creation pins the pragmas to the exact connection the
49
+ * instance captured (see `applySqlitePragmas`). Skipped when the caller
50
+ * supplies its own `state.sql` (reserved/transaction connections derive
51
+ * from an already-bootstrapped parent).
52
+ *
53
+ * Also re-asserts the model-executor bootstrap: framework entry points run
54
+ * through here on boot and on config reloads, so an executor Database that
55
+ * was lazily (re)created from a config change gets its pragmas without any
56
+ * caller having to know the two-connection topology.
57
+ */
58
+ export declare function createQueryBuilder<DB extends DatabaseSchema<any> = DatabaseSchema<any>>(state?: Parameters<typeof createBunQueryBuilder>[0]): ReturnType<typeof createBunQueryBuilder<DB>>;
59
+ /**
60
+ * Register a model with bun-query-builder when the installed version
61
+ * exposes that hook, or fall back to `defineModel()` for older releases.
62
+ */
63
+ export declare function registerModel(name: string, model: unknown): unknown;
64
+ /**
65
+ * Validate a single SQL identifier (column, table, or alias name).
66
+ *
67
+ * - Must match `SAFE_IDENTIFIER` (letters/digits/underscores; must
68
+ * start with letter or underscore).
69
+ * - Must be ≤ 64 characters (matches MySQL's identifier limit; the
70
+ * shortest cap across supported dialects).
71
+ * - When `allowlist` is provided, the value must appear in it. Use
72
+ * this with a model's known column names (`Object.keys(definition.attributes)`)
73
+ * so a query that builds column names from `req.query.sortBy` etc.
74
+ * can't smuggle anything past the schema.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { assertSafeIdentifier } from '@stacksjs/query-builder'
79
+ *
80
+ * const sortBy = req.query.sortBy as string
81
+ * assertSafeIdentifier(sortBy, { allowlist: ['name', 'email', 'created_at'] })
82
+ * Model.orderBy(sortBy as keyof Model)
83
+ * ```
84
+ */
85
+ export declare function validateIdentifier(value: unknown, opts?: { allowlist?: readonly string[] }): IdentifierValidation;
86
+ /**
87
+ * Throwing variant of {@link validateIdentifier}. Use at the boundary
88
+ * where user input meets SQL identifier interpolation.
89
+ *
90
+ * @throws {Error} when the value isn't a safe identifier.
91
+ */
92
+ export declare function assertSafeIdentifier(value: unknown, opts?: { allowlist?: readonly string[], context?: string }): asserts value is string;
93
+ export declare function isSafeOperator(op: unknown): op is string;
94
+ export declare function assertSafeOperator(op: unknown, context?: string): asserts op is string;
95
+ /**
96
+ * Per-connection SQLite bootstrap pragmas (stacksjs/stacks#1951).
97
+ * `foreign_keys` does not persist in the database file — SQLite ships with
98
+ * enforcement OFF on every new connection — so the inline
99
+ * `REFERENCES … ON DELETE CASCADE` emitted by migrations (#1916) is inert
100
+ * unless the connection bootstrap turns it on. bun-query-builder delegates
101
+ * this to the consumer, and it opens sqlite connections in TWO independent
102
+ * layers — both are bootstrapped here:
103
+ *
104
+ * 1. The query-builder connection (`getOrCreateBunSql` → `SQLiteWrapper`,
105
+ * which only sets `journal_mode = WAL`): covered by the wrapped
106
+ * `createQueryBuilder` below.
107
+ * 2. The MODEL-EXECUTOR connection (`configureOrm`/`getExecutor` → a raw
108
+ * `bun:sqlite` `Database` with NO pragmas at all) — the connection every
109
+ * `Model.create()/save()/delete()` actually writes through: covered by
110
+ * the wrapped `configureOrm` + `bootstrapModelExecutorPragmas` below.
111
+ * Pre-fix, production model writes ran with `foreign_keys = OFF` while
112
+ * the (idle) query-builder connection was correctly bootstrapped —
113
+ * confirmed on a live deploy via lsof (two connections) and WAL frames
114
+ * from ORM inserts never auto-checkpointing.
115
+ */
116
+ export declare const SQLITE_BOOTSTRAP_PRAGMAS: readonly [unknown, unknown, unknown, unknown];
117
+ /**
118
+ * Return value of `validateIdentifier` / `assertSafeIdentifier`.
119
+ */
120
+ export declare interface IdentifierValidation {
121
+ valid: boolean
122
+ reason?: 'invalid-shape' | 'not-in-allowlist' | 'empty' | 'too-long'
123
+ }
124
+ export type StacksDialect = import('bun-query-builder').SupportedDialect | 'singlestore';
125
+ // bun-query-builder types `unsafe()` as returning `Promise<any>`, but at
126
+ // runtime it returns a Bun SQL Statement that has `.execute()`.
127
+ declare type UnsafeReturn = Promise<any> & { execute: () => Promise<any> }
128
+ // Re-export everything from bun-query-builder
129
+ export * from 'bun-query-builder';
130
+ export { saveMigrationSnapshot } from 'bun-query-builder';
131
+ // For backwards compatibility, export QueryBuilder as an alias
132
+ export { createQueryBuilder as QueryBuilder };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/query-builder",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.166",
5
+ "version": "0.70.167",
6
6
  "description": "The Stacks Query Builder integration",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -51,11 +51,11 @@
51
51
  "prepublishOnly": "bun run build"
52
52
  },
53
53
  "devDependencies": {
54
- "@stacksjs/database": "0.70.166",
54
+ "@stacksjs/database": "0.70.167",
55
55
  "better-dx": "^0.2.17",
56
- "@stacksjs/types": "0.70.166"
56
+ "@stacksjs/types": "0.70.167"
57
57
  },
58
58
  "dependencies": {
59
- "bun-query-builder": "^0.1.56"
59
+ "bun-query-builder": "^0.1.58"
60
60
  }
61
61
  }