diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index 1d9469f2e7..346a15ab89 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -5,6 +5,8 @@ const { getQueryParams, } = require("../../db/utils") const { integrations } = require("../../integrations") +const plusIntegrations = require("../../integrations/plus") +const PostgresConnector = require("../../integrations/plus/Postgres") exports.fetch = async function (ctx) { const database = new CouchDB(ctx.appId) @@ -30,9 +32,11 @@ exports.save = async function (ctx) { datasource._rev = response.rev // Drain connection pools when configuration is changed - const source = integrations[datasource.source] - if (source && source.pool) { - await source.pool.end() + if (datasource.source) { + const source = integrations[datasource.source] + if (source && source.pool) { + await source.pool.end() + } } ctx.status = 200 @@ -58,3 +62,26 @@ exports.find = async function (ctx) { const database = new CouchDB(ctx.appId) ctx.body = await database.get(ctx.params.datasourceId) } + +// TODO: merge endpoint with main datasource endpoint +exports.plus = async function (ctx) { + const db = new CouchDB(ctx.appId) + + const PlusConnector = plusIntegrations[ctx.request.body.source] + + const connector = new PlusConnector(ctx.request.body) + await connector.init() + + const datasource = { + _id: generateDatasourceID(), + type: "datasource:plus", + ...ctx.request.body, + entities: connector.tables, + relationships: {}, + } + + const response = await db.post(datasource) + datasource._rev = response.rev + + ctx.body = datasource +} diff --git a/packages/server/src/api/routes/datasource.js b/packages/server/src/api/routes/datasource.js index 3c022e8e26..791118b336 100644 --- a/packages/server/src/api/routes/datasource.js +++ b/packages/server/src/api/routes/datasource.js @@ -16,6 +16,7 @@ router authorized(PermissionTypes.TABLE, PermissionLevels.READ), datasourceController.find ) + .post("/api/datasources/plus", datasourceController.plus) .post("/api/datasources", authorized(BUILDER), datasourceController.save) .delete( "/api/datasources/:datasourceId/:revId", diff --git a/packages/server/src/integrations/plus/index.js b/packages/server/src/integrations/plus/index.js new file mode 100644 index 0000000000..bb9fad7b24 --- /dev/null +++ b/packages/server/src/integrations/plus/index.js @@ -0,0 +1,5 @@ +const postgres = require("./postgres") + +module.exports = { + postgres, +} diff --git a/packages/server/src/integrations/plus/postgres.js b/packages/server/src/integrations/plus/postgres.js new file mode 100644 index 0000000000..2606195ff3 --- /dev/null +++ b/packages/server/src/integrations/plus/postgres.js @@ -0,0 +1,55 @@ +const { Pool } = require("pg") +const { FieldTypes } = require("../../constants") + +const TYPE_MAP = { + text: FieldTypes.LONGFORM, + varchar: FieldTypes.STRING, + integer: FieldTypes.NUMBER, + bigint: FieldTypes.NUMBER, + decimal: FieldTypes.NUMBER, + smallint: FieldTypes.NUMBER, + timestamp: FieldTypes.DATETIME, + time: FieldTypes.DATETIME, + boolean: FieldTypes.BOOLEAN, +} + +class PostgresPlus { + static pool + COLUMNS_SQL = + "select * from information_schema.columns where table_schema = 'public'" + + constructor(config) { + this.config = config + if (!this.pool) { + this.pool = new Pool(this.config) + } + + this.client = this.pool + } + + async init() { + const response = await this.client.query(this.COLUMNS_SQL) + + const tables = {} + for (let column of response.rows) { + // table key doesn't exist yet + if (!tables[column.table_name]) { + tables[column.table_name] = [] + } + + // Add the new column + const columnData = { + type: TYPE_MAP[column.data_type] || "unknown", + table: column.table_name, + name: column.column_name, + updateable: column.is_updatable, + precision: column.numeric_precision, + nullable: column.is_nullable === "YES", + } + tables[column.table_name].push(columnData) + } + this.tables = tables + } +} + +module.exports = PostgresPlus