Skip to content

Commit 11a140f

Browse files
authored
feat(schema-compiler): Yaml - duplicate check for view/cube names (cube-js#10400)
1 parent d711612 commit 11a140f

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

packages/cubejs-schema-compiler/src/compiler/YamlCompiler.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,15 @@ export class YamlCompiler {
9696

9797
for (const key of Object.keys(yamlObj)) {
9898
if (key === 'cubes') {
99+
this.checkDuplicateNames(yamlObj.cubes || [], 'cube', errorsReport);
100+
99101
(yamlObj.cubes || []).forEach(({ name, ...cube }) => {
100102
const transpiledCube = this.transpileAndPrepareJsFile('cube', { name, ...cube }, errorsReport);
101103
transpiledFilesContent.push(transpiledCube);
102104
});
103105
} else if (key === 'views') {
106+
this.checkDuplicateNames(yamlObj.views || [], 'view', errorsReport);
107+
104108
(yamlObj.views || []).forEach(({ name, ...cube }) => {
105109
const transpiledView = this.transpileAndPrepareJsFile('view', { name, ...cube }, errorsReport);
106110
transpiledFilesContent.push(transpiledView);
@@ -316,6 +320,22 @@ export class YamlCompiler {
316320
return body?.expression;
317321
}
318322

323+
private checkDuplicateNames(items: any[], type: 'cube' | 'view', errorsReport: ErrorReporter) {
324+
const seen = new Set<string>();
325+
326+
for (const item of items) {
327+
if (item?.name) {
328+
if (seen.has(item.name)) {
329+
errorsReport.error(
330+
`Found duplicate ${type} name '${item.name}'.`
331+
);
332+
} else {
333+
seen.add(item.name);
334+
}
335+
}
336+
}
337+
}
338+
319339
private yamlArrayToObj(
320340
yamlArray,
321341
memberType: string,

packages/cubejs-schema-compiler/test/unit/yaml-schema.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,69 @@ cubes:
146146
}
147147
});
148148

149+
it('detects duplicate cube names', async () => {
150+
const { compiler } = prepareYamlCompiler(`
151+
cubes:
152+
- name: orders
153+
sql_table: orders
154+
dimensions:
155+
- name: id
156+
sql: id
157+
type: number
158+
primary_key: true
159+
160+
- name: orders
161+
sql_table: orders_v2
162+
dimensions:
163+
- name: id
164+
sql: id
165+
type: number
166+
primary_key: true
167+
`);
168+
169+
try {
170+
await compiler.compile();
171+
throw new Error('compile must return an error');
172+
} catch (e: any) {
173+
expect(e.message).toContain("Found duplicate cube name 'orders'");
174+
}
175+
});
176+
177+
it('detects duplicate view names', async () => {
178+
const { compiler } = prepareYamlCompiler(`
179+
cubes:
180+
- name: orders
181+
sql_table: orders
182+
dimensions:
183+
- name: id
184+
sql: id
185+
type: number
186+
primary_key: true
187+
- name: status
188+
sql: status
189+
type: string
190+
views:
191+
- name: orders_view
192+
cubes:
193+
- join_path: orders
194+
includes:
195+
- id
196+
197+
- name: orders_view
198+
cubes:
199+
- join_path: orders
200+
includes:
201+
- status
202+
`);
203+
204+
try {
205+
await compiler.compile();
206+
throw new Error('compile must return an error');
207+
} catch (e: any) {
208+
expect(e.message).toContain("Found duplicate view name 'orders_view'");
209+
}
210+
});
211+
149212
it('detects duplicate dimension granularities', async () => {
150213
const { compiler } = prepareYamlCompiler(`
151214
cubes:

0 commit comments

Comments
 (0)