Skip to content

Commit

Permalink
feat: dynamic case label (#236)
Browse files Browse the repository at this point in the history
* Make label dynamic

#235

* fixes

* cleanup and docs

* better docs

* improve

* fix

Fixes #235
  • Loading branch information
ferrants authored and paveltiunov committed Oct 22, 2019
1 parent 33d5fda commit 1a82605
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 8 deletions.
19 changes: 18 additions & 1 deletion docs/Schema/dimensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ The first `when` statement declares a condition and result if the rule returns a
The second `else` statement declares results for options when rules return a false value.


The following example will create a `size` dimension with values 'xl' and 'xxl'.
The following static `label` example will create a `size` dimension with values 'xl' and 'xxl'.

```javascript
size: {
Expand All @@ -100,6 +100,23 @@ size: {
}
```

`label` can be defined dynamically as an object with a `sql` property.

```javascript
size: {
type: `string`,
case: {
when: [
{ sql: `${CUBE}.meta_value = 'xl-en'`, label: {sql: `${CUBE}.english_size`} },
{ sql: `${CUBE}.meta_value = 'xl'`, label: {sql: `${CUBE}.euro_size`} },
{ sql: `${CUBE}.meta_value = 'xxl-en'`, label: {sql: `${CUBE}.english_size`} },
{ sql: `${CUBE}.meta_value = 'xxl'`, label: {sql: `${CUBE}.euro_size`} },
],
else: { label: `Unknown` }
}
}
```

### primaryKey
Specify which dimension is a primary key for a cube. The default value is `false`.

Expand Down
19 changes: 16 additions & 3 deletions packages/cubejs-schema-compiler/adapter/BaseQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -1167,13 +1167,26 @@ class BaseQuery {
}

renderDimensionCase(symbol, cubeName) {
const when = symbol.case.when.map(w => ({ sql: this.evaluateSql(cubeName, w.sql), label: w.label }));
return this.caseWhenStatement(when, symbol.case.else && symbol.case.else.label);
const when = symbol.case.when.map(w => ({
sql: this.evaluateSql(cubeName, w.sql),
label: this.renderDimensionCaseLabel(w.label, cubeName)
}));
return this.caseWhenStatement(
when,
symbol.case.else && this.renderDimensionCaseLabel(symbol.case.else.label, cubeName)
);
}

renderDimensionCaseLabel(label, cubeName) {
if (typeof label === 'object' && label.sql){
return this.evaluateSql(cubeName, label.sql)
}
return `'${label}'`
}

caseWhenStatement(when, elseLabel) {
return `CASE
${when.map(w => `WHEN ${w.sql} THEN '${w.label}'`).join("\n")}${elseLabel ? ` ELSE '${elseLabel}'` : ''} END`;
${when.map(w => `WHEN ${w.sql} THEN ${w.label}`).join("\n")}${elseLabel ? ` ELSE ${elseLabel}` : ''} END`;
}

applyMeasureFilters(evaluateSql, symbol, cubeName) {
Expand Down
14 changes: 12 additions & 2 deletions packages/cubejs-schema-compiler/compiler/CubeValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,20 @@ const cubeSchema = Joi.object().keys({
case: Joi.object().keys({
when: Joi.array().items(Joi.object().keys({
sql: Joi.func().required(),
label: Joi.string()
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})),
else: Joi.object().keys({
label: Joi.string()
label: Joi.alternatives([
Joi.string(),
Joi.object().keys({
sql: Joi.func().required()
})
])
})
}).required()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe('ClickHouse DataSchemaCompiler', function test() {
return result;
});

it('dimension case', () => {
it('static dimension case', () => {
const { compiler, transformer, cubeEvaluator, joinGraph } = prepareCompiler(`
cube('visitors', {
sql: \`
Expand Down Expand Up @@ -240,6 +240,80 @@ describe('ClickHouse DataSchemaCompiler', function test() {

return result;
});

it('dynamic dimension case', () => {
const { compiler, transformer, cubeEvaluator, joinGraph } = prepareCompiler(`
cube('visitors', {
sql: \`
select * from visitors
\`,
measures: {
visitor_count: {
type: 'count',
sql: 'id'
}
},
dimensions: {
source: {
type: 'string',
sql: 'source'
},
latitude: {
type: 'string',
sql: 'latitude'
},
enabled_source: {
type: 'string',
case: {
when: [{
sql: \`\${CUBE}.status = 3\`,
label: 'three'
}, {
sql: \`\${CUBE}.status = 2\`,
label: {
sql: \`\${CUBE}.source\`
}
}],
else: {
label: {
sql: \`\${CUBE}.source\`
}
}
}
},
created_at: {
type: 'time',
sql: 'created_at'
}
}
})
`);
const result = compiler.compile().then(() => {
const query = dbRunner.newQuery({ joinGraph, cubeEvaluator, compiler }, {
measures: ['visitors.visitor_count'],
dimensions: ['visitors.enabled_source'],
timezone: 'America/Los_Angeles',
order: [{
id: 'visitors.enabled_source'
}]
});
logSqlAndParams(query);

return dbRunner.testQuery(query.buildSqlAndParams()).then(res => {
res.should.be.deepEqual(
[
{ "visitors__enabled_source": "google", "visitors__visitor_count": "1" },
{ "visitors__enabled_source": "some", "visitors__visitor_count": "2" },
{ "visitors__enabled_source": null, "visitors__visitor_count": "3" },
]
);
});
});

return result;
});

{
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe('DataSchemaCompiler', function test() {
return result;
});

it('dimension case', () => {
it('static dimension case', () => {
const { compiler, transformer, cubeEvaluator, joinGraph } = prepareCompiler(`
cube('visitors', {
sql: \`
Expand Down Expand Up @@ -233,6 +233,7 @@ describe('DataSchemaCompiler', function test() {

return result;
});

it('filtered dates', () => {
const { compiler, cubeEvaluator, joinGraph } = prepareCompiler(`
cube('visitors', {
Expand Down

0 comments on commit 1a82605

Please sign in to comment.