cube.js 动态schema 编译处理
cube.js 支持动态schema 的编译生成(只执行一次)
一些约定
基于asyncModule() 函数,自定义的schema 需要放schema 目录下(当然可以自己扩展resopitryFactory)
sql 以及drillMembers 需要是函数,函数的签名为()=>string
参考使用
- schema 帮助函数
sql 函数以及drillMembers 的处理,按照上边的约定
schema/utils.js
export const convertStringPropToFunction = (propNames, dimensionDefinition) => {
const newResult = { ...dimensionDefinition }
propNames.forEach((propName) => {
const propValue = newResult[propName]
if (!propValue) {
return
}
newResult[propName] = () => propValue
})
return newResult
};
export const transformDimensions = (dimensions) => {
return Object.keys(dimensions).reduce((result, dimensionName) => {
const dimensionDefinition = dimensions[dimensionName]
return {
...result,
[dimensionName]: convertStringPropToFunction(
['sql'],
dimensionDefinition
)
}
}, {})
};
export const transformMeasures = (measures) => {
return Object.keys(measures).reduce((result, dimensionName) => {
const dimensionDefinition = measures[dimensionName]
return {
...result,
[dimensionName]: convertStringPropToFunction(
['sql', 'drillMembers'],
dimensionDefinition
)
}
}, {})
};
- schema 动态生成
基于node-fetch 通过api 获取定义 asyncModule 是比较重要的
const fetch = require('node-fetch');
import {
transformDimensions,
transformMeasures,
} from './utils';
asyncModule(async () => {
const dynamicCubes = await (
await fetch('http://localhost:8080/app.json')
).json();
console.log(dynamicCubes);
dynamicCubes.forEach((dynamicCube) => {
const dimensions = transformDimensions(dynamicCube.dimensions);
const measures = transformMeasures(dynamicCube.measures);
cube(dynamicCube.title, {
sql: dynamicCube.sql,
dimensions,
measures,
preAggregations: {
main: {
type: `originalSql`,
},
},
});
});
});
app.json
[
{
"preAggregations": {
"mydemo": {
"type": "autoRollup",
"measureReferences": [
"DynamicCubeSchema.price"
],
"dimensionReferences": [
"name"
],
"external": true
}
},
"dimensions": {
"name": {
"sql": "name",
"type": "string"
}
},
"measures": {
"price": {
"drillMembers": [
"name",
"id"
],
"type": "count"
}
},
"title": "DynamicCubeSchema",
"sql": "SELECT * FROM demoapp"
}
]
运行&&效果
- 入口
index.js 基于throng 提升多线程能力
const CubejsServer = require('@cubejs-backend/server');
const cubejs = require("./cube")
const throng = require('throng')
const WORKERS = process.env.WEB_CONCURRENCY || 2
const server = new CubejsServer(cubejs);
throng(WORKERS, start)
function start(){
server
.listen()
.then(({ version, port }) => {
console.log(`???? Cube.js server (${version}) is listening on ${port}`);
})
.catch((e) => {
console.error('Fatal error during server start: ');
console.error(e.stack || e);
});
}
- 启动
需要先启动提供动态schema 的api 然后提供cube.js 效果
说明
完整代码可以参考GitHub https:///rongfengliang/cubejs-pre-age/tree/v2 包含了cubestore的使用,但是一些不太好的地方是es6 string 模版的支持,因为api 的特性,但是我们可以通过扩展function 支持,参考
String.prototype.interpolate = function(params) {
const names = Object.keys(params);
const vals = Object.values(params);
return new Function(...names, `return \`${this}\`;`)(...vals);
}