diff --git a/packages/cubejs-schema-compiler/adapter/QueryBuilder.js b/packages/cubejs-schema-compiler/adapter/QueryBuilder.js index b15aabb2a7a6a..5574095df9668 100644 --- a/packages/cubejs-schema-compiler/adapter/QueryBuilder.js +++ b/packages/cubejs-schema-compiler/adapter/QueryBuilder.js @@ -34,12 +34,13 @@ const ADAPTERS = { elasticsearch }; exports.query = (compilers, dbType, queryOptions) => { - if (!ADAPTERS[dbType]) { + if (!queryOptions.dialectClass && !ADAPTERS[dbType]) { return null; } - return new (ADAPTERS[dbType])(compilers, { + return new (queryOptions.dialectClass || ADAPTERS[dbType])(compilers, { ...queryOptions, - externalQueryClass: queryOptions.externalDbType && ADAPTERS[queryOptions.externalDbType] + externalQueryClass: queryOptions.externalDialectClass || + queryOptions.externalDbType && ADAPTERS[queryOptions.externalDbType] }); }; diff --git a/packages/cubejs-server-core/core/CompilerApi.js b/packages/cubejs-server-core/core/CompilerApi.js index 524e186ab822a..62eecb32b4305 100644 --- a/packages/cubejs-server-core/core/CompilerApi.js +++ b/packages/cubejs-server-core/core/CompilerApi.js @@ -6,6 +6,7 @@ class CompilerApi { constructor(repository, dbType, options) { this.repository = repository; this.dbType = dbType; + this.dialectClass = options.dialectClass; this.options = options || {}; this.allowNodeRequire = options.allowNodeRequire == null ? true : options.allowNodeRequire; this.logger = this.options.logger; @@ -47,12 +48,17 @@ class CompilerApi { return this.dbType; } + getDialectClass(dataSource) { + return this.dialectClass && this.dialectClass({ dataSource: dataSource || 'default' }); + } + async getSql(query, options) { options = options || {}; const { includeDebugInfo } = options; const dbType = this.getDbType('default'); + const dialectClass = this.getDialectClass('default'); const compilers = await this.getCompilers({ requestId: query.requestId }); - let sqlGenerator = this.createQuery(compilers, dbType, query); + let sqlGenerator = this.createQuery(compilers, dbType, dialectClass, query); if (!sqlGenerator) { throw new Error(`Unknown dbType: ${dbType}`); } @@ -61,7 +67,12 @@ class CompilerApi { if (dataSource !== 'default' && dbType !== this.getDbType(dataSource)) { // TODO consider more efficient way than instantiating query - sqlGenerator = this.createQuery(compilers, this.getDbType(dataSource), query); + sqlGenerator = this.createQuery( + compilers, + this.getDbType(dataSource), + this.getDialectClass(dataSource), + query + ); } return compilers.compiler.withQuery(sqlGenerator, () => ({ @@ -85,11 +96,13 @@ class CompilerApi { return cubeEvaluator.scheduledPreAggregations(); } - createQuery(compilers, dbType, query) { + createQuery(compilers, dbType, dialectClass, query) { return QueryBuilder.query( compilers, dbType, { ...query, + dialectClass, + externalDialectClass: this.options.externalDialectClass, externalDbType: this.options.externalDbType, preAggregationsSchema: this.preAggregationsSchema, allowUngroupedWithoutPrimaryKey: this.allowUngroupedWithoutPrimaryKey diff --git a/packages/cubejs-server-core/core/index.js b/packages/cubejs-server-core/core/index.js index b76f0dba5887a..1cae0c6fe1ed6 100644 --- a/packages/cubejs-server-core/core/index.js +++ b/packages/cubejs-server-core/core/index.js @@ -172,6 +172,8 @@ class CubejsServerCore { options = options || {}; options = { driverFactory: () => CubejsServerCore.createDriver(options.dbType), + dialectFactory: () => CubejsServerCore.lookupDriverClass(options.dbType).dialectClass && + CubejsServerCore.lookupDriverClass(options.dbType).dialectClass(), apiSecret: process.env.CUBEJS_API_SECRET, dbType: process.env.CUBEJS_DB_TYPE, devServer: process.env.NODE_ENV !== 'production', @@ -188,6 +190,8 @@ class CubejsServerCore { this.options = options; this.driverFactory = options.driverFactory; this.externalDriverFactory = options.externalDriverFactory; + this.dialectFactory = options.dialectFactory; + this.externalDialectFactory = options.externalDialectFactory; this.apiSecret = options.apiSecret; this.schemaPath = options.schemaPath || process.env.CUBEJS_SCHEMA_PATH || 'schema'; this.dbType = options.dbType; @@ -419,6 +423,9 @@ class CubejsServerCore { this.repositoryFactory(context), { dbType: (dataSourceContext) => this.contextToDbType({ ...context, ...dataSourceContext }), externalDbType: this.contextToExternalDbType(context), + dialectClass: (dataSourceContext) => this.dialectFactory && + this.dialectFactory({ ...context, ...dataSourceContext }), + externalDialectClass: this.externalDialectFactory && this.externalDialectFactory(context), schemaVersion: currentSchemaVersion, preAggregationsSchema: this.preAggregationsSchema(context), context @@ -477,7 +484,9 @@ class CubejsServerCore { externalDbType: options.externalDbType, preAggregationsSchema: options.preAggregationsSchema, allowUngroupedWithoutPrimaryKey: this.options.allowUngroupedWithoutPrimaryKey, - compileContext: options.context + compileContext: options.context, + dialectClass: options.dialectClass, + externalDialectClass: options.externalDialectClass, }); } @@ -506,15 +515,21 @@ class CubejsServerCore { static createDriver(dbType) { checkEnvForPlaceholders(); + return new (CubejsServerCore.lookupDriverClass(dbType))(); + } + + static lookupDriverClass(dbType) { // eslint-disable-next-line global-require,import/no-dynamic-require - return new (require(CubejsServerCore.driverDependencies(dbType || process.env.CUBEJS_DB_TYPE)))(); + return require(CubejsServerCore.driverDependencies(dbType || process.env.CUBEJS_DB_TYPE)); } static driverDependencies(dbType) { - if (!DriverDependencies[dbType]) { - throw new Error(`Unsupported db type: ${dbType}`); + if (DriverDependencies[dbType]) { + return DriverDependencies[dbType]; + } else if (fs.existsSync(path.join('node_modules', `${dbType}-cubejs-driver`))) { + return `${dbType}-cubejs-driver`; } - return DriverDependencies[dbType]; + throw new Error(`Unsupported db type: ${dbType}`); } testConnections() {