npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@qtk/orm-framework

v3.4.1

Published

orm

Downloads

53

Readme

qtk-orm-framework

qtk-orm-framework是一个Node版的K-V型数据操作框架,支持一对一,一对多两种关系,存储目前支持MysqlRedis两种类型.框架致力于提供一套简单的API去操作K-V结构数据,使用者只需定义一份数据描述文件数据库配置文件,框架将会帮你实现建库建表(Mysql)建索引(Mysql)增删改查数据分表分库数据校验数据缓存数据热迁移. 框架有两个核心概念ObjectRelation

  • Object: 存储一对一关系的实体,可以将其理解为Document(文档),数据中必须包含id字段,主键为id
  • Relation: 存储一对多关系的实体,可以将其理解为Collection(容器),一个容器里面有多个Document(文档),数据中必须包含subjectobject字段,subject为容器id,object为文档id,主键为${subject}_${object}

安装

#in your project
npm install @qtk/orm-framework --save
# install global
npm install @qtk/orm-framework -g

文档

建库建表建索引

orm_build_mysql -s <schema path> -r <router path> -t <object or relation> <module name>

# example
orm_build_mysql -s ./test/config/object/schema -r ./test/config/object/router -t object user
orm_build_mysql -s ./test/config/relation/schema -r ./test/config/relation/router -t relation user.message

删库删表删索引

orm_destroy_mysql -r <router path> <module name>

#example
orm_destroy_mysql -r ./test/config/object/router user
orm_destroy_mysql -r ./test/config/relation/router user.message

清库

orm_purge_data -r <router path> <module name>

#example
orm_purge_data -r ./test/config/object/router user
orm_purge_data -r ./test/config/object/router user.message

API

初始化

const ORM = require('@qtk/orm-framework');
ORM.setup({
    objectSchemaPath: `${__dirname}/config/object/schema`,
    objectRouterPath: `${__dirname}/config/object/router`,
    relationSchemaPath: `${__dirname}/config/relation/schema`,
    relationRouterPath: `${__dirname}/config/relation/router`,
    strict: true
});
const ObjectUser = new ORM.Object('user');
const RelationUserMessage = new ORM.Relation('user.message');
  • objectSchemaPath: object的schema文件夹路径
  • objectRouterPath: object的router文件夹路径
  • relationSchemaPath: relation的schema文件夹路径
  • relationRouterPath: relation的router文件夹路径
  • strict: 严格模式,默认true.当数据库中的值结构跟schema数据描述不相符时,为false时会依照schema描述重新构造拷贝数据后,再进行schema校验.而true时则直接进入schema校验,此情况抛数据错误.

Object

提供对象操作方法

|方法名|输入|返回|作用| |--|--|--|--| |set|(object)|无|添加/更新一条数据,object里必须含有id字段| |get|(id)|object|读取某条记录| |has|(id)|boolean|查询某条数据是否存在| |del|(id)|无|删除某条数据| |arrayNodeAppend|(id, path, ...items)|无|给某条记录下的数组节点尾部添加一个或多个元素| |arrayNodeUnshift|(id, path, ...items)|无|给某条记录下的数组节点头部添加一个或多个元素| |arrayNodeInsert|(id, path, item)|无|给某条记录下的数组节点某个索引位置插入一个元素| |arrayNodeUnshift|(id, path, ...items)|无|给某条记录下的数组节点头部添加一个或多个元素| |arrayNodeDel|(id, path)|无|删除某条记录下的数组节点里指定位置的元素| |arrayNodePop|(id, path)|object|弹出某条记录下的数组节点尾部一个元素| |arrayNodeShift|(id, path)|object|弹出某条记录下的数组节点头部一个元素| |find|({where?, sort?, limit?, group?})|array|查找所有符合规则的object,支持排序、分页、分组| |fieldFind|({field?,where?, sort?, limit?,group?})|array|查找所有符合规则的object,支持排序、分页、分组、取单个字段| |count|(where,group)|integer|统计所有符合规则的object数量| |query|(sql)|array|执行原生sql|

Relation

提供关系操作方

|方法名|输入|返回|作用| |--|--|--|--| |fetch|(subject, object)|object|返回关系中某个对象| |put|(relation)|无|将某个对象放入关系中,relation必须包含subject, object两个字段| |has|(subject, object)|boolean|判断关系中含有某个对象| |remove|(subject, object)|无|从关系中移除某个对象| |clear|(subject)|无|清空关系里所有对象| |list|(subject, sort?, limit?, filter?)|array|返回关系中的对象,可筛选、排序、分页| |count|(subject, filter?)|integer|统计关系中的对象,可筛选|

Logic

提供一套标准的查询、排序、分页语法,在Objectfindcount,Relationlistcount中可以使用

const {whereEq, whereNq, whereGt, whereGe, whereLt, whereLe, whereContain, whereContainBoolean,whereIn, whereBetween, whereLike, whereAnd, whereOr, whereNot, sort, limit, field , group } = require('@qtk/orm-framework').Logic;

|方法|作用|参数|示例(按照属性栏的顺序)| |--|--|--|--| |whereEq|等于|(field, value)|whereEq('.a', 1)| |whereNq|不等于|(field, value)|whereNq('.a', 1)| |whereGt|大于|(field, value)|whereGt('.a', 1)| |whereGe|大于等于|(field, value)|whereGe('.a', 1)| |whereLt|小于|(field, value)|whereLt('.a', 1)| |whereLe|小于等于|(field, value)|whereLe('.a', 1)| |whereContain|数组包含|(field, value)|whereContain('.arr[]', 1)| |whereContainBoolean|数组包含|(field, value)|whereContainBoolean('.arr[]', 1)| |whereIn|枚举|(field, ...values)|whereIn('.a', 1, 2, 3)| |whereBetween|区段之间|(field, from, to)|whereBetween('.a', 1, 2)| |whereLike|模糊匹配|(field, value)|whereLike('.a', '%a%')| |whereAnd|与|(...items)|whereAnd(whereEq('.a', 1), whereLt('.b', 1))| |whereOr|或|(...items)|whereOr(whereEq('.a', 1), whereLt('.b', 1))| |whereNot|非|item|whereNot(whereEq('.a', 1))| |WhereIsUndef|是否为非NULL (判断是否为非空数组也可以使用这个方法)|(field)|WhereIsUndef('.a')| |WhereIsDef|是否为NULL (判断是否为空数组也可以使用这个方法)|(field)|WhereIsDef('.a')| |sort|排序|(field, order = "ASC")|sort('.a', 'DESC')| |limit|分页|(limit, skip = 0)|limit(1,1)| |field|select 单个字段 |(field, alias)|field('.name','nameS'),field('count(1)','count')| |group|分组|(field)|group('.name')|

JSON化

Logic对象是一个类对象,不支持通过网络传输。故Logic对象提供toJson方法,允许将Logic对象转换为JSON对象.同时在原本使用Logic对象的地方支持使用JSON化后对象进行操作

let result = await ObjectUser.find({where: ORM.Logic.whereEq('.id', Users[0].id)});
assert(result.length == 1 && result[0].id == Users[0].id, `object find where [.find(id where operator =)] failed`);

//等同于下面
result = await ObjectUser.find({where: ORM.Logic.whereEq('.id', Users[0].id).toJson()});
assert(result.length == 1 && result[0].id == Users[0].id, `[toJson]object find where [.find(id where operator =)] failed`);

例子

const ORM = require('@qtk/orm-framework');
ORM.setup({
    objectSchemaPath: `${__dirname}/config/object/schema`,
    objectRouterPath: `${__dirname}/config/object/router`,
    relationSchemaPath: `${__dirname}/config/relation/schema`,
    relationRouterPath: `${__dirname}/config/relation/router`,
});
const ObjectUser = new ORM.Object('user');
const ObjectMessage = new ORM.Object('message');
const RelationUserMessage = new ORM.Relation('user.message');

const user = {
    id: '0000000000000001',
    name: 'Cindy',
    gender: 0,
    money: 110,
    null: null,
    location: {
        lng: '113.46',
        lat: '22.27'
    },
    isVip: false,
    friends: [],
    extraObject: {
        count: 1
    },
    maybeUndef: 1
}
const user2 = {
    id: '0000000000000002',
    name: 'Jessica',
    gender: 0,
    money: 120,
    null: null,
    location: {
        lng: '122.67',
        lat: '23.45'
    },
    isVip: true,
    friends: [{
        fid: '0000000000000003',
        time: 1516538014
    }],
    extraArray: ["1","2","3"],
    extraInteger: 0
}
const message = {
    id: 1,
    title: "hello",
    content: "hey",
    sendTime: 1516538014
}
const userMessage = {
    subject: '0000000000000001',
    object: 1,
    status: 1,
    readTime: 1516538014,
    maybeUndef: 1
}
const friend1 = {fid: uuid().replace(/-/g, ""), time: parseInt(Math.random() * 100)};
const friend2 = {fid: uuid().replace(/-/g, ""), time: parseInt(Math.random() * 100)};

await ObjectUser.set(user);
await ObjectUser.set(user2);
await ObjectMessage.set(message);
console.log(await ObjectUser.has(user.id));
console.log(await ObjectUser.get(user.id));

await ObjectUser.arrayNodeAppend(user.id, '.friends', friend1, friend2);
await ObjectUser.arrayNodeUnshift(user.id, '.friends', friend1, friend2);
await ObjectUser.arrayNodeInsert(user.id, '.friends', 1, friend2);
await ObjectUser.arrayNodeDel(user.id, '.friends', 1);
console.log(await ObjectUser.arrayNodePop(user.id, '.friends'));
console.log(await ObjectUser.arrayNodeShift(user.id, '.friends'));

console.log(await ObjectUser.find());
console.log(await ObjectUser.find({where: ORM.Logic.whereEq('.id', user.id)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereEq('.name', user.name)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereNot(ORM.Logic.whereEq('.name', user.name))}));
console.log(await ObjectUser.find({where: ORM.Logic.whereIn('.name', user.name, user2.name)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereAnd(
    ORM.Logic.whereEq('.name', user.name),
    ORM.Logic.whereEq('.id', user.id)
)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereOr(
    ORM.Logic.whereEq('.name', user.name),
    ORM.Logic.whereEq('.name', user2.name)
)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereLike('.name', `%${user.name.substr(1, 3)}%`)}));
console.log(await ObjectUser.find({where: ORM.Logic.whereBetween('.money', 1, 111)}));  
console.log(await ObjectUser.find({where: ORM.Logic.whereContain('.friends[*].fid', '0000000000000003')})); 
console.log(await ObjectUser.find({where: ORM.Logic.whereIsUndef('.maybeUndef')}));
console.log(await ObjectUser.find({where: ORM.Logic.whereIsDef('.maybeUndef')}));
console.log(await ObjectUser.find({sort: ORM.Logic.sort('.id', "desc")}));
console.log(await ObjectUser.find({limit: ORM.Logic.limit(1), sort: ORM.Logic.sort('.id')}));
console.log(await ObjectUser.find({limit: ORM.Logic.limit(1, 1), sort: ORM.Logic.sort('.id', 'DESC')}));
console.log(await ObjectUser.find({limit: ORM.Logic.limit(1, 1), sort: [ORM.Logic.sort('.id', 'DESC'), ORM.Logic.sort('.money', 'ASC')]}));

console.log(await ObjectUser.count());
console.log(await ObjectUser.count(ORM.Logic.whereEq('.id', user.id)));
console.log(await ObjectUser.count(ORM.Logic.whereEq('.name', user.name)}));
console.log(await ObjectUser.count(ORM.Logic.whereNot(ORM.Logic.whereEq('.name', user.name))));
console.log(await ObjectUser.count(ORM.Logic.whereIn('.name', user.name, user2.name)));
console.log(await ObjectUser.count(ORM.Logic.whereAnd(
    ORM.Logic.whereEq('.name', user.name),
    ORM.Logic.whereEq('.id', user.id)
)));
console.log(await ObjectUser.count(ORM.Logic.whereOr(
    ORM.Logic.whereEq('.name', user.name),
    ORM.Logic.whereEq('.name', user2.name)
)));
console.log(await ObjectUser.count(ORM.Logic.whereLike('.name', `%${user.name.substr(1, 3)}%`)));
console.log(await ObjectUser.count(ORM.Logic.whereBetween('.money', 1, 111)}));  
console.log(await ObjectUser.count(ORM.Logic.whereContain('.friends[*].fid', '0000000000000003'))); 
console.log(await ObjectUser.count(ORM.Logic.whereIsUndef('.maybeUndef')));
console.log(await ObjectUser.count(ORM.Logic.whereIsDef('.maybeUndef')));
console.log(await ObjectUser.count(RM.Logic.sort('.id', "desc")));
console.log(await ObjectUser.count(ORM.Logic.limit(1), sort: ORM.Logic.sort('.id')));
console.log(await ObjectUser.count(ORM.Logic.limit(1, 1), sort: ORM.Logic.sort('.id', 'DESC')));
console.log(await ObjectUser.count(ORM.Logic.limit(1, 1), sort: [ORM.Logic.sort('.id', 'DESC'), ORM.Logic.sort('.money', 'ASC')]));

console.log(await ObjectUser.del(user.id));

await RelationUserMessage.put(userMessage);
console.log(await RelationUserMessage.has(user.id, message.id));
console.log(await RelationUserMessage.fetch(user.id, message.id));
console.log(await RelationUserMessage.count(user.id));
console.log(await RelationUserMessage.count(Users[0].id, ORM.Logic.whereEq('.status', 2)));
console.log(await RelationUserMessage.count(Users[0].id, ORM.Logic.whereIsUndef('.maybeUndef')));
console.log(await RelationUserMessage.count(Users[0].id, ORM.Logic.whereIsDef('.maybeUndef')));
console.log(await RelationUserMessage.list(user.id, ORM.Logic.sort('.status', 'DESC'), ORM.Logic.limit(1, 1)));
console.log(await RelationUserMessage.list(user.id, [ORM.Logic.sort('.status', 'DESC'), ORM.Logic.sort('.readTime', 'DESC')], ORM.Logic.limit(1, 1)));
console.log(await RelationUserMessage.list(user.id, [ORM.Logic.sort('.status', 'DESC'), ORM.Logic.sort('.readTime', 'DESC')], ORM.Logic.limit(1, 1)), ORM.Logic.whereEq('.status', 2));

console.log(await RelationUserMessage.remove(user.id, message.id));
console.log(await RelationUserMessage.clear(user.id));

更详细的操作,请看测试用例[github才能支持]

Schema定义(数据描述)

  • 关键字

    • id : object的主键
    • subject : relation键之一
    • object : relation键之一,relation的主键为 ${subject}_${object}
  • 数据类型

    • string : 字符串
    • boolean : 布尔型
    • integer : 整形
    • number : 数字
    • object : 对象
    • array : 数组
    • empty : 空对象,值为 null
  • 方法

    • 通用
      • desc(value) : 字段描述
      • example(value) : 字段值例子
      • default(value) : 字段默认值, 如果字段是必须的,但数据库里的值是undefined, 那么object的getfind,relation的fetch, list操作将会在返回数据时候自动给其加上默认值.注意:对于设置了默认值且数据库里值为undefined的字段,在进行排序、查找时,使用的值是数据库里的值,即undefined而不是默认值
      • enum(value1,value2...) : 值枚举
    • number/integer
      • max(value) : 最大值
      • min(value) : 最小值
      • exclusiveMin(value) : 字段值不小于
      • exclusiveMax(value) : 字段值不大于
      • multipleOf(value) : 字段值是定义值的整数倍
    • array
      • minItems(value) : 元素最少个数
      • maxItems(value) : 元素最多个数
      • length(value) : 元素个数
      • contains(value) : 数组必须包含的值
      • uniqueItems() : 每个元素必须唯一,支持对象元素(比较每个对象的key && value是否相同)
      • item(value/array) : 定义数组里每个元素的结构
    • string
      • maxLength(value) : 最大长度
      • minLength(value) : 最小长度
      • length(value) : 长度
      • pattern(value) : 字符串必须匹配的正则
    • object
      • properties(object) : 定义对象的结构
      • patternProperties(object) : 使用正则来定义对象的结构
      • additionalProperties(boolean) : 是否允许实例拥有非[properties]里定义的节点
      • require(value1, value2...) : 实例必须拥有[properties]里定义的节点
      • requireAll() : [properties]里定义的节点全是必须的
      • if...then...elseIf...else...endIf : 根据实例不同的情况可以拥有不同的propertiespatternPropertiesrequirerequireAll定义
    • string/number/integer
      • index() : 给对应的Key加索引.目前支持stringintegernumberarray里的元素类型,对于非数组元素里的string类型,必须设置length或者maxLength. 由于Objectkeyword的id,Relationkeyword的subjectobject默认设置了索引,故当其为string类型时,必须设置长度.而对于数组元素里的string类型则不用设置长度,因为采用的是全文索引
  • 语法糖

| sugar | equivalent | | -------------- | -------------------------------------------- | | 1 | integer().enum(1) | | 1.1 | number().enum(1.1) | | 'foo' | string().enum('foo') | | /^foo|bar$/ | string().pattern(/^foo|bar$/) | | true | boolean().enum(true) | | null | NULL() or empty() | | {foo: 1} | object().properties({foo: 1}).requiredAll().additionalProperties(false) | | [1, 2, 3] | integer().enum(1, 2, 3) | | [1.1, 2.2, 3] | number().enum(1.1, 2.2, 3) | | ['foo', 'bar'] | string().enum('foo', 'bar') | | [true, false] | boolean().enum(true, false) |

module.exports = {
    id: string().length(16), //如果id是字符串类型, 那么必须设置length或者maxLength
    name: string(),
    gender: integer().enum(0, 1).index(),
    money: number().min(0),
    null: empty(),
    location: {
        lng: string().length(6).index(), //对象里某个节点做索引
        lat: string().desc('lat').default("2")
    },
    isVip: boolean(),
    friends: array().item({
        fid: string().pattern(/^[A-Za-z0-9]{1,}$/).index(), //可以针对数组里每个元素的某个值做索引
        time: integer()
    }),
    record: array(string().index()), //可以针对数组里每个元素做索引
    extraObject: object({
        count: integer()
    }).default({count: 10}),
    extraArray: array(string()).default(['default array']),
    extraInteger: integer().default(0),
    extraNumber: number().default(0.9).index(),
    extraBoolean: boolean().default(false),
    extraString: string().default("default").index().maxLength(32)
};
module.exports = object({
    subject: string().length(32), //string类型必须设置长度
    object: integer(), //若是string类型也应设置长度
    status: integer().enum(0, 1, 2).desc('0:未读; 1:已读; 2:已删'),
    readTime: integer().default(0),
    deletedTime: integer().default(0)
})
    .if.properties({status: 1})
    .then.require('subject', 'object', 'status', 'readTime').additionalProperties(false)
    .elseIf.properties({status: 2})
    .then.require('subject', 'object', 'status', 'deletedTime').additionalProperties(false)
    .else
    .require('subject', 'object', 'status').additionalProperties(false)
    .endIf

Router定义(数据库配置)

user.js //当前使用的数据库路由文件
user.deprecated.js //废弃的数据库路由文件
module.exports = {
    persistence: {
        shards: [
            {
                media: "mysql",
                host: "localhost",
                port: 3306,
                user: "root",
                password: "",
                database: "db_test_game",
                table: "o_user",
            }
        ],
        hash: function (id) {
            return this.shards[0];
        }
    },
    cache: {
        shards: [
            {
                media: "redis",
                host: "localhost",
                port: 6379,
                bucket: 'o_user_'
            }
        ],
        hash: function (id) {
            return this.shards[0];
        }
    }
};

路由的文件名跟schema定义的文件名一一对应,路由文件有两种状态:当前(xxx.js)及废弃(xxx.deprecated.js).框架主力使用当前路由配置,万一同级目录下存在同名废弃路由的话,使用过程中会对数据进行热迁移. 每份路由可配置persistencecache节点,每个节点下配置分片信息shards及分片规则hash.persistence顾名思义就持久化存储,目前框架内置支持mysql,而cache内置支持redis. shards: 数组,每个元素表示一个分片信息 hash: 哈希函数,输入参数是id.在对某条数据进行操作时,框架将给哈希函数传入数据的id(Object是id字段,Relation是subject字段),函数根据id映射到shards某个分片上 若persistencecache同时配置的话,那么读操作会优先操作cache(除了Objectfindcount,Relationlistcount),若有数据则立即返回,若无则会继续查询persistence,若有数据,在返回数据同时也同步一份到cache中.写操作则是等待两边操作完毕后才返回

具体热迁移逻辑如下:

|模式|方法|处理逻辑| |--|--|--| |Object|get|优先查当前,若无则查废弃,有结果则同步该数据到当前| |Object|set|只写当前| |Object|has|同Object.get| |Object|del|当前、废弃同时删除| |Object|arrayNodeAppend|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|arrayNodeUnshift|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|arrayNodeInsert|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|arrayNodeDel|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|arrayNodePop|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|arrayNodeShift|首先Object.has检查,其顺带数据迁移,之后只写当前| |Object|find|优先查当前,若无则查废弃,有结果则返回但不做同步| |Object|fieldFind|优先查当前,若无则查废弃,有结果则返回但不做同步| |Object|count|同Object.find| |Relation|fetch|同Object.get| |Relation|put|同Object.set| |Relation|has|同Object.has| |Relation|remove|同Object.del| |Relation|clear|同Object.del| |Relation|list|同Object.find|

注意(坑)

  • schema定义文件若给字段设置默认值, 那么该字段也应是必须的,否则不会自动补上默认值
  • schema定义文件若给字段设置默认值且数据库里该字段值为undefined时,在进行排序、查找操作时,使用的值是数据库里的值,即undefined而不是默认值
  • Objectfindcount,Relationlist,count考虑到可能会涉及多条数据情况,为了不影响性能,故上述方法不支持数据热迁移
  • 当Router里配置cachepersistence时,即开启数据缓存功能(加速读),此情况存在有些数据还未加载到cache情况,故Objectfindcount、Relationlistcount将会直接读取persistence来保证数据的准确性
  • Objectfind提供的是Object搜索功能,若Router里存在多个shards时,即开启数据分片功能,由于无法根据id定位到具体的分片,故会查询所有的分片信息,并合并结果返回.在此种情况下无法进行分页排序,故不支持sortlimit
  • 使用whereContain时,其实现原理是全文搜索,故需要保证字段内容长度 >=ft_min_word_len ,数据库默认ft_min_word_len为4

自定义存储介质

框架内部支持mysql与redis两种存储介质,若想换一种存储媒介或者重新设计底层数据结构的话,那么可以继承框架的BackendMedia基类,实现指定的函数功能后,以插件的形式注册到框架上.那么即可无痛更换,而不用修改任何代码.

构造函数

负责初始化存储媒介的链接.构造函数有两个参数:

connParam: 经过哈希函数计算得到的分片信息

indexes: 该ObjectRelation的字段索引列表

constructor(connParam, indexes) {
    super(connParam, indexes);
}

connParam值例子:

{
    "media":"mysql",
    "host":"localhost",
    "port":3306,
    "user":"root",
    "password":"",
    "database":"db_orm",
    "table":"o_user"
}

indexes值例子:

[
    '.id', 
    '.gender', 
    '.location.lng', //对象里某个字段索引
    '.extraNumber',
    '.arr[*]', //数组索引
    '.friends[*].fid' //数组索引
]

插件名

实现静态media,返回值与路由文件里shards里配置的media字符值相同

static get media() { //set media name
    return 'redis';
}

方法

|方法|入参|有结果返回|无结果返回|必须实现|作用| |--|--|--|--|--|--| |objectGet|(id)|object|undefined|是|获取对象记录| |objectSet|(id, value)|无|无|是|添加/更新对象记录| |objectHas|(id)|true|false|是|查询对象记录是否存在| |objectDel|(id)|无|无|是|删除对象记录| |objectArrayNodeAppend|(id, path, items)|无|无|否|给某条记录下的数组节点尾部添加一个或多个元素| |objectArrayNodeUnshift|(id, path, items)|无|无|否|给某条记录下的数组节点尾部添加一个或多个元素| |objectArrayNodeInsert|(id, path, index, item)|无|无|否|给某条记录下的数组节点某个索引位置插入一个元素| |objectArrayNodeUnshift|(id, path, items)|object|undefined|否|给某条记录下的数组节点头部添加一个或多个元素| |objectArrayNodeDel|(id, path, index)|无|无|否|删除某条记录下的数组节点里指定位置的元素| |objectArrayNodePop|(id, path)|object|undefined|否|弹出某条记录下的数组节点尾部一个元素| |objectArrayNodeShift|(id, path)|object|undefined|否|弹出某条记录下的数组节点头部一个元素| |objectArrayNodeShift|(id, path)|object|undefined|否|弹出某条记录下的数组节点头部一个元素| |objectFind|({where, sort, limit, group})|array|[]|否|查找所有符合规则的对象,支持排序、分页、分组| |objectFieldFind|({field, where, sort, limit, group})|array|[]|否|查找所有符合规则的对象,支持排序、分页、分组、查询单个字段| |objectCount|(where,group)|integer|0|否|统计所有符合规则的对象数量| |objectQuery|(sql)|array|0|否|执行原生sql| |relationFetch|(subject, object)|object|undefined|是|返回关系中某个对象| |relationPut|(relation)|无|无|是|将某个对象放入关系中| |relationRemove|(subject, object)|无|无|是|从关系中移除某个对象| |relationHas|(subject, object)|true|false|是|判断关系中含有某个对象| |relationList|(subject, sort?, limit?, filter?)|array|[]|是|返回关系中的对象,可筛选、排序、分页| |relationCount|(subject, filter?)|integer|0|是|统计关系中的对象,可筛选| |relationClear|(subject)|无|无|是|清空关系里所有对象|

支持的高级数据操作配置

媒介可以不实现上一小节某些数据高级操作功能,此时必须在介质配置里时关闭该功能支持,否则框架调用该函数会导致报错.默认都不支持

get support() {
    return {
        objectFind: false,
        objectCount: false,
        objectArrayNodeAppend: false,
        objectArrayNodeUnshift: false,
        objectArrayNodeInsert: false,
        objectArrayNodeDel: false,
        objectArrayNodePop: false,
        objectArrayNodeShift: false
    }
}

解析Logic

逻辑分where,sort,limit三类,objectFind,objectCount,relationList, relationCount函数传入的是标准逻辑对象,需要开发者自行转化成对应媒介数据的操作逻辑.所有标准逻辑对象都在ORM.Logic.Type定义

|标准对象|属性|示例(按照属性栏的顺序)| |--|--|--| |WhereAnd|items|标准逻辑对象数组| |WhereOr|items|标准逻辑对象数组| |WhereNot|item|标准逻辑对象| |WhereIn|field, items|'.a', [1, 2, 3]| |WhereBetween|field, from, to|'.a', 1, 2| |WhereLike|field, value|'.a', '%a%'| |WhereEq|field, value|'.a', 1| |WhereNq|field, value|'.a', 1| |WhereGt|field, value|'.a', 1| |WhereGe|field, value|'.a', 1| |WhereLt|field, value|'.a', 1| |WhereLe|field, value|'.a', 1| |WhereIsUndef|field|'.a'| |WhereIsDef|field|'.a'| |WhereContain|field, value|'.arr[]', 1| |WhereContainBoolean|field, value|'.arr[]', 1| |Sort|field, order|'.a', 'DESC'| |Limit|limit, skip|1,1| |Field|field, alias|'.name','nameS'| |Group|field|'.name'|

Redis媒介插件代码

请移步这里[github才能支持]

更新日志

  • 2019-06-08: Logic对象支持转换为json对象。同时在原使用Logic对象的地方支持直接传入json对象进行查询
  • 2019-09-30:
    • 重写数据默认值填充器
    • 更新数据校验器为qtk-validator,提示更加友好
    • core部分代码整理,优化执行速度
    • 去除数据取操作时做数据校验
    • bug修复
    • 增加orm_rebuild_column_index重建表列/索引命令
  • 2020-04-26:
    • Logic增加WhereIsUndef,WhereIsDef

致谢

schema语法引用的是semantic-schema项目代码,感谢Magnus同学的支持