Skip to main content

stacks-query-builder

Use when building database queries in a Stacks application - constructing SQL queries, using the fluent query API, or configuring the query builder. Covers @stacksjs/query-builder which wraps bun-query-builder, and config/query-builder.ts.

来源信息

仓库
stacksjs/stacks
最近来源活动
2026年10月10日 17:01
检测到的 SKILL.md 语言
英语
星标
633
Forks
20

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
stacks-query-builder
description
Use when building database queries in a Stacks application - constructing SQL queries, using the fluent query API, or configuring the query builder. Covers @stacksjs/query-builder which wraps bun-query-builder, and config/query-builder.ts.
license
MIT
compatibility
Bun >= 1.3.0, TypeScript, SQLite >= 3.47.2
allowed-tools
Read Edit Write Bash Grep Glob
# Stacks Query Builder ## Key Paths - Core package: `storage/framework/core/query-builder/src/` - Configuration: `config/query-builder.ts` - Migration snapshot: `storage/framework/database/model-snapshot.<dialect>.json` - External library: `bun-query-builder` - Package: `@stacksjs/query-builder` ## API The package wraps `bun-query-builder`, preserves its fluent surface, and adds Stacks configuration, persistent query hooks, SQLite bootstrap behavior, and identifier/operator validation. The `QueryBuilder` compatibility alias remains: ```typescript export * from 'bun-query-builder' export { createQueryBuilder as QueryBuilder } from 'bun-query-builder' ``` ## Usage ```typescript import { db } from '@stacksjs/database/runtime' // Select const users = await db.selectFrom('users') .where('active', '=', true) .orderBy('name', 'asc') .limit(10) .get() // Insert await db.insertInto('users') .values({ name: 'Alice', email: 'alice@example.com' }) .execute() // Update await db.update('users') .set({ active: false }) .where('id', '=', 1) .execute() // Delete await db.deleteFrom('users') .where('id', '=', 1) .execute() // Joins const posts = await db.selectFrom('posts') .join('users', 'posts.user_id', '=', 'users.id') .select(['posts.*', 'users.name as author_name']) .get() // Aggregates const count = await db.selectFrom('users').count() const total = await db.selectFrom('orders').sum('amount') ``` Production SQLite uses a compact deferred builder for the common `select().where().limit().execute()` chain when no query hooks or global soft-delete scope is active. Complex methods and arguments automatically replay onto the complete upstream builder. Use the normal API in either case; do not fork application code into a separate raw-query path for this optimization. ## Configuration (config/query-builder.ts) ```typescript { verbose: true, dialect: env.DB_CONNECTION || 'sqlite', database: { database, username?, password?, host?, port? }, snapshotDir: 'storage/framework/database', timestamps: { createdAt: 'created_at', updatedAt: 'updated_at', defaultOrderColumn: 'created_at', }, pagination: { defaultPerPage: 25, cursorColumn: 'id', }, aliasing: { relationColumnAliasFormat: 'table_column', }, relations: { foreignKeyFormat: 'singularParent_id', maxDepth: 10, maxEagerLoad: 50, detectCycles: true, }, transactionDefaults: { retries: 2, isolation: 'read committed', sqlStates: ['40001', '40P01'], backoff: { baseMs: 50, factor: 2, maxMs: 2000, jitter: true }, }, sql: { randomFunction: 'RANDOM()', sharedLockSyntax: 'FOR SHARE', jsonContainsMode: 'operator', }, features: { distinctOn: true }, debug: { captureText: true }, softDeletes: { enabled: false, column: 'deleted_at', defaultFilter: true, }, } ``` ## Gotchas - **Wrapped surface** - use `assertSafeIdentifier`, `assertSafeOperator`, and allowlists when a request influences column, table, ordering or operator names. Parameter binding protects values, not arbitrary SQL identifiers. - **One config file** — `config/query-builder.ts`. Its `dialect` and connection details are derived from `DB_CONNECTION` and the other `DB_*` env vars, so switching databases is an env change, not a config edit - **One committed snapshot** - Stacks config directs migration state to `storage/framework/database`; a second `.qb` snapshot indicates the wrong configuration. - **Prefer ORM models** — query builder is the low-level interface; use models for most operations - **`db` proxy** — the `db` export from `@stacksjs/database` is a lazy proxy that auto-initializes the query builder on first access - **Soft deletes disabled by default** — must be explicitly enabled in config - **Transaction retries** — defaults to 2 retries with exponential backoff + jitter - **Dialect detection** — reads `DB_CONNECTION` env var, falls back to `sqlite` - **Turso/libSQL** - uses SQLite SQL with a remote transport selected by the libSQL URL and credentials. Vitess maps to MySQL wire SQL with distinct DDL and transaction constraints. Read the driver capability registry. - **Raw versus model queries** - raw `db` has no model definition and cannot infer ownership, hidden fields, per-model casts, encryption or soft-delete traits. - **After commit** - `@stacksjs/database/runtime` exposes the native transaction scope helpers; deferring side effects does not rebind model executors to `tx`. Source: `core/query-builder/src/index.ts`, `config/query-builder.ts`, and the database runtime, query-hook, pragma, identifier and transaction tests.
在 GitHub 查看