# simple-jsre-orm **Repository Path**: edgeros/simple-jsre-orm ## Basic Information - **Project Name**: simple-jsre-orm - **Description**: JSRE的一个简单的 ORM 框架。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-11-01 - **Last Updated**: 2024-06-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SIMPLE-JSRE-ORM Module API ## 概述 使用 simple-jsre-orm 时,首先创建自己的schema模型,随后将 scheam 导入 orm。即可通过 orm 对数据库进行操作。 ## 引用 > 创建 jsreOrm 实例,SimplejsreOrm 是 jsre-orm 的管理类,其中包含了数据库引擎选择, 初始化 Schema 模块,数据库事务封装等功能。 首先应当创建数据库引擎实例,目前 simple-jsre-orm 支持 better-sqlite3,jsre-sqlite3 数据库引擎。 ``` const database = new Database('./exa.db', { verbose: (sqlStr) => { console.log('[sqlite3:sql :]:', sqlStr) } }) ``` 如上,database 为 better-sqlite3 的数据库引擎。随后使用构造出的数据库引擎构造 SimpleJsreOrm 对象。传入的参数分别为: > database:数据库引擎实例. > type: 使用的数据库类型. > schemas: 构造的 shcema 类数组. ``` const SimpleJsreOrm = require('@edgeros/simple-jsre-orm') jsreOrm = new SimpleJsreOrm({ database: database, // 数据库实例 type: 'better-sqlite3', schemas: schemas // 模型 }) // schemas: [User, Table] User,Table 都是 schema 类 ``` ## 构建 schema 模型 const { BaseSchema } = require('@edgeros/simple-jsre-orm') 需引用 BaseSchema 模块。 BaseSchema 是 schema 模块的基类。主要有数据库建表,构造sqlQuery对象等功能。所有的 shcame 模型应继承于 BaseSchema。 ``` class User extends BaseSchema { // 表名 table = 'user' // 字段信息 columns = { id: { type: 'VARCHAR(32)', allowNull: false, autoIncrement: false, primaryKey: true }, name: { type: 'VARCHAR(32)' }, author: { type: 'VARCHAR(32)' }, releasetime: { type: 'DATETIME', aliasName: 'release_time' } } } ``` ``` table: 表名称 columns: 字段信息 字段名称: { type:数据库字段类型 allowNull: 是否允许为空 autoIncrement: 是否自增 primaryKey: 是否为主键 defaultValue: { name: '默认值', type: '类型' } aliasName: 拥有别名的字段的真实名称,若填写此字段,orm的操作均需要使用别名操作 } ``` ## 构建 better-sqlite3 引擎的 Orm 模型操作对象 ``` const db = new Database('./exa.db', { verbose: (sqlStr) => { console.log('[sqlite3:sql :]:', sqlStr) } }) jsreOrm = new SimpleJsreOrm({ database: database, // 数据库实例 type: 'better-sqlite3', schemas: schemas // 模型 }) ``` ## 构建 jsre-sqlite3 引擎的 Orm 模型操作对象 ``` const db = new Database('./exa.db', { verbose: (sqlStr) => { console.log('[jsre-sqlite3:sql :]:', sqlStr) } }) const jsreOrm = new SimpleJsreOrm({ database: database, // 数据库实例 type: 'jsre-sqlite3', // 数据库引擎类型 schemas: schemas // 模型 }) ``` ## 通过 schema 对数据库进行操作 ``` const user = jsreOrm.schema(User) /** * 插入数据 */ jsreOrm.transaction(() => { user.createQueryBuilder().insert().into(user).value({id: '7', name: 'kongfu', author: 'chouxingchi', release_time: '11:30'}).execute() user.createQueryBuilder().insert().into(user).value({id: '8', name: 'yixia', author: 'zhangtianguang', release_time: '10:30'}).execute() user.createQueryBuilder().insert().into(user).value({id: '5', name: 'liutiaohutong', author: 'erleizi', release_time: '10:30'}).execute() user.createQueryBuilder().insert().into(user).value({id: '9', name: 'zhangjiagulou', author: 'zhangqiling', release_time: '10:30'}).execute() user.createQueryBuilder().insert().into(user).value({id: '10', name: 'yundingtiangong', author: 'zhangergoou', release_time: '10:30'}).execute() }) /** * 更新数据 */ const data = { id: '7', name: 'liweikang', author: 'js', release_time: '11:30' } user.createQueryBuilder().update(user).set(data).where('id = :ids', { ids: '7' }).execute() /** * 查找单条数据 */ const row = user.createQueryBuilder().where('id = :id', { id: '7' }).getOne() console.log(row) /** * 查找多条数据 */ const rowAll = user.createQueryBuilder().getMany() console.log(rowAll) /** * 删除数据 */ jsreOrm.transaction(() => { user.createQueryBuilder().delete(user).where('id = :id', { id: '7' }).execute() user.createQueryBuilder().delete(user).where('id = :id', { id: '8' }).execute() user.createQueryBuilder().delete(user).where('id = :id', { id: '5' }).execute() user.createQueryBuilder().delete(user).where('id = :id', { id: '9' }).execute() user.createQueryBuilder().delete(user).where('id = :id', { id: '10' }).execute() }) ``` ## 通过 schema 增加通用方法操作数据库 ``` /** * 获取到 schema 对象 */ const user = jsreOrm.schema(User) /** * 通过通用方法 create 像数据库表插入一条数据 */ jsreOrm.transaction(() => { user.create({ ids: '7', name: 'kongfu', author: 'chouxingchi', releasetime: '11:30' }) user.create({ ids: '8', name: 'yixia' }) user.create({ ids: '5', name: 'liutiaohutong', author: 'erleizi', releasetime: '10:30' }) user.create({ ids: '9', name: 'zhangjiagulou', author: 'zhangqiling', releasetime: '10:30' }) user.create({ ids: '10', name: 'yundingtiangong', author: 'zhangergoou', releasetime: '10:30' }) }) /** * 通过通用方法 findBy findOne 查找数据库数据(findBy 查找多条数据,findOne 查找一条数据) * 第一个参数为 查找条件 对应 select 语句中的 where/andwhere * 第二个参数为查找目标,不填默认为查找所有 */ const raw = user.findBy({ name: 'kongfu' }) console.log(raw) console.log(user.findOne()) /** * 通过通用方法 save 升级数据库数据 * 第一个参数为替换数据 * 第二个参数为 查找条件 对应 select 语句中的 where/andwhere * 若所替换数据不存在,则插入数据 */ const str = { created: '2022-09-14T21:45:06.123229049Z', created_by: "/bin/sh -c set -eux; \tarch=\"$(uname -m)\"; \tcase \"$arch\" in \t\taarch64) gosuArch='arm64' ;; \t\tx86_64) gosuArch='amd64' ;; \t\t*) echo \u003e\u00262 \"error: unsupported architecture: '$arch'\"; exit 1 ;; \tesac; \tcurl -fL -o /usr/local/bin/gosu.asc \"https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$gosuArch.asc\"; \tcurl -fL -o /usr/local/bin/gosu \"https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$gosuArch\"; \texport GNUPGHOME=\"$(mktemp -d)\"; \tgpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \tgpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \trm -rf \"$GNUPGHOME\" /usr/local/bin/gosu.asc; \tchmod +x /usr/local/bin/gosu; \tgosu --version; \tgosu nobody true" } const js = JSON.stringify(str) const data = { ids: '7', name: 'liweikang', author: js, releasetime: '11:30' } user.save(data, { ids: '7' }) /** * 通过通用方法 removeBy 删除数据库数据 * 参数为条件 * 若所替换数据不存在,则插入数据 */ user.removeBy({ ids: '7' }) user.removeBy({ ids: '8', name: 'yixia', author: 'zhangtianguang', releasetime: '10:30' }) user.removeBy({ ids: '5', name: 'liutiaohutong', author: 'erleizi', releasetime: '10:30' }) user.removeBy({ ids: '9', name: 'zhangjiagulou', author: 'zhangqiling', releasetime: '10:30' }) user.removeBy({ ids: '10', name: 'yundingtiangong', author: 'zhangergoou', releasetime: '10:30' }) /** * 通过通用方法 findLike 生成 where Like 语句 getMany */ const keyWord = 'aaaa' const raw = user.findLike({ 'user.name': `%${keyWord || ''}%` }, 'count(id) as count') console.log(raw) /** * 通过通用方法 findLikeOne 生成 where Like 语句 getOne */ const keyWord = 'aaaa' const raw = user.findLikeOne({ 'user.name': `%${keyWord || ''}%` }, 'count(id) as count') console.log(raw) ``` ## Query Builder操作说明 # Query Builder操作说明 ## 什么是Query Builder QueryBuilder 是 jsre-orm 的功能之一 ,它允许你使用优雅便捷的语法构建 SQL 查询,执行并获得自动转换的实体 ### 使用参数来转义数据 我们使用了 `where('user.name = :name', { name: 'Timber' })` 其中 `{name:'Timber'} `代表什么? 这是我们用来阻止 SQL 注入的参数。 我们可以写:`where("user.name ='"+ name +"')` 但是这不安全,因为有可能被 SQL 注入。 安全的方法是使用这种特殊的语法:`where('user.name =name',{name:'Timber'})` 其中 name 是参数名,值在对象中指定: `{name:'Timber'}` `.where("user.name = :name", { name: 'Timber' })` ### 使用 Query Builder 查询 我们使用 `createQueryBuilder('user')` 来构建一个 `QueryBuilder` 对象。其中 `createQueryBuilder` 传参既可以是这个 `schemas` 的 `table` 名称。也可以是这个 `schema` 的对象名。 #### 添加 WHERE 表达式 添加 WHERE 表达式就像: ``` const row = user.createQueryBuilder().where('id =:ids', {ids: 1}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句 ``` SELECT ... FROM 'user' WHERE id =1 ``` 你可以将 AND 添加到现有的 WHERE 表达式中: ``` const SelectQuery = user.createQueryBuilder() .where('id =:ids', {ids: 1}) .andWhere('name = :name', {name: 'xiaoming'}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句 ``` SELECT ... FROM 'user' WHERE id =1 AND name = 'xiaoming' ``` 你也可以将OR添加到现有的WHERE表达式中: ``` const SelectQuery = .user.createQueryBuilder() .where('id =:ids', {ids: 1}) .orWhere('name = :name', {name: 'xiaoming'}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句 ``` SELECT ... FROM 'user' WHERE id =1 OR name = 'xiaoming' ``` 当然你也可以随意组合 ``` const SelectQuery = user.createQueryBuilder() .where('id =:ids AND age = :ages', {ids: 1, ages: 26}) .orWhere('(name = :name AND count = :count)', {name: 'xiaoming', count: 20}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句 ``` SELECT ... FROM 'user' WHERE id =1 AND age = 26 OR (name = 'xiaoming' AND count = 20) ``` 你可以根据需要组合尽可能多的 AND 和 OR 表达式。 如果你多次使用.where,你将覆盖所有以前的 WHERE 表达式。 #### 添加HAVING表达式 添加 HAVING 表达式很简单: ``` const SelectQuery = user.createQueryBuilder() .having('name = :names', {names: 'xiaoming'}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT people.id, people.name, people.author, people.release_time FROM 'user' 'people' HAVING name = 'xiaoming' ``` 你可以添加 AND 到已经存在的 HAVING 表达式中: ``` const SelectQuery = user.createQueryBuilder() .having('name = :names', {names: 'xiaoming'}) .andHaving('id = :ids', {ids: 2}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT people.id, people.name, people.author, people.release_time FROM 'user' 'people' HAVING name = 'xiaoming' AND id = 2 ``` 你可以添加 OR 到已经存在的 HAVING 表达式中: ``` const SelectQuery = user.createQueryBuilder() .having('name = :names', {names: 'xiaoming'}) .orHaving('id = :ids', {ids: 2}) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT people.id, people.name, people.author, people.release_time FROM 'user' 'people' HAVING name = 'xiaoming' OR id = 2 ``` #### 添加ORDER BY表达式 添加 ORDER BY 很简单 ``` const SelectQuery = usr.createQueryBuilder() .orderBy('id') // 其中 user 为 schema 模型对象 ``` 将会生成一下 SQL 语句: ``` SELECT ... FROM 'user' 'people' ORDER BY id ASC ``` 你可以将排序方向从升序更改为降序(或反之亦然): ``` const SelectQuery = user.createQueryBuilder() .orderBy('id', 'DESC') // 其中 user 为 schema 模型对象 ``` ``` const SelectQuery = user.createQueryBuilder() .orderBy('id', 'ASC') // 其中 user 为 schema 模型对象 ``` 也可以添加多个排序条件 ``` const SelectQuery = user.createQueryBuilder() .orderBy('id').addOrderBy('count') // 其中 user 为 schema 模型对象 ``` 还可以使用排序字段作为一个 map: ``` const SelectQuery = user.createQueryBuilder() .orderBy({ 'id': 'ASC', 'name':'DESC' }) // 其中 user 为 schema 模型对象 ``` 如果你使用了多个.orderBy,后面的将覆盖所有之前的ORDER BY表达式 #### 添加 GROUP BY 表达式 添加 GROUP BY 表达式很简单: ``` const SelectQuery = user.createQueryBuilder() .groupBy('id') // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT ... FROM 'user' 'people' GROUP BY id ``` 如果要使用更多 group-by, 则可以使用 addGroupBy: ``` const SelectQuery = user.createQueryBuilder() .groupBy('id').addGroupBy('name') // 其中 user 为 schema 模型对象 ``` 如果使用了多个.groupBy ,则后面的将会覆盖之前所有的 GroupBy表达式。 #### 添加 LIMIT 表达式 添加 LIMIT 表达式很简单: ``` const SelectQuery = user.createQueryBuilder() .limit(10) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT ... FROM 'user' 'people' LIMIT 10 ``` 添加 OFFSET 表达式 添加 SQLOFFSET 表达式很简单: ``` const SelectQuery = user.createQueryBuilder() .offset(10) // 其中 user 为 schema 模型对象 ``` 将会生成以下 SQL 语句: ``` SELECT ... FROM 'user' 'people' OFFSET 10 ``` ### 联查 #### 如果你想使用 INNER JOIN ``` const SelectQuery = user.createQueryBuilder() .innerJoin('table', 'grade', 'grade.id = :id', {id: 'people.id'}) .where('count = :count', {count: 22}) // 其中 user 为 schema 模型对象 ``` 这将生成以下SQL : ``` SELECT people.id, people.name, people.author, people.release_time FROM 'user' 'people' INNER JOIN 'table' 'grade' ON grade.id = people.id WHERE count = 22 ``` #### 如果你想使用 LEFT JOIN ``` const SelectQuery = user.createQueryBuilder() .leftJoin('table', 'grade', 'grade.id = :id', {id: 'people.id'}) .where('count = :counts', {counts: 22}) // 其中 user 为 schema 模型对象 ``` 这将生成以下SQL : ``` SELECT people.id, people.name, people.author, people.release_time FROM 'user' 'people' LEFT JOIN 'table' 'grade' ON grade.id = people.id WHERE count = 22 ``` #### 使用 Query Builder 插入 ``` user.createQueryBuilder().insert() .into(user) .value({id: 3, name: 'sanguoyanyi', author: 'luoguanzhong', release_time: '10:30'}) // 其中 user 为 schema 模型对象 ``` #### 使用 Query Builder 更新 ``` const UpdataQuery = user.createQueryBuilder() .update(user) .set({id: 10, name: 'zhangwuji'}) .where('id = :ids AND name = :names', {id: 1, name: 'liweikang'}) // 其中 user 为 schema 模型对象 ``` #### 使用 Query Builder 删除 ``` const DeleteQuery = user.createQueryBuilder() .delete() .from(user) .where('release_time = :num', {num: '14:30'}) // 其中 user 为 schema 模型对象 ``` 获取 SQL 语句和执行 SQL 使用 toSql() 方法 使用 toSql() 方法,只是获取 SQL 语句,并不执行 使用 execute() 方法 使用 execute() 方法,执行 SQL 操作 使用 getOne(), getMany() 方法执行查询操作 要从数据库中获取单个结果,使用 getOne() ,要从数据库中获取多个结果,使用 getMany() ### 事务 #### jsreOrm 封装事务处理 ``` jsreOrm.transaction(() => { user.createQueryBuilder().insert().into(user).value({ id: '7', name: 'kongfu', author: 'chouxingchi', release_time: '11:30' }).execute() user.createQueryBuilder().insert().into(user).value({ id: '8', name: 'yixia', author: 'zhangtianguang', release_time: '10:30' }).execute() user.createQueryBuilder().insert().into(user).value({ id: '5', name: 'liutiaohutong', author: 'erleizi', release_time: '10:30' }).execute() user.createQueryBuilder().insert().into(user).value({ id: '9', name: 'zhangjiagulou', author: 'zhangqiling', release_time: '10:30' }).execute() user.createQueryBuilder().insert().into(user).value({ id: '10', name: 'yundingtiangong', author: 'zhangergoou', release_time: '10:30' }).execute() }) }) ``` ### 迁移 构建 MigrateOperate 对象,调用init方法执行检测迁移。MigrateOperate 对象参数分别为 db 实例,配置目标版本号,版本文件夹路径, jsreOrm 实例。 使用迁移需配置项目的数据库版本表,使用指令 npx createmigrate path='./......' 会根据指定的路径创建一个以时间戳命名的数据库版本文件 ecsmdb_migrate_20221027154159 ``` module.exports = { up (sqlInterface) { sqlInterface.transaction(() => { }) }, down (sqlInterface) { sqlInterface.transaction(() => { }) } } ``` 用户可以在生成的文件中填充升级和降级需求,例如: ``` module.exports = { up (sqlInterface) { sqlInterface.transaction(() => { sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task ADD os varchar(10)' ) sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task ADD arch varchar(10)' ) }) }, down (sqlInterface) { sqlInterface.transaction(() => { sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task drop os' ) sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task drop arch' ) }) } } ``` 如上,在生成的新脚本文件中 up() 函数中,执行升级事务操作。若回退版本,则需完成 down() 函数的编写。 ``` up (sqlInterface) { sqlInterface.transaction(() => { sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task ADD os varchar(10)' ) sqlInterface.schema('image_sync_task')._executeSql( 'ALTER TABLE image_sync_task ADD arch varchar(10)' }) } ``` 配置完成后,构造 MigrateOperate 对象,并调用其 init() 方法执行数据库 MigrateOperate 对象是数据库迁移的核心单元。构造 MigrateOperate 对象时传参:migrateTarget 中包含目标版本号, 数据库版本脚本文件路径。jsreOrm 为构造出来的 Jsre-Orm 对象。构造成功后调用 init() 接口,会根据传入的config 与数据库的版本信息做对比,判断升级还是降级,并执行版本脚本到目标脚本。 ``` const sqlMigrate = new MigrateOperate(migrateTarget, jsreOrm) sqlMigrate.init() /* migrateTarget : { migrationTarget: 目标版本号, versionsFilePath: 版本脚本路径} jsreOrm: jsreOrm = new SimpleJsreOrm({ database: database, // 数据库实例 type: 'better-sqlite3', schemas: schemas // 模型 }) */ ```