1
0
Fork 0
mirror of synced 2024-06-28 02:50:50 +12:00
budibase/packages/server/src/api/controllers/datasource.js

177 lines
4.6 KiB
JavaScript

const CouchDB = require("../../db")
const {
generateDatasourceID,
getDatasourceParams,
getQueryParams,
DocumentTypes,
BudibaseInternalDB,
getTableParams,
} = require("../../db/utils")
const { BuildSchemaErrors } = require("../../constants")
const { integrations } = require("../../integrations")
const { getDatasourceAndQuery } = require("./row/utils")
exports.fetch = async function (ctx) {
const database = new CouchDB(ctx.appId)
// Get internal tables
const db = new CouchDB(ctx.appId)
const internalTables = await db.allDocs(
getTableParams(null, {
include_docs: true,
})
)
const internal = internalTables.rows.map(row => row.doc)
const bbInternalDb = {
...BudibaseInternalDB,
entities: internal,
}
// Get external datasources
const datasources = (
await database.allDocs(
getDatasourceParams(null, {
include_docs: true,
})
)
).rows.map(row => row.doc)
ctx.body = [bbInternalDb, ...datasources]
}
exports.buildSchemaFromDb = async function (ctx) {
const db = new CouchDB(ctx.appId)
const datasource = await db.get(ctx.params.datasourceId)
const { tables, error } = await buildSchemaHelper(datasource)
datasource.entities = tables
const dbResp = await db.put(datasource)
datasource._rev = dbResp.rev
const response = { datasource }
if (error) {
response.error = error
}
ctx.body = response
}
exports.update = async function (ctx) {
const db = new CouchDB(ctx.appId)
const datasourceId = ctx.params.datasourceId
let datasource = await db.get(datasourceId)
datasource = { ...datasource, ...ctx.request.body }
const response = await db.put(datasource)
datasource._rev = response.rev
// Drain connection pools when configuration is changed
if (datasource.source) {
const source = integrations[datasource.source]
if (source && source.pool) {
await source.pool.end()
}
}
ctx.status = 200
ctx.message = "Datasource saved successfully."
ctx.body = { datasource }
}
exports.save = async function (ctx) {
const db = new CouchDB(ctx.appId)
const plus = ctx.request.body.datasource.plus
const fetchSchema = ctx.request.body.fetchSchema
const datasource = {
_id: generateDatasourceID({ plus }),
type: plus ? DocumentTypes.DATASOURCE_PLUS : DocumentTypes.DATASOURCE,
...ctx.request.body.datasource,
}
let schemaError = null
if (fetchSchema) {
const { tables, error } = await buildSchemaHelper(datasource)
schemaError = error
datasource.entities = tables
}
const dbResp = await db.put(datasource)
datasource._rev = dbResp.rev
// Drain connection pools when configuration is changed
if (datasource.source) {
const source = integrations[datasource.source]
if (source && source.pool) {
await source.pool.end()
}
}
const response = { datasource }
if (schemaError) {
response.error = schemaError
}
ctx.body = response
}
exports.destroy = async function (ctx) {
const db = new CouchDB(ctx.appId)
// Delete all queries for the datasource
const rows = await db.allDocs(getQueryParams(ctx.params.datasourceId, null))
await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
// delete the datasource
await db.remove(ctx.params.datasourceId, ctx.params.revId)
ctx.message = `Datasource deleted.`
ctx.status = 200
}
exports.find = async function (ctx) {
const database = new CouchDB(ctx.appId)
ctx.body = await database.get(ctx.params.datasourceId)
}
// dynamic query functionality
exports.query = async function (ctx) {
const queryJson = ctx.request.body
try {
ctx.body = await getDatasourceAndQuery(ctx.appId, queryJson)
} catch (err) {
ctx.throw(400, err)
}
}
const buildSchemaHelper = async datasource => {
const Connector = integrations[datasource.source]
// Connect to the DB and build the schema
const connector = new Connector(datasource.config)
await connector.buildSchema(datasource._id, datasource.entities)
datasource.entities = connector.tables
// make sure they all have a display name selected
for (let entity of Object.values(datasource.entities)) {
if (entity.primaryDisplay) {
continue
}
entity.primaryDisplay = Object.values(entity.schema).find(
schema => !schema.autocolumn
).name
}
const errors = connector.schemaErrors
let error = null
if (errors && Object.keys(errors).length > 0) {
const noKeyTables = Object.entries(errors)
.filter(entry => entry[1] === BuildSchemaErrors.NO_KEY)
.map(([name]) => name)
error = `No primary key constraint found for the following: ${noKeyTables.join(
", "
)}`
}
return { tables: connector.tables, error }
}