diff --git a/packages/plugins/@hera/plugin-external-data-source/.npmignore b/packages/plugins/@tachybase/plugin-external-data-source/.npmignore similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/.npmignore rename to packages/plugins/@tachybase/plugin-external-data-source/.npmignore diff --git a/packages/plugins/@hera/plugin-external-data-source/README.md b/packages/plugins/@tachybase/plugin-external-data-source/README.md similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/README.md rename to packages/plugins/@tachybase/plugin-external-data-source/README.md diff --git a/packages/plugins/@hera/plugin-external-data-source/client.d.ts b/packages/plugins/@tachybase/plugin-external-data-source/client.d.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/client.d.ts rename to packages/plugins/@tachybase/plugin-external-data-source/client.d.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/client.js b/packages/plugins/@tachybase/plugin-external-data-source/client.js similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/client.js rename to packages/plugins/@tachybase/plugin-external-data-source/client.js diff --git a/packages/plugins/@hera/plugin-external-data-source/package.json b/packages/plugins/@tachybase/plugin-external-data-source/package.json similarity index 90% rename from packages/plugins/@hera/plugin-external-data-source/package.json rename to packages/plugins/@tachybase/plugin-external-data-source/package.json index 595263c42..391e0cb31 100644 --- a/packages/plugins/@hera/plugin-external-data-source/package.json +++ b/packages/plugins/@tachybase/plugin-external-data-source/package.json @@ -1,5 +1,5 @@ { - "name": "@hera/plugin-external-data-source", + "name": "@tachybase/plugin-external-data-source", "version": "0.0.13", "main": "dist/server/index.js", "dependencies": { diff --git a/packages/plugins/@hera/plugin-external-data-source/server.d.ts b/packages/plugins/@tachybase/plugin-external-data-source/server.d.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/server.d.ts rename to packages/plugins/@tachybase/plugin-external-data-source/server.d.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/server.js b/packages/plugins/@tachybase/plugin-external-data-source/server.js similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/server.js rename to packages/plugins/@tachybase/plugin-external-data-source/server.js diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/msql.tsx b/packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/msql.tsx new file mode 100644 index 000000000..c50e557e2 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/msql.tsx @@ -0,0 +1,90 @@ +import React from 'react'; +import { SchemaComponent } from '@tachybase/client'; +import { tval, usePluginTranslation } from '../locale'; + +export const MysqlDataSourceSettingsForm = () => { + const { t } = usePluginTranslation(); + return ( + + ); +}; diff --git a/packages/plugins/@hera/plugin-external-data-source/src/client/index.tsx b/packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/pg.tsx similarity index 78% rename from packages/plugins/@hera/plugin-external-data-source/src/client/index.tsx rename to packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/pg.tsx index 3ea0edaba..6840f36d7 100644 --- a/packages/plugins/@hera/plugin-external-data-source/src/client/index.tsx +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/client/forms/pg.tsx @@ -1,11 +1,9 @@ import React from 'react'; -import { Plugin, SchemaComponent } from '@tachybase/client'; -import {} from '@tachybase/client'; -import { PluginDataSourceManagerClient } from '@nocobase/plugin-data-source-manager/client'; import { Space } from 'antd'; -import { generateNTemplate as tval, usePluginTranslation } from './locale'; +import { SchemaComponent } from '@tachybase/client'; +import { tval, usePluginTranslation } from '../locale'; -const DataSourceSettingsForm = () => { +export const PgDataSourceSettingsForm = () => { const { t } = usePluginTranslation(); return ( { displayName: { type: 'string', title: tval('Data source display name'), - required: !0, + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', }, @@ -39,7 +37,7 @@ const DataSourceSettingsForm = () => { host: { type: 'string', title: tval('Host'), - required: !0, + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', default: 'localhost', @@ -47,7 +45,7 @@ const DataSourceSettingsForm = () => { port: { type: 'string', title: tval('Port'), - required: !0, + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', default: 5432, @@ -55,14 +53,14 @@ const DataSourceSettingsForm = () => { database: { type: 'string', title: tval('Database'), - required: !0, + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', }, username: { type: 'string', title: tval('Username'), - required: !0, + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', }, @@ -98,13 +96,3 @@ const DataSourceSettingsForm = () => { /> ); }; - -export class PluginExternalDataSourceClient extends Plugin { - async load() { - this.app.pm - .get(PluginDataSourceManagerClient) - .registerType('postgres', { DataSourceSettingsForm, label: tval('PostgreSQL') }); - } -} - -export default PluginExternalDataSourceClient; diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/client/index.tsx b/packages/plugins/@tachybase/plugin-external-data-source/src/client/index.tsx new file mode 100644 index 000000000..4d15e16cc --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/client/index.tsx @@ -0,0 +1,19 @@ +import { Plugin } from '@tachybase/client'; +import { PluginDataSourceManagerClient } from '@nocobase/plugin-data-source-manager/client'; +import { tval } from './locale'; +import { PgDataSourceSettingsForm } from './forms/pg'; +import { MysqlDataSourceSettingsForm } from './forms/msql'; + +export class PluginExternalDataSourceClient extends Plugin { + async load() { + this.app.pm + .get(PluginDataSourceManagerClient) + .registerType('postgres', { DataSourceSettingsForm: PgDataSourceSettingsForm, label: tval('PostgreSQL') }); + + this.app.pm + .get(PluginDataSourceManagerClient) + .registerType('mysql', { DataSourceSettingsForm: MysqlDataSourceSettingsForm, label: tval('MySQL') }); + } +} + +export default PluginExternalDataSourceClient; diff --git a/packages/plugins/@hera/plugin-external-data-source/src/client/locale.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/client/locale.ts similarity index 89% rename from packages/plugins/@hera/plugin-external-data-source/src/client/locale.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/client/locale.ts index 4aefde70b..fa6b8c21f 100644 --- a/packages/plugins/@hera/plugin-external-data-source/src/client/locale.ts +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/client/locale.ts @@ -6,7 +6,7 @@ export const NAMESPACE = '@hera/plugin-external-data-source'; export function lang(key: string, options = {}) { return i18n.t(key, { ...options, ns: NAMESPACE }); } -export function generateNTemplate(key: string) { +export function tval(key: string) { return `{{t('${key}', { ns: '${NAMESPACE}', nsMode: 'fallback' })}}`; } export function usePluginTranslation() { diff --git a/packages/plugins/@hera/plugin-external-data-source/src/index.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/index.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/index.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/index.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/src/locale/en-US.json b/packages/plugins/@tachybase/plugin-external-data-source/src/locale/en-US.json similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/locale/en-US.json rename to packages/plugins/@tachybase/plugin-external-data-source/src/locale/en-US.json diff --git a/packages/plugins/@hera/plugin-external-data-source/src/locale/zh-CN.json b/packages/plugins/@tachybase/plugin-external-data-source/src/locale/zh-CN.json similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/locale/zh-CN.json rename to packages/plugins/@tachybase/plugin-external-data-source/src/locale/zh-CN.json diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/collections/.gitkeep b/packages/plugins/@tachybase/plugin-external-data-source/src/server/collections/.gitkeep similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/collections/.gitkeep rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/collections/.gitkeep diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/index.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/index.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/index.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/index.ts diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/database-introspector.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/database-introspector.ts new file mode 100644 index 000000000..8e451f556 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/database-introspector.ts @@ -0,0 +1,219 @@ +import { ViewFieldInference } from '@tachybase/database'; +import { mergeOptions } from '@nocobase/plugin-data-source-manager'; +import { EventEmitter } from 'events'; +import _ from 'lodash'; + +export class DatabaseIntrospector extends EventEmitter { + db; + typeInterfaceMap; + constructor(options) { + super(); + this.db = options.db; + this.typeInterfaceMap = options.typeInterfaceMap; + } + async getCollections(options: any = {}) { + let tableList = await this.db.sequelize.getQueryInterface().showAllTables(); + const views = (await this.db.queryInterface.listViews()).map((view) => view.name); + tableList = tableList.concat(views); + if (this.db.options.tablePrefix) { + tableList = tableList.filter((tableName) => { + return tableName.startsWith(this.db.options.tablePrefix); + }); + } + const batchSize = 5; + const results = []; + for (let i = 0; i < tableList.length; i += batchSize) { + const batch = tableList.slice(i, i + batchSize); + const batchResults = await Promise.all( + batch.map(async (tableName) => { + const tableInfo = { + tableName, + }; + this.emit('loadMessage', { + message: `load table ${tableName}`, + }); + const collectionOptions = this.tableInfoToCollectionOptions(tableInfo); + const localOptions = options.localData?.[collectionOptions.name]; + try { + return await this.getCollection({ + tableInfo, + localOptions, + mergedOptions: views.includes(tableName) ? { view: true, template: 'view' } : {}, + }); + } catch (e) { + if (e.message.includes('No description found for')) { + return false; + } + throw e; + } + }), + ); + results.push(...batchResults); + } + return results.filter(Boolean); + } + async getCollection(options) { + const { tableInfo } = options; + const columnsInfo = await this.db.sequelize.getQueryInterface().describeTable(tableInfo); + const collectionOptions = this.tableInfoToCollectionOptions(tableInfo); + const constraints = await this.db.sequelize + .getQueryInterface() + .showIndex(this.db.inDialect('postgres') ? tableInfo : tableInfo.tableName); + try { + const fields = Object.keys(columnsInfo).map((columnName) => { + return this.columnInfoToFieldOptions(columnsInfo, columnName, constraints); + }); + const unsupportedFields = fields.filter((field: any) => { + return field.supported === false; + }); + const supportFields = fields.filter((field: any) => { + return field.supported !== false; + }); + const remoteCollectionInfo = { + ...collectionOptions, + ...((options == null ? void 0 : options.mergedOptions) || {}), + ...this.collectionOptionsByFields(supportFields), + fields: supportFields, + }; + if (unsupportedFields.length) { + remoteCollectionInfo.unsupportedFields = unsupportedFields; + } + const finalOptions = this.mergeLocalDataIntoCollectionOptions(remoteCollectionInfo, options.localOptions); + if (finalOptions.view && !finalOptions.filterTargetKey && supportFields.find((field) => field.name === 'id')) { + finalOptions.filterTargetKey = 'id'; + } + return finalOptions; + } catch (e) { + throw new Error(`table ${tableInfo.tableName} introspection error: ${e.message}`); + } + } + loadCollection(options) { + this.db.collection({ + ...options, + introspected: true, + }); + } + loadCollections(options) { + options.collections.forEach((collection) => { + this.loadCollection(collection); + }); + } + tableInfoToCollectionOptions(tableInfo) { + const tableName = tableInfo.tableName; + let name = tableName; + if (this.db.options.tablePrefix) { + name = tableName.replace(this.db.options.tablePrefix, ''); + } + return { + name, + title: name, + schema: tableInfo.schema, + tableName, + }; + } + collectionOptionsByFields(fields) { + const options: any = { + timestamps: false, + autoGenId: false, + }; + const autoIncrementField = fields.find((field) => field.autoIncrement); + if (autoIncrementField) { + options.filterTargetKey = autoIncrementField.name; + } + const primaryKeys = fields.filter((field) => field.primaryKey); + if (!options.filterTargetKey && primaryKeys.length == 1) { + options.filterTargetKey = primaryKeys[0].name; + } + const uniques = fields.filter((field) => field.unique); + if (!options.filterTargetKey && uniques.length == 1) { + options.filterTargetKey = uniques[0].name; + } + return options; + } + mergeLocalDataIntoCollectionOptions(collectionOptions, localData) { + if (!localData) { + return collectionOptions; + } + const collectionFields = collectionOptions.fields || []; + const localFieldsAsObject = _.keyBy(localData.fields, 'name'); + const newFields = collectionFields.map((field) => { + const localField = localFieldsAsObject[field.name]; + if (!localField) { + return field; + } + return mergeOptions(field, localField); + }); + const localAssociationFields = localData.fields?.filter((field) => { + return ['belongsTo', 'belongsToMany', 'hasMany', 'hasOne'].includes(field.type); + }); + if (localAssociationFields) { + newFields.push(...localAssociationFields); + } + return { + ...collectionOptions, + ..._.omit(localData, ['fields']), + fields: newFields, + }; + } + columnInfoToFieldOptions(columnsInfo, columnName, indexes) { + const columnInfo = columnsInfo[columnName]; + let fieldOptions: any = { + ...this.columnAttribute(columnsInfo, columnName, indexes), + ...ViewFieldInference.inferToFieldType({ + dialect: this.db.options.dialect, + type: columnInfo.type, + name: columnName, + }), + rawType: columnInfo.type, + name: columnName, + }; + if (!fieldOptions.type) { + return { + rawType: columnInfo.type, + name: columnName, + supported: false, + }; + } + const interfaceConfig = this.getDefaultInterfaceByType(columnsInfo, columnName, fieldOptions.type); + if (typeof interfaceConfig === 'string') { + fieldOptions.interface = interfaceConfig; + } else { + fieldOptions = { + ...fieldOptions, + ...interfaceConfig, + }; + } + _.set(fieldOptions, 'uiSchema.title', columnName); + return fieldOptions; + } + getDefaultInterfaceByType(columnsInfo, columnName, type) { + const interfaceConfig = this.typeInterfaceMap[type]; + if (typeof interfaceConfig === 'function') { + return interfaceConfig(columnsInfo[columnName]); + } + return interfaceConfig; + } + columnAttribute(columnsInfo, columnName, indexes) { + const columnInfo = columnsInfo[columnName]; + const attr = { + type: columnInfo.type, + allowNull: columnInfo.allowNull, + primaryKey: columnInfo.primaryKey, + unique: false, + autoIncrement: columnInfo.autoIncrement, + }; + if (columnInfo.defaultValue && typeof columnInfo.defaultValue === 'string') { + const isSerial = columnInfo.defaultValue.match(/^nextval\(/); + const isUUID = columnInfo.defaultValue.match(/^uuid_generate_v4\(/); + if (isSerial || isUUID) { + attr.autoIncrement = true; + } + } + for (const index of indexes) { + if (index.fields.length == 1 && index.fields[0].attribute == columnName && index.unique) { + attr.unique = true; + } + } + return attr; + } +} diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-collection-manager.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-collection-manager.ts new file mode 100644 index 000000000..4335b889e --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-collection-manager.ts @@ -0,0 +1,2 @@ +import { SequelizeCollectionManager } from '@tachybase/data-source-manager'; +export class MySQLCollectionManager extends SequelizeCollectionManager {} diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-data-source.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-data-source.ts new file mode 100644 index 000000000..d4c962ad4 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/mysql-data-source.ts @@ -0,0 +1,76 @@ +import { DataSource } from '@tachybase/data-source-manager'; +import { Database } from '@tachybase/database'; +import { MySQLCollectionManager } from './mysql-collection-manager'; +import { DatabaseIntrospector } from './database-introspector'; +import typeInterfaceMap from './type-interface-map'; + +export class MySQLDataSource extends DataSource { + static async testConnection(options) { + const database = new Database({ + dialect: 'mysql', + ...options, + }); + try { + await database.sequelize.authenticate(); + } catch (e) { + throw e; + } finally { + await database.close(); + } + return true; + } + async load(options) { + const db = this.collectionManager.db; + const introspector = new DatabaseIntrospector({ + db, + typeInterfaceMap, + }); + introspector.on('loadMessage', ({ message }) => { + this.emit('loadMessage', { message }); + }); + const { localData } = options; + const collections = await introspector.getCollections({ + localData, + }); + const delayFields = new Map(); + for (const collection of collections) { + try { + const fields = collection.fields; + for (const field of fields) { + if (field.type === 'belongsToMany') { + if (!delayFields.has(collection.name)) { + delayFields.set(collection.name, []); + } + delayFields.get(collection.name).push(field); + } + } + this.collectionManager.defineCollection({ + ...collection, + fields: fields.filter((field) => field.type !== 'belongsToMany'), + introspected: true, + }); + } catch (e) { + db.logger.error(`load collection failed, ${e}`); + delayFields.delete(collection.name); + } + } + for (const [name, fields] of delayFields.entries()) { + try { + for (const field of fields) { + this.collectionManager.getCollection(name).setField(field.name, field); + } + } catch (e) { + db.logger.error(`load belongs to many field failed, ${e}`); + } + } + } + createCollectionManager(options) { + const database = new Database({ + dialect: 'mysql', + ...options, + }); + return new MySQLCollectionManager({ + database, + }); + } +} diff --git a/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/type-interface-map.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/type-interface-map.ts new file mode 100644 index 000000000..daae201e1 --- /dev/null +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/mysql/type-interface-map.ts @@ -0,0 +1,241 @@ +const typeInterfaceMap = { + array: '', + belongsTo: '', + belongsToMany: '', + boolean: () => { + return { + interface: 'checkbox', + uiSchema: { + type: 'boolean', + 'x-component': 'Checkbox', + }, + }; + }, + context: '', + date: () => { + return { + interface: 'datetime', + uiSchema: { + 'x-component': 'DatePicker', + 'x-component-props': { + dateFormat: 'YYYY-MM-DD', + showTime: false, + }, + }, + }; + }, + hasMany: '', + hasOne: '', + json: () => { + return { + interface: 'json', + uiSchema: { + 'x-component': 'Input.JSON', + 'x-component-props': { + autoSize: { + minRows: 5, + // maxRows: 20, + }, + }, + default: null, + }, + }; + }, + jsonb: () => { + return { + interface: 'json', + uiSchema: { + 'x-component': 'Input.JSON', + 'x-component-props': { + autoSize: { + minRows: 5, + // maxRows: 20, + }, + }, + default: null, + }, + }; + }, + integer: () => ({ + interface: 'integer', + // name, + uiSchema: { + type: 'number', + // title, + 'x-component': 'InputNumber', + 'x-component-props': { + stringMode: true, + step: '1', + }, + 'x-validator': 'integer', + }, + }), + bigInt: (columnInfo) => { + return { + interface: 'integer', + uiSchema: { + 'x-component': 'InputNumber', + 'x-component-props': { + style: { + width: '100%', + }, + }, + }, + }; + }, + float: () => { + return { + interface: 'number', + uiSchema: { + type: 'number', + // title, + 'x-component': 'InputNumber', + 'x-component-props': { + stringMode: true, + step: '1', + }, + }, + }; + }, + double: () => { + return { + interface: 'number', + uiSchema: { + type: 'number', + // title, + 'x-component': 'InputNumber', + 'x-component-props': { + stringMode: true, + step: '1', + }, + }, + }; + }, + real: () => { + return { + interface: 'number', + uiSchema: { + type: 'number', + // title, + 'x-component': 'InputNumber', + 'x-component-props': { + stringMode: true, + step: '1', + }, + }, + }; + }, + decimal: () => { + return { + interface: 'number', + uiSchema: { + type: 'number', + // title, + 'x-component': 'InputNumber', + 'x-component-props': { + stringMode: true, + step: '1', + }, + }, + }; + }, + password: () => ({ + interface: 'password', + hidden: true, + // name, + uiSchema: { + type: 'string', + // title, + 'x-component': 'Password', + }, + }), + radio: '', + set: '', + sort: '', + string: (columnInfo) => { + const type = columnInfo.type; + if (type.startsWith('ENUM')) { + return { + interface: 'select', + uiSchema: { + type: 'string', + 'x-component': 'Select', + enum: type + .replace('ENUM(', '') + .replace(')', '') + .replace(/'/g, '') + .split(',') + .map((item) => ({ + label: item, + value: item, + })), + }, + }; + } + return { + interface: 'input', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': { + style: { + width: '100%', + }, + }, + }, + }; + }, + text: () => { + return { + interface: 'textarea', + // name, + uiSchema: { + type: 'string', + 'x-component': 'Input.TextArea', + }, + }; + }, + time: () => ({ + interface: 'time', + // name, + uiSchema: { + type: 'string', + 'x-component': 'TimePicker', + 'x-component-props': { + format: 'HH:mm:ss', + }, + }, + }), + uid: () => { + return { + interface: 'input', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': { + style: { + width: '100%', + }, + }, + }, + }; + }, + uuid: () => { + return { + interface: 'uuid', + uiSchema: { + 'x-component': 'Input', + 'x-component-props': { + style: { + width: '100%', + }, + }, + }, + }; + }, + virtual: '', + point: '', + polygon: '', + lineString: '', + circle: '', +}; + +export default typeInterfaceMap; diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/services/database-introspector.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/database-introspector.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/services/database-introspector.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/database-introspector.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/postgres-collection-manager.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/postgres-collection-manager.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/postgres-collection-manager.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/postgres-collection-manager.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/postgres-data-source.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/postgres-data-source.ts similarity index 95% rename from packages/plugins/@hera/plugin-external-data-source/src/server/postgres-data-source.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/postgres-data-source.ts index 7ffd97b7d..bf051ac9d 100644 --- a/packages/plugins/@hera/plugin-external-data-source/src/server/postgres-data-source.ts +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/postgres-data-source.ts @@ -1,8 +1,8 @@ import { DataSource } from '@tachybase/data-source-manager'; import { Database } from '@tachybase/database'; import { PostgresCollectionManager } from './postgres-collection-manager'; -import { DatabaseIntrospector } from './services/database-introspector'; -import typeInterfaceMap from './services/type-interface-map'; +import { DatabaseIntrospector } from './database-introspector'; +import typeInterfaceMap from './type-interface-map'; export class PostgresDataSource extends DataSource { static async testConnection(options) { diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/services/type-interface-map.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/type-interface-map.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/services/type-interface-map.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/type-interface-map.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/services/utils.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/utils.ts similarity index 100% rename from packages/plugins/@hera/plugin-external-data-source/src/server/services/utils.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/pg/utils.ts diff --git a/packages/plugins/@hera/plugin-external-data-source/src/server/plugin.ts b/packages/plugins/@tachybase/plugin-external-data-source/src/server/plugin.ts similarity index 75% rename from packages/plugins/@hera/plugin-external-data-source/src/server/plugin.ts rename to packages/plugins/@tachybase/plugin-external-data-source/src/server/plugin.ts index 5d779c28b..69f0b1d11 100644 --- a/packages/plugins/@hera/plugin-external-data-source/src/server/plugin.ts +++ b/packages/plugins/@tachybase/plugin-external-data-source/src/server/plugin.ts @@ -1,11 +1,13 @@ import { Plugin } from '@tachybase/server'; -import { PostgresDataSource } from './postgres-data-source'; +import { PostgresDataSource } from './pg/postgres-data-source'; +import { MySQLDataSource } from './mysql/mysql-data-source'; export class PluginExternalDataSourceServer extends Plugin { async afterAdd() {} async beforeLoad() { this.app.dataSourceManager.factory.register('postgres', PostgresDataSource); + this.app.dataSourceManager.factory.register('mysql', MySQLDataSource); } async beforeEnable() { const plugin = this.pm.get('data-source-manager'); diff --git a/packages/presets/rental/package.json b/packages/presets/rental/package.json index fb7d85866..8769992d1 100644 --- a/packages/presets/rental/package.json +++ b/packages/presets/rental/package.json @@ -51,6 +51,7 @@ "@nocobase/plugin-users": "workspace:*", "@nocobase/plugin-verification": "workspace:*", "@tachybase/client": "workspace:*", + "@tachybase/plugin-external-data-source": "workspace:*", "@tachybase/plugin-mobile-client": "workspace:*", "@tachybase/plugin-system-settings": "workspace:*", "@tachybase/plugin-workflow": "workspace:*", diff --git a/packages/presets/rental/src/server/index.ts b/packages/presets/rental/src/server/index.ts index c637bd9cf..b0e51b63f 100644 --- a/packages/presets/rental/src/server/index.ts +++ b/packages/presets/rental/src/server/index.ts @@ -2,7 +2,7 @@ import PresetTachyBase from '@tachybase/preset-tachybase'; import _ from 'lodash'; export class PluginRental extends PresetTachyBase { - #builtInPlugins = ['approval-mobile', 'core', 'homepage']; + #builtInPlugins = ['approval-mobile', 'core', 'homepage', 'external-data-source']; get builtInPlugins() { return super.builtInPlugins.concat(this.#builtInPlugins); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 275dd79d4..1d97e5467 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1638,40 +1638,6 @@ importers: specifier: ^8.13.0 version: 8.15.1 - packages/plugins/@hera/plugin-external-data-source: - dependencies: - '@tachybase/client': - specifier: workspace:* - version: link:../../../core/client - '@tachybase/data-source-manager': - specifier: workspace:* - version: link:../../../core/data-source-manager - '@tachybase/database': - specifier: workspace:* - version: link:../../../core/database - '@tachybase/server': - specifier: workspace:* - version: link:../../../core/server - '@tachybase/test': - specifier: workspace:* - version: link:../../../core/test - antd: - specifier: 5.16.1 - version: 5.16.1(react-dom@18.2.0)(react@18.2.0) - lodash: - specifier: ^4.17.21 - version: 4.17.21 - pg: - specifier: ^8.11.3 - version: 8.11.3 - react-i18next: - specifier: ^11.15.1 - version: 11.18.6(i18next@22.5.1)(react-dom@18.2.0)(react@18.2.0) - devDependencies: - '@types/lodash': - specifier: ^4.17.0 - version: 4.17.0 - packages/plugins/@hera/plugin-homepage: dependencies: '@tachybase/client': @@ -3819,6 +3785,40 @@ importers: specifier: ^4.0.525 version: 4.0.759 + packages/plugins/@tachybase/plugin-external-data-source: + dependencies: + '@tachybase/client': + specifier: workspace:* + version: link:../../../core/client + '@tachybase/data-source-manager': + specifier: workspace:* + version: link:../../../core/data-source-manager + '@tachybase/database': + specifier: workspace:* + version: link:../../../core/database + '@tachybase/server': + specifier: workspace:* + version: link:../../../core/server + '@tachybase/test': + specifier: workspace:* + version: link:../../../core/test + antd: + specifier: 5.16.1 + version: 5.16.1(react-dom@18.2.0)(react@18.2.0) + lodash: + specifier: ^4.17.21 + version: 4.17.21 + pg: + specifier: ^8.11.3 + version: 8.11.3 + react-i18next: + specifier: ^11.15.1 + version: 11.18.6(i18next@22.5.1)(react-dom@18.2.0)(react@18.2.0) + devDependencies: + '@types/lodash': + specifier: ^4.17.0 + version: 4.17.0 + packages/plugins/@tachybase/plugin-field-markdown-vditor: dependencies: '@tachybase/client': @@ -4357,6 +4357,9 @@ importers: '@tachybase/client': specifier: workspace:* version: link:../../core/client + '@tachybase/plugin-external-data-source': + specifier: workspace:* + version: link:../../plugins/@tachybase/plugin-external-data-source '@tachybase/plugin-mobile-client': specifier: workspace:* version: link:../../plugins/@tachybase/plugin-mobile-client @@ -4847,7 +4850,7 @@ packages: react-dom: '>=17.0.0' dependencies: '@ant-design/cssinjs': 1.20.0(react-dom@18.2.0)(react@18.2.0) - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@ctrl/tinycolor': 3.6.1 antd: 5.16.1(react-dom@18.2.0)(react@18.2.0) rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0) @@ -4864,7 +4867,7 @@ packages: dependencies: '@ant-design/icons': 5.3.6(react-dom@18.2.0)(react@18.2.0) '@ant-design/pro-provider': 2.13.5(antd@5.16.1)(react-dom@18.2.0)(react@18.2.0) - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 antd: 5.16.1(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 dayjs: 1.11.10 @@ -4880,7 +4883,7 @@ packages: peerDependencies: react: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 classnames: 2.5.1 json2mq: 0.2.0 react: 18.2.0 @@ -8056,7 +8059,7 @@ packages: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: '@babel/helper-module-imports': 7.22.15 - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.2 @@ -8109,7 +8112,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@emotion/babel-plugin': 11.11.0 '@emotion/cache': 11.11.0 '@emotion/serialize': 1.1.2 @@ -10530,7 +10533,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) '@rc-component/trigger': 2.1.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 @@ -10562,7 +10565,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -25641,7 +25644,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 array-tree-filter: 2.1.0 classnames: 2.5.1 rc-select: 14.13.0(react-dom@18.2.0)(react@18.2.0) @@ -25681,7 +25684,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -25695,7 +25698,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -25736,7 +25739,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 async-validator: 4.2.5 rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 @@ -25748,7 +25751,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-dialog: 9.4.0(react-dom@18.2.0)(react@18.2.0) @@ -25763,7 +25766,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 rc-input: 1.4.5(react-dom@18.2.0)(react@18.2.0) @@ -25805,7 +25808,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/trigger': 2.1.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -25885,7 +25888,7 @@ packages: moment: optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/trigger': 2.1.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 dayjs: 1.11.10 @@ -25971,7 +25974,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/trigger': 1.18.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -25989,7 +25992,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/trigger': 2.1.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) @@ -26044,7 +26047,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) @@ -26117,7 +26120,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 classnames: 2.5.1 rc-select: 14.13.0(react-dom@18.2.0)(react@18.2.0) rc-tree: 5.8.5(react-dom@18.2.0)(react@18.2.0) @@ -26163,7 +26166,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0) @@ -26179,7 +26182,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 classnames: 2.5.1 rc-motion: 2.9.0(react-dom@18.2.0)(react@18.2.0) rc-util: 5.39.1(react-dom@18.2.0)(react@18.2.0) @@ -26585,7 +26588,7 @@ packages: react-native: optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react-redux': 7.1.33 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 @@ -26943,7 +26946,7 @@ packages: /redux@4.2.1: resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 /reflect-metadata@0.1.14: resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}