cube.js 对于sql 方言支持的处理

sql 方言主要是为了进行不通数据库sql 兼容的支持,一般我们是不需要做的,但是一些特殊情况下我们
可能需要自己开发sql 方言处理

参考方法

server 初始化
packages/cubejs-server-core/src/core/server.ts

 
const options: ServerCoreInitializedOptions = {
      dbType,
      externalDbType,
      devServer,
      driverFactory: () => typeof dbType === 'string' && CubejsServerCore.createDriver(dbType),
      dialectFactory: (ctx) => CubejsServerCore.lookupDriverClass(ctx.dbType).dialectClass &&
        CubejsServerCore.lookupDriverClass(ctx.dbType).dialectClass(),
      externalDriverFactory: externalDbType && (
        () => new (CubejsServerCore.lookupDriverClass(externalDbType))({
          host: process.env.CUBEJS_EXT_DB_HOST,
          database: process.env.CUBEJS_EXT_DB_NAME,
          port: process.env.CUBEJS_EXT_DB_PORT,
          user: process.env.CUBEJS_EXT_DB_USER,
          password: process.env.CUBEJS_EXT_DB_PASS,
        })
      ),
      externalDialectFactory: () => typeof externalDbType === 'string' &&
        CubejsServerCore.lookupDriverClass(externalDbType).dialectClass &&
        CubejsServerCore.lookupDriverClass(externalDbType).dialectClass(),
      apiSecret: process.env.CUBEJS_API_SECRET,
      telemetry: process.env.CUBEJS_TELEMETRY !== 'false',
      scheduledRefreshTimeZones: process.env.CUBEJS_SCHEDULED_REFRESH_TIMEZONES &&
        process.env.CUBEJS_SCHEDULED_REFRESH_TIMEZONES.split(',').map(t => t.trim()),
      scheduledRefreshContexts: async () => [null],
      basePath: '/cubejs-api',
      dashboardAppPath: 'dashboard-app',
      dashboardAppPort: 3000,
      scheduledRefreshConcurrency: parseInt(process.env.CUBEJS_SCHEDULED_REFRESH_CONCURRENCY, 10),
      preAggregationsSchema: getEnv('preAggregationsSchema') || (
        devServer ? 'dev_pre_aggregations' : 'prod_pre_aggregations'
      ),
      schemaPath: process.env.CUBEJS_SCHEMA_PATH || 'schema',
      logger: opts.logger || process.env.NODE_ENV !== 'production'
        ? devLogger(process.env.CUBEJS_LOG_LEVEL)
        : prodLogger(process.env.CUBEJS_LOG_LEVEL),
      ...opts,
    };
    if (opts.contextToAppId && !opts.scheduledRefreshContexts) {
      options.logger('Multitenancy Without ScheduledRefreshContexts', {
        warning: (
          'You are using multitenancy without configuring scheduledRefreshContexts, which can lead to issues where the ' +
          'security context will be undefined while Cube.js will do background refreshing: ' +
          'https://cube.dev/docs/config#options-reference-scheduled-refresh-contexts'
        ),
      });
    }
 

编译api 对于方言的处理
packages/cubejs-server-core/src/core/server.ts

 
public getCompilerApi(context: RequestContext) {
    const appId = this.contextToAppId(context);
    let compilerApi = this.compilerCache.get(appId);
    const currentSchemaVersion = this.options.schemaVersion && (() => this.options.schemaVersion(context));
    if (!compilerApi) {
      compilerApi = this.createCompilerApi(
        this.repositoryFactory(context), {
          dbType: (dataSourceContext) => this.contextToDbType({ ...context, ...dataSourceContext }),
          externalDbType: this.contextToExternalDbType(context),
          dialectClass: (dialectContext) => this.options.dialectFactory &&
            this.options.dialectFactory({ ...context, ...dialectContext }),
          externalDialectClass: this.options.externalDialectFactory && this.options.externalDialectFactory(context),
          schemaVersion: currentSchemaVersion,
          preAggregationsSchema: this.preAggregationsSchema(context),
          context,
          allowJsDuplicatePropsInSchema: this.options.allowJsDuplicatePropsInSchema
        }
      );
      this.compilerCache.set(appId, compilerApi);
    }
    compilerApi.schemaVersion = currentSchemaVersion;
    return compilerApi;
  }
   

方法处理部分(主要是进行了一个判断,没有的使用默认的)
packages/cubejs-schema-compiler/src/adapter/QueryBuilder.js

export const createQuery = (compilers, dbType, queryOptions) => {
  if (!queryOptions.dialectClass && !ADAPTERS[dbType]) {
    return null;
  }
  let externalQueryClass = queryOptions.externalDialectClass;
  if (!externalQueryClass && queryOptions.externalDbType) {
    if (!ADAPTERS[queryOptions.externalDbType]) {
      throw new Error(`Dialect for '${queryOptions.externalDbType}' is not found`);
    }
    externalQueryClass = ADAPTERS[queryOptions.externalDbType];
  }
  // 有使用方言,没有的使用默认的driver 基于BaseQuery的实现
  return new (queryOptions.dialectClass || ADAPTERS[dbType])(compilers, {
    ...queryOptions,
    externalQueryClass
  });
};
 

默认提供的adapter
packages/cubejs-schema-compiler/src/adapter/QueryBuilder.js

 
const ADAPTERS = {
  postgres: PostgresQuery,
  redshift: RedshiftQuery,
  mysql: MysqlQuery,
  mysqlauroraserverless: MysqlQuery,
  mongobi: MongoBiQuery,
  mssql: MssqlQuery,
  bigquery: BigqueryQuery,
  prestodb: PrestodbQuery,
  qubole_prestodb: PrestodbQuery,
  athena: PrestodbQuery,
  vertica: VerticaQuery,
  snowflake: SnowflakeQuery,
  clickhouse: ClickHouseQuery,
  hive: HiveQuery,
  oracle: OracleQuery,
  sqlite: SqliteQuery,
  awselasticsearch: AWSElasticSearchQuery,
  elasticsearch: ElasticSearchQuery
};

参考方言的编写

可以参考druid,参考格式
packages/cubejs-schema-compiler/src/adapter/BaseQuery.js
packages/cubejs-query-orchestrator/src/driver/BaseDriver.js
packages/cubejs-druid-driver/src/DruidDriver.ts

 
export class DruidDriver extends BaseDriver {
  protected readonly config: DruidDriverConfiguration;
  protected readonly client: DruidClient;
  // 此处比较重要
  public static dialectClass() {
    return DruidQuery;
  }
....

DruidQuery 的实现继承自BaseQuery

说明

官方提供方言支持的核心也是让大家方便的进行driver的开发,因为一些内置的driver 是直接打包在
packages/cubejs-schema-compiler中了,修改此包是不明智的选择,同时也不利于社区参与贡献
如果关注代码会发现有一个直接使用基于npm 包模式的驱动依赖管理,处理参考代码

 
 public static driverDependencies(dbType: DatabaseType) {
    if (DriverDependencies[dbType]) {
      return DriverDependencies[dbType];
    } else if (fs.existsSync(path.join('node_modules', `${dbType}-cubejs-driver`))) {
      return `${dbType}-cubejs-driver`;
    }
    throw new Error(`Unsupported db type: ${dbType}`);
  }

所以只要我们的格式符合${dbType}-cubejs-driver 并且是通过npm 包发布的,也就是一个合格的driver

参考资料

https://github.com/cube-js/cube.js/blob/master/CONTRIBUTING.md#implementing-sql-dialect

上一篇:cube.js的多数据源试用


下一篇:Oracle 其他函数