sql-petra
v1.0.1
Published
生成SQLite数据库的SQL语法
Readme
SQLPetra
SQLPetra 是一个基于 TypeScript 装饰器的 SQLite SQL 生成工具。它负责根据实体类和链式方法生成 SQL 语句与参数,不直接连接或执行数据库。
快速开始
安装
// 使用npm
npm i sql-petra
// 或者使用pnpm
pnpm add sql-petra卸载
npm uninstall sql-petra更新
npm update sql-petra导入
import { SQLHelp, table, column, type SQLType } from "sql-petra";完整示例
import { SQLHelp, table, column } from "sql-petra";
@table("tn_sys_user")
class User {
@column({ fieldName: "user_id", isPrimaryKey: true })
id?: number;
@column({ fieldName: "user_name" })
name?: string;
}
const sqlInfo = SQLHelp.Queryable<User>(User)
.Where("id", 1)
.ToList();
console.log(sqlInfo.SQL);
console.log(sqlInfo.data);返回结构
查询、新增、修改、删除的结束方法都会返回 SQLType:
type SQLType = {
SQL: string;
data: Record<string, any>;
};在项目中组织实体
实体类只需要使用 @table 和 @column 标记,不需要继承 SQLPetra 的类。
import { table, column } from "sql-petra";
@table("tn_sys_user")
export class UserEntity {
@column({ fieldName: "user_id", isPrimaryKey: true })
id?: number;
@column({ fieldName: "user_name", isNull: false })
name?: string;
}如果你的项目里有公共字段,可以让实体继承你自己的基础类:
import { column } from "sql-petra";
export class BaseEntity {
@column({ fieldName: "created_at", fieldType: "text", isNull: true })
createdAt?: string;
@column({ fieldName: "updated_at", fieldType: "text", isNull: true })
updatedAt?: string;
}import { table, column } from "sql-petra";
import { BaseEntity } from "./BaseEntity";
@table("tn_sys_user")
export class UserEntity extends BaseEntity {
@column({ fieldName: "user_id", isPrimaryKey: true })
id?: number;
@column({ fieldName: "user_name" })
name?: string;
}在项目中封装使用
SQLPetra 不负责连接数据库,推荐在你的项目里封装一层 Repository 或 Service,把 SQLHelp 生成的 SQL 交给自己的数据库执行方法。
import { SQLHelp, type SQLType } from "sql-petra";
import { UserEntity } from "../entity/UserEntity";
export class UserRepository {
findById(id: number): SQLType {
return SQLHelp.Queryable<UserEntity>(UserEntity)
.Where("id", id)
.First();
}
create(user: UserEntity): SQLType {
return SQLHelp.Insertable<UserEntity>(UserEntity, user)
.ExecuteCommand();
}
updateName(id: number, name: string): SQLType {
return SQLHelp.Updateable<UserEntity>(UserEntity)
.SetColumnFiled("name", name)
.Where("id", id)
.ExecuteCommand();
}
deleteById(id: number): SQLType {
return SQLHelp.Deleteable<UserEntity>(UserEntity)
.Where("id", id)
.ExecuteCommand();
}
}拿到 SQLType 后,再接入你自己的 SQLite 执行层:
const sqlInfo = userRepository.findById(1);
// 示例:交给你的数据库工具执行
// db.prepare(sqlInfo.SQL).all(sqlInfo.data);是否需要继承 SQLPetra 的接口
一般业务项目不需要继承 IQueryable、IInsertable、IUpdateable、IDeleteable。这些接口主要用于描述 SQLPetra 内部 builder 需要实现的方法。
业务代码推荐继承自己的实体基类,或封装自己的 Repository;只有你要扩展 SQLPetra 内部 builder 时,才需要关注这些接口。
配置 TypeScript
tsconfig.json 需要开启装饰器:
如果是electron项目的话最好需要在
tsconfig.node.json中也添加配置
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}装饰器
标记表名@table
说明:
@table("test_table")表示实体对应数据库表test_table。- 如果没有使用
@table,默认使用实体类名作为表名。
使用
import { table } from "sql-petra";
@table("test_table")
export class TestTable {
}标记字段属性@column
参数
| 参数 | 类型 | 默认值 | 说明 |
| -------------- | -------------------------------------------------- | ----------- | ----------------- |
| fieldName | string | 当前属性名 | 数据库字段名 |
| fieldType | "text" | "integer" | "real" | "blob" | "numeric" | 自动推断 | SQLite 字段类型 |
| isPrimaryKey | boolean | false | 是否主键 |
| isNull | boolean | false | 是否允许为 null |
| defaultValue | string | number | null | undefined | undefined | 建表时的默认值 |
| IsIgnore | boolean | false | 是否忽略该属性 |
使用示例
import { column, table } from "sql-petra";
@table("test_table")
export class TestTable {
@column({ fieldName: "table_id", isPrimaryKey: true, isNull: true })
id?: number;
@column({ isNull: true })
name?: string;
@column({ isNull: false })
note?: string;
@column({ IsIgnore: true })
age?: number;
}字段类型推断说明
| TypeScript 类型 | SQLite 类型 |
| --------------- | ----------- |
| number | integer |
| string | text |
| boolean | integer |
| Date | text |
| Buffer | blob |
| 其它或无法识别 | text |
条件方法
该条件方法可用于查询、修改、删除 链式方法中
方法总览
| 方法名 | 参数 | 备注 |
| ------------ | ------------------------------------ | -------------------------------------------------------- |
| Where | (key, value, operator?) | where条件 |
| WhereIF | (haveValue, key, value, operator?) | where条件,如果表达式为false则不触发查询条件 |
| BetweenAnd | (key, begin, end) | 查询某个范围内的数据,比如 ID 范围、价格范围、时间范围 |
| Or | () | 把下一条条件和上一条条件用 OR 连接 |
| In | (key, values, type?) | 在给定的这个范围内查询 |
| Like | (key, value, type?) | 模糊匹配 |
类型总览
// 用于Where和WhereIF方法中的operator中
type WhereOperator = "=" | ">" | "<" | ">=" | "<=";
// 用于In方法中的type
type InType = "IN" | "NOT IN"
// 一般用于Like中的type方法
type LikeType = "left"|"right"|"all"Where条件
字段描述
key:该字段是给定类型中的字段value:条件语句的值,需要查询的条件值operator:类型条件,类型请看WhereOperator类型
数据库中做什么
生成 WHERE 字段 = @参数、WHERE 字段 > @参数 等条件;value 为 null 时生成 IS NULL
是什么意思 / 干嘛用
最常用的筛选条件,用来指定某个字段必须等于、大于、小于某个值
WhereIF条件
字段描述
haveValue:是否生效该条件key:该字段是给定类型中的字段value:条件语句的值,需要查询的条件值operator:类型条件,类型请看WhereOperator类型
数据库中做什么
haveValue 为 true 时才生成一段 WHERE 条件
是什么意思 / 干嘛用
用来写动态查询,比如搜索框有值才按关键字过滤,没有值就不过滤
BetweenAnd条件
字段描述
key:该字段是给定类型中的字段begin:其实条件值end:结束条件值
数据库中做什么
生成 字段 BETWEEN @begin AND @end
是什么意思 / 干嘛用
查询某个范围内的数据,比如 ID 范围、价格范围、时间范围
Or条件
数据库中做什么
把下一条条件和上一条条件用 OR 连接
是什么意思 / 干嘛用
表示“或者”,比如名字是张三或者李四都查出来
In条件
字段描述
key:该字段是给定类型中的字段values:条件语句的值,需要查询的条件值,类型是数组type:是否在当前范围做筛选还是在非范围内做筛选,类型请看InType
数据库中做什么
生成 字段 IN (...) 或 字段 NOT IN (...)
是什么意思 / 干嘛用
批量匹配多个值,比如查询 ID 在 [1,2,3] 中的数据,或排除这些 ID
Like条件
字段描述
key:该字段是给定类型中的字段value:条件语句的值,需要查询的条件值type:是左匹配还是右匹配还是全匹配,类型请看LikeType
数据库中做什么
生成 字段 LIKE @参数
是什么意思 / 干嘛用
模糊搜索文本,比如按姓名、标题、备注中的关键字查数据
查询数据
查询一条数据-Where
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable).Where("name", "张三").First();查询所有数据-ToList
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable).ToList();分页查询数据-ToPageList
字段描述
pageIndex:当前查询第几页pageSize:每一页的数据量大小
使用示例
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable).ToPageList(1, 20);说明
ToPageList(pageIndex, pageSize) 会生成带 LIMIT 和 OFFSET 的分页 SQL,返回值仍然是 SQLType,不直接返回分页数据对象。
查询指定字段-SelectField
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable).SelectField("name").ToList();查询字段并设置别名-Select
type TestTableView = {
tableId?: number;
userName?: string;
};
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable)
.Select<TestTableView>(x => ({
tableId: x.id,
userName: x.name
}))
.ToList();分组-GroupBy和Having
const sqlInfo = SQLHelp.Queryable<TestTable>(TestTable)
.GroupBy(["name"])
.Having("SUM", "id", 1, ">")
.ToList();GroupBy(keys) 会生成 GROUP BY,并把查询字段重置为分组字段。Having(type, key, value, operator?) 当前支持 "SUM" 和 "AVG",会生成类似 SUM(table_id) > @having_table_id_0 的条件。
聚合方法
聚合方法说明:
| 方法 | 数据库中做什么 | 是什么意思 / 干嘛用 | 返回 |
| ---------- | ------------------------------------ | ------------------------------------------------------------ | --------- |
| Count() | 生成 SELECT COUNT(1) | 统计符合条件的数据有多少条 | SQLType |
| Sum(key) | 生成 SELECT SUM(字段) | 对某个数字字段求总和,比如统计金额合计、数量合计 | SQLType |
| Avg(key) | 生成 SELECT AVG(字段) | 对某个数字字段求平均值,比如平均分、平均价格 | SQLType |
| Max(key) | 生成 SELECT MAX(字段) | 查询某个字段的最大值,比如最大 ID、最高价格 | SQLType |
| Min(key) | 生成 SELECT MIN(字段) | 查询某个字段的最小值,比如最小 ID、最低价格 | SQLType |
| Any() | 生成 SELECT COUNT(1) | 判断数据库里是否存在符合条件的数据,常用于重复校验、存在性判断 | SQLType |
注意:SQLPetra 只生成 SQL,聚合结果需要交给你的数据库执行层读取。
const countSql = SQLHelp.Queryable<TestTable>(TestTable).Count();
const sumSql = SQLHelp.Queryable<TestTable>(TestTable).Sum("id");
const avgSql = SQLHelp.Queryable<TestTable>(TestTable).Avg("id");
const maxSql = SQLHelp.Queryable<TestTable>(TestTable).Max("id");
const minSql = SQLHelp.Queryable<TestTable>(TestTable).Min("id");
const anySql = SQLHelp.Queryable<TestTable>(TestTable).Where("name", "张三").Any();新增数据
方法说明
ExecuteCommand()返回生成的SQL和参数,类型为SQLType。- 空数组会直接返回
{ SQL: "", data: {} }。 - 新增时会按实体字段统一生成 INSERT,未传入字段会以
undefined作为参数值。
新增方法说明:
| 方法 | 数据库中做什么 | 是什么意思 / 干嘛用 | 返回 |
| ----------------------------- | -------------------------------------- | ------------------------------------------------------------ | --------------- |
| SQLHelp.Insertable(Entity, data) | 生成 INSERT INTO 表(...) VALUES(...) | 告诉 SQLPetra 要为哪个表生成新增 SQL,data 可以是一条对象或对象数组 | Insertable<T> |
| ExecuteCommand() | 返回 INSERT SQL 和参数 | 前面的 Insertable 只是构造新增操作,调用它才会得到 SQL | SQLType |
新增单条数据
const sqlInfo = SQLHelp.Insertable<TestTable>(TestTable, {
id: 1,
name: "张三",
note: "第一条数据"
}).ExecuteCommand();批量新增数据
const sqlInfo = SQLHelp.Insertable<TestTable>(TestTable, [
{ id: 2, name: "张三", note: "备注" },
{ id: 3, name: "李四", note: "备注" }
]).ExecuteCommand();修改数据
方法说明
| 方法 | 数据库中做什么 | 是什么意思 / 干嘛用 | 返回 |
| ----------------------------------------------- | ---------------------------- | ---------------------------------------------------------- | --------------- |
| SQLHelp.Updateable(Entity) | 准备 UPDATE 表 SET ... | 告诉 SQLPetra 接下来要生成哪个实体对应表的更新 SQL | Updateable<T> |
| SetColumns(columns) | 生成多个 SET 字段 = @参数 | 一次设置多个要修改的列,适合表单保存、批量字段更新 | this |
| SetColumnFiled(field, value) | 生成单个 SET 字段 = @参数 | 只修改某一列,field 可传实体属性名,会映射到数据库字段名 | this |
| Where / WhereIF / BetweenAnd / Or / In / Like | 生成 WHERE 条件 | 限制更新哪些行,避免把整张表都改掉 | this |
| AllowAll() | 允许没有 WHERE 的 UPDATE | 明确告诉 ORM:这次就是要更新整张表 | this |
| ExecuteCommand() | 返回 UPDATE SQL 和参数 | 前面的链式方法只是构造更新语句,调用它才会得到 SQL | SQLType |
注意:
- 不加条件执行更新会抛出
请给定条件更新。 - 没有设置任何更新字段会抛出
请给定要更新的列。 SetColumnFiled方法名目前保留了历史拼写。
更新多个字段
const sqlInfo = SQLHelp.Updateable<TestTable>(TestTable)
.SetColumns({
id: 1,
name: "新名称",
note: "新备注"
})
.Where("id", 1)
.ExecuteCommand();更新单个字段
const sqlInfo = SQLHelp.Updateable<TestTable>(TestTable)
.SetColumnFiled("name", "新名称")
.Where("id", 1)
.ExecuteCommand();全表更新
默认不允许无条件更新。如果确实要更新全表,必须显式调用 AllowAll():
const sqlInfo = SQLHelp.Updateable<TestTable>(TestTable)
.SetColumnFiled("note", "全部修改")
.AllowAll()
.ExecuteCommand();删除数据
方法说明
| 方法 | 数据库中做什么 | 是什么意思 / 干嘛用 | 返回 |
| ----------------------------------------------- | ---------------------------- | ------------------------------------------------------ | --------------- |
| SQLHelp.Deleteable(Entity) | 准备 DELETE FROM 表 | 告诉 SQLPetra 接下来要生成哪个实体对应表的删除 SQL | Deleteable<T> |
| Where / WhereIF / BetweenAnd / Or / In / Like | 生成 WHERE 条件 | 限制删除哪些行,常见用法是按主键、状态或 ID 列表删除 | this |
| AllowAll() | 允许没有 WHERE 的 DELETE | 明确告诉 ORM:这次就是要清空整张表数据 | this |
| ExecuteCommand() | 返回 DELETE SQL 和参数 | 前面的链式方法只是构造删除语句,调用它才会得到 SQL | SQLType |
注意:不加条件执行删除会抛出 请给定条件删除。
按条件删除
const sqlInfo = SQLHelp.Deleteable<TestTable>(TestTable)
.Where("id", 1)
.ExecuteCommand();批量删除
const sqlInfo = SQLHelp.Deleteable<TestTable>(TestTable)
.In("id", [1, 2, 3], "IN")
.ExecuteCommand();全表删除
默认不允许无条件删除。如果确实要删除全表,必须显式调用 AllowAll():
const sqlInfo = SQLHelp.Deleteable<TestTable>(TestTable)
.AllowAll()
.ExecuteCommand();