V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KouShuiYu
V2EX  ›  Node.js

不喜欢使用 orm 框架,分享一个自己写 postgresql 的 sql 构造库

  •  
  •   KouShuiYu · 2021-02-23 11:49:40 +08:00 · 3201 次点击
    这是一个创建于 1367 天前的主题,其中的信息可能已经有所发展或是发生改变。

    GitHub 地址

    API 文档暂时还没有,下面是使用的 demo

    pg-helper

    use node-postgres easier

    Examples

    const {PgHelper} = require('@c_kai/pg-helper');
    
    // detail https://node-postgres.com/api/pool
    const pgHelper = new PgHelper({
        host,
        user,
        password,
        database,
        port: 5432,
        max: 20,
        idleTimeoutMillis: 30000,
        connectionTimeoutMillis: 2000,
    });
    

    insert

    const result = await pgHelper.insert([{
      percentage: 0,
      type: 'public',
      params: {},
      created_by: 1,
      status: 'created',
      job_uuid: '103',
    },{
      percentage: 0,
      type: 'public',
      params: {},
      created_by: 1,
      status: 'created',
      job_uuid: '104',
    }], {
      tableName: 'jobs',
      returning: true,
    });
    

    delete

    const result = await pgHelper.delete({}, {
      tableName: 'jobs',
      transaction,
    });
    

    update

    const result = await pgHelper.update({
      type: 'pravate',
      status: 'gg',
    }, {
      update: ['type', 'status'],
      tableName: 'jobs',
      returning: ['id'],
      transaction,
    });
    

    select

    const result = await pgHelper.select({
      percentage: 0,
    }, {
      where: {
        percentage: '= {percentage}'
        or: {
          id: '=1',
        }
      },
      schemaName: 'public',
      tableName: 'jobs',
      autoHump: false,
      count: true,
    });
    

    Run sql

    await pgHelper.runSql('select now()');
    
    // with params
    await pgHelper.runSql('select power({a}, {b})', { a: 2, b: 4 });
    

    Run sql use transaction

    await pgHelper.runTSql([
        {
            sql: 'select now()',
        },
        {
            sql: 'select power({a}, {b})',
            params: { a: 2, b: 4}
        }
    ])
    

    OR

    let transaction;
    try {
      transaction = await pgHelper.getTransaction();
      let result4 = await pgHelper.runSql('select {str1} || {str2}', {
        str1: 'xiao',
        str2: 'hong',
      }, {
        transaction,
      });
      transaction.commit();
    
      console.log(result4)
    } catch (error) {
      transaction.rollback();
    }
    
    第 1 条附言  ·  2021-02-23 15:08:43 +08:00
    API 文档完成了 字段限制,分割了

    # pg-helper

    A small helper for node-postgres to help you with building your queries.


    [node-postgres]( https://node-postgres.com/) 使用序数参数查询`($1, $2, etc)`, 因此变量需要有明确的顺序,一旦参数过多使用起来就异常麻烦,该模块使你更容易、更快速、更安全的构建 SQL 。

    ## Featrues

    + 你可以使用`pgHelper.runSql` 函数

    ```js
    pgHelper.runSql('SELECT * FROM table WHERE field1 = {field1} AND field2 = {field2}', {field1, field2});

    //当然你仍然可以使用
    pgHelper.runSql('SELECT * FROM table WHERE field1 = $1 AND field2 = $2', [field1, field2]);
    ```

    + 该模块还提供了`select`、`update`、`delete`、`insert` 等函数方便对单表进行 CURD ;

    + 该模块封装了对事务的操作

    ```js
    await pgHelper.runTSql([
    {
    sql: 'select now()',
    },
    {
    sql: 'select power({a}, {b})',
    params: { a: 2, b: 4}
    }
    ]);

    //OR

    let transaction;
    try {
    transaction = await pgHelper.getTransaction();
    await pgHelper.runSql('select now()', {
    transaction,
    });
    await pgHelper.runSql('select power({a}, {b})', { a: 2, b: 4}, {
    transaction,
    });
    transaction.commit();

    } catch (error) {
    transaction.rollback();
    }
    ```
    第 2 条附言  ·  2021-02-23 15:17:44 +08:00

    API

    PgHelper Class

    new PgHelper(config, options)

    • config same as pg.Pool
    • options
      • options.autoHump Boolean - 如果autoHump为true返回字段的名称会格式化为驼峰
      • options.returning Boolean - 如果returning为true返回结果会包含更新、插入、修改的数据
      • options.logger Object - 替换默认的日志需要包含infoerror两个函数

    pgHelper.insert(params, options)

    Function

    params

    • params Array<Object> - 插入表的数据,其中Object的key需要和字段一一对应
    • options
      • options.tableNameString- 表名称
      • options.schemaNameString- 表名称;default: public
      • options.returning Boolean|Array - 如果returning为true,返回结果会包含插入的数据,为数组时返回数组包含的字段

    return

    same as pg.queries

    pgHelper.delete(params, options)

    Function

    params

    • params Object - 模版参数,其中Object的key需要和SQL模版中{key}值一一对应

    • options

      • options.tableNameString- 表名称

      • options.schemaNameString- 表名称;default: public

      • options.returning Boolean|Array - 如果returning为true,返回结果会包含删除的数据,为数组时返回数组包含的字段

      • options.whereObject 构建where sql

        {
        	id: '>10',
        	type: '={type}',
        	or:{
        		id:'= any({ids})'
        	}
        }
        
        // sql
        //where (id > 0 and type={type} or (id = any({ids} ) )
        
    第 3 条附言  ·  2021-02-23 15:19:37 +08:00

    pgHelper.update(params, options)

    Function

    params

    • params Object - 模版参数,其中Object的key需要和SQL模版中{key}值一一对应

    • options

      • options.tableNameString- 表名称

      • options.schemaNameString- 表名称;default: public

      • options.returning Boolean|Array - 如果returning为true,返回结果会包含更新的数据,为数组时返回数组包含的字段

      • options.whereObject 构建where sql

        {
        	id: '>10',
        	type: '={type}',
        	or:{
        		id:'= any({ids})'
        	}
        }
        
        // sql
        //where (id > 0 and type={type} or (id = any({ids} ) )
        
      • options. updateArray|Object - 需要更新的字段

        ['name', 'type']
        // name = {name},type={type}
        
        OR
        {
        	name: 'name',
        	type: 'myType',
        }
        name = {name},type={myType}
        
        

    return

    same as pg.queries

    pgHelper.select(params, options)

    Function

    params

    • params Object - 模版参数,其中Object的key需要和SQL模版中{key}值一一对应

    • options

      • options.tableNameString- 表名称

      • options.schemaNameString- 表名称;default: public

      • options.whereObject 构建where sql

        {
        	id: '>10',
        	type: '={type}',
        	or:{
        		id:'= any({ids})'
        	}
        }
        
        // sql
        //where (id > 0 and type={type} or (id = any({ids} ) )
        
      • options.limit int - limit number

      • options.offset int -offset number

      • options.count Boolean -是否返回查询的行数

      • options.include array - 返回的字段数组default*

      • options.order array 构建ordersql

        ['id', ['type', 'desc'], [''name'', 'asc']]
        
        // order by id, type desc, name asc
        

    return

    same as pg.queries

    18 条回复    2021-02-24 11:40:54 +08:00
    bleepbloop
        1
    bleepbloop  
       2021-02-23 11:53:25 +08:00
    看了一下,好像不能防注入?
    KouShuiYu
        2
    KouShuiYu  
    OP
       2021-02-23 11:55:02 +08:00
    @bleepbloop 可以防止注入 sql 中的{params}会被替换为$n 的形式
    KouShuiYu
        3
    KouShuiYu  
    OP
       2021-02-23 11:56:07 +08:00
    KouShuiYu
        4
    KouShuiYu  
    OP
       2021-02-23 11:58:44 +08:00
    官方提供的这种方式感觉太不好用了
    ```js
    const query = {
    text: 'INSERT INTO users(name, email) VALUES($1, $2)',
    values: ['brianc', '[email protected]'],
    }

    ```

    我改成了这种形式
    ```
    const query = {
    text: 'INSERT INTO users(name, email) VALUES({name}, {email})',
    values: { name: 'brianc', email: '[email protected]']
    }
    ``
    KouShuiYu
        5
    KouShuiYu  
    OP
       2021-02-23 11:59:33 +08:00
    官方提供的这种方式感觉太不好用了
    ```js
    const query = {
    text: 'INSERT INTO users(name, email) VALUES($1, $2)',
    values: ['brianc', '[email protected]'],
    }

    ```

    我改成了这种形式
    ```js
    const query = {
    text: 'INSERT INTO users(name, email) VALUES({name}, {email})',
    values: { name: 'brianc', email: '[email protected]']
    }
    ```
    KouShuiYu
        6
    KouShuiYu  
    OP
       2021-02-23 12:00:06 +08:00
    额,好像不支持代码块
    fucUup
        7
    fucUup  
       2021-02-23 12:39:42 +08:00
    js 读写数据库?????

    小心清库跑路
    KiseXu
        8
    KiseXu  
       2021-02-23 12:45:26 +08:00
    @fucUup 这个节点是 Node.js
    fucUup
        9
    fucUup  
       2021-02-23 12:48:21 +08:00
    @KiseXu 跟语言无关, 我是吐槽你的交付物, 用起来很容易犯错的, 这样就不好, 一定要用核电站的思维写代码, 把容易犯错的设计砍掉
    fucUup
        10
    fucUup  
       2021-02-23 12:49:53 +08:00
    这种交付物, 接近裸写 sql, 不仅分库分表 一旦表动难维护, 还有容易清库跑路嫌疑
    RockShake
        11
    RockShake  
       2021-02-23 13:04:00 +08:00
    做小项目没问题的,楼主说了这是 ORM 的替代方案
    0clickjacking0
        12
    0clickjacking0  
       2021-02-23 15:23:28 +08:00
    orm 是真的可以杜绝 sql 注入的
    xieren58
        13
    xieren58  
       2021-02-23 15:24:54 +08:00
    knexjs 不好用吗?
    KouShuiYu
        14
    KouShuiYu  
    OP
       2021-02-23 16:05:25 +08:00
    @xieren58 这个用起来比较简单,对照的是 https://github.com/felixfbecker/node-sql-template-strings,我又加上了方便单表 CURD 的四个方法
    ERRASYNCTYPE
        15
    ERRASYNCTYPE  
       2021-02-24 11:11:05 +08:00
    哈哈哈哈跟我自己做的一个好像,不过我用 gt gte lt lte 这些 mongodb 的保留词来做 where 构造
    KouShuiYu
        16
    KouShuiYu  
    OP
       2021-02-24 11:33:35 +08:00
    @ERRASYNCTYPE 考虑到 where 表达式情况太复杂了,还要额外加好多接口,所以就放开了
    ERRASYNCTYPE
        17
    ERRASYNCTYPE  
       2021-02-24 11:40:07 +08:00
    @KouShuiYu 确实,还有 or between 什么的要处理,所以我都是自己根据自己业务去个别调整来着,不完备
    felixin
        18
    felixin  
       2021-02-24 11:40:54 +08:00 via Android
    看一下 slonik
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2111 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:13 · PVG 00:13 · LAX 08:13 · JFK 11:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.