EggBornJS对EggJS中的数据库操作方法进行了进一步封装和扩展,提供了以下机制:
- 提供
ctx.db
对象,可以便利的支持数据库事务
- 提供
model
对象,可以便利的支持多实例
和软删除
ctx.db对象
EggJS是在app
对象上提供数据库连接对象,而EggBornJS在ctx
对象上提供数据库连接对象,便于在启动数据库事务
时,在上下文环境中保持同一个数据库连接。在这里,我们先看看通过ctx.db
如何完成常规的增删改查
等操作
ctx.db
提供的数据库操作方法与EggJS基本一致
在模块test-party
中,有一个数据表testParty
,我们新增后端API路由kitchen-sink/guide/echo6
,在其对应的控制器方法中进行testParty
的增删改查
等操作
src/suite-vendor/test-party/modules/test-party/backend/src/controller/kitchen-sink/guide.js
- 1async echo6() {
- 2 // testParty: insert/udpate/delete/get
- 3
- 4 // insert
- 5 const res = await this.ctx.db.insert('testParty', {
- 6 iid: this.ctx.instance.id,
- 7 deleted: 0,
- 8 personCount: 3,
- 9 });
- 10 const id = res.insertId;
- 11 // update
- 12 await this.ctx.db.update('testParty', {
- 13 id,
- 14 personCount: 5,
- 15 });
- 16 // get
- 17 const item = await this.ctx.db.get('testParty', {
- 18 id,
- 19 });
- 20 // delete
- 21 await this.ctx.db.delete('testParty', {
- 22 id,
- 23 });
- 24 // ok
- 25 this.ctx.success(item);
- 26}
model对象
model
对象对ctx.db
进行了进一步封装,可以便利的支持多实例
和软删除
多实例
:自动将ctx.instance.id
注入到ctx.db
相关方法的参数中软删除
:自动将model
的delete
方法修改为update
方法,并将数据表的deleted
字段从0
修改为1
比如,前面的代码向数据表testParty
插入一条数据,使用model
就是如下的风格:
- 1// insert
- 2await this.ctx.model.party.insert({
- 3 personCount: 3,
- 4});
model.party
自动封装了对iid
和deleted
两个字段的处理,从而使我们的代码风格更加简洁
下面,我们看看如何定义并使用model
对象
定义model对象
src/suite-vendor/test-party/modules/test-party/backend/src/model/party.js
- 1module.exports = app => {
- 2 class Party extends app.meta.Model {
- 3 constructor(ctx) {
- 4 super(ctx, { table: 'testParty', options: { disableDeleted: false } });
- 5 }
- 6 }
- 7 return Party;
- 8};
名称 | 默认值 | 说明 |
---|---|---|
table | model对象对应的数据表名,也可以是视图名 | |
disableDeleted | false | 是否禁用软删除 特性 |
注册model对象
为了支持业务模块
的编译特性,便于Webpack打包,所有对象都需要显式require
,model对象也不例外
src/suite-vendor/test-party/modules/test-party/backend/src/models.js
- 1const party = require('./model/party.js');
- 2
- 3module.exports = app => {
- 4 const models = {
- 5 party,
- 6 };
- 7 return models;
- 8};
通过models.js
注册的Model,系统会自动注册为Bean组件,并有如下约定:
注册名称 | 场景 | 所属模块 | global | beanFullName |
---|---|---|---|---|
party | model | test-party | false | test-party.model.party |
使用model对象
- 本模块内部调用
EggBornJS的Model
一般在模块内部
使用,通过ctx
对象,访问的都是当前模块
注册的Model
正是因为这种
模块隔离
设计,使得我们在大型业务开发过程中,不必担心其他模块是否也存在同名Model
- 跨模块调用
EggBornJS的Model
也允许跨模块调用,比如在模块test-party
中访问模块a-base
中的model: atom
,访问方式如下:
src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/feat/model.js
- 1// model
- 2const model = this.ctx.model.module('a-base').atom;
model方法
model对象提供了大量便利的方法,允许我们便利的操作数据库
名称 | 说明 |
---|---|
model.module | 直接访问其他模块提供的model对象 |
insert(object) | 插入单行数据 |
insert(array) | 插入多行数据 |
select | 查询数据集 |
read | 查询单行数据 |
update(object) | 更新单行数据 |
update(object,object) | 按条件更新单行或多行数据 |
delete | 删除匹配数据 |
count | 统计数据行数 |
query | 直接执行SQL语句 |
queryOne | 直接执行SQL语句,并返回首行数据 |
columns | 获取数据表的字段集合 |
prepareData(item) | 对数据进行预处理,不在columns 字段集合中的丢弃,值为undefined 的丢弃 |
- EggBornJS对
select
进行了扩展,支持更多条件设置
名称 | 说明 | 渲染效果 |
---|---|---|
select: in | 条件为数组 | key in (values) |
select: is null | 条件为null | key is null |
select: is not null | 条件为not null | key is not null |
select: like | 条件为模糊匹配 | key like ‘%value%’ |
select: likeLeft | 条件为模糊匹配 | key like ‘%value’ |
select: likeRight | 条件为模糊匹配 | key like ‘value%’ |
select: or | or语句 | ((key1 clause) or (key2 clause)) |
src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/feat/model.js
- 1const require3 = require('require3');
- 2const assert = require3('assert');
- 3
- 4module.exports = app => {
- 5
- 6 const atomStaticKey = '--model--test--';
- 7 const __rows = [
- 8 { atomStaticKey, atomName: 'atom-one', atomStage: 0 },
- 9 { atomStaticKey, atomName: 'atom-two', atomStage: 1 },
- 10 { atomStaticKey, atomName: 'atom-three', atomStage: 2 },
- 11 ];
- 12
- 13 class ModelController extends app.Controller {
- 14
- 15 async model() {
- 16
- 17 // model
- 18 const model = this.ctx.model.module('a-base').atom;
- 19
- 20 // insert one row
- 21 await model.insert(__rows[0]);
- 22 // insert multi rows
- 23 await model.insert(__rows.slice(1));
- 24
- 25 // select
- 26 let list = await model.select({
- 27 where: { atomStaticKey },
- 28 });
- 29 assert.equal(list.length, 3);
- 30
- 31 // read
- 32 const item = await model.get({
- 33 atomStaticKey,
- 34 atomName: 'atom-one',
- 35 });
- 36
- 37 // update one row
- 38 await model.update({
- 39 id: item.id,
- 40 readCount: item.readCount + 1,
- 41 });
- 42
- 43 // update with options.where and options.columns
- 44 await model.update({
- 45 readCount: 1,
- 46 }, {
- 47 where: { atomStaticKey },
- 48 columns: [ 'readCount' ],
- 49 });
- 50
- 51 // select: in
- 52 list = await model.select({
- 53 where: { atomStaticKey: [ atomStaticKey ] },
- 54 });
- 55 assert.equal(list.length, 3);
- 56 list = await model.select({
- 57 where: {
- 58 atomStaticKey: {
- 59 op: 'in', val: [ atomStaticKey ],
- 60 },
- 61 },
- 62 });
- 63 assert.equal(list.length, 3);
- 64
- 65 // select: is null
- 66 list = await model.select({
- 67 where: {
- 68 atomStaticKey: [ atomStaticKey ],
- 69 atomName: null,
- 70 },
- 71 });
- 72 assert.equal(list.length, 0);
- 73
- 74 // select: is not null
- 75 list = await model.select({
- 76 where: {
- 77 atomStaticKey: [ atomStaticKey ],
- 78 atomName: {
- 79 op: 'notNull',
- 80 },
- 81 },
- 82 });
- 83 assert.equal(list.length, 3);
- 84
- 85 // select: like
- 86 list = await model.select({
- 87 where: {
- 88 atomStaticKey: [ atomStaticKey ],
- 89 atomName: {
- 90 op: 'likeRight',
- 91 val: 'atom-',
- 92 },
- 93 },
- 94 });
- 95 assert.equal(list.length, 3);
- 96
- 97 // select: or
- 98 list = await model.select({
- 99 where: {
- 100 atomStaticKey: [ atomStaticKey ],
- 101 __or__: [
- 102 { atomName: 'atom-one' },
- 103 { atomName: 'atom-two' },
- 104 ],
- 105 },
- 106 });
- 107 assert.equal(list.length, 2);
- 108
- 109
- 110 // delete
- 111 await model.delete({ atomStaticKey });
- 112
- 113 // count
- 114 const count = await model.count({ atomStaticKey });
- 115 assert.equal(count, 0);
- 116
- 117 // done
- 118 this.ctx.success();
- 119 }
- 120
- 121 }
- 122
- 123 return ModelController;
- 124
- 125};
评论: