Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion docs/pages/product/data-modeling/syntax.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,73 @@ the [template context](/reference/python/cube#templatecontext-class).

</ReferenceBox>

### Curly braces and escaping

As you can see in the examples above, within [SQL expressions][self-sql-expressions],
curly braces are used to reference cubes and members.

In YAML data models, use `{reference}`:

```yaml
cubes:
- name: orders
sql: >
SELECT id, created_at
FROM {other_cube.sql()}

dimensions:
- name: status
sql: status
type: string

- name: status_x2
sql: "{status} || ' ' || {status}"
type: string
```

In JavaScript data models, use `${reference}` in [JavaScript template
literals][link-js-template-literals] (mind the dollar sign):

```javascript
cube(`orders`, {
sql: `
SELECT id, created_at
FROM ${other_cube.sql()}
`,

dimensions: {
status: {
sql: `status`,
type: `string`
},

status_x2: {
sql: `${status} || ' ' || ${status}`,
type: `string`
}
}
})
```

If you need to use literal, non-referential curly braces in YAML, e.g.,
to define a JSON object, you can escape them with a backslash:

```yaml
cubes:
- name: json_object_in_postgres
sql: SELECT CAST('\{"key":"value"\}'::JSON AS TEXT) AS json_column

- name: csv_from_s3_in_duckdb
sql: >
SELECT *
FROM read_csv(
's3://bbb/aaa.csv',
delim = ',',
header = true,
columns=\{'time':'DATE','count':'NUMERIC'\}
)
```

### Non-SQL references

Outside [SQL expressions][self-sql-expressions], `column` is not recognized
Expand Down Expand Up @@ -693,4 +760,5 @@ defining dynamic data models.
[ref-custom-granularities]: /reference/data-model/dimensions#granularities
[ref-style-guide]: /guides/style-guide
[ref-polymorphism]: /product/data-modeling/concepts/polymorphic-cubes
[ref-data-blending]: /product/data-modeling/concepts/data-blending
[ref-data-blending]: /product/data-modeling/concepts/data-blending
[link-js-template-literals]: https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Strings#embedding_javascript
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ export class YamlCompiler {
} else if (str[i] === '`' && peek().inStr) {
result.push(str[i]);
stateStack.pop();
} else if (str[i] === '{' && str[i + 1] === '{' && peek()?.inFormattedStr) {
result.push('{{');
} else if (str[i] === '\\' && str[i + 1] === '{' && stateStack.length === 0) {
result.push('\\{');
i += 1;
} else if (str[i] === '}' && str[i + 1] === '}' && peek()?.inFormattedStr) {
result.push('}}');
} else if (str[i] === '\\' && str[i + 1] === '}' && stateStack.length === 0) {
result.push('\\}');
i += 1;
} else if (str[i] === '{' && peek()?.inFormattedStr) {
result.push(str[i]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,40 @@ cubes:
);
});

it('simple with json/curly in sql', async () => {
const { compiler, joinGraph, cubeEvaluator } = prepareYamlCompiler(`
cubes:
- name: ActiveUsers
sql: SELECT 1 as user_id, '2022-01-01'::TIMESTAMP as timestamp, CAST('\\{"key":"value"\\}'::JSON AS TEXT) AS json_col

dimensions:
- name: time
sql: "{CUBE}.timestamp"
type: time
- name: json_col
sql: json_col
type: string
`);
await compiler.compile();

const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, {
dimensions: ['ActiveUsers.time', 'ActiveUsers.json_col'],
timezone: 'UTC'
});

console.log(query.buildSqlAndParams());

const res = await dbRunner.testQuery(query.buildSqlAndParams());
console.log(JSON.stringify(res));

expect(res).toEqual(
[{
active_users__time: '2022-01-01T00:00:00.000Z',
active_users__json_col: '{"key":"value"}',
}]
);
});

it('missed sql', async () => {
const { compiler } = prepareYamlCompiler(`
cubes:
Expand Down
Loading
Loading