@civitas-cerebrum/sql-client

中文文档
0.1.3发布于 2026/10/24MITTypeScriptCommonJS构建来源已验证近 30 天下载 3103

一个轻量级多引擎的SQL客户端(Postgres, MySQL, SQLite, SQL Server, Oracle),拥有流畅的查询构建器,打出结果,以及被默认的查询.

中文使用文档
文档目录22 节
  1. 一个API,五个引擎
  2. * 安装
  3. QQ 快速启动
  4. * 特性
  5. 使用量: SqlClient
  6. 原始查询
  7. sql 标记模板
  8. 交易
  9. QQ 查询构建器
  10. 阅读结果
  11. 过滤行
  12. API 参考
  13. 🔌 SqlClient
  14. 📊 SqlResult<T>
  15. 📖 ResultSet 编号 : Row
  16. 🏷️ sql 标记脚本( c)
  17. · 例外情况
  18. 扩展
  19. 测试工作流程
  20. 发动机陷阱
  21. 非目标
  22. 克劳德代码技能

多引擎 SQL 客户端

NPM Version

轻量级 多引擎 用于查询和测试自动化的SQL客户端——一个API横跨 PostgreSQL, MySQL/MariaDB, SQLite, SQL 服务器和甲骨文,带有流畅的查询构建器,键入结果,并且总是被参数化的查询.

这个包是 数据层:用于人类+LLM代理写作的节目SQL外观. 这是兄弟 @civitas-cerebrum/wasapi (HTTP),他们一起支持步骤API @civitas-cerebrum/element-interactions如果您正在通过此框架编写 E2E 测试规格,请使用其 steps.sql* 包件——这个包就是它们的力量, 以及你用固定装置、种子脚本、控制内部和独立的工具来达到的.


一个API,五个引擎

每个数据库驱动程序都有自己的连接仪式,占位符风格,以及结果形状. 多引擎代码通常指5个代码路径.

在( 驱动程序) 之前 :

// pg: Pool, $1 placeholders
const pool = new Pool({ connectionString });
const res = await pool.query('SELECT * FROM books WHERE genre = $1', ['Fiction']);

// mysql2: createPool, ? placeholders, [rows, fields] tuples
const [rows] = await mysqlPool.query('SELECT * FROM books WHERE genre = ?', ['Fiction']);

// mssql: request objects with named .input() bindings
const r = await pool.request().input('p1', 'Fiction')
  .query('SELECT * FROM books WHERE genre = @p1');

// oracledb: outFormat option, UPPERCASE column keys, manual connection release
const conn = await pool.getConnection();
const result = await conn.execute('SELECT * FROM books WHERE genre = :1', ['Fiction'],
  { outFormat: oracledb.OUT_FORMAT_OBJECT });
await conn.close();

(@civitas-cerebrum/sql-客户端):

// Same client, same call, any engine — detected from the connection string.
const db = new SqlClient({ connectionString: process.env.DB_URL! });
const res = await db.query('SELECT * FROM books WHERE genre = $1', ['Fiction']);

// Or fully portable: the builder renders engine-correct placeholders,
// quoting, and pagination from one chain.
const top = await QueryBuilder.select('books')
  .where('genre = ?', 'Fiction')
  .orderBy('price', 'desc')
  .limit(5)
  .run(db);

* 安装

安装软件包 加引擎的驱动程序 - 驾驶员是 可选同伴依赖关系,因此您只拉取您使用的(没有自动安装,包括依赖于 sql-客户端的软件包):

# PostgreSQL
npm install @civitas-cerebrum/sql-client pg

# MySQL / MariaDB
npm install @civitas-cerebrum/sql-client mysql2

# SQLite (zero infrastructure)
npm install @civitas-cerebrum/sql-client better-sqlite3

# SQL Server
npm install @civitas-cerebrum/sql-client mssql

# Oracle (Thin mode — no Instant Client needed)
npm install @civitas-cerebrum/sql-client oracledb

要几个引擎吗? 将它们的驾驶员一起列出npm install @civitas-cerebrum/sql-client pg mysql2) (中文(简体) ). 导入软件包从不装入驱动程序; 是 require第一次使用时,一个缺失的投出一个清晰 UnsupportedEngineException 命名要安装的驱动程序.

所需经费: 节点.js 20.

发动机连接字符串方案驱动程序占位符returning()
邮递SQLpostgres:// • 妇女 postgresql://pg$1✅ RETURNING
MySQL / 马里亚DBmysql:// • 妇女 mariadb://mysql2?❌
SQL 点sqlite: • 妇女 sqlite::memory: • 妇女 file: • 妇女 :memory: • 妇女 *.db • 妇女 *.sqlitebetter-sqlite3?✅ RETURNING
SQL 服务器mssql:// • 妇女 sqlserver://mssql@p1✅ OUTPUT
甲骨文oracle:// • 妇女 oracledb://oracledb:1❌

QQ 快速启动

0基础设施 — 一个内存 SQLite 数据库, 没有 Docker, 没有服务器 。 复制复制并运行 :

import { SqlClient, QueryBuilder } from '@civitas-cerebrum/sql-client';

const db = new SqlClient({ engine: 'sqlite', connectionString: ':memory:' });

// Create a table (runScript splits a multi-statement script per engine)
await db.runScript(`
  CREATE TABLE books (id INTEGER PRIMARY KEY, title TEXT, price REAL, in_stock INTEGER);
`);

// Insert (multi-row in one statement)
await QueryBuilder.insert('books')
  .values([
    { title: 'Dune', price: 12.99, in_stock: true },
    { title: '1984', price: 9.5,  in_stock: false },
  ])
  .run(db);

// Read straight into a typed, coercing ResultSet
const cheap = await QueryBuilder.select('books').where('price < ?', 10).fetch(db);
console.log(cheap.column('title'));            // ['1984']

const dune = await db.fetch('SELECT * FROM books WHERE title = ?', ['Dune']);
console.log(dune.one().number('price'));       // 12.99
console.log(dune.one().boolean('in_stock'));   // true  (1 → true)

await db.end();

* 特性

  • 引擎自动检测 - 从连接字符串方案推断出发动机;通过 { engine } 只有在没有计划读取时才明确.
  • 可选、懒散的司机 – 驱动程序是可选的对等分解程序:只安装您使用的引擎;没有强迫您(或依赖于sql-客户端的软件包). 每个都是 required 在第一次客户端构建, 和缺失一个扔 UnsupportedEngineException 命名要安装的驱动程序.
  • 总是瘫痪 —— Raw calls take a params range; 构建者需要 ? 标记并让引擎正确的占位符样式。 无弦插入处.
  • sql 标记模板 —— 说 sql`... ${value}` 安全地插入绑定参数,并编译到每个引擎正确的占位符样式; sql.id() 用于识别器,碎片巢.
  • 流利的查询构建器 —— 说 select编号 :insert编号 :update编号 :delete 带有引擎正确标识符的链条引用和页标( )LIMIT/OFFSET 对 OFFSET..FETCH),加 (中文(简体) ) whereIn编号 :whereNull编号 :whereNotNull 财务报告和审定财务报表 count()编号 :exists() 终端.
  • 一通电话读作: —— 说 fetch编号 :one编号 :maybeOne编号 :scalar 直上陆地 ResultSet编号 :Row 从客户端或构建器链中找到 – 没有手动 rows() 包装.
  • 多行插图 —— 说 values() 接受一个数组(或重复调用),并编译一个单一多行语句.
  • 返回行写 —— 说 returning(...cols) 编译 RETURNING (邮递)或 OUTPUT INSERTED./DELETED. (msql);引擎在编译时没有等效的拒绝,有明显的错误.
  • 已打入、已规范的结果 - 每一个引擎的结果都被重塑成 { rows, rowCount, fields },在行型上通用; Row<T> 提供列名自动完成,同时仍然允许对大小写不敏感查找.
  • 不区分大小写、 类型强制存取器 —— 说 rows(res).one().number('price') 引擎是否返回 PRICE (甲骨文)或 "12.99" 作为字符串(postgres/mysql NUMERIC). 匹配者也比较数字,所以 find({ price: 6.5 }) 匹配一个 "6.50" 电话.
  • 模拟行匹配者 —— 说 where编号 :find 接受文字、匹配者(lt, (中文(简体) ), oneOf, (中文(简体) ), contains),或全行上游; where() 返回可链条 ResultSet。 。 。 .
  • 交易 —— 说 transaction(fn) 自动 COMMIT 返回时 ROLLBACK 铸造者在五台发动机中运行qb.run(tx)) (中文(简体) ).
  • 脚本运行器 —— 说 runScript() 编号 : splitSqlScript() 拆分多语句 .sql 带有引擎意识规则的文件( Oracle) /, SQL 服务器 GO,评论/引文注意).
  • 连接失败 —— 说 ping() 准备状态检查和a connectTimeoutMs 选项,所以错误的主机会迅速死亡而不是被挂起.
  • 类型失败 —— 说 QueryFailedException 显示信件中的 SQL + 参数并携带 .sql, (中文(简体) ), .params驱动器 .cause;占位符式错误得到跨引擎提示.
  • 可插载发动机 —— 说 registerEngineFactory() 以自定义驱动器+方言对换.
  • 调试日志 —— 说 DEBUG=sql:* 用参数打印每个语句( 包括内部交易), 每个引擎命名空格(sql:postgres, (中文(简体) ), sql:mysql(中文(简体) ).

使用量: SqlClient

import { SqlClient } from '@civitas-cerebrum/sql-client';

// --- PostgreSQL (engine auto-detected from the URL scheme) ---
const pg = new SqlClient({ connectionString: 'postgres://user:pass@localhost:5432/mydb' });

// --- MySQL ---
const mysql = new SqlClient({ connectionString: 'mysql://user:pass@localhost:3306/mydb' });

// --- SQLite (in-memory, zero infra) ---
const sqlite = new SqlClient({ engine: 'sqlite', connectionString: ':memory:' });

// --- SQL Server (engine-native connection object) ---
const mssql = new SqlClient({
  engine: 'mssql',
  connection: { server: 'localhost', port: 1433, user: 'sa', password: 'Secret!1',
                database: 'mydb', options: { trustServerCertificate: true } },
});

// --- Oracle ---
const oracle = new SqlClient({ connectionString: 'oracle://user:pass@localhost:1521/FREEPDB1' });

连接会很快失败, 而不是挂在错误的主机上 – pass connectTimeoutMs 输入 配置并使用 ping() (例如在测试中) globalSetup核查前面的可达到性:

const db = new SqlClient({ connectionString: process.env.DB_URL!, connectTimeoutMs: 5000 });
await db.ping();   // throws if the engine is unreachable

原始查询

原始 SQL 中的占位符为 引擎内置 (单位:千美元)$1 编号 : ? 编号 : @p1 编号 : :1 - 参见上表:

const { rows } = await pg.query('SELECT * FROM books WHERE genre = $1', ['Fiction']);
await pg.execute('UPDATE books SET stock = 0 WHERE book_id = $1', ['b1']);

// fetch() wraps the result in a ResultSet in one step
const book = (await pg.fetch('SELECT * FROM books WHERE book_id = $1', ['b1'])).one();

sql 标记模板

喜欢 sql 便携式原始 SQL 标记: 插入在 引擎正确的占位符样式,所以相同的查询会随处可见。 使用 sql.id() 页:1 标识符(每个方言引用,从未参数化),并用巢片来作曲:

import { sql } from '@civitas-cerebrum/sql-client';

const genre = 'Fiction', max = 15;
await db.query(sql`SELECT * FROM books WHERE genre = ${genre} AND price < ${max}`);
// postgres → "... WHERE genre = $1 AND price < $2"; mysql → "... = ? AND < ?"; etc.

const onlyCheap = sql`AND price < ${10}`;
await db.query(sql`SELECT ${sql.id('title')} FROM books WHERE in_stock = ${true} ${onlyCheap}`);

交易

transaction(fn) 承诺返回和滚回抛出。 手柄带着方言,所以 QueryBuilder.run(tx) 在其中工作 sql 标记是只使用客户端的——在 tx 内部使用构建器 或原始 SQL 通过 tx.query:

await pg.transaction(async (tx) => {
  await QueryBuilder.update('books').set({ stock: 0 }).where('book_id = ?', 'b1').run(tx);
  await tx.execute('UPDATE books SET stock = stock - 1 WHERE book_id = $1', ['book-002']);
  // throw → automatic ROLLBACK; return → automatic COMMIT
});

完成时总是关闭客户端 :

await pg.end();

QQ 查询构建器

便携式SQL从一个链- ? 标记、引用和页码都按引擎编译:

import { QueryBuilder } from '@civitas-cerebrum/sql-client';

const top = await QueryBuilder.select('books')
  .columns('title', 'price')
  .where('price < ?', 15)
  .orderBy('price', 'desc')
  .limit(5)
  .run(pg);

// Multi-row INSERT — values() takes an array (or repeated calls)
await QueryBuilder.insert('books')
  .values([
    { book_id: 'b1', title: 'Dune' },
    { book_id: 'b2', title: '1984' },
  ])
  .run(pg);

// Writes can hand rows back: RETURNING (postgres/sqlite) or OUTPUT (mssql).
// mysql/oracle have no equivalent — returning() throws UnsupportedEngineException there.
const ins = await QueryBuilder.insert('books')
  .values({ title: 'Dune' })
  .returning('book_id', 'title')   // no args → all columns
  .run(pg);

// whereIn expands one placeholder per value (throws on an empty array, so you never compile
// `IN ()`); whereNull/whereNotNull avoid the `= NULL` footgun that silently matches nothing.
const some = await QueryBuilder.select('books')
  .whereIn('book_id', ['b1', 'b2', 'b3'])
  .whereNotNull('isbn')
  .fetch(pg);

// Inspect without executing — toSql() requires an explicit dialect
const { text, values } = QueryBuilder.select('books').where('price < ?', 15).toSql(pg.dialect);

终端 通过客户端发送查询,并将结果成一个调用:

await QueryBuilder.select('books').where('book_id = ?', 'b1').one(pg);        // Row (else ResultError)
await QueryBuilder.select('books').where('genre = ?', 'Fiction').fetch(pg);   // ResultSet
await QueryBuilder.select('books').where('book_id = ?', 'b1').maybeOne(pg);   // Row | undefined
await QueryBuilder.select('books').scalar(pg, 'title');                       // first cell
await QueryBuilder.select('books').where('price < ?', 10).count(pg);          // number
await QueryBuilder.select('books').where('book_id = ?', 'b1').exists(pg);     // boolean

可链: columns(...cols) • 妇女 join(table, on) • 妇女 where(clause, ...params) (多次电话拨打)- whereIn(col, values) • 妇女 whereNull(col) • 妇女 whereNotNull(col) • 妇女 groupBy(...cols) • 妇女 having(clause, ...params) • 妇女 orderBy(col, dir) • 妇女 limit(n) • 妇女 offset(n) • 妇女 values(row | row[]) • 妇女 set(row) • 妇女 returning(...cols)。 。 。 . 终端 : run(client) • 妇女 fetch(client) • 妇女 one(client) • 妇女 maybeOne(client) • 妇女 scalar(client, col?) • 妇女 count(client) • 妇女 exists(client) • 妇女 toSql(dialect)。 。 。 .

说明: SQL 服务器和甲骨文需要 orderBy() 开始时(OFFSET..FETCH 需要它吗. 要组队吗? 把它放入一个片段: where('(genre = ? OR genre = ?)', a, b)。 。 。 .


阅读结果

按名称从行中拉出值—— 不区分大小写 (甲骨文返回 UPPERCASE 密钥)和 类型强制 (postgres/mysql 返回 NUMERIC/DECIMAL 作为字符串):

import { rows, getNumber } from '@civitas-cerebrum/sql-client';

const res = await db.query('SELECT * FROM books WHERE book_id = $1', ['book-001']);

// Fluent wrapper
const book = rows(res).one();                 // exactly one row, else throws ResultError
book.string('title');                         // 'To Kill a Mockingbird'
book.number('price');                         // 12.99
book.boolean('in_stock');                     // normalizes 1/0, 't'/'f', 'true'/'false'

rows(await db.query('SELECT count(*) FROM books')).scalar();   // first cell of first row
rows(res).column('title');                    // every title
rows(res).find({ genre: 'Fiction' });         // first matching row, or undefined
rows(res).maybeOne();                         // 0..1 rows, else throws ResultError

// Or standalone functions on a raw row
getNumber(res.rows[0], 'price');              // 12.99

语义学:缺栏- undefined; SQL NULL → null;否则被胁迫.

过滤行

where编号 :find 接受部分(栏-正文) 或者说 )或全行上游:

import { rows, lt, oneOf, contains } from '@civitas-cerebrum/sql-client';

const res = await db.query('SELECT * FROM books');
rows(res).where({ genre: 'Fiction', price: lt(10) });        // matchers
rows(res).find({ title: contains('1984') });
rows(res).where(row => row.number('price')! < 10);           // predicate

// where() returns a ResultSet, so filtering keeps chaining:
rows(res).where({ genre: 'Fiction' }).column('title');
rows(res).where({ book_id: 'b1' }).one();
if (rows(res).where({ status: 'SOLD' }).isEmpty()) { /* none sold */ }
rows(res).where({ genre: 'Fiction' }).all().forEach(r => { /* Row[] */ });

// standalone, on raw rows
import { filterRows } from '@civitas-cerebrum/sql-client';
filterRows(res.rows, { status: oneOf(['ACTIVE', 'SOLD']) });

匹配者 : eq ne lt lte gt gte between oneOf like contains startsWith endsWith matches isNull notNull not。 。 。 . 无效/ 未定义单元格只匹配 isNull(); 比较/字符串匹配器返回 false 对于它。 平等 匹配者(eq编号 :ne编号 :oneOf)和字面部分在双方都是数字时进行数字比较,所以 6.5 查询与 "6.50" 由 postgres/ misql 返回的单元格.


API 参考

🔌 SqlClient

成员说明
new SqlClient(config)config数字 : { connectionString?, engine?, connection?, max?, connectTimeoutMs?, dialect? }
query<T>(sql, params?) 编号 : query<T>(fragment)参数化查询(字符串或 sql ∗∗∗∗∗ Promise<SqlResult<T>>
execute(sql, params?) 编号 : execute(fragment)书面陈述 – Promise<SqlResult> (受影响行的行数)
fetch<T>(sql, params?)query() 接下来 rows() → Promise<ResultSet<T>>
transaction(fn)原子块; fn(tx) 获得 tx.query编号 :tx.execute 加号 tx.dialect编号 :tx.engine这样 QueryBuilder.run(tx) 工作内容
runScript(sqlText)拆分一个多语句脚本( 引擎意识) 并按顺序执行
ping()廉价连接探测器; 如果引擎无法到达则丢弃
end()关闭池/连接
engine 编号 : dialect解决的引擎名称和方言实例

📊 SqlResult<T>

{ rows: T[], rowCount: number, fields: { name, dataTypeID }[] } ——每个引擎产生的正态形状.

📖 ResultSet 编号 : Row

成员说明
rows<T>(result | rawRows)将结果( 或原始数组) 包入 a ResultSet<T>
.one() 编号 : .maybeOne()完全1/在 - 最一行,否则 ResultError
.first() 编号 : .at(i)Row 或者说 undefined
.scalar(column?)第一行的第一个单元格
.column(name)所有行各一栏
.find(where)第一个匹配 Row (部分字数/对等,或 (row) => boolean(中文(简体) )
.where(where)过滤器 → 可链条 ResultSet (相同的部分/预选表格)
.map(fn) 编号 : .all() 编号 : .raw()逐行绘制地图/ 全部覆盖为 Row[] / 打开到生行
Row<T>.get/string/number/boolean(col)大小写不敏感、类型强制的单元格访问; T 给列名自动完成
Row.has(col) 编号 : Row.raw()存在检查/ 内在对象

🏷️ sql 标记脚本( c)

导出说明
sql`...${v}`构建一个 SqlFragment; 插件 ; 捆绑的活体; 筑巢的碎片
sql.id(name)插入一个标识符( 引号, 不参数化)
splitSqlScript(sqlText, engine?)将多声明脚本拆分为单个声明( 引擎意识)

· 例外情况

类掷出时额外
SqlException下方所有东西的基类—— 说
QueryFailedException查询/执行失败消息包括 SQL + params(+ 占位符提示); .sql, (中文(简体) ), .params, (中文(简体) ), .cause
UnsupportedEngineException未知引擎、 缺少驱动程序或不支持 returning()—— 说
ResultErrorone()编号 :maybeOne() 基本要求或失败的胁迫—— 说

扩展

函数说明
registerEngineFactory(engine, factory)插入自定义 { createDriver, createDialect } 组合
detectEngine(connectionString)用于检测 SqlClient
Dialect执行 placeholder, (中文(简体) ), quoteIdentifier, (中文(简体) ), compilePagination, (中文(简体) ), compileReturning
createLogger(ns) 编号 : logdebug- 基于记录器(SqlLogger在 sql:* 命名空间

测试工作流程

# Light (unit + zero-infra SQLite) — no Docker needed
npm test

# Single engine (bring up just that engine's container)
docker compose --profile postgres up -d --wait && npm run test:postgres
docker compose --profile mysql    up -d --wait && npm run test:mysql
docker compose --profile mssql    up -d --wait && npm run test:mssql
docker compose --profile oracle   up -d --wait && npm run test:oracle

# Full matrix — all five live engines
docker compose --profile all up -d --wait
npm run test:all-engines
docker compose --profile all down -v

以上命令用于局部迭代. 每个公关都由CI负责: 节点24上的单元 + SQLite 套房, 财务报告和审定财务报表 完整的四引擎活矩阵(Postgres, MySQL, SQL Server, Oracle)——每个引擎在自己的孤立容器中——所以在合并前会捕捉到引擎特有的回归.

主机端口与已经运行的东西相撞? 覆盖它们: SQL_CLIENT_PG_PORT, (中文(简体) ), SQL_CLIENT_MYSQL_PORT, (中文(简体) ), SQL_CLIENT_MSSQL_PORT, (中文(简体) ), SQL_CLIENT_ORACLE_PORT (并指所取所取所取所取所取所取等. SQL_TEST_URL=postgres://bookhive:bookhive@localhost:15432/bookhive npm run test:postgres) (中文(简体) ).

调试日志 : DEBUG=sql:* npm test (每个引擎命名空间) sql:postgres, (中文(简体) ), sql:mysql, (中文(简体) ), sql:sqlite, (中文(简体) ), sql:mssql, (中文(简体) ), sql:oracle;涵盖交易报表和生命周期).


发动机陷阱

跨引擎不同 包吸收你- 少数不能:

  • 原始 SQL 的占位符样式不同 —— 说 $1 (邮递员) ? · (misql/sqlite) - @p1 · (msql) · :1 (甲骨文). 使用构建器或 sql 标记可移植代码; 两者都使正确的样式.
  • Oracle 返回 UPPERCASE 列键 —— 说 Row 访问者不敏感,所以 row.string('title') 不管怎么样,都行 仅生 res.rows[i].title 索引受到影响.
  • NUMERIC/DECIMAL 作为字符串到达 邮递/邮件 row.number() 强迫,和匹配者比较数字,所以你很少注意到。 原始的细胞访问并不强制.
  • SQL 服务器 UNIQUE 将 NULLs 视为重复 第二行为: NULL 在一个 UNIQUE 列违反了对msql(不同于其他引擎)的限制。 在测试固定装置中使用不同的监视值 .
  • SQL 组合键 服务器按位置绑定参数 —— 说 @p1..@pN 映射到参数阵列的顺序; 构建者和 sql 标记自动处理.
  • SQLite 没有本地日期/ 布尔 - 驱动程序正常 Date → ISO string, (中文(简体) ), boolean → 1/0, (中文(简体) ), undefined → null 因此,相同的固定代码 工作与其他引擎.

非目标

故意超出范围保持精干和可预期. 为此,可使用专用工具:

  • ORM / 关系/ 实体映射 这是查询客户端 不是ORM.
  • 移徙和计划管理 使用你的移徙工具; runScript() 只执行您给出的 SQL .
  • 正在流出/ 光标 对于庞大的成果组合——成果是实实在在的数组.
  • 命名参数 —— 仅定位(建造者 ? 编辑 sql 标记覆盖人类学差距.
  • 或组合的建树 - 单人内部的表达式 OR where() 换成碎片.
  • 提升助手 ——特写引擎 ON CONFLICT 编号 : MERGE 现在直接使用 SQL.

克劳德代码技能

货包船a 克劳德代码 技术(skills/sql-client/SKILL.md(中文(简体) ) 它教毒剂 完整的API表面。 它自动安装在 npm install 改为 ~/.claude/skills/ 全球安装-g),或仅此 <project>/.claude/skills/ 对于本地的( 当工程根没有时从未写入) package.json)——包是直接安装还是到达 穿过另一个 @civitas-cerebrum 软件包。 在使用步骤-API测试的项目中 技术将测试光谱数据库的工作推迟到 database-testing 技术.

跳过副本——例如,在CI或容器中——设置 SQL_CLIENT_SKIP_SKILLS=1 在安装前.

版本与发布记录

@civitas-cerebrum/sql-client 共发布 4 个版本,首次发布于 2026/06/13;过去 12 个月发布了 4 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.1.3latest2026/10/2417 天前
0.1.22026/06/174 个月前
0.1.12026/06/174 个月前
0.1.02026/06/134 个月前

关于 @civitas-cerebrum/sql-client 的常见问题

@civitas-cerebrum/sql-client 是什么?

一个轻量级多引擎的SQL客户端(Postgres, MySQL, SQLite, SQL Server, Oracle),拥有流畅的查询构建器,打出结果,以及被默认的查询.

如何安装 @civitas-cerebrum/sql-client?

在项目目录运行 npm install @civitas-cerebrum/sql-client,或使用 pnpm add / yarn add / bun add。

@civitas-cerebrum/sql-client 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@civitas-cerebrum/sql-client 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@civitas-cerebrum/sql-client 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@civitas-cerebrum/sql-client 可以商用吗?

@civitas-cerebrum/sql-client 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@civitas-cerebrum/sql-client 的下载量有多少?

根据 npm 官方下载统计,@civitas-cerebrum/sql-client 在 2026/10/10 – 2026/11/08 这 30 天内被下载 3,103 次,日均约 103 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@civitas-cerebrum/sql-client 还在维护吗?

最新版本 0.1.3 发布于 2026/10/24(17 天前);至今共发布 4 个版本,其中过去 12 个月发布了 4 个;首次发布于 2026/06/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。