node.js oracle修补程序请求不是动态的

w46czmvw  于 2021-08-09  发布在  Java
关注(0)|答案(1)|浏览(281)

我正在尝试通过node.js动态地对oracle表发出补丁请求
以下是我的设置:
在我的router.js文件中,我有:

const express = require('express');
const router = new express.Router();
const employees = require('../controllers/employees.js');
const smiCats = require('../controllers/smi/smiCats.js');
const auth = require('../controllers/auth.js');

router.route('/login/:id?')
    .post(auth.getToken);

router.route('/ams/:id?')
    .get(auth.verifyToken, employees.get)
    .post(auth.verifyToken, employees.post)
    .put(auth.verifyToken, employees.put)
    .delete(auth.verifyToken, employees.delete)
    .patch(auth.verifyToken, employees.patch);

router.route('/smi/cats/:id?')
    .get(auth.verifyToken, smiCats.get)
    .post(auth.verifyToken, smiCats.post)
    .put(auth.verifyToken, smiCats.put)
    .patch(auth.verifyToken, smiCats.patch);

module.exports = router;

然后调用我的控制器,该控制器具有我的补丁函数,并得到净化。

//sanitizer
function sanitizeCats(req) {
    const cats = {
        cat_desc: req.body.cat_desc,
        msg_for: req.body.msg_for,
        msg_user_owner: req.body.msg_user_owner || 0,
        msg_realtor_owner: req.body.msg_realtor_owner || 0
    };

    return cats;
}
async function patch(req, res, next) {
    try {
        let category = sanitizeCats(req);
        category.cat_id = parseInt(req.params.id, 10);

        const success = await smiCats.patch(category);

        if (success) {
            res.status(204).end();
        } else {
            res.status(404).end();
        }
    } catch (err) {
        next(err);
    }
}

module.exports.patch = patch;

当它被执行时,它调用我的db\uapi模块,该模块组装sql语句
(下一个代码部分是我的问题的来源)

const database = require('../../services/database.js');
const oracledb = require('oracledb');
const patchSql =
    `BEGIN
   DECLARE
   BEGIN

  IF nvl(:cat_desc,'zzz') != 'zzz' THEN  
  UPDATE smi_contact_cats
     SET cat_desc = :cat_desc
   WHERE cat_id = :cat_id;
  END IF;

  IF nvl(:msg_for,'zzz') != 'zzz' THEN
  UPDATE smi_contact_cats
     SET msg_for = :msg_for
   WHERE cat_id = :cat_id;
  END IF;

  IF nvl(:msg_user_owner,-1) > -1 THEN
  UPDATE smi_contact_cats
     SET msg_user_owner = :msg_user_owner
   WHERE cat_id = :cat_id;
  END IF;

  IF nvl(:msg_realtor_owner,-1) > -1 THEN
  UPDATE smi_contact_cats
     SET msg_realtor_owner = :msg_realtor_owner
   WHERE cat_id = :cat_id;
  END IF;

  :rowcount := sql%rowcount;
  END;
  END;`;

async function patch(cats) {
    const category = Object.assign({}, cats);
    //add binds
    category.rowcount = {
        dir: oracledb.BIND_OUT,
        type: oracledb.NUMBER
    };

    const result = await database.simpleExecute(patchSql, category);
    return result.outBinds.rowcount === 1;
}

module.exports.patch = patch;

然后调用数据库函数来实际执行和组装带有绑定变量的sql:

const oracledb = require('oracledb');
const dbConfig = require('../config/database.js');

async function initialize() {
    const pool = await oracledb.createPool(dbConfig.beta);
}

module.exports.initialize = initialize;

async function close() {
    await oracledb.getPool().close();
}

module.exports.close = close;

function simpleExecute(statement, binds = [], opts = {}) {
    return new Promise(async (resolve, reject) => {
        let conn;

        opts.outFormat = oracledb.OBJECT;
        opts.autoCommit = true;

        try {
            conn = await oracledb.getConnection();
            const result = await conn.execute(statement, binds, opts);

            resolve(result);
        } catch (err) {
            reject(err);
        } finally {
            if (conn) { // conn assignment worked, need to close
                try {
                    await conn.close();
                } catch (err) {
                    console.log(err);
                }
            }
        }
    });
}

module.exports.simpleExecute = simpleExecute;

所以所有这些工作。。。但它的动态性不足以让我构建我们公司的api。如何在node.js中生成一个更动态的补丁请求,而不必键入每一列并在其周围放置一个nvl来检查它是否存在。作为一方,如果没有更好的方法来动态清理,我洗耳恭听,但主要的问题是如何更好地动态构建补丁请求。

moiiocjp

moiiocjp1#

当前代码不太理想,因为它对每个属性执行一次更新。这里有一个更动态的解决方案。。。
鉴于以下情况:

create table smi_contact_cats (
  cat_id            number,
  cat_desc          varchar2(50),
  msg_for           varchar2(50),
  msg_user_owner    varchar2(50),
  msg_realtor_owner varchar2(50)
);

insert into smi_contact_cats (
  cat_id,
  cat_desc,
  msg_for,
  msg_user_owner,
  msg_realtor_owner
) values (
  1,
  'cat_desc orginal value',
  'msg_for orginal value',
  'msg_user_owner orginal value',
  'msg_realtor_owner orginal value'
);

commit;

你可以用这样的逻辑。 updatableColumns 是可以更新的列的白名单。注意,您可以对底部的一些行进行注解和取消注解,以测试各种输入。

const oracledb = require('oracledb');
const config = require('./db-config.js');

async function patch(cat) {
  let conn;

  try {
    const category = Object.assign({}, cat);
    const categoryProps = Object.getOwnPropertyNames(category);
    const updatableColumns = ['cat_desc', 'msg_for', 'msg_user_owner'];

    // Validate that the pk was passed in
    if (!categoryProps.includes('cat_id')) {
      throw new Error('cat_id is required');
    }

    // Now remove the pk col from categoryProps
    categoryProps.splice(categoryProps.indexOf('cat_id'), 1);

    if (categoryProps.length === 0) {
      throw new Error('At least one property must be specified');
    }

    let sql = 'update smi_contact_cats\nset ';

    for (let propIdx = 0; propIdx < categoryProps.length; propIdx++) {
      // Here's the whitelist check
      if (!updatableColumns.includes(categoryProps[propIdx])) {
        throw new Error('Invalid "update" column');
      } else {
        if (propIdx > 0 && propIdx < categoryProps.length) {
          sql += ',\n  ';
        }

        sql += categoryProps[propIdx] + ' = :' + categoryProps[propIdx];
      }
    }

    sql += '\nwhere cat_id = :cat_id';

    console.log('here is the sql', sql);

    conn = await oracledb.getConnection(config);

    const result = await conn.execute(
      sql,
      category,
      {
        autoCommit: true
      }
    );

    if (result.rowsAffected && result.rowsAffected === 1) {
      return category;
    } else {
      return null;
    }
  } catch (err) {
    console.error(err);
  } finally {
    if (conn) {
      try {
        await conn.close();
      } catch (err) {
        console.error(err);
      }
    }
  }
}

const patchObj = {
  cat_id: 1
};

// Comment and uncomment the following to see various dynamic statements
patchObj.cat_desc = 'cat_desc value';
patchObj.msg_for = 'msg_for value';
patchObj.msg_user_owner = 'msg_user_owner value';

// Uncomment the following line to add a column that's not whitelisted
//patchObj.msg_realtor_owner = 'msg_realtor_owner value';

patch(patchObj)
  .then(function(cat) {
    console.log('Updated succeeded', cat);
  })
  .catch(function(err) {
    console.log(err);
  });

相关问题