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

View File

@ -9,9 +9,10 @@ const {
breakRowIdField, breakRowIdField,
} = require("../../../integrations/utils") } = require("../../../integrations/utils")
const ExternalRequest = require("./ExternalRequest") const ExternalRequest = require("./ExternalRequest")
const CouchDB = require("../../../db")
async function handleRequest(appId, operation, tableId, opts = {}) { 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 => { exports.patch = async ctx => {
@ -162,14 +163,19 @@ exports.fetchEnrichedRow = async ctx => {
const id = ctx.params.rowId const id = ctx.params.rowId
const tableId = ctx.params.tableId const tableId = ctx.params.tableId
const { datasourceId, tableName } = breakExternalTableId(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( const response = await handleRequest(
appId, appId,
DataSourceOperation.READ, DataSourceOperation.READ,
tableId, tableId,
{ {
id, id,
tables, datasource,
} }
) )
const table = tables[tableName] const table = tables[tableName]

View File

@ -1,3 +1,5 @@
import { SourceNames } from "./datasource"
interface Base { interface Base {
_id?: string _id?: string
_rev?: string _rev?: string
@ -82,3 +84,17 @@ export interface Automation extends Base {
trigger?: AutomationStep 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", 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 { export interface QueryDefinition {
type: QueryTypes type: QueryTypes
displayName?: string displayName?: string

View File

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

View File

@ -1,4 +1,6 @@
import { SqlQuery } from "../definitions/datasource" import { SqlQuery } from "../definitions/datasource"
import { Datasource } from "../definitions/common"
import { SourceNames } from "../definitions/datasource"
const { DocumentTypes, SEPARATOR } = require("../db/utils") const { DocumentTypes, SEPARATOR } = require("../db/utils")
const { FieldTypes } = require("../constants") const { FieldTypes } = require("../constants")
@ -51,3 +53,11 @@ export function getSqlQuery(query: SqlQuery | string): SqlQuery {
return query 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
}