Skip to content

Commit 41b644c

Browse files
committed
feat: dynRef for dynamic member referencing
1 parent 8fec0c1 commit 41b644c

File tree

5 files changed

+76
-6
lines changed

5 files changed

+76
-6
lines changed

packages/cubejs-schema-compiler/compiler/CubeSymbols.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const R = require('ramda');
22
const UserError = require('./UserError');
3+
const DynamicReference = require('./DynamicReference');
34

45
const FunctionRegex = /function\s+\w+\(([A-Za-z0-9_,]*)|\(([\s\S]*?)\)\s+|\(?(\w+)\)?\s+=>\s/;
56
const CONTEXT_SYMBOLS = {
@@ -92,7 +93,11 @@ class CubeSymbols {
9293
const oldContext = this.resolveSymbolsCallContext;
9394
this.resolveSymbolsCallContext = context;
9495
try {
95-
return func.apply(null, this.funcArguments(func).map((id) => nameResolver(id.trim())));
96+
let res = func.apply(null, this.funcArguments(func).map((id) => nameResolver(id.trim())));
97+
if (res instanceof DynamicReference) {
98+
res = res.fn.apply(null, res.memberNames.map((id) => nameResolver(id.trim())));
99+
}
100+
return res;
96101
} finally {
97102
this.resolveSymbolsCallContext = oldContext;
98103
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class DynamicReference {
2+
constructor(memberNames, fn) {
3+
this.memberNames = memberNames;
4+
this.fn = fn;
5+
}
6+
}
7+
8+
module.exports = DynamicReference;

packages/cubejs-schema-compiler/compiler/PrepareCompiler.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const DashboardTemplateEvaluator = require('./DashboardTemplateEvaluator');
1010
const JoinGraph = require('./JoinGraph');
1111
const Funnels = require('../extensions/Funnels');
1212
const RefreshKeys = require('../extensions/RefreshKeys');
13+
const Reflection = require('../extensions/Reflection');
1314
const CubeToMetaTransformer = require('./CubeToMetaTransformer');
1415

1516
exports.compile = (repo, options) => {
@@ -38,7 +39,8 @@ exports.prepareCompiler = (repo, options) => {
3839
cubeFactory: cubeSymbols.createCube.bind(cubeSymbols),
3940
extensions: {
4041
Funnels,
41-
RefreshKeys
42+
RefreshKeys,
43+
Reflection
4244
}
4345
}, options));
4446
return {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const R = require('ramda');
2+
const DynamicReference = require('../compiler/DynamicReference');
3+
4+
class RefreshKeys {
5+
constructor(cubeFactory, compiler) {
6+
this.cubeFactory = cubeFactory;
7+
this.compiler = compiler;
8+
this.dynRef = this.dynRef.bind(this);
9+
}
10+
11+
dynRef(...args) {
12+
if (args.length < 2) {
13+
throw new Error(`List of references and a function are expected in form: dynRef('ref', (r) => (...))`);
14+
}
15+
const references = R.dropLast(1, args);
16+
const fn = args[args.length - 1];
17+
if (typeof fn !== 'function') {
18+
throw new Error(`Last argument should be a function`);
19+
}
20+
return new DynamicReference(references, fn);
21+
}
22+
}
23+
24+
module.exports = RefreshKeys;

packages/cubejs-schema-compiler/test/ExtensionsTest.js

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
const CompileError = require('../compiler/CompileError');
1+
/* globals it,describe */
2+
/* eslint-disable quote-props */
23
const PostgresQuery = require('../adapter/PostgresQuery');
34
const PrepareCompiler = require('./PrepareCompiler');
45
require('should');
56

6-
const prepareCompiler = PrepareCompiler.prepareCompiler;
7+
const { prepareCompiler } = PrepareCompiler;
78

89
describe('Extensions', () => {
9-
const { compiler, joinGraph, cubeEvaluator, transformer } = prepareCompiler(`
10+
const {
11+
compiler, joinGraph, cubeEvaluator
12+
} = prepareCompiler(`
1013
const Funnels = require('Funnels');
14+
import { dynRef } from 'Reflection';
1115
1216
cube(\`VisitorsFunnel\`, {
1317
extends: Funnels.eventFunnel({
@@ -49,7 +53,14 @@ describe('Extensions', () => {
4953
})
5054
5155
cube(\`FooBar\`, {
52-
extends: VisitorsFunnel
56+
extends: VisitorsFunnel,
57+
58+
measures: {
59+
conversionsFraction: {
60+
sql: dynRef('conversions', (c) => \`\${c} / 100.0\`),
61+
type: 'number'
62+
}
63+
}
5364
})
5465
`);
5566

@@ -72,4 +83,24 @@ describe('Extensions', () => {
7283

7384
return result;
7485
});
86+
87+
it('dyn ref', () => {
88+
const result = compiler.compile().then(() => {
89+
const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
90+
measures: [
91+
'FooBar.conversionsFraction'
92+
],
93+
timeDimensions: [{
94+
dimension: 'FooBar.time',
95+
granularity: 'day',
96+
dateRange: { from: '2017-01-01', to: '2017-01-30' }
97+
}],
98+
timezone: 'America/Los_Angeles'
99+
});
100+
101+
console.log(query.buildSqlAndParams()[0]);
102+
});
103+
104+
return result;
105+
});
75106
});

0 commit comments

Comments
 (0)