Easy ORM, easy query. easy typing! Auto generate typescript declaration.
Node.js 数据库 ORM 框架
ZenWeb 衍生的核心项目,此项目可以独立使用
本框架不主动创建数据库结构,而是根据已有数据库结构来生成操作代码,这么做的原因:
- 在数据库设计层面直接定义表结构比框架生成的通用结构更细致
- 对于已有项目想要使用 ORM 支持更加友好
本框架并不是真正的 ORM 系统,而是类 ORM 的数据库操作层,几乎任何复杂查询都可实现(试试强大的 AB 工具类)
本框架诞生之因就是为了解决 SAAS 系统的单实例多租户问题,所以所有设计上都是从如何在一个系统中使用多个数据库服务器以及多个数据库而导向,
当然也支持传统的单体应用方式(配置 @zenorm/generate 的 bindQuery 即可)。
以下样例代码即是单体应用的使用方式
``bash生产依赖
npm install zenorm mysql-easy-query
配置
在
package.json 的 scripts 中增加如下代码,用于执行 dbgen 命令`json title="package.json"
{
"scripts": {
"dbgen": "zenorm-generate .dbgen.js"
}
}
`创建文件
.dbgen.js 用于生成数据库结构代码时连接到指定数据库提示:运行时并不使用此配置
`js title=".dbgen.js"
/* @type {import("@zenorm/generate").GenerateConfig} /
export default {
host: "localhost",
port: 3306,
user: "root",
password: "",
bindQuery: "pool@../db",
database: "test"
};
`演示
以下数据库结构为演示用,在数据中创建表结构
`sql
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE
profile (
id int(11) NOT NULL,
edu varchar(255) DEFAULT NULL,
work varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE
message (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) NOT NULL,
content varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`运行命令开始生成数据库结构代码
`bash
npm run dbgen
`$3
编辑生成的模型文件
src/model/user.ts`ts
import { model, join, many, propset } from 'zenorm';
import { UserTable } from './_tables';
import { Profile } from './profile';
import { Message } from './message';@model({
pk: 'id',
table: 'user',
})
export default class User extends UserTable {
// 添加以下代码
// join 描述支持使用文件名,解决互相依赖问题
@join(__dirname + '/profile', { type: 'OneToMany', asList: false })
profile?: Profile;
@join(Message)
messages?: Message[];
@many(Message)
messageList?: Message[];
@propset(function (v) {
if (v === undefined) throw new Error('age is undefined');
if (v === 99) return false;
const date = new Date();
date.setFullYear(date.getFullYear() - v, 1, 1);
this.birthday = date;
return true;
})
age = this.birthday ? ((new Date().getFullYear()) - this.birthday.getFullYear()) : undefined;
// 结束
}
`编辑生成的模型文件
src/model/profile.ts`ts
import { model, join } from 'zenorm';
import { ProfileTable } from './_tables';
import User from './user';@model({
pk: 'id',
table: 'profile',
})
export default class Profile extends ProfileTable {
// 添加以下代码
@join(User)
user?: User;
// 结束
}
`$3
创建代码
src/db.ts`ts title="src/test.ts"
import { createPoolCompatible } from 'mysql-easy-query';
import { Repositories } from './model';// 创建数据库连接池
export const pool = createPoolCompatible({
pools: {
// 主库
MASTER: {
host: '10.0.0.1',
user: 'root',
database: 'test',
password: '',
},
// 如果需要读写分离,创建命令规则为 SLAVE* 的只读配置
/*
SLAVE1: {
host: '10.0.0.2'
},
*/
}
});
`$3
#### 常规使用
`ts
import { User, Message } from './model';async function test() {
// create
const id = await User.create({ name: 'yf' });
console.log(id); // 1
// get and update
const user = await User.findByPk(id);
user.name = 'yefei';
user.age = 20;
await User.save(user);
// find all
const users = await User.find().all();
// find limit
const users = await User.find().limit(10).all();
// find by where
const users = await User.find({ name: { $like:
%y% } }).all(); // get all count
const count = await User.find().count();
// page
const page = await User.find().page();
// exists
const exists = await User.find({ name: 'yf' }).exists();
// update
const updatedCount = await User.find({ id: 1 }).update({ name: 'yf', age: 11 });
// delete
const user = await User.findByPk(1);
const deletedCount = await user.delete();
// sql delete
await User.find({ name: 'aaa' }).delete();
// join 预定义
const user = await User.find().join("messages").get();
// join 模型(未定义的)
const user = await Message.find().join(User).all();
// many 独立查询功能
const userList = await User.find().many("messageList").all();
// 指定使用主从库
await User.find().of('MASTER').all();
await User.find().of('SLAVE*').all();
}
`#### 事物支持
`ts
import { pool } from './db';
import { User, Message } from './model';async function test() {
await pool.transaction(async tx => {
await User.query(tx).find().update({ some: 'data' });
await Message.query(tx).find().update({ some: 'data' });
});
}
``