Re-writing a bit so that it is aware some functionality is SQL only, makes future plus endpoints easier.

This commit is contained in:
mike12345567 2021-07-03 11:15:01 +01:00
parent 71f96f9601
commit 11f6abee0a
6 changed files with 92 additions and 35 deletions

View File

@ -5,7 +5,7 @@ import {
PaginationJson,
RelationshipsJson,
} from "../../../definitions/datasource"
import { Row, Table, FieldSchema } from "../../../definitions/common"
import {Row, Table, FieldSchema, Datasource} from "../../../definitions/common"
import {
breakRowIdField,
generateRowIdField,
@ -29,11 +29,11 @@ interface RunConfig {
module External {
const { makeExternalQuery } = require("./utils")
const { DataSourceOperation, FieldTypes } = require("../../../constants")
const { getAllExternalTables } = require("../table/utils")
const { breakExternalTableId } = require("../../../integrations/utils")
const { breakExternalTableId, isSQL } = require("../../../integrations/utils")
const { processObjectSync } = require("@budibase/string-templates")
const { cloneDeep } = require("lodash/fp")
const { isEqual } = require("lodash")
const CouchDB = require("../../../db")
function buildFilters(
id: string | undefined,
@ -128,18 +128,22 @@ module External {
private readonly appId: string
private operation: Operation
private tableId: string
private tables: { [key: string]: Table }
private datasource: Datasource
private tables: { [key: string]: Table } = {}
constructor(
appId: string,
operation: Operation,
tableId: string,
tables: { [key: string]: Table }
datasource: Datasource
) {
this.appId = appId
this.operation = operation
this.tableId = tableId
this.tables = tables
this.datasource = datasource
if (datasource && datasource.entities) {
this.tables = datasource.entities
}
}
inputProcessing(row: Row, table: Table) {
@ -451,10 +455,16 @@ module External {
async run({ id, row, filters, sort, paginate }: RunConfig) {
const { appId, operation, tableId } = this
let { datasourceId, tableName } = breakExternalTableId(tableId)
if (!this.tables) {
this.tables = await getAllExternalTables(appId, datasourceId)
if (!this.datasource) {
const db = new CouchDB(appId)
this.datasource = await db.get(datasourceId)
if (!this.datasource || !this.datasource.entities) {
throw "No tables found, fetch tables before query."
}
this.tables = this.datasource.entities
}
const table = this.tables[tableName]
let isSql = isSQL(this.datasource)
if (!table) {
throw `Unable to process query, table "${tableName}" not defined.`
}
@ -476,8 +486,8 @@ module External {
operation,
},
resource: {
// have to specify the fields to avoid column overlap
fields: this.buildFields(table),
// have to specify the fields to avoid column overlap (for SQL)
fields: isSql ? this.buildFields(table) : [],
},
filters,
sort,

View File

@ -9,9 +9,10 @@ const {
breakRowIdField,
} = require("../../../integrations/utils")
const ExternalRequest = require("./ExternalRequest")
const CouchDB = require("../../../db")
async function handleRequest(appId, operation, tableId, opts = {}) {
return new ExternalRequest(appId, operation, tableId, opts.tables).run(opts)
return new ExternalRequest(appId, operation, tableId, opts.datasource).run(opts)
}
exports.patch = async ctx => {
@ -162,14 +163,19 @@ exports.fetchEnrichedRow = async ctx => {
const id = ctx.params.rowId
const tableId = ctx.params.tableId
const { datasourceId, tableName } = breakExternalTableId(tableId)
const tables = await getAllExternalTables(appId, datasourceId)
const db = new CouchDB(appId)
const datasource = await db.get(datasourceId)
if (!datasource || !datasource.entities) {
ctx.throw(400, "Datasource has not been configured for plus API.")
}
const tables = datasource.entities
const response = await handleRequest(
appId,
DataSourceOperation.READ,
tableId,
{
id,
tables,
datasource,
}
)
const table = tables[tableName]

View File

@ -1,3 +1,5 @@
import { SourceNames } from "./datasource"
interface Base {
_id?: string
_rev?: string
@ -82,3 +84,17 @@ export interface Automation extends Base {
trigger?: AutomationStep
}
}
export interface Datasource extends Base {
type: string
name: string
source: SourceNames
// the config is defined by the schema
config: {
[key: string]: string | number | boolean
}
plus: boolean
entities?: {
[key: string]: Table
}
}

View File

@ -26,6 +26,20 @@ export enum DatasourceFieldTypes {
JSON = "json",
}
export enum SourceNames {
POSTGRES = "POSTGRES",
DYNAMODB = "DYNAMODB",
MONGODB = "MONGODB",
ELASTICSEARCH = "ELASTICSEARCH",
COUCHDB = "COUCHDB",
SQL_SERVER = "SQL_SERVER",
S3 = "S3",
AIRTABLE = "AIRTABLE",
MYSQL = "MYSQL",
ARANGODB = "ARANGODB",
REST = "REST",
}
export interface QueryDefinition {
type: QueryTypes
displayName?: string

View File

@ -9,33 +9,34 @@ const airtable = require("./airtable")
const mysql = require("./mysql")
const arangodb = require("./arangodb")
const rest = require("./rest")
const { SourceNames } = require("../definitions/datasource")
const DEFINITIONS = {
POSTGRES: postgres.schema,
DYNAMODB: dynamodb.schema,
MONGODB: mongodb.schema,
ELASTICSEARCH: elasticsearch.schema,
COUCHDB: couchdb.schema,
SQL_SERVER: sqlServer.schema,
S3: s3.schema,
AIRTABLE: airtable.schema,
MYSQL: mysql.schema,
ARANGODB: arangodb.schema,
REST: rest.schema,
[SourceNames.POSTGRES]: postgres.schema,
[SourceNames.DYNAMODB]: dynamodb.schema,
[SourceNames.MONGODB]: mongodb.schema,
[SourceNames.ELASTICSEARCH]: elasticsearch.schema,
[SourceNames.COUCHDB]: couchdb.schema,
[SourceNames.SQL_SERVER]: sqlServer.schema,
[SourceNames.S3]: s3.schema,
[SourceNames.AIRTABLE]: airtable.schema,
[SourceNames.MYSQL]: mysql.schema,
[SourceNames.ARANGODB]: arangodb.schema,
[SourceNames.REST]: rest.schema,
}
const INTEGRATIONS = {
POSTGRES: postgres.integration,
DYNAMODB: dynamodb.integration,
MONGODB: mongodb.integration,
ELASTICSEARCH: elasticsearch.integration,
COUCHDB: couchdb.integration,
S3: s3.integration,
SQL_SERVER: sqlServer.integration,
AIRTABLE: airtable.integration,
MYSQL: mysql.integration,
ARANGODB: arangodb.integration,
REST: rest.integration,
[SourceNames.POSTGRES]: postgres.integration,
[SourceNames.DYNAMODB]: dynamodb.integration,
[SourceNames.MONGODB]: mongodb.integration,
[SourceNames.ELASTICSEARCH]: elasticsearch.integration,
[SourceNames.COUCHDB]: couchdb.integration,
[SourceNames.SQL_SERVER]: s3.integration,
[SourceNames.S3]: sqlServer.integration,
[SourceNames.AIRTABLE]: airtable.integration,
[SourceNames.MYSQL]: mysql.integration,
[SourceNames.ARANGODB]: arangodb.integration,
[SourceNames.REST]: rest.integration,
}
module.exports = {

View File

@ -1,4 +1,6 @@
import { SqlQuery } from "../definitions/datasource"
import { Datasource } from "../definitions/common"
import { SourceNames } from "../definitions/datasource"
const { DocumentTypes, SEPARATOR } = require("../db/utils")
const { FieldTypes } = require("../constants")
@ -51,3 +53,11 @@ export function getSqlQuery(query: SqlQuery | string): SqlQuery {
return query
}
}
export function isSQL(datasource: Datasource): boolean {
if (!datasource || !datasource.source) {
return false
}
const SQL = [SourceNames.POSTGRES, SourceNames.SQL_SERVER, SourceNames.MYSQL]
return SQL.indexOf(datasource.source) !== -1
}