一键导入
hai-reldb
使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQL/DDL/CRUD/事务与分页操作;当需求涉及数据库访问、CRUD 仓库、事务处理、分页查询或 HaiReldbError 分支处理时使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQL/DDL/CRUD/事务与分页操作;当需求涉及数据库访问、CRUD 仓库、事务处理、分页查询或 HaiReldbError 分支处理时使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when: using @h-ai/ai, LLM calls, chat completion, tool calling, function calling, MCP server, streaming, memory management, context compression, summarization, token estimation, RAG, knowledge base, AI client, embeddings, reasoning, rerank, file parsing, speech recognition ASR, speech synthesis TTS, audio, A2A agent-to-agent. 使用 @h-ai/ai 进行 LLM 调用、工具定义、MCP 服务器、流式处理、记忆管理、上下文压缩、知识库、推理引擎、Rerank、文件解析、语音识别与合成、A2A 与会话持久化。
Use when: using @h-ai/ai for LLM calls, tools, MCP, streaming, memory/context, RAG, audio, A2A, or the AI client. 当需求涉及 AI 对话、工具、Audio、会话、知识库或 AI 客户端时使用。
Use when: creating or extending apps in hai-framework, adding routes, pages, API endpoints, service workspaces, mobile app, H5 app, admin console. 在 hai-framework 中创建或扩展应用或 API service workspace,包含路由、API 端点、typed contract、服务层与 UI 脚手架代码。
Use when: creating a new module, new package, scaffold, add sub-feature, add provider, create repository, module structure, tsup config, error codes, NotInitializedKit pattern. 在 hai-framework 中创建新模块(package)。
Use when: reviewing app code in hai-framework, auditing app quality, checking app conventions, reviewing routes, reviewing API service workspaces, app security, app i18n review. 对 hai-framework 应用层代码进行审查:路由安全 → 认证授权 → i18n → 组件使用 → API 端点 / service workspace → 服务层 → 性能。
Use when: reviewing code, code review, auditing module quality, checking hai-framework conventions, verifying HaiResult<T> usage, reviewing module structure, PR review, checking naming consistency, verifying NotInitializedKit pattern, auditing performance, security, distributed systems. 对 hai-framework 模块进行全维度代码审查:架构 → 命名 → 类型 → 注释 → 性能 → 分布式 → 安全 → 日志 → 测试 → 文档。
| name | hai-reldb |
| description | 使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQL/DDL/CRUD/事务与分页操作;当需求涉及数据库访问、CRUD 仓库、事务处理、分页查询或 HaiReldbError 分支处理时使用。 |
| 项目 | 契约 |
|---|---|
| 能力 | 使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQL/DDL/CRUD/事务与分页操作;当需求涉及数据库访问、CRUD 仓库、事务处理、分页查询或 HaiReldbError 分支处理时使用。 |
| 适用场景 | 当任务与 hai-reldb 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
@h-ai/reldb提供统一的数据库操作接口,支持 SQLite、PostgreSQL、MySQL,包含 DDL、SQL、CRUD 抽象、事务与分页。
⚠️ 服务端模块(Node.js only)。 浏览器端请通过
@h-ai/api-contract+@h-ai/serv暴露的 API 端点间接访问数据库。
reldb.crud.table 或 BaseReldbCrudRepository 构建数据仓库HaiReldbError 做错误分支处理# config/_db.yml
type: ${HAI_RELDB_TYPE:sqlite}
database: ${HAI_RELDB_DATABASE:./data/app.db}
# PostgreSQL/MySQL 额外字段:
# host: ${HAI_RELDB_HOST:localhost}
# port: ${HAI_RELDB_PORT:5432}
# user: ${HAI_RELDB_USER:postgres}
# password: ${HAI_RELDB_PASSWORD:}
operationLog:
read: false # query / get / queryPage
write: false # DDL, execute / batch, tx.begin / tx.commit / tx.rollback
maxLength: 1000
level: debug # info | debug | trace
operationLog 在 reldb provider-base 的 DML 操作层统一输出日志,不要在 reldb-main.ts、各 raw provider 或调用方重复包装。read 覆盖 query/get/queryPage,write 覆盖 DDL、execute/batch 与 tx.begin/commit/rollback,maxLength 用于截断序列化后的 SQL 参数和批量语句,level 默认 debug。
import { core } from '@h-ai/core'
import { reldb } from '@h-ai/reldb'
await reldb.init(core.config.get('db'))
// ... 使用数据库
await reldb.close()
reldb.config 返回的是脱敏后的配置快照;数据库密码与 URL 内嵌凭证会自动隐藏。
| 接口 | 用途 | 入口 |
|---|---|---|
| DDL | 建表/索引/字段变更 | reldb.ddl |
| SQL | 原始查询/执行/分页 | reldb.sql |
| CRUD | 通用增删改查 | reldb.crud.table(config) |
| 仓库 | 业务数据仓库封装 | extends BaseReldbCrudRepository |
| 事务 | 事务管理 | reldb.tx |
| 分页 | 分页参数与结果 | reldb.pagination |
| JSON | JSON 路径操作 | reldb.json |
reldb.ddl| 方法 | 签名 | 说明 |
|---|---|---|
createTable | (tableName, columns: TableDef, ifNotExists?: boolean) => HaiResult<void> | 建表(默认 IF NOT EXISTS) |
dropTable | (tableName, ifExists?: boolean) => HaiResult<void> | 删除表(默认 IF EXISTS) |
addColumn | (tableName, columnName, columnDef: ColumnDef) => HaiResult<void> | 添加列 |
dropColumn | (tableName, columnName) => HaiResult<void> | 删除列 |
renameTable | (oldName, newName) => HaiResult<void> | 重命名表 |
createIndex | (tableName, indexName, indexDef: IndexDef) => HaiResult<void> | 创建索引 |
dropIndex | (indexName, ifExists?: boolean) => HaiResult<void> | 删除索引 |
raw | (sql: string) => HaiResult<void> | 执行原始 DDL |
所有方法均返回
Promise<HaiResult<void>>,上表省略异步与错误类型。
TableDef(列名到列定义的映射):
const columns: TableDef = {
id: { type: 'INTEGER', primaryKey: true, autoIncrement: true },
name: { type: 'TEXT', notNull: true },
email: { type: 'TEXT', unique: true },
score: { type: 'REAL', defaultValue: 0 },
active: { type: 'BOOLEAN' },
metadata: { type: 'JSON' },
created_at: { type: 'TIMESTAMP' },
}
ColumnDef(列类型与约束):
interface ColumnDef {
type: 'TEXT' | 'INTEGER' | 'REAL' | 'BLOB' | 'BOOLEAN' | 'TIMESTAMP' | 'JSON'
primaryKey?: boolean
autoIncrement?: boolean
notNull?: boolean
unique?: boolean
defaultValue?: string | number | boolean | null
references?: { table: string, column: string, onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT' | 'NO ACTION', onUpdate?: '...' }
}
跨数据库类型映射:
| 类型 | SQLite | PostgreSQL | MySQL |
|---|---|---|---|
| TEXT | TEXT | TEXT | VARCHAR(255) |
| INTEGER | INTEGER | INTEGER/SERIAL | INT/BIGINT |
| REAL | REAL | DOUBLE PRECISION | DOUBLE |
| BLOB | BLOB | BYTEA | BLOB |
| BOOLEAN | INTEGER | BOOLEAN | TINYINT(1) |
| TIMESTAMP | INTEGER | TIMESTAMP | DATETIME |
| JSON | TEXT | JSONB | JSON |
MySQL 将 TEXT 映射为 VARCHAR(255) 以支持索引和 UNIQUE 约束。INTEGER + autoIncrement 在 MySQL 映射为 BIGINT。
reldb.sql| 方法 | 签名 | 说明 |
|---|---|---|
query | <T>(sql, params?) => HaiResult<T[]> | 查询返回多行 |
get | <T>(sql, params?) => HaiResult<T | null> | 查询返回单行 |
execute | (sql, params?) => HaiResult<ExecuteResult> | 执行写操作 |
batch | (statements: Array<{ sql, params? }>) => HaiResult<void> | 批量执行 |
queryPage | <T>(options: PaginationQueryOptions) => HaiResult<PaginatedResult> | 分页查询 |
所有方法均返回
Promise<HaiResult<T>>,上表省略异步与错误类型。
参数占位符统一使用 ?(PostgreSQL 的 $n 由 Provider 自动转换):
const result = await reldb.sql.query<User>(
'SELECT * FROM users WHERE status = ? AND age > ?',
['active', 18],
)
ExecuteResult:
interface ExecuteResult {
changes: number // 影响的行数
lastInsertRowid?: number | bigint // INSERT 时生效(PostgreSQL 不返回此字段)
}
分页查询:
const page = await reldb.sql.queryPage<User>({
sql: 'SELECT * FROM users WHERE status = ? ORDER BY id',
params: ['active'],
pagination: { page: 1, pageSize: 20 },
overrides: { maxPageSize: 100 }, // 可选:限制最大页大小
})
// page.data => { items, total, page, pageSize }
reldb.crud.table(config)通过配置创建单表 CRUD 仓库,免写 SQL:
const userCrud = reldb.crud.table<{ id: number, name: string, email: string }>({
table: 'users',
idColumn: 'id', // 主键列,默认 'id'
select: ['id', 'name', 'email'], // 查询列,默认 '*'
createColumns: ['name', 'email'], // 允许插入的列
updateColumns: ['name', 'email'], // 允许更新的列
})
返回的 ReldbCrudRepository 方法:
| 方法 | 签名 | 说明 |
|---|---|---|
create | (data, tx?) => HaiResult<ExecuteResult> | 创建单条 |
createMany | (items, tx?) => HaiResult<void> | 批量创建 |
findById | (id, tx?) => HaiResult<T | null> | 按 ID 查询 |
findAll | (options?, tx?) => HaiResult<T[]> | 条件查询 |
findPage | (options, tx?) => HaiResult<PaginatedResult<T>> | 分页查询 |
updateById | (id, data, tx?) => HaiResult<ExecuteResult> | 按 ID 更新 |
deleteById | (id, tx?) => HaiResult<ExecuteResult> | 按 ID 删除 |
count | (options?, tx?) => HaiResult<number> | 计数 |
exists | (options?, tx?) => HaiResult<boolean> | 条件是否存在 |
existsById | (id, tx?) => HaiResult<boolean> | ID 是否存在 |
所有方法均支持可选
tx事务参数。create/updateById中的data会根据createColumns/updateColumns白名单过滤列。
使用示例:
// 单条插入
const result = await userCrud.create({ name: '张三', email: 'test@example.com' })
// result.data → { changes: 1, lastInsertRowid: 1 }
// 批量插入
await userCrud.createMany([
{ name: '用户A', email: 'a@test.com' },
{ name: '用户B', email: 'b@test.com' },
])
// 主键查找
const user = await userCrud.findById(1)
// user.data → { id: 1, name: '张三', email: 'test@example.com' } | null
// 条件查询(where + params 占位符)
const actives = await userCrud.findAll({
where: 'name LIKE ?',
params: ['%张%'],
orderBy: 'id DESC',
limit: 10,
offset: 0,
})
// 分页查询
const page = await userCrud.findPage({
where: 'name LIKE ?',
params: ['%张%'],
orderBy: 'id DESC',
pagination: { page: 1, pageSize: 20 },
})
// page.data → { items: [...], total: 100, page: 1, pageSize: 20 }
// 更新 / 删除
await userCrud.updateById(1, { name: '新名字' })
await userCrud.deleteById(1)
// 计数 / 存在性
const total = await userCrud.count({ where: 'name LIKE ?', params: ['%张%'] })
const has = await userCrud.exists({ where: 'email = ?', params: ['test@example.com'] })
const found = await userCrud.existsById(1)
// 事务中使用(所有方法均支持 tx 参数)
await reldb.tx.wrap(async (tx) => {
await userCrud.create({ name: '用户A', email: 'a@test.com' }, tx)
await userCrud.updateById(1, { name: '新名字' }, tx)
const user = await userCrud.findById(1, tx)
})
业务仓库基类,提供字段映射、自动建表与类型转换能力:
import { BaseReldbCrudRepository } from '@h-ai/reldb'
interface User { id: number, name: string, email: string, createdAt: Date, updatedAt: Date }
class UserRepository extends BaseReldbCrudRepository<User> {
constructor() {
super(db, {
table: 'users',
idColumn: 'id',
fields: [
{ fieldName: 'id', columnName: 'id', def: { type: 'INTEGER', primaryKey: true, autoIncrement: true }, select: true, create: false, update: false },
{ fieldName: 'name', columnName: 'name', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: true },
{ fieldName: 'email', columnName: 'email', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: true },
{ fieldName: 'createdAt', columnName: 'created_at', def: { type: 'TIMESTAMP', notNull: true }, select: true, create: true, update: false },
{ fieldName: 'updatedAt', columnName: 'updated_at', def: { type: 'TIMESTAMP', notNull: true }, select: true, create: true, update: false },
],
})
}
/** 自定义查询示例 */
async findByEmail(email: string, tx?: DmlWithTxOperations) {
return this.sql(tx).get<User>('SELECT * FROM users WHERE email = ?', [email])
}
}
this.sql(tx?):返回 DmlOperations(reldb.sql 或传入的事务句柄),自动适配事务场景。
自动能力:
createdAt / updatedAt 字段自动填充时间戳crypto.randomUUID())reldb.tx// 方式1:wrap(自动 commit/rollback)
const result = await reldb.tx.wrap(async (tx) => {
await tx.execute('INSERT INTO users (name) VALUES (?)', ['张三'])
await tx.execute('INSERT INTO logs (action) VALUES (?)', ['user_created'])
return 'done'
})
// result.data === 'done'(正常返回自动 commit)
// 回调抛异常 → 自动 rollback → result.success === false
// 方式2:手动管理
const txResult = await reldb.tx.begin()
if (txResult.success) {
const tx = txResult.data
try {
await tx.execute('INSERT INTO users (name) VALUES (?)', ['李四'])
await tx.commit()
}
catch {
await tx.rollback()
}
}
事务内可用操作:
tx.query / tx.get / tx.execute / tx.batch / tx.queryPagetx.crud.table(config) — 事务内的 CRUD 仓库tx.commit() / tx.rollback()reldb.pagination| 方法 | 签名 | 说明 |
|---|---|---|
normalize | (options?, overrides?) => NormalizedPagination | 规范化分页参数(含 offset/limit 计算) |
build | <T>(items, total, pagination) => PaginatedResult<T> | 构建分页结果对象 |
// PaginatedResult 结构
interface PaginatedResult<T> {
items: T[]
total: number
page: number
pageSize: number
}
// 默认值:page=1, pageSize=20, maxPageSize=200
reldb.json通过 reldb.json 构建跨数据库统一的 JSON 路径操作 SQL 表达式,返回 { sql, params } 可直接嵌入 reldb.sql.*。
路径格式遵循 SQL/JSON Path 标准,以 $ 开头(如 $.key、$.key.subkey、$[0])。
| 操作 | SQLite | PostgreSQL | MySQL |
|---|---|---|---|
extract | json_extract | #> (text[]) | JSON_EXTRACT |
set | json_set | jsonb_set | JSON_SET |
insert | json_insert | jsonb_insert | JSON_INSERT |
remove | json_remove | #- (text[]) | JSON_REMOVE |
merge | json_patch | ` |
// 提取 JSON 字段值(用于 WHERE 条件)
const { sql, params } = reldb.json.extract('settings', '$.theme')
const rows = await reldb.sql.query(
`SELECT * FROM users WHERE ${sql} = ?`,
[...params, '"dark"'],
)
// 设置 JSON 字段路径(创建或替换)
const { sql, params } = reldb.json.set('settings', '$.theme', 'dark')
await reldb.sql.execute(
`UPDATE users SET settings = ${sql} WHERE id = ?`,
[...params, userId],
)
// 删除 JSON 字段路径
const { sql, params } = reldb.json.remove('settings', '$.deprecated')
await reldb.sql.execute(`UPDATE users SET settings = ${sql} WHERE id = ?`, [...params, id])
// 合并 JSON 对象(RFC 7396:null 值表示删除对应键)
const { sql, params } = reldb.json.merge('profile', { bio: '新简介', avatar: null })
await reldb.sql.execute(`UPDATE users SET profile = ${sql} WHERE id = ?`, [...params, userId])
column参数为列名,禁止传入用户输入(开发者负责安全性)。
HaiReldbError| 错误码 | code | 说明 |
|---|---|---|
HaiReldbError.CONNECTION_FAILED | hai:reldb:001 | 数据库连接失败 |
HaiReldbError.QUERY_FAILED | hai:reldb:002 | 查询或执行失败 |
HaiReldbError.CONSTRAINT_VIOLATION | hai:reldb:003 | 约束违反 |
HaiReldbError.TRANSACTION_FAILED | hai:reldb:004 | 事务失败 |
HaiReldbError.MIGRATION_FAILED | hai:reldb:005 | 迁移失败 |
HaiReldbError.RECORD_NOT_FOUND | hai:reldb:006 | 记录不存在 |
HaiReldbError.DUPLICATE_ENTRY | hai:reldb:007 | 重复条目 |
HaiReldbError.DEADLOCK | hai:reldb:008 | 死锁 |
HaiReldbError.TIMEOUT | hai:reldb:009 | 超时 |
HaiReldbError.NOT_INITIALIZED | hai:reldb:010 | 数据库未初始化 |
HaiReldbError.POOL_EXHAUSTED | hai:reldb:011 | 连接池耗尽 |
HaiReldbError.UNSUPPORTED_TYPE | hai:reldb:012 | 不支持的数据库类型 |
HaiReldbError.CONFIG_ERROR | hai:reldb:013 | 配置错误 |
HaiReldbError.DDL_FAILED | hai:reldb:020 | DDL 操作失败 |
import { reldb, HaiReldbError } from '@h-ai/reldb'
import { kit } from '@h-ai/kit'
export async function GET(event) {
const { valid, data } = kit.validate.query(event.url, PageSchema)
if (!valid)
return kit.response.badRequest('Invalid params')
const result = await userCrud.findPage({
pagination: data,
orderBy: 'id ASC',
})
if (!result.success)
return kit.response.internalError()
return kit.response.ok(result.data)
}
const result = await reldb.tx.wrap(async (tx) => {
const user = await userRepo.create(userData, tx)
if (!user.success)
throw new Error(user.error.message)
await profileRepo.create({ userId: user.data.lastInsertRowid, ...profileData }, tx)
return user.data
})
const txResult = await reldb.tx.begin()
if (txResult.success) {
const tx = txResult.data
await userRepo.create({ name: '用户A', email: 'a@test.com' }, tx)
await userRepo.create({ name: '用户B', email: 'b@test.com' }, tx)
await tx.commit()
}
hai-build:模块初始化顺序hai-core:配置管理、HaiResult 模型hai-iam:IAM 模块内部使用 reldb 进行用户/角色/权限存储hai-cache:缓存穿透保护中配合 reldb 使用