'use strict'; const { VALIDATED_QUERY_BLOCK_TYPES } = require('./constants'); const { hasOwn, toInt, ensureObjectPayload } = require('./helpers'); const { ensureDataSource, ensureInstance, ensureTemplate } = require('./repository'); const clickhouse = require('./clickhouse'); const dataease = require('./dataease'); const resolveDataSourceType = dataSource => String(dataSource?.type || '').trim().toLowerCase(); const getAdapterByType = type => { switch (type) { case 'clickhouse': return clickhouse; case 'dataease': return dataease; default: throw `unsupported data source type: ${type}`; } }; const getAdapterByDataSource = dataSource => { return getAdapterByType(resolveDataSourceType(dataSource)); }; const getDataSourceTables = async (ctx, dataSourceId, transaction = null) => { const dataSource = await ensureDataSource(ctx, dataSourceId, transaction); const adapter = getAdapterByDataSource(dataSource); if (resolveDataSourceType(dataSource) === 'clickhouse') { const payload = await adapter.listClickHouseTables(ctx, dataSource, transaction); return { sourceType: 'clickhouse', ...payload }; } const rows = await adapter.listDataEaseDatasets(ctx, dataSource); return { sourceType: 'dataease', dataSourceId: toInt(dataSourceId), clientKey: null, database: null, rows, }; }; const getDataSourceTableColumns = async (ctx, dataSourceId, tableId, transaction = null) => { const dataSource = await ensureDataSource(ctx, dataSourceId, transaction); const type = resolveDataSourceType(dataSource); const adapter = getAdapterByDataSource(dataSource); if (type === 'clickhouse') { const payload = await adapter.getClickHouseTableColumnsPayload(ctx, dataSource, tableId, transaction); return { sourceType: 'clickhouse', ...payload }; } const payload = await adapter.getDataEaseDatasetColumns(ctx, dataSource, tableId); return { sourceType: 'dataease', dataSourceId: toInt(dataSourceId), clientKey: payload.clientKey, database: payload.database, table: payload.datasetId, datasetName: payload.datasetName, rows: payload.rows, }; }; const previewDataSourceQuery = async (ctx, dataSourceId, rawDsl, transaction = null) => { const dataSource = await ensureDataSource(ctx, dataSourceId, transaction); const type = resolveDataSourceType(dataSource); const adapter = getAdapterByDataSource(dataSource); if (type === 'clickhouse') { const payload = await adapter.previewClickHouseQuery(ctx, dataSource, rawDsl, transaction); return { sourceType: 'clickhouse', dataSourceId: toInt(dataSourceId), ...payload, }; } const payload = await adapter.previewDataEaseQuery(ctx, dataSource, rawDsl); return { ...payload, dataSourceId: toInt(dataSourceId), }; }; const normalizeBlockConfigForDataSource = async (ctx, dataSourceId, blockType, config, transaction = null) => { const normalizedBlockType = String(blockType || 'text').trim().toLowerCase(); if (!VALIDATED_QUERY_BLOCK_TYPES.has(normalizedBlockType)) { if (config === null || config === undefined) return {}; return ensureObjectPayload(config, 'config'); } const safeConfig = ensureObjectPayload(config, 'config'); const dslPayload = hasOwn(safeConfig, 'query') ? ensureObjectPayload(safeConfig.query, 'config.query') : safeConfig; const parsedDataSourceId = toInt(dataSourceId); if (!parsedDataSourceId) throw 'missing param: dataSourceId'; const dataSource = await ensureDataSource(ctx, parsedDataSourceId, transaction); const type = resolveDataSourceType(dataSource); let normalizedDsl = null; if (type === 'clickhouse') { const dataSourceContext = await clickhouse.resolveClickHouseDataSourceContext(ctx, parsedDataSourceId, transaction); normalizedDsl = await clickhouse.validateStructuredQueryDsl(dataSourceContext, dslPayload); } else if (type === 'dataease') { normalizedDsl = (await dataease.validateDataEaseStructuredQueryDsl(ctx, dataSource, dslPayload)).normalizedDsl; } else { throw `unsupported data source type: ${type}`; } if (hasOwn(safeConfig, 'query')) { return { ...safeConfig, dataSourceId: parsedDataSourceId, query: { ...normalizedDsl, dataSourceId: parsedDataSourceId, }, }; } return { ...safeConfig, ...normalizedDsl, dataSourceId: parsedDataSourceId, }; }; const normalizeBlockConfigForStorage = async (ctx, instanceId, blockType, config, transaction = null) => { const instance = await ensureInstance(ctx, instanceId, transaction); const safeConfig = ensureObjectPayload(config || {}, 'config'); const dslPayload = hasOwn(safeConfig, 'query') ? ensureObjectPayload(safeConfig.query, 'config.query') : safeConfig; const dataSourceId = toInt(instance.dataSourceId || dslPayload.dataSourceId || safeConfig.dataSourceId); return normalizeBlockConfigForDataSource(ctx, dataSourceId, blockType, safeConfig, transaction); }; const normalizeTemplateBlockConfigForStorage = async (ctx, templateId, blockType, config, transaction = null) => { const template = await ensureTemplate(ctx, templateId, transaction); const safeConfig = ensureObjectPayload(config || {}, 'config'); const dataSourceId = toInt(template.dataSourceId); if (!dataSourceId) throw '模板未绑定数据源'; return normalizeBlockConfigForDataSource(ctx, dataSourceId, blockType, safeConfig, transaction); }; module.exports = { getDataSourceTables, getDataSourceTableColumns, previewDataSourceQuery, normalizeBlockConfigForDataSource, normalizeBlockConfigForStorage, normalizeTemplateBlockConfigForStorage, };