asai-nodejs-db
v0.2.8
Published
asai for you
Readme
asai-nodejs-db
统一 SQL 风格的数据库操作插件。通过同一套 Idb 数据结构与 sqlDb() 接口,对接 MySQL、SQLite、Excel、本地文件四种存储后端。
快速开始
import initDb from './src/plugs/asai-nodejs-db/db';
// 创建驱动实例(默认 file)
const db = initDb('sqlite', {
database: './data/app.db',
create: 1,
poolMin: 2,
poolMax: 10,
});
// 统一查询
const users = await db.sqlDb({
type: 'select',
table: 'users',
field: ['id', 'name'],
where: [['age', '>', 18]],
order: [['id', 'desc']],
limit: 10,
});架构概览
asai-nodejs-db/
├── db.ts # 工厂入口 initDb(type, config)
└── src/
├── type.ts # Idb 接口定义
├── common.ts # 公共工具(Promise 封装、条件解析等)
├── Sql.ts # SQL 字符串生成器
├── mysql/Index.ts # MySQL 连接池驱动
├── sqlite/Index.ts # SQLite 连接池 / 单连接驱动
├── excel/Index.ts # Excel 文件驱动
└── file/Index.ts # 本地文件系统驱动调用链路:
initDb(type, config)
→ new XxxDriver(config)
→ sqlDb(Idb)
→ Sql.makeSql(Idb) [mysql / sqlite]
→ 文件 / Excel 专有逻辑 [file / excel]驱动对比
| 类型 | npm 依赖 | 存储介质 | 适用场景 |
|------|----------|----------|----------|
| mysql | mysql | MySQL 8 数据库 | 正式业务库 |
| sqlite | sqlite3 | 本地 .db 文件 | 嵌入式、单机、测试 |
| excel | xlsx | .xlsx / .xls | 报表、轻量表格数据 |
| file | 无(Node fs) | 目录 + JSON 文件 | 配置、轻量 CMS 数据 |
Idb 接口说明
所有驱动共用 Idb 对象描述一次操作:
| 字段 | 类型 | 说明 |
|------|------|------|
| type | string | select / insert / update / delete;file 额外支持 re(恢复软删除) |
| table | string | 表名;file 类型为相对目录名(如 config 对应 dir/config/) |
| field | string[] | string | 字段列表,如 ['id','name'] 或 'id,name' |
| value | [][] | string | 插入行,如 [['Tom', 20], ['Jerry', 18]] |
| set | [][] | string | 更新赋值,如 [['name','Tom']] 或 [['count','+',1]] |
| where | [][] | string | 条件,支持 or/and 与 [字段, 运算符, 值] 混排 |
| order | [][] | string | 排序,如 [['id','desc']] |
| limit | number | 限制返回行数(select) |
| list | number | file:列表模式,返回 { open, delete } |
| deltrue | any | file:软删除模式下传 1 表示物理删除 |
| filename | string | file:目录模式下的子文件名 |
| as | number | file:1 单文件 JSON 解析;2 目录 JSON 聚合查询 |
WHERE 条件示例
// 简单条件
where: [['id', '=', 1]]
// 组合条件(or/and 会生成括号分组)
where: ['or', ['name', 'like', '%张%'], 'and', ['age', '>', 18]]
// 原始 SQL 片段
where: 'status = 1 AND deleted = 0'SET 更新示例
// 直接赋值
set: [['name', '新名称']]
// 自增(mysql/sqlite 生成 field=field+1)
set: [['count', '+', 1]]
// 字符串拼接(mysql CONCAT)
set: [['title', 'CONCAT', '后缀']]各驱动配置
MySQL
const db = initDb('mysql', {
host: 'localhost',
user: 'root',
password: '123456',
database: 'mydb',
create: 1, // 表不存在时自动建库建表
});| 参数 | 说明 |
|------|------|
| host / user / password / database | 标准 MySQL 连接参数 |
| create | 非 0 / true 时,insert 遇「表不存在」自动建库建表 |
方法:
| 方法 | 说明 |
|------|------|
| sqlDb(sql) | Promise 查询 |
| query(sql, callback) | 回调风格查询 |
| close(callback?) | 关闭连接池 |
安装说明见 src/mysql/MYSQL.md。
SQLite
const db = initDb('sqlite', {
database: './data/app.db',
create: 1,
usePool: true, // 默认 true,false 为单连接模式
poolMin: 2,
poolMax: 10,
idleTimeout: 30000,
acquireTimeout: 5000,
$asai: globalAsai, // 可选,注入日志对象
});| 参数 | 默认值 | 说明 |
|------|--------|------|
| database | — | .db 文件路径(自动创建目录) |
| usePool | true | 是否启用连接池 |
| poolMin | 2 | 最小连接数 |
| poolMax | 10 | 最大连接数 |
| idleTimeout | 30000 | 空闲连接回收时间(ms) |
| acquireTimeout | 5000 | 获取连接超时(ms) |
| create | — | 非 0 时 insert 遇「表不存在」自动建表 |
方法:
| 方法 | 说明 |
|------|------|
| sqlDb(sql) | Promise 查询 |
| query(sql, callback) | 回调风格查询 |
| getPoolStatus() | 连接池状态 { total, inUse, idle, waiting, min, max } |
| close() | 关闭连接池或单连接 |
性能说明: 连接池在 acquire 时仅对长时间空闲的连接执行 SELECT 1 检测,刚释放的连接直接复用,降低高频查询开销。
安装说明见 src/sqlite/SQLite.md。
Excel
const db = initDb('excel', {
database: './data/report.xlsx',
});| 方法 | 说明 |
|------|------|
| sqlDb(sql) | 通过 Idb 操作工作表(table 为 sheet 名,空则用首个 sheet) |
| readSheet(where, order, top, sheetName) | 直接读取并过滤 |
| addData(data, sheetName) | 追加行 |
| editData(data, where, sheetName) | 更新首条匹配行 |
| deleteData(where, sheetName) | 删除首条匹配行 |
限制: WHERE 仅支持等值匹配(字段 === 值);ORDER 按数值字段排序。
File(文件系统)
const db = initDb('file', {
dir: './webdata/webdb/',
ext: '.json',
create: 1,
del: 1, // 启用软删除(重命名为 .delete.ext)
});| 参数 | 默认值 | 说明 |
|------|--------|------|
| dir | — | 数据根目录(相对 process.cwd()) |
| ext | '' | 文件扩展名,.* 表示无扩展名 |
| del | 0 | 非 0 启用软删除 |
| create | false | 自动创建不存在的目录 |
sqlDb 路由:
| type | 行为 |
|--------|------|
| insert | value[0] 为 [文件名, 内容],写入 table/文件名 |
| delete | 从 where 取文件名并删除 |
| re | 恢复软删除文件 |
| update | 从 where 取文件名,set[0][1] 为新内容 |
| select | 有 where 且 as !== 2 → 读单文件;as === 2 → 目录 JSON 聚合;否则 → 列表 |
安全: 路径解析限制在 dir 根目录内,阻止 ../ 路径穿越。
跨平台: 路径统一使用 Node.js path 模块(path.resolve / path.join),兼容 Windows 正反斜杠、Linux/macOS 路径及不同盘符场景。table 支持 URL 风格的 / 分隔(如 cocontrol/projectconfig)。
使用示例
增删改查(mysql / sqlite)
// 查询
await db.sqlDb({
type: 'select',
table: 'users',
field: ['id', 'name', 'age'],
where: [['age', '>', 18]],
order: [['id', 'DESC']],
limit: 10,
});
// 批量插入
await db.sqlDb({
type: 'insert',
table: 'users',
field: ['name', 'age'],
value: [['张三', 25], ['李四', 30]],
});
// 更新
await db.sqlDb({
type: 'update',
table: 'users',
set: [['name', '王五']],
where: [['id', '=', 1]],
});
// 删除
await db.sqlDb({
type: 'delete',
table: 'users',
where: [['id', '=', 1]],
});File 目录 JSON 查询(as=2)
const list = await db.sqlDb({
type: 'select',
table: 'config',
as: 2,
field: ['key', 'value', 'title'],
where: [['title', 'like', '设置']],
order: [['key', 'ASC']],
});在 asai-host 中使用
// app.ts 中已挂载
$asai.dataserver = initDb;
// 业务代码
const DataServer = $asai.dataserver('file', { dir: './webdata/', ext: '.json', create: 1 });
const data = await DataServer.sqlDb({ type: 'select', table: 'articles', as: 2 });Sql.ts 生成规则
Sql.makeSql(Idb) 将操作对象转为 SQL 字符串:
| type | 生成示例 |
|------|----------|
| insert | insert into users (name,age) values ('Tom',20) |
| delete | delete from users where id = 1 |
| update | update users set name='Tom' where id = 1 |
| select | select id,name from users where age > 18 order by id desc limit 10 |
Sql.createSql(Idb, dialect) 自动建表,补充 id 主键与 asdate 时间戳列。
注意: SQL 由字符串拼接生成,适用于受信任的内部数据。对外部输入应自行校验或改用参数化查询。
返回值约定
sqlDb() 统一约定:
- 查询成功且有数据 → 返回结果数组或对象
- 查询成功但无数据 → 返回空字符串
'' - 失败 →
Promise.reject(错误信息)
file 驱动 select 在 list 模式下返回 { open: [], delete: [] }。
依赖安装
# MySQL 驱动
npm install mysql
# SQLite 驱动(Windows 可能需要 node-gyp,见 SQLite.md)
npm install sqlite3
# Excel 驱动
npm install xlsx跨平台验证
在项目根目录(webserver/)执行冒烟测试,自动覆盖 Sql 生成、路径安全、file/sqlite 读写:
npx tsx src/plugs/asai-nodejs-db/verify.mjs支持 Windows / Linux / macOS(含 pkg 打包目标 node20-win-x64、node20-linux-x64、node20-linux-arm64)。
版本优化记录
本次优化在保持 API 与行为兼容的前提下:
- 提取
common.ts公共模块,消除sqlDbPromise 包装重复代码 - 重构
Sql.ts,用join替代循环拼接,修复field子句冗余逻辑 - MySQL:修复连接错误时回调未触发、连接未释放问题;新增
close();仅在表不存在时自动建表 - SQLite:空闲连接按需检测,减少每次
acquire的SELECT 1开销 - Excel:补全
sqlDb对insert/update/delete/select的 Idb 映射 - File:增加路径穿越防护
- 完善 TypeScript 类型与关键注释
