Final typescript conversions for server.
This commit is contained in:
parent
3aed49778f
commit
93cb1c52de
|
@ -18,11 +18,7 @@ import {
|
||||||
convertRowId,
|
convertRowId,
|
||||||
} from "../../../integrations/utils"
|
} from "../../../integrations/utils"
|
||||||
import { getDatasourceAndQuery } from "./utils"
|
import { getDatasourceAndQuery } from "./utils"
|
||||||
import {
|
import { FieldTypes, RelationshipTypes } from "../../../constants"
|
||||||
DataSourceOperation,
|
|
||||||
FieldTypes,
|
|
||||||
RelationshipTypes,
|
|
||||||
} from "../../../constants"
|
|
||||||
import { breakExternalTableId, isSQL } from "../../../integrations/utils"
|
import { breakExternalTableId, isSQL } from "../../../integrations/utils"
|
||||||
import { processObjectSync } from "@budibase/string-templates"
|
import { processObjectSync } from "@budibase/string-templates"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -30,7 +26,7 @@ import { cloneDeep } from "lodash/fp"
|
||||||
import { processFormulas, processDates } from "../../../utilities/rowProcessor"
|
import { processFormulas, processDates } from "../../../utilities/rowProcessor"
|
||||||
import { context } from "@budibase/backend-core"
|
import { context } from "@budibase/backend-core"
|
||||||
|
|
||||||
interface ManyRelationship {
|
export interface ManyRelationship {
|
||||||
tableId?: string
|
tableId?: string
|
||||||
id?: string
|
id?: string
|
||||||
isUpdate?: boolean
|
isUpdate?: boolean
|
||||||
|
@ -38,21 +34,22 @@ interface ManyRelationship {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RunConfig {
|
export interface RunConfig {
|
||||||
id?: string
|
id?: any[]
|
||||||
filters?: SearchFilters
|
filters?: SearchFilters
|
||||||
sort?: SortJson
|
sort?: SortJson
|
||||||
paginate?: PaginationJson
|
paginate?: PaginationJson
|
||||||
|
datasource?: Datasource
|
||||||
row?: Row
|
row?: Row
|
||||||
rows?: Row[]
|
rows?: Row[]
|
||||||
|
tables?: Record<string, Table>
|
||||||
}
|
}
|
||||||
|
|
||||||
module External {
|
function buildFilters(
|
||||||
function buildFilters(
|
|
||||||
id: string | undefined | string[],
|
id: string | undefined | string[],
|
||||||
filters: SearchFilters,
|
filters: SearchFilters,
|
||||||
table: Table
|
table: Table
|
||||||
) {
|
) {
|
||||||
const primary = table.primary
|
const primary = table.primary
|
||||||
// if passed in array need to copy for shifting etc
|
// if passed in array need to copy for shifting etc
|
||||||
let idCopy: undefined | string | any[] = cloneDeep(id)
|
let idCopy: undefined | string | any[] = cloneDeep(id)
|
||||||
|
@ -87,9 +84,9 @@ module External {
|
||||||
return {
|
return {
|
||||||
equal,
|
equal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function checks the incoming parameters to make sure all the inputs are
|
* This function checks the incoming parameters to make sure all the inputs are
|
||||||
* valid based on on the table schema. The main thing this is looking for is when a
|
* valid based on on the table schema. The main thing this is looking for is when a
|
||||||
* user has made use of the _id field of a row for a foreign key or a search parameter.
|
* user has made use of the _id field of a row for a foreign key or a search parameter.
|
||||||
|
@ -97,7 +94,7 @@ module External {
|
||||||
* simplify it down to the requirements. This function is quite complex as we try to be
|
* simplify it down to the requirements. This function is quite complex as we try to be
|
||||||
* relatively restrictive over what types of columns we will perform this action for.
|
* relatively restrictive over what types of columns we will perform this action for.
|
||||||
*/
|
*/
|
||||||
function cleanupConfig(config: RunConfig, table: Table): RunConfig {
|
function cleanupConfig(config: RunConfig, table: Table): RunConfig {
|
||||||
const primaryOptions = [
|
const primaryOptions = [
|
||||||
FieldTypes.STRING,
|
FieldTypes.STRING,
|
||||||
FieldTypes.LONGFORM,
|
FieldTypes.LONGFORM,
|
||||||
|
@ -134,9 +131,9 @@ module External {
|
||||||
}
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateIdForRow(row: Row | undefined, table: Table): string {
|
function generateIdForRow(row: Row | undefined, table: Table): string {
|
||||||
const primary = table.primary
|
const primary = table.primary
|
||||||
if (!row || !primary) {
|
if (!row || !primary) {
|
||||||
return ""
|
return ""
|
||||||
|
@ -154,9 +151,9 @@ module External {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return generateRowIdField(idParts)
|
return generateRowIdField(idParts)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEndpoint(tableId: string | undefined, operation: string) {
|
function getEndpoint(tableId: string | undefined, operation: string) {
|
||||||
if (!tableId) {
|
if (!tableId) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
@ -166,9 +163,9 @@ module External {
|
||||||
entityId: tableName,
|
entityId: tableName,
|
||||||
operation,
|
operation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function basicProcessing(row: Row, table: Table): Row {
|
function basicProcessing(row: Row, table: Table): Row {
|
||||||
const thisRow: Row = {}
|
const thisRow: Row = {}
|
||||||
// filter the row down to what is actually the row (not joined)
|
// filter the row down to what is actually the row (not joined)
|
||||||
for (let fieldName of Object.keys(table.schema)) {
|
for (let fieldName of Object.keys(table.schema)) {
|
||||||
|
@ -183,9 +180,9 @@ module External {
|
||||||
thisRow.tableId = table._id
|
thisRow.tableId = table._id
|
||||||
thisRow._rev = "rev"
|
thisRow._rev = "rev"
|
||||||
return processFormulas(table, thisRow)
|
return processFormulas(table, thisRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixArrayTypes(row: Row, table: Table) {
|
function fixArrayTypes(row: Row, table: Table) {
|
||||||
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
||||||
if (
|
if (
|
||||||
schema.type === FieldTypes.ARRAY &&
|
schema.type === FieldTypes.ARRAY &&
|
||||||
|
@ -200,25 +197,21 @@ module External {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOneSide(field: FieldSchema) {
|
function isOneSide(field: FieldSchema) {
|
||||||
return (
|
return (
|
||||||
field.relationshipType && field.relationshipType.split("-")[0] === "one"
|
field.relationshipType && field.relationshipType.split("-")[0] === "one"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExternalRequest {
|
export class ExternalRequest {
|
||||||
private operation: DataSourceOperation
|
private operation: Operation
|
||||||
private tableId: string
|
private tableId: string
|
||||||
private datasource: Datasource
|
private datasource?: Datasource
|
||||||
private tables: { [key: string]: Table } = {}
|
private tables: { [key: string]: Table } = {}
|
||||||
|
|
||||||
constructor(
|
constructor(operation: Operation, tableId: string, datasource?: Datasource) {
|
||||||
operation: DataSourceOperation,
|
|
||||||
tableId: string,
|
|
||||||
datasource: Datasource
|
|
||||||
) {
|
|
||||||
this.operation = operation
|
this.operation = operation
|
||||||
this.tableId = tableId
|
this.tableId = tableId
|
||||||
this.datasource = datasource
|
this.datasource = datasource
|
||||||
|
@ -270,9 +263,7 @@ module External {
|
||||||
newRow[key] = row[key]
|
newRow[key] = row[key]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const { tableName: linkTableName } = breakExternalTableId(
|
const { tableName: linkTableName } = breakExternalTableId(field?.tableId)
|
||||||
field?.tableId
|
|
||||||
)
|
|
||||||
// table has to exist for many to many
|
// table has to exist for many to many
|
||||||
if (!linkTableName || !this.tables[linkTableName]) {
|
if (!linkTableName || !this.tables[linkTableName]) {
|
||||||
continue
|
continue
|
||||||
|
@ -530,7 +521,7 @@ module External {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const response = await getDatasourceAndQuery({
|
const response = await getDatasourceAndQuery({
|
||||||
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
endpoint: getEndpoint(tableId, Operation.READ),
|
||||||
filters: {
|
filters: {
|
||||||
equal: {
|
equal: {
|
||||||
[fieldName]: row[lookupField],
|
[fieldName]: row[lookupField],
|
||||||
|
@ -578,9 +569,7 @@ module External {
|
||||||
row[linkPrimary] === relationship.id ||
|
row[linkPrimary] === relationship.id ||
|
||||||
row[linkPrimary] === body?.[linkPrimary]
|
row[linkPrimary] === body?.[linkPrimary]
|
||||||
)
|
)
|
||||||
const operation = isUpdate
|
const operation = isUpdate ? Operation.UPDATE : Operation.CREATE
|
||||||
? DataSourceOperation.UPDATE
|
|
||||||
: DataSourceOperation.CREATE
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
promises.push(
|
promises.push(
|
||||||
getDatasourceAndQuery({
|
getDatasourceAndQuery({
|
||||||
|
@ -596,24 +585,17 @@ module External {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// finally cleanup anything that needs to be removed
|
// finally cleanup anything that needs to be removed
|
||||||
for (let [colName, { isMany, rows, tableId }] of Object.entries(
|
for (let [colName, { isMany, rows, tableId }] of Object.entries(related)) {
|
||||||
related
|
|
||||||
)) {
|
|
||||||
const table: Table | undefined = this.getTable(tableId)
|
const table: Table | undefined = this.getTable(tableId)
|
||||||
// if its not the foreign key skip it, nothing to do
|
// if its not the foreign key skip it, nothing to do
|
||||||
if (
|
if (!table || (table.primary && table.primary.indexOf(colName) !== -1)) {
|
||||||
!table ||
|
|
||||||
(table.primary && table.primary.indexOf(colName) !== -1)
|
|
||||||
) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
const filters = buildFilters(generateIdForRow(row, table), {}, table)
|
const filters = buildFilters(generateIdForRow(row, table), {}, table)
|
||||||
// safety check, if there are no filters on deletion bad things happen
|
// safety check, if there are no filters on deletion bad things happen
|
||||||
if (Object.keys(filters).length !== 0) {
|
if (Object.keys(filters).length !== 0) {
|
||||||
const op = isMany
|
const op = isMany ? Operation.DELETE : Operation.UPDATE
|
||||||
? DataSourceOperation.DELETE
|
|
||||||
: DataSourceOperation.UPDATE
|
|
||||||
const body = isMany ? null : { [colName]: null }
|
const body = isMany ? null : { [colName]: null }
|
||||||
promises.push(
|
promises.push(
|
||||||
getDatasourceAndQuery({
|
getDatasourceAndQuery({
|
||||||
|
@ -696,7 +678,7 @@ module External {
|
||||||
const processed = this.inputProcessing(row, table)
|
const processed = this.inputProcessing(row, table)
|
||||||
row = processed.row
|
row = processed.row
|
||||||
if (
|
if (
|
||||||
operation === DataSourceOperation.DELETE &&
|
operation === Operation.DELETE &&
|
||||||
(filters == null || Object.keys(filters).length === 0)
|
(filters == null || Object.keys(filters).length === 0)
|
||||||
) {
|
) {
|
||||||
throw "Deletion must be filtered"
|
throw "Deletion must be filtered"
|
||||||
|
@ -727,10 +709,7 @@ module External {
|
||||||
// can't really use response right now
|
// can't really use response right now
|
||||||
const response = await getDatasourceAndQuery(json)
|
const response = await getDatasourceAndQuery(json)
|
||||||
// handle many to many relationships now if we know the ID (could be auto increment)
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
||||||
if (
|
if (operation !== Operation.READ && processed.manyRelationships) {
|
||||||
operation !== DataSourceOperation.READ &&
|
|
||||||
processed.manyRelationships
|
|
||||||
) {
|
|
||||||
await this.handleManyRelationships(
|
await this.handleManyRelationships(
|
||||||
table._id || "",
|
table._id || "",
|
||||||
response[0],
|
response[0],
|
||||||
|
@ -739,11 +718,8 @@ module External {
|
||||||
}
|
}
|
||||||
const output = this.outputProcessing(response, table, relationships)
|
const output = this.outputProcessing(response, table, relationships)
|
||||||
// if reading it'll just be an array of rows, return whole thing
|
// if reading it'll just be an array of rows, return whole thing
|
||||||
return operation === DataSourceOperation.READ && Array.isArray(response)
|
return operation === Operation.READ && Array.isArray(response)
|
||||||
? output
|
? output
|
||||||
: { row: output[0], table }
|
: { row: output[0], table }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ExternalRequest
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,104 +1,117 @@
|
||||||
const {
|
import {
|
||||||
DataSourceOperation,
|
|
||||||
SortDirection,
|
SortDirection,
|
||||||
FieldTypes,
|
FieldTypes,
|
||||||
NoEmptyFilterStrings,
|
NoEmptyFilterStrings,
|
||||||
} = require("../../../constants")
|
} from "../../../constants"
|
||||||
const {
|
import {
|
||||||
breakExternalTableId,
|
breakExternalTableId,
|
||||||
breakRowIdField,
|
breakRowIdField,
|
||||||
} = require("../../../integrations/utils")
|
} from "../../../integrations/utils"
|
||||||
const ExternalRequest = require("./ExternalRequest")
|
import { ExternalRequest, RunConfig } from "./ExternalRequest"
|
||||||
const { context } = require("@budibase/backend-core")
|
import { context } from "@budibase/backend-core"
|
||||||
const exporters = require("../view/exporters")
|
import * as exporters from "../view/exporters"
|
||||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
import { apiFileReturn } from "../../../utilities/fileSystem"
|
||||||
|
import {
|
||||||
|
Operation,
|
||||||
|
BBContext,
|
||||||
|
Row,
|
||||||
|
PaginationJson,
|
||||||
|
Table,
|
||||||
|
Datasource,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
async function handleRequest(operation, tableId, opts = {}) {
|
export async function handleRequest(
|
||||||
|
operation: Operation,
|
||||||
|
tableId: string,
|
||||||
|
opts?: RunConfig
|
||||||
|
) {
|
||||||
// make sure the filters are cleaned up, no empty strings for equals, fuzzy or string
|
// make sure the filters are cleaned up, no empty strings for equals, fuzzy or string
|
||||||
if (opts && opts.filters) {
|
if (opts && opts.filters) {
|
||||||
for (let filterField of NoEmptyFilterStrings) {
|
for (let filterField of NoEmptyFilterStrings) {
|
||||||
if (!opts.filters[filterField]) {
|
if (!opts.filters[filterField]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
for (let [key, value] of Object.entries(opts.filters[filterField])) {
|
for (let [key, value] of Object.entries(opts.filters[filterField])) {
|
||||||
if (!value || value === "") {
|
if (!value || value === "") {
|
||||||
|
// @ts-ignore
|
||||||
delete opts.filters[filterField][key]
|
delete opts.filters[filterField][key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ExternalRequest(operation, tableId, opts.datasource).run(opts)
|
return new ExternalRequest(operation, tableId, opts?.datasource).run(
|
||||||
|
opts || {}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.handleRequest = handleRequest
|
export async function patch(ctx: BBContext) {
|
||||||
|
|
||||||
exports.patch = async ctx => {
|
|
||||||
const inputs = ctx.request.body
|
const inputs = ctx.request.body
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
const id = inputs._id
|
const id = inputs._id
|
||||||
// don't save the ID to db
|
// don't save the ID to db
|
||||||
delete inputs._id
|
delete inputs._id
|
||||||
return handleRequest(DataSourceOperation.UPDATE, tableId, {
|
return handleRequest(Operation.UPDATE, tableId, {
|
||||||
id: breakRowIdField(id),
|
id: breakRowIdField(id),
|
||||||
row: inputs,
|
row: inputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async ctx => {
|
export async function save(ctx: BBContext) {
|
||||||
const inputs = ctx.request.body
|
const inputs = ctx.request.body
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
return handleRequest(DataSourceOperation.CREATE, tableId, {
|
return handleRequest(Operation.CREATE, tableId, {
|
||||||
row: inputs,
|
row: inputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchView = async ctx => {
|
export async function fetchView(ctx: BBContext) {
|
||||||
// there are no views in external datasources, shouldn't ever be called
|
// there are no views in external datasources, shouldn't ever be called
|
||||||
// for now just fetch
|
// for now just fetch
|
||||||
const split = ctx.params.viewName.split("all_")
|
const split = ctx.params.viewName.split("all_")
|
||||||
ctx.params.tableId = split[1] ? split[1] : split[0]
|
ctx.params.tableId = split[1] ? split[1] : split[0]
|
||||||
return exports.fetch(ctx)
|
return fetch(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
export async function fetch(ctx: BBContext) {
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
return handleRequest(DataSourceOperation.READ, tableId)
|
return handleRequest(Operation.READ, tableId)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async ctx => {
|
export async function find(ctx: BBContext) {
|
||||||
const id = ctx.params.rowId
|
const id = ctx.params.rowId
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
const response = await handleRequest(DataSourceOperation.READ, tableId, {
|
const response = (await handleRequest(Operation.READ, tableId, {
|
||||||
id: breakRowIdField(id),
|
id: breakRowIdField(id),
|
||||||
})
|
})) as Row[]
|
||||||
return response ? response[0] : response
|
return response ? response[0] : response
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async ctx => {
|
export async function destroy(ctx: BBContext) {
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
const id = ctx.request.body._id
|
const id = ctx.request.body._id
|
||||||
const { row } = await handleRequest(DataSourceOperation.DELETE, tableId, {
|
const { row } = (await handleRequest(Operation.DELETE, tableId, {
|
||||||
id: breakRowIdField(id),
|
id: breakRowIdField(id),
|
||||||
})
|
})) as { row: Row }
|
||||||
return { response: { ok: true }, row }
|
return { response: { ok: true }, row }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.bulkDestroy = async ctx => {
|
export async function bulkDestroy(ctx: BBContext) {
|
||||||
const { rows } = ctx.request.body
|
const { rows } = ctx.request.body
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
let promises = []
|
let promises = []
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
promises.push(
|
promises.push(
|
||||||
handleRequest(DataSourceOperation.DELETE, tableId, {
|
handleRequest(Operation.DELETE, tableId, {
|
||||||
id: breakRowIdField(row._id),
|
id: breakRowIdField(row._id),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const responses = await Promise.all(promises)
|
const responses = (await Promise.all(promises)) as { row: Row }[]
|
||||||
return { response: { ok: true }, rows: responses.map(resp => resp.row) }
|
return { response: { ok: true }, rows: responses.map(resp => resp.row) }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.search = async ctx => {
|
export async function search(ctx: BBContext) {
|
||||||
const tableId = ctx.params.tableId
|
const tableId = ctx.params.tableId
|
||||||
const { paginate, query, ...params } = ctx.request.body
|
const { paginate, query, ...params } = ctx.request.body
|
||||||
let { bookmark, limit } = params
|
let { bookmark, limit } = params
|
||||||
|
@ -129,26 +142,26 @@ exports.search = async ctx => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const rows = await handleRequest(DataSourceOperation.READ, tableId, {
|
const rows = (await handleRequest(Operation.READ, tableId, {
|
||||||
filters: query,
|
filters: query,
|
||||||
sort,
|
sort,
|
||||||
paginate: paginateObj,
|
paginate: paginateObj as PaginationJson,
|
||||||
})
|
})) as Row[]
|
||||||
let hasNextPage = false
|
let hasNextPage = false
|
||||||
if (paginate && rows.length === limit) {
|
if (paginate && rows.length === limit) {
|
||||||
const nextRows = await handleRequest(DataSourceOperation.READ, tableId, {
|
const nextRows = (await handleRequest(Operation.READ, tableId, {
|
||||||
filters: query,
|
filters: query,
|
||||||
sort,
|
sort,
|
||||||
paginate: {
|
paginate: {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
page: bookmark * limit + 1,
|
page: bookmark * limit + 1,
|
||||||
},
|
},
|
||||||
})
|
})) as Row[]
|
||||||
hasNextPage = nextRows.length > 0
|
hasNextPage = nextRows.length > 0
|
||||||
}
|
}
|
||||||
// need wrapper object for bookmarks etc when paginating
|
// need wrapper object for bookmarks etc when paginating
|
||||||
return { rows, hasNextPage, bookmark: bookmark + 1 }
|
return { rows, hasNextPage, bookmark: bookmark + 1 }
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.message && err.message.includes("does not exist")) {
|
if (err.message && err.message.includes("does not exist")) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Table updated externally, please re-fetch - ${err.message}`
|
`Table updated externally, please re-fetch - ${err.message}`
|
||||||
|
@ -159,12 +172,12 @@ exports.search = async ctx => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.validate = async () => {
|
export async function validate(ctx: BBContext) {
|
||||||
// can't validate external right now - maybe in future
|
// can't validate external right now - maybe in future
|
||||||
return { valid: true }
|
return { valid: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.exportRows = async ctx => {
|
export async function exportRows(ctx: BBContext) {
|
||||||
const { datasourceId } = breakExternalTableId(ctx.params.tableId)
|
const { datasourceId } = breakExternalTableId(ctx.params.tableId)
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const format = ctx.query.format
|
const format = ctx.query.format
|
||||||
|
@ -176,13 +189,15 @@ exports.exportRows = async ctx => {
|
||||||
ctx.request.body = {
|
ctx.request.body = {
|
||||||
query: {
|
query: {
|
||||||
oneOf: {
|
oneOf: {
|
||||||
_id: ctx.request.body.rows.map(row => JSON.parse(decodeURI(row))[0]),
|
_id: ctx.request.body.rows.map(
|
||||||
|
(row: string) => JSON.parse(decodeURI(row))[0]
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = await exports.search(ctx)
|
let result = await search(ctx)
|
||||||
let rows = []
|
let rows: Row[] = []
|
||||||
|
|
||||||
// Filter data to only specified columns if required
|
// Filter data to only specified columns if required
|
||||||
if (columns && columns.length) {
|
if (columns && columns.length) {
|
||||||
|
@ -197,6 +212,7 @@ exports.exportRows = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let headers = Object.keys(rows[0])
|
let headers = Object.keys(rows[0])
|
||||||
|
// @ts-ignore
|
||||||
const exporter = exporters[format]
|
const exporter = exporters[format]
|
||||||
const filename = `export.${format}`
|
const filename = `export.${format}`
|
||||||
|
|
||||||
|
@ -205,21 +221,24 @@ exports.exportRows = async ctx => {
|
||||||
return apiFileReturn(exporter(headers, rows))
|
return apiFileReturn(exporter(headers, rows))
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchEnrichedRow = async ctx => {
|
export async function fetchEnrichedRow(ctx: BBContext) {
|
||||||
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 db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const datasource = await db.get(datasourceId)
|
const datasource: Datasource = await db.get(datasourceId)
|
||||||
|
if (!tableName) {
|
||||||
|
ctx.throw(400, "Unable to find table.")
|
||||||
|
}
|
||||||
if (!datasource || !datasource.entities) {
|
if (!datasource || !datasource.entities) {
|
||||||
ctx.throw(400, "Datasource has not been configured for plus API.")
|
ctx.throw(400, "Datasource has not been configured for plus API.")
|
||||||
}
|
}
|
||||||
const tables = datasource.entities
|
const tables = datasource.entities
|
||||||
const response = await handleRequest(DataSourceOperation.READ, tableId, {
|
const response = (await handleRequest(Operation.READ, tableId, {
|
||||||
id,
|
id,
|
||||||
datasource,
|
datasource,
|
||||||
})
|
})) as Row[]
|
||||||
const table = tables[tableName]
|
const table: Table = tables[tableName]
|
||||||
const row = response[0]
|
const row = response[0]
|
||||||
// this seems like a lot of work, but basically we need to dig deeper for the enrich
|
// this seems like a lot of work, but basically we need to dig deeper for the enrich
|
||||||
// for a single row, there is probably a better way to do this with some smart multi-layer joins
|
// for a single row, there is probably a better way to do this with some smart multi-layer joins
|
||||||
|
@ -233,21 +252,19 @@ exports.fetchEnrichedRow = async ctx => {
|
||||||
}
|
}
|
||||||
const links = row[fieldName]
|
const links = row[fieldName]
|
||||||
const linkedTableId = field.tableId
|
const linkedTableId = field.tableId
|
||||||
const linkedTable = tables[breakExternalTableId(linkedTableId).tableName]
|
const linkedTableName = breakExternalTableId(linkedTableId).tableName!
|
||||||
|
const linkedTable = tables[linkedTableName]
|
||||||
// don't support composite keys right now
|
// don't support composite keys right now
|
||||||
const linkedIds = links.map(link => breakRowIdField(link._id)[0])
|
const linkedIds = links.map((link: Row) => breakRowIdField(link._id!)[0])
|
||||||
row[fieldName] = await handleRequest(
|
const primaryLink = linkedTable.primary?.[0] as string
|
||||||
DataSourceOperation.READ,
|
row[fieldName] = await handleRequest(Operation.READ, linkedTableId!, {
|
||||||
linkedTableId,
|
|
||||||
{
|
|
||||||
tables,
|
tables,
|
||||||
filters: {
|
filters: {
|
||||||
oneOf: {
|
oneOf: {
|
||||||
[linkedTable.primary]: linkedIds,
|
[primaryLink]: linkedIds,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return row
|
return row
|
||||||
}
|
}
|
|
@ -191,7 +191,7 @@ export async function fetchView(ctx: BBContext) {
|
||||||
// if this is a table view being looked for just transfer to that
|
// if this is a table view being looked for just transfer to that
|
||||||
if (viewName.startsWith(DocumentType.TABLE)) {
|
if (viewName.startsWith(DocumentType.TABLE)) {
|
||||||
ctx.params.tableId = viewName
|
ctx.params.tableId = viewName
|
||||||
return exports.fetch(ctx)
|
return fetch(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
@ -347,7 +347,7 @@ export async function bulkDestroy(ctx: BBContext) {
|
||||||
export async function search(ctx: BBContext) {
|
export async function search(ctx: BBContext) {
|
||||||
// Fetch the whole table when running in cypress, as search doesn't work
|
// Fetch the whole table when running in cypress, as search doesn't work
|
||||||
if (!env.COUCH_DB_URL && env.isCypress()) {
|
if (!env.COUCH_DB_URL && env.isCypress()) {
|
||||||
return { rows: await exports.fetch(ctx) }
|
return { rows: await fetch(ctx) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tableId } = ctx.params
|
const { tableId } = ctx.params
|
||||||
|
|
|
@ -8,11 +8,7 @@ import {
|
||||||
foreignKeyStructure,
|
foreignKeyStructure,
|
||||||
hasTypeChanged,
|
hasTypeChanged,
|
||||||
} from "./utils"
|
} from "./utils"
|
||||||
import {
|
import { FieldTypes, RelationshipTypes } from "../../../constants"
|
||||||
DataSourceOperation,
|
|
||||||
FieldTypes,
|
|
||||||
RelationshipTypes,
|
|
||||||
} from "../../../constants"
|
|
||||||
import { makeExternalQuery } from "../../../integrations/base/query"
|
import { makeExternalQuery } from "../../../integrations/base/query"
|
||||||
import * as csvParser from "../../../utilities/csvParser"
|
import * as csvParser from "../../../utilities/csvParser"
|
||||||
import { handleRequest } from "../row/external"
|
import { handleRequest } from "../row/external"
|
||||||
|
@ -347,7 +343,7 @@ export async function bulkImport(ctx: BBContext) {
|
||||||
...dataImport,
|
...dataImport,
|
||||||
existingTable: table,
|
existingTable: table,
|
||||||
})
|
})
|
||||||
await handleRequest(DataSourceOperation.BULK_CREATE, table._id, {
|
await handleRequest(Operation.BULK_CREATE, table._id!, {
|
||||||
rows,
|
rows,
|
||||||
})
|
})
|
||||||
await events.rows.imported(table, "csv", rows.length)
|
await events.rows.imported(table, "csv", rows.length)
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"lib": ["es2020"],
|
"lib": ["es2020"],
|
||||||
"allowJs": true,
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|
Loading…
Reference in New Issue