plv8 require 模塊試用

plv8 是postgres 的一個比較強大的插件,社區有人基於babel,browserify 實現了一個方便的require 模塊加載
實際上官方也有介紹過了相似的基於數據庫存儲js,而後經過eval 動態加載代碼,如下是一個簡單的試用html

環境準備

  • docker-compose 文件
 
version: '3.6'
services:
  postgres:
    image: dalongrong/plv8:2.3.12
    ports:
    - "5432:5432"
    environment: 
    - "POSTGRES_PASSWORD=dalong"
  graphql-engine:
    image: hasura/graphql-engine:v1.0.0-beta.9
    ports:
    - "8080:8080"
    depends_on:
    - "postgres"
    environment:
      HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:dalong@postgres:5432/postgres
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # set to "false" to disable console
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
  • node-plv8 項目
    package.json
 
{
  "name": "node-plv8",
  "version": "1.0.0",
  "main": "app.js",
  "bin": "app.js",
  "license": "MIT",
  "dependencies": {
    "cuid": "^2.1.6",
    "knex": "^0.20.1",
    "lodash": "^4.17.15",
    "pg": "^7.12.1",
    "plv8": "^2.1.4",
    "uuid": "^3.3.3"
  },
  "scripts": {
    "init:app": "node app"
  }
}

app.js
進行模塊的註冊,目前包含了lodash以及一個本身的node

 
// setup plv8 connection
const PLV8 = require('plv8')
const knex = require('knex')
const knexHandle = knex({
    client: 'pg',
    connection: {
      host: "127.0.0.1",
      user: "postgres",
      password: "dalong",
      database: "postgres"
    }
  })
const plv8 = new PLV8(knexHandle)
// setup a log listener
plv8.on('log:error', msg => {
  console.error(msg)
})
// install the lodash module so that it can be loaded (via require()) later
plv8.install({modulePath:require.resolve('lodash'),moduleName:"lodash"})
  .then(() => {
    // eval some code
    return plv8.eval(() => {
      const _ = require('lodash')
      return _.map([ 1, 2, 3 ], e => e + 1)
    })
  })
  .then(result => {
   console.log(result)
  }).catch(err=>{
      console.log(err)
  })
    plv8.install({modulePath:require.resolve("./login"),moduleName:"login"})
  .then(() => {
    // eval some code
    return plv8.eval(() => {
      const login = require('login')
      return login
    })
  })
  .then(result => {
   console.log(result)
  }).catch(err=>{
      console.log(err)
  })

login.js 模塊git

module.exports = {
    name:"dalong",
    age:333
}

運行&&測試

  • 啓動docker 服務
docker-compose up -d
  • 運行nodejs demo 服務
yarn init:app
  • 效果
    目前有關於pg 通訊的一些異常log,多是和代碼很就已經沒維護,包版本兼容pg 的問題,後邊
    調試研究下
 
yarn run v1.17.3
$ node app
(node:56198) UnhandledPromiseRejectionWarning: error: syntax error at or near ":"
    at Connection.parseE (/Users/dalong/mylearning/hasura-project/plv8/node-plv8/node_modules/pg/lib/connection.js:604:11)
    at Connection.parseMessage (/Users/dalong/mylearning/hasura-project/plv8/node-plv8/node_modules/pg/lib/connection.js:401:19)
    at Socket.<anonymous> (/Users/dalong/mylearning/hasura-project/plv8/node-plv8/node_modules/pg/lib/connection.js:121:22)
    at Socket.emit (events.js:182:13)
    at addChunk (_stream_readable.js:283:12)
    at readableAddChunk (_stream_readable.js:264:11)
    at Socket.Readable.push (_stream_readable.js:219:10)
    at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
(node:56198) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:56198) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Use async .hasTable to check if table exists and then use plain .createTable. Since .createTableIfNotExists actually just generates plain "CREATE TABLE IF NOT EXIST..." query it will not work correctly if there are any alter table queries generated for columns afterwards. To not break old migrations this function is left untouched for now, but it should not be used when writing new code and it is removed from documentation.
Use async .hasTable to check if table exists and then use plain .createTable. Since .createTableIfNotExists actually just generates plain "CREATE TABLE IF NOT EXIST..." query it will not work correctly if there are any alter table queries generated for columns afterwards. To not break old migrations this function is left untouched for now, but it should not be used when writing new code and it is removed from documentation.
{ name: 'dalong', age: 333 }
[ 2, 3, 4 ]
 

sql 方式調用

  • 函數定義
CREATE or replace FUNCTION dalong2() RETURNS json AS
$$
    const login = require('login')
    return JSON.stringify(login);
$$
LANGUAGE plv8;
  • 查詢
SET plv8.start_proc = 'v8.plv8_init';
select * from dalong2();
 
  • 效果
{"name":"dalong","age":333}

簡單原理說明

node plv8 將生成的js 經過browserify 以及babel 轉換,存儲在v8 schema 中的modules 表中
同時註冊了SET plv8.start_proc = 'v8.plv8_init'; 須要的plv8.init 函數,同時也註冊了幾個依賴的
函數,代碼的執行經過的是eval 函數,總體上仍是比較簡單的,可是實現的功能確實很方便的
github

 

 

參考資料

https://pgxn.org/dist/plv8/doc/plv8.html
https://github.com/plv8/plv8
https://plv8.github.io/
https://github.com/rongfengliang/plv8-require-learningweb

相關文章
相關標籤/搜索