postgresql(1).md 5.2 KB

title: PostgreSQL(1) author: Gamehu tags:

  • PostgreSQL categories:
  • 工作 date: 2019-11-29 10:45:00

{% asset_img 1.jpg Photo by fabio on Unsplash %}

最近产品提了一个需求,要做菜单优化。

菜单优化:

  1. 重写菜单数据初始化sql脚本,数据结构两层变为三层
  2. 权限数据调整
  3. 兼容原有菜单权限数据

这里面第三点是最麻烦的,兼容原有的菜单数据,我给需求说了两个方案。

PlanA:从时间方面(因为是个小迭代,整个迭代的功能只有一周时间开发)考虑管理员菜单权限保留,其它普通角色菜单权限一律置空,需求也接受(因为客户现场大多数情况都是用管理员账号)。

PlanB:保留原有数据,但是需要1-2天预研一下升级方案是否可行,我提出的方案是直接用sql脚本做,需求也认可,PlanA为兜底方案。

我就提个解决方案,结果这事最后让我支援一下给做了...,所以在这简单记录一下过程产物。

PLV8

简单地说就算PostgreSQL里加个扩展,这个扩展就是V8引擎,是的,你理解的没错,就是Google开源的JavaScript引擎,有了这个扩展那就能在sql里写js代码了,这对于在脚本里写逻辑那可是爽歪歪了。

安装过程我就不多说了,网上有很多,大体流程就是

  1. 从GitHub wget 下来
  2. make install

    #添加扩展
    CREATE EXTENSION plv8;
    
    #验证plv8的版本,出来版本号就证明装上了
    SELECT plv8_version();
    

然后你就可以写JS代码了,ES6、coffeeScript等都可以,只要最终是v8能解析的就成。

好现在开始写了,一开始不太了解,打算用存储过程做,但是后来老前辈提醒我,我这个是升级脚本,只需要执行一遍就成,所以没必要做存储过程,最后还得删掉,因为留着没意义。

然后建议我用DO $$的写法,此方式执行完不会留下其它痕迹就跟执行一条长sql一样,贴个代码:

DO
$$
plv8.elog(INFO, '------------------------------------update user menus start------------------------------------');
buildTree = function(list) {
  try {
    let temp = {};
    let tree = {};
    for (let menu of list) {
      temp[menu.id] = menu;
    }
    for (let i in temp) {
      if (temp[i].parent) {
        if (!temp[temp[i].parent].children) {
          temp[temp[i].parent].children = {};
        }
        temp[temp[i].parent].children[temp[i].id] = temp[i];
      } else {

        tree[temp[i].id] = temp[i];
      }
    }
    return tree;

  } catch (error) {
    plv8.elog(ERROR, 'buildTree ' + error);
  }
};

getTreeOfMenus = function() {
  let cmdb = require('xxx');
  let result = cmdb.service.query('default', '{xxx{id name}}', {});
  return buildTree(result);
};
let allMenus = getTreeOfMenus();

delete allMenus['xxx'];

let ids = [];
idsOfflatten = function(data) {
  try {
    for (let id in data) {
      ids.push(id);
      if (data[id].children) {
        idsOfflatten(data[id].children);
      }
    }
    return ids;
  } catch (error) {
    plv8.elog(ERROR, 'idsOfflatten ' + error);
  }
};
let flatIds = idsOfflatten(allMenus);
plv8.elog(INFO, 'new menu ids:' + flatIds);
getNormalMenus = function(menus) {
  try {
    plv8.elog(INFO, 'old menus : ' + JSON.stringify(menus));
    let old_keys = Object.keys(menus);
    old_keys.forEach(id => {
      if (!flatIds.includes(id)) {
        plv8.elog(INFO, 'delete menu id: ' + id);
        delete menus[id];
      }
    });
    return menus;
  } catch (error) {
    plv8.elog(ERROR, 'getNormalMenus ' + error);
  }
};

updateMenus = function() {
  try {
    let ROLE_ADMIN = 'admin',
      ROLE_DOMAIN = 'domain';
    let query = 'SELECT name,  menus, role_type FROM xxx';
    let updateAdmin =
      'UPDATE xxx SET  menus=NULL,  last_modified=CURRENT_TIMESTAMP where  name = $1';
    let updateNormal = 'UPDATE xxx SET  menus=$1, last_modified=CURRENT_TIMESTAMP where name = $2';
    let execCount=0;
    plv8.execute(query).forEach(row => {
      let roleType = row.role_type;
      if (roleType === ROLE_DOMAIN || roleType === ROLE_ADMIN) {  
        let adminCount = plv8.execute(updateAdmin, [row.name]);
        plv8.elog(INFO, 'update admin user menus is null ,count: '+adminCount );
        adminCount>0 ? execCount+=1:null;
        return;
      }

      let newMenus = getNormalMenus(row.menus);
      let normalCount = plv8.execute(updateNormal, [newMenus, row.name]);
      plv8.elog(INFO, 'update normal user menus , ' + JSON.stringify(newMenus)+',count:'+normalCount);
      normalCount>0 ? execCount+=1:null;
    });

   return execCount;
  } catch (error) {
    plv8.elog(ERROR, 'updateMenus ' + error);
  }
};

let updateCount=updateMenus();
plv8.elog(INFO,'total of successes :'+updateCount);
plv8.elog(INFO,'------------------------------------update user menus end------------------------------------');
$$ LANGUAGE plv8;

小结:

PostgreSQL很强大,这是我初试水,后续有机会会再写写工作中的一些PostgreSQL的实践例子。

其实PostgreSQL几乎可扩展主流的所有编程语言比如C++、Java、nodejs等。

参考文档:

{% blockquote plv8 documention https://plv8.github.io/ %} {% endblockquote %}