Skip to content

Commit 128d017

Browse files
authored
feat(api-gateway, server-core): Added dataSources method (#5789)
1 parent 8d798c4 commit 128d017

File tree

5 files changed

+152
-2
lines changed

5 files changed

+152
-2
lines changed

packages/cubejs-api-gateway/src/gateway.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,18 @@ class ApiGateway {
366366
});
367367
}
368368
);
369+
370+
app.get(
371+
'/cubejs-system/v1/data-sources',
372+
jsonParser,
373+
systemMiddlewares,
374+
async (req: Request, res: Response) => {
375+
await this.dataSources({
376+
context: req.context,
377+
res: this.resToResultFn(res),
378+
});
379+
}
380+
);
369381
}
370382

371383
app.get('/readyz', guestMiddlewares, cachedHandler(this.readiness));
@@ -1005,6 +1017,24 @@ class ApiGateway {
10051017
});
10061018
}
10071019
}
1020+
1021+
protected async dataSources({ context, res }: { context?: RequestContext, res: ResponseResultFn }) {
1022+
const requestStarted = new Date();
1023+
1024+
try {
1025+
const orchestratorApi = await this.getAdapterApi(context);
1026+
const { dataSources } = await this.getCompilerApi(context).dataSources(orchestratorApi);
1027+
1028+
res({ dataSources });
1029+
} catch (e) {
1030+
this.handleError({
1031+
e,
1032+
context,
1033+
res,
1034+
requestStarted,
1035+
});
1036+
}
1037+
}
10081038

10091039
protected async sqlRunner({ query, context, res }: QueryRequest) {
10101040
const requestStarted = new Date();

packages/cubejs-api-gateway/test/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ describe('API Gateway', () => {
592592
}
593593
}]
594594
},
595+
{ route: 'data-sources', successResult: { dataSources: ['default'] } },
595596
];
596597

597598
testConfigs.forEach((config) => {

packages/cubejs-api-gateway/test/mocks.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,13 @@ export const compilerApi = jest.fn().mockImplementation(() => ({
139139

140140
async preAggregations() {
141141
return preAggregationsResultFactory();
142-
}
142+
},
143+
144+
async dataSources() {
145+
return {
146+
dataSources: ['default']
147+
};
148+
},
143149
}));
144150

145151
export class RefreshSchedulerMock {

packages/cubejs-server-core/src/core/CompilerApi.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,54 @@ export class CompilerApi {
196196
};
197197
}
198198

199+
async dataSources(orchestratorApi) {
200+
let compilerVersion = (
201+
this.schemaVersion && await this.schemaVersion() ||
202+
'default_schema_version'
203+
);
204+
205+
if (typeof compilerVersion === 'object') {
206+
compilerVersion = JSON.stringify(compilerVersion);
207+
}
208+
209+
let { compilers } = this;
210+
if (!compilers || this.compilerVersion !== compilerVersion) {
211+
compilers = await compile(this.repository, {
212+
allowNodeRequire: this.allowNodeRequire,
213+
compileContext: this.compileContext,
214+
allowJsDuplicatePropsInSchema: this.allowJsDuplicatePropsInSchema,
215+
standalone: this.standalone,
216+
});
217+
}
218+
219+
const { cubeEvaluator } = await compilers;
220+
221+
let dataSources = await Promise.all(
222+
cubeEvaluator
223+
.cubeNames()
224+
.map(
225+
async (cube) => cubeEvaluator.cubeFromPath(cube).dataSource ?? 'default'
226+
)
227+
);
228+
229+
dataSources = [...new Set(dataSources)];
230+
231+
dataSources = await Promise.all(
232+
dataSources.map(async (dataSource) => {
233+
try {
234+
await orchestratorApi.driverFactory(dataSource);
235+
return dataSource;
236+
} catch (err) {
237+
return null;
238+
}
239+
})
240+
);
241+
242+
return {
243+
dataSources: dataSources.filter((source) => source),
244+
};
245+
}
246+
199247
canUsePreAggregationForTransformedQuery(transformedQuery, refs) {
200248
return PreAggregations.canUsePreAggregationForTransformedQueryFn(transformedQuery, refs);
201249
}

packages/cubejs-server-core/test/unit/index.test.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ cube('Bar', {
3939
type: 'count'
4040
}
4141
},
42-
42+
4343
dimensions: {
4444
time: {
4545
sql: 'timestamp',
@@ -57,6 +57,28 @@ const repositoryWithoutContent: SchemaFileRepository = {
5757
dataSchemaFiles: () => Promise.resolve([{ fileName: 'main.js', content: '' }]),
5858
};
5959

60+
const repositoryWithDataSource: SchemaFileRepository = {
61+
localPath: () => __dirname,
62+
dataSchemaFiles: () => Promise.resolve([{ fileName: 'main.js', content: `
63+
cube('Bar', {
64+
sql: 'select * from bar',
65+
66+
measures: {
67+
count: {
68+
type: 'count'
69+
}
70+
},
71+
dimensions: {
72+
time: {
73+
sql: 'timestamp',
74+
type: 'time'
75+
}
76+
},
77+
dataSource: 'main'
78+
});
79+
` }]),
80+
};
81+
6082
describe('index.test', () => {
6183
beforeEach(() => {
6284
delete process.env.CUBEJS_EXT_DB_TYPE;
@@ -366,6 +388,49 @@ describe('index.test', () => {
366388
expect(metaConfigExtendedSpy).toHaveBeenCalled();
367389
metaConfigExtendedSpy.mockClear();
368390
});
391+
392+
test('CompilerApi dataSources default', async () => {
393+
const dataSources = await compilerApi.dataSources({
394+
driverFactory: jest.fn(async () => true)
395+
});
396+
397+
expect(dataSources).toHaveProperty('dataSources');
398+
expect(dataSources.dataSources).toEqual([]);
399+
});
400+
});
401+
402+
describe('CompilerApi dataSources method', () => {
403+
const logger = jest.fn(() => {});
404+
const compilerApi = new CompilerApi(
405+
repositoryWithDataSource,
406+
async () => 'mysql',
407+
{ logger }
408+
);
409+
410+
const dataSourcesSpy = jest.spyOn(compilerApi, 'dataSources');
411+
test('CompilerApi dataSources', async () => {
412+
const dataSources = await compilerApi.dataSources({
413+
driverFactory: jest.fn(async () => true)
414+
});
415+
416+
expect(dataSources).toHaveProperty('dataSources');
417+
expect(dataSources.dataSources).toEqual(['main']);
418+
expect(dataSourcesSpy).toHaveBeenCalled();
419+
dataSourcesSpy.mockClear();
420+
});
421+
422+
test('CompilerApi dataSources with driverFactory error', async () => {
423+
const dataSources = await compilerApi.dataSources({
424+
driverFactory: jest.fn(async () => {
425+
throw new Error('Some driverFactory error');
426+
})
427+
});
428+
429+
expect(dataSources).toHaveProperty('dataSources');
430+
expect(dataSources.dataSources).toEqual([]);
431+
expect(dataSourcesSpy).toHaveBeenCalled();
432+
dataSourcesSpy.mockClear();
433+
});
369434
});
370435

371436
test('Should create instance of CubejsServerCore, dbType from process.env.CUBEJS_DB_TYPE', () => {

0 commit comments

Comments
 (0)