1 Star 0 Fork 0

阿豪 / haorm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

haorm框架

一个学习向工程,为了学习Node.js和ORM框架原理。Node.js下的ORM框架,帮助用户处理数据库。支持一二级缓存、读写分离。避免SQL注入、快速生成SQL语句,同时允许自定义SQL。

参考学习sequelize框架,但内部实现有差别,同时抛弃了许多功能,只能进行简单的增删改查。

声明:历时一个月完成,生产环境不能保证稳定。本人暂时会用于本人的项目中,但处于随时弃坑状态。


使用教程

具体教程-点击查看,也可以直接查看下面

- 基础教程

- 1.导入框架

- 2.初始化框架

​ - 配置

​ - 导入依赖

​ - 创建启动类

- 3.注册模型

​ - QueryTypes查询类型

​ - 初始化实体类

​ - 模型管理器(重要)

​ - 验证 & 约束

- 4.数据库操作(基础)

​ - 查询

​ - 插入/更新

​ - 删除

- 5.表关联查询(进阶)

- 6.自定义查询

- 其他

- 1.Wrapper查询

- 2.事务

- 3.配置参数

- 4.自定义日志插件

- 5.依赖项

- 6.关于

基础教程

1.导入框架

npm install haorm -S

2.初始化框架

配置

数据库连接配置可以参考mysql2的配置

  • 单个数据库
const MYSQL_CONFIG = {
    host     : 'localhost', //数据库地址
    port     : '3306', //端口
    user     : 'root', //用户名
    password : '123456',//数据库密码
    database : 'test', //数据库名
    connectionLimit: 1000 //连接池数量
};
  • 读写分离数据库(数据同步需要数据库层面的另外设置)
const MYSQL_CONFIG = {
    LoadBalance: 'Default', //负载均衡策略(具体在下面)
    Expiration: 120 * 1000, //单点故障(ms)
    read:[{ //读库列表(从)
        host     : 'localhost', //数据库地址
        port     : '3306', //端口
        user     : 'root', //数据库用户名
        password : '123456', //数据库密码
        database : 'test' //数据库库名
        weight   : 2, //权重(负载均衡策略为加权时)默认1
    },{
        host     : 'localhost',
        port     : '3306',
        user     : 'root', 
        password : '123456',
        database : 'test',
        weight   : 4,
        connectionLimit: 4000 //连接池最大连接数量
    }],
    write:[{ //写库列表(主)
        host     : 'localhost',
        port     : '3306',
        user     : 'root',
        password : '123456',
        database : 'test'
    },{
        host     : 'localhost',
        port     : '3306',
        user     : 'root',
        password : '123456',
        database : 'test',
        weight   : 4,
        connectionLimit: 4000
    }],
    common:{ //所有数据库配置通用设置,单个设置优先
        connectionLimit: 2000
    }
}
  • 其中LoadBalance为字符串,目前含:

    • ROUNDROBIN //轮询

    • RANDOM //随机

    • WEIGHTEDROUNDROBIN //加权轮询

    • WEIGHTEDRANDOM //加权随机

导入依赖

const { Haorm } = require('haorm')

const Haorm = require('haorm')

创建启动类

const haorm= new Haorm('mysql',MYSQL_CONFIG,{timeout:4000});

Haorm构造器含三个参数: 1.第一个参数——指定数据库类型【必填】。 字符串,目前仅含mysql 2.第二个参数——数据库连接配置【必填】。 - 参考数据库配置 3.第三个参数——其他全局配置【选填】。

​ - 可以才能考配置参数

{
	timeout: 4000 //数据库请求最大时间(ms),默认4000ms
	logging: (info,type)=>{
		console.log(info)
	}
	//自定义日志函数,框架会传2个参数。
	//第一个为日志信息,第二个为信息的类型(目前仅支持'query','transaction'两个类型。)
}

3.注册模型

QueryTypes查询类型

需要导入haorm包,不使用QueryTypes直接用字符串也是可以的。

读(READ)写(WRITE)或者增(INSERT)删(DELETE)改(UPDATE)查(SELECT)可以用来选择和判断使用主从库

  • SELECT : 'SELECT',
  • INSERT : 'INSERT',
  • UPDATE : 'UPDATE',
  • DELETE : 'DELETE',
  • UPSERT : 'UPSERT',
  • READ : 'READ',
  • WRITE : 'WRITE',

初始化实体类

使用Haorm类中的define方法注册模型(参考如下代码)

define方法含2个参数: 1.第一个参数——标签,用于从模型管理器中获取模型【必填】。 自定义字符串。唯一标签、不可重复。 2.第二个参数——数据库连接配置【必填】。 - 参考如下代码的注释

const { Haorm,QueryTypes } = require('haorm')
const haorm= new Haorm('mysql',MYSQL_CONFIG,{timeout:4000});
const user = haorm.define('user'/*标签,用于模型管理*/,{
    tablename:'b_user',//表名
    struct : {
    //数据库结构,key为自定义名称(开头不能为$)
        id : {
            fieldName : 'id',//表字段名称
            value : 'number',//暂时没用
            primarykey: true //是否是主键
        },
        name : {
            fieldName : 'u_login',
            value : 'string',
            validate:{//【可选】验证,参考验证 & 约束的章节
            	not:'ttt',
            	//自定义方法
            	notTTT(val){
            		if(val == 'ttt'){
            			throw new Error('validate error!');
            		}
            	}
            }
        },
        password : {
            fieldName : 'u_passwd',
            value : 'string',
            ignore:[QueryTypes.UPDATE] //忽略的操作,例子为修改时忽略该字段
        },
        mail : {
            fieldName : 'u_mail',
            value : 'string'
        }
    },
    cache: {
      enable: true, //是否启动二级缓存,若开启必填
      type: 'FIFO',  //选择二级缓存算法,类型参考下方
                    //不填默认LIRS算法
      size: 200 //该模型下二级缓存池的大小
                //不填默认100
    } //该模型是否使用二级缓存,不存在cache不启动二级缓存   
})

**二级缓存算法:**FIFO、LRU、LIRS

模型管理器(重要)

  • 先导入haorm框架包

    const Haorm = require('haorm')
  • 获取模型

    示例中user为标签

    //'user'为标签
    const userModel = Harom.getModel('user'); //参数为注册模型的标签
  • 获取接口

    1.基础查询接口,不存在缓存,不建议使用

    const interface = userModel.getInterface(); //基础查询接口,不存在缓存,不建议使用

    2.session里包含了查询接口,同时使用session则自动开启了一级缓存

    const session = Harom.openSession('user'); //session里包含了查询接口,同时使用session则自动开启了一级缓存
    或者
    const session = Harom.openSession('user',{timeout:1000}); //第二个参数表示session的全局配置

    可以更换session里的模型(更换其他表查询)

    session.changeModel('group'); //'group'为注册模型时的标签
    或者
    const groupModel = Harom.getModel('group');
    session.changeModel(groupModel); //直接使用模型更换

    开启事务(具体参考其他-事务章节)

    session.beginTransaction();
    session.push(sql/*自定义sql语句*/)或者session.insert({name:'abc'});
    cosnt result = session.commit();//结果按照顺序排列

验证 & 约束

创建模型的时候,使用validate参数即可使用。

mail:{
	fieldName : 'u_mail',
  validate:{
    is: /^[a-z]+$/i,          // 匹配这个 RegExp
    is: ["^[a-z]+$",'i'],     // 与上面相同,但是以字符串构造 RegExp
    not: /^[a-z]+$/i,         // 不匹配 RegExp
    not: ["^[a-z]+$",'i'],    // 与上面相同,但是以字符串构造 RegExp
    isInt: true,              // 检查有效的整数
    isFloat: true,            // 检查有效的浮点数
    isLowercase: true,        // 检查小写
    isUppercase: true,        // 检查大写
    notNull: true,            // 不允许为空
    isNull: true,             // 只允许为空
    notEmpty: true,           // 不允许空字符串
    contains: 'foo',          // 强制特定子字符串
    notIn: ['foo', 'bar'],    // 检查值不是这些之一
    isIn: ['foo', 'bar'],     // 检查值是其中之一
    notContains: 'bar',       // 不允许特定的子字符串
    len: [2,10],              // 仅允许长度在2到10之间的值,第二个小于0时表示最大长度无限。
    isDate: true,             // 只允许日期字符串
    max: 23,                  // 仅允许值 <= 23
    min: 23,                  // 仅允许值 >= 23

    // 自定义验证器的示例:
    nottt(val){
      if(val == 'ttt'){
          throw new Error('test is success!');
      }
    }

    DivideBy2(value) {
      if (parseInt(value) % 2 !== 0) {
        throw new Error('can't divide by two!');
      }
    }

  }
}

4.数据库操作(基础)

以下接口的参数用[]包住的,表示可选,即可以不传该参数。

PS:所有方法均为异步,所以一定要使用async-await

查询

  • findList([conditions,config]) :基础查询

    • conditions : 【可选】Object或String类型。条件。不选择默认返回所有列。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • findAll([conditions,config]) :查询所有(经过项目迭代,已经等同于findList了)

    • conditions : 【可选】Object或String类型。条件。不选择默认返回所有列。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • findOne([conditions,config]) :仅查询一条/只获取第一条(底层使用了limit 1语句)

    • conditions : 【可选】Object或String类型。条件。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • findById(id,[fields,config]) :根据id查询(底层采用WHERE id = 'id'的sql语句)

    • id : string或number类型。查询的主键条件的值。

      当id为Array时,表示主键条件符合等于多个值

    • fields : 【可选】object或者array类型。需要查询的列。不选则返回所有列。

    • config : 【可选】object类型。局部配置(优先级最高)。

  • findAndCountAll([conditions,config]) : 查询结果和不带limitoffset的条件结果数量(结合了 findAllcount 的便捷方法)

    • conditions : 【可选】Object或String类型。条件。不选择默认返回所有列。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • count([conditions,config]) :获取查询的数量。

    • conditions : 【可选】object类型。条件。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • max(key,[conditions,config]) :获取某列的最大值。

    • key : string类型。模型的列名称。
    • conditions : 【可选】object类型。条件。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • min(key,[conditions,config]) :获取某列的最小值。

    • key : string类型。模型的列名称。
    • conditions : 【可选】object类型。条件。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。
  • sum(key,[conditions,config]) :获取某列的求和。

    • key : string类型。模型的列名称。
    • conditions : 【可选】object类型。条件。参考:conditions参数文档
    • config : 【可选】object类型。局部配置(优先级最高)。

- 返回值:

findXXX之类的方法:
{
	results:[
		{每行的结果(key键为自定义的列名)}
		{每行的结果,$join:[{},{}]}//如果有表连接,则会出现$join的键key,为数组Array格式,表示第几个表连接。
	]
}

count、sum、max、min等统计函数的方法
直接返回统计结果,比如 100 (Number类型)。

插入/更新

  • insert(params,[config]) :插入数据

    • params : object类型。插入的数据,使用键值对,键表示模型的列名称,值表示插入的值。如下:

      {
      	id:1,
      	name:'name'
      }
    • config : 【可选】object类型。局部配置(优先级最高)。

  • update(params,conditions,[config]) : 更新数据

    • params : object类型。修改的数据,使用键值对,键表示模型的列名称,值表示更新的值。

      **PS:**如果存在id(主键)的键值,自动在条件中使用WHERE id = 值。如下:

      {
      	name:'name',
      	mail:'123@qq.com'
      } ==> UPDATE name,mail 
      或者
      {
      	id: 1,//主键
      	name:'name',
      	mail:'123@qq.com'
      } ==> UPDATE name,mail WHERE id = 1
    • conditions : 【可选,如果params存在主键】object类型。条件参考:conditions参数文档(仅使用where和limit条件)。

      update更新有一个特殊的配置参数noWhere。默认为false。为ture时,才可以不带WHERE;
      {
      	noWhere: true //默认为false。为ture时,才可以不带WHERE。
      }
    • config : 【可选】object类型。局部配置(优先级最高)。

  • saveOrUpdate(params,[config]) : 更新或插入(更新无效后插入数据)

    • params : object类型。修改的数据,使用键值对,键表示模型的列名称,值表示更新/插入的值。

      PS:必须包含主键(id),如下:

      {
      	id: 1,
      	name: 'TEST'
      }
    • config : 【可选】object类型。局部配置(优先级最高)。

- 返回值:

插入insert(params)的方法:
{
	results:[10,11], //插入后自动递增生成的主键,根据params的顺序排列。
	affectedRows: 2, //影响的行数
}

更新的方法
{
	affectedRows: 2, //影响的行数
}

删除

  • delete(conditions,[config]) : 删除数据

    • conditions: object类型。条件参考:conditions参数文档(仅使用where和limit条件)。

      delete删除有一个特殊的参数noWhere。默认为false。为ture时,才可以不带WHERE;
      {
      	noWhere: true //默认为false。为ture时,才可以不带WHERE。
      }

      conditions例子如下:

      {
      	where:{
              id: 1, //默认使用=
              name:{value:'name',symbol:'!='} //需要其他符号判断,可以使用这种格式
          }
      }
      或者
      [{key:'id',value:1,symbol:'='},{key:'name',value:'name',symbol:'!='}]
      ==> DELET WHERE id = 1 AND name != 'name'
    • config : 【可选】object类型。局部配置(优先级最高)。

  • deleteById(id,config) : 根据(id)主键删除数据

    • id : string或number或Array类型。查询的主键条件的值。

      当id为Array时,表示主键条件符合等于多个值

    • config : 【可选】object类型。局部配置(优先级最高)。

- 返回值

  删除的方法
  {
  	affectedRows: 2, //影响的行数
  }

5.表关联查询(进阶)

参考:conditions参数文档-join表连接

6.自定义查询

1.使用基础查询接口(不使用缓存)【不推荐

const result = Harom.query(sql,config);
  • sql : string或array类型。

  • config : 【可选】object类型。局部配置(优先级最高)。此时建议使用type参数,可以参考QueryType

    {
    	//设置你查询的sql语句的类型,QueryType需要导入haorm框架包
    	type:'SELECT'或者 QueryType.SELECT 
    	model: 需要查询的model //如果没有,就不使用二级缓存
    }

2.使用openSession()的查询接口(使用缓存)【推荐

  • 导入haorm包,const Haorm = require('haorm')

  • 生成Haom类,const sqlOperation = new Haorm('mysql',MYSQL_CONFIG,{timeout:4000});

  • 开启session,let session = sqlOperation.openSession('user');

  • 使用自定义查询,let result = session.query(sql,config)

    • sql : string或array类型。

    • config : 【可选】object类型。局部配置(优先级最高)。此时建议使用type参数,可以参考QueryType

      {
      	//设置你查询的sql语句的类型,QueryType需要导入haorm框架包
      	type:'SELECT'或者 QueryType.SELECT
      	//model默认已经添加上了
      }

其他

1.Wrapper查询

虽然已经实现部分功能,但未来版本不再维护。仅个人练手而实现。

参考:Wrapper文档

2.事务

导入haorm包const Haorm = require('haorm')

生成Haom类const sqlOperation = new Haorm('mysql',MYSQL_CONFIG,{timeout:4000});

开启session,同时开启事务

let session = sqlOperation.openSession('user');
session.beginTransaction();

进行查询(期间不输出结果),比如

let resultT = await session.update({id:1,name:'name'});
resultT = await session.insert({name:'name2'});
//resultT is undefined

最后提交事务,commit()方法参数可以为空或者config(参考3.配置参数

let result = session.commit();
或者let result = await session.commit({timeout:4000});

此时,result结果输出,为Array数组类型,按照查询的顺序排列。比如例子中第一个为更新结果、第二个为插入结果。

3.配置参数

  • 参数

    - timeout : number类型。连接请求超时时间,单位ms。默认4000ms。

    - logging: 只支持全局,自定义日志函数,会传两个参数。第一个为日志信息,第二个为信息的类型(目前仅支持'query','transaction'两个类型。)

    - type : string类型。查询类型,参考QueryType。READ和WRITE等可以用于选择主从数据库。不建议使用,不填写使用默认即可。

    **-tag: ** 模型标签(优先于model参数),关乎二级缓存。如果使用session默认会添加tag标签对应的model模型。如果使用原始接口但没添加tag,则不使用缓存。

    - model: 模型类,关乎二级缓存。如果使用session默认会添加对应的model模型。如果使用原始接口但没添加model,则不使用缓存。

  • 结构如下:

    {
    	timeout: 4000,
    	logging: (info,type)=>{
    		console.log(info)
    	}
    }

4.自定义日志插件

本项目不自带日志,若要启动日志需要自行使用第三方日志。

具体使用方法参考初始化框架-创建启动类3.配置参数

在创建启动类的时候,在第三个参数config中加入键logging自定义日志函数,如下:

{
	logging: (info,type)=>{
		console.log(info)
	}
}

会传两个参数。第一个为日志信息,第二个为信息的类型(目前仅支持'query','transaction'两个类型。)

5.依赖项

"mysql2": "^2.2.5",

"sqlstring": "^2.3.2"

6.关于

邮箱(ahaohe@foxmail.com

MIT License Copyright (c) 2021 AhaoHe(ahaohe@foxmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Node.js的ORM框架。一个学习向工程,为了学习Node.js和ORM框架原理,,帮助用户处理数据库。支持一二级缓存、读写分离。避免SQL注入、快速生成SQL语句,同时允许自定义SQL。 参考学习sequelize框架,但内部实现有差别,同时抛弃了许多功能,只能进行简单的增删改查。 展开 收起
JavaScript 等 3 种语言
MIT
取消

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/hmh98/haorm.git
git@gitee.com:hmh98/haorm.git
hmh98
haorm
haorm
main

搜索帮助