204 lines
5.1 KiB
TypeScript
204 lines
5.1 KiB
TypeScript
import { quotas } from "@budibase/pro"
|
|
import * as internal from "./internal"
|
|
import * as external from "./external"
|
|
import { isExternalTable } from "../../../integrations/utils"
|
|
import { Ctx } from "@budibase/types"
|
|
import * as utils from "./utils"
|
|
import { gridSocket } from "../../../websockets"
|
|
import sdk from "../../../sdk"
|
|
import * as exporters from "../view/exporters"
|
|
import { apiFileReturn } from "../../../utilities/fileSystem"
|
|
|
|
function pickApi(tableId: any) {
|
|
if (isExternalTable(tableId)) {
|
|
return external
|
|
}
|
|
return internal
|
|
}
|
|
|
|
export async function patch(ctx: any): Promise<any> {
|
|
const appId = ctx.appId
|
|
const tableId = utils.getTableId(ctx)
|
|
const body = ctx.request.body
|
|
// if it doesn't have an _id then its save
|
|
if (body && !body._id) {
|
|
return save(ctx)
|
|
}
|
|
try {
|
|
const { row, table } = await quotas.addQuery(
|
|
() => pickApi(tableId).patch(ctx),
|
|
{
|
|
datasourceId: tableId,
|
|
}
|
|
)
|
|
if (!row) {
|
|
ctx.throw(404, "Row not found")
|
|
}
|
|
ctx.status = 200
|
|
ctx.eventEmitter &&
|
|
ctx.eventEmitter.emitRow(`row:update`, appId, row, table)
|
|
ctx.message = `${table.name} updated successfully.`
|
|
ctx.body = row
|
|
gridSocket?.emitRowUpdate(ctx, row)
|
|
} catch (err) {
|
|
ctx.throw(400, err)
|
|
}
|
|
}
|
|
|
|
export const save = async (ctx: any) => {
|
|
const appId = ctx.appId
|
|
const tableId = utils.getTableId(ctx)
|
|
const body = ctx.request.body
|
|
// if it has an ID already then its a patch
|
|
if (body && body._id) {
|
|
return patch(ctx)
|
|
}
|
|
const { row, table, squashed } = await quotas.addRow(() =>
|
|
quotas.addQuery(() => pickApi(tableId).save(ctx), {
|
|
datasourceId: tableId,
|
|
})
|
|
)
|
|
ctx.status = 200
|
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:save`, appId, row, table)
|
|
ctx.message = `${table.name} saved successfully`
|
|
// prefer squashed for response
|
|
ctx.body = row || squashed
|
|
gridSocket?.emitRowUpdate(ctx, row || squashed)
|
|
}
|
|
export async function fetchView(ctx: any) {
|
|
const tableId = utils.getTableId(ctx)
|
|
const viewName = decodeURIComponent(ctx.params.viewName)
|
|
|
|
const { calculation, group, field } = ctx.query
|
|
|
|
ctx.body = await quotas.addQuery(
|
|
() =>
|
|
sdk.rows.fetchView(tableId, viewName, {
|
|
calculation,
|
|
group,
|
|
field,
|
|
}),
|
|
{
|
|
datasourceId: tableId,
|
|
}
|
|
)
|
|
}
|
|
|
|
export async function fetch(ctx: any) {
|
|
const tableId = utils.getTableId(ctx)
|
|
ctx.body = await quotas.addQuery(() => sdk.rows.fetch(tableId), {
|
|
datasourceId: tableId,
|
|
})
|
|
}
|
|
|
|
export async function find(ctx: any) {
|
|
const tableId = utils.getTableId(ctx)
|
|
ctx.body = await quotas.addQuery(() => pickApi(tableId).find(ctx), {
|
|
datasourceId: tableId,
|
|
})
|
|
}
|
|
|
|
export async function destroy(ctx: any) {
|
|
const appId = ctx.appId
|
|
const inputs = ctx.request.body
|
|
const tableId = utils.getTableId(ctx)
|
|
let response, row
|
|
if (inputs.rows) {
|
|
let { rows } = await quotas.addQuery(
|
|
() => pickApi(tableId).bulkDestroy(ctx),
|
|
{
|
|
datasourceId: tableId,
|
|
}
|
|
)
|
|
await quotas.removeRows(rows.length)
|
|
response = rows
|
|
for (let row of rows) {
|
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
|
gridSocket?.emitRowDeletion(ctx, row._id)
|
|
}
|
|
} else {
|
|
let resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), {
|
|
datasourceId: tableId,
|
|
})
|
|
await quotas.removeRow()
|
|
response = resp.response
|
|
row = resp.row
|
|
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, row)
|
|
gridSocket?.emitRowDeletion(ctx, row._id)
|
|
}
|
|
ctx.status = 200
|
|
// for automations include the row that was deleted
|
|
ctx.row = row || {}
|
|
ctx.body = response
|
|
}
|
|
|
|
export async function search(ctx: any) {
|
|
const tableId = utils.getTableId(ctx)
|
|
|
|
const searchParams = {
|
|
...ctx.request.body,
|
|
tableId,
|
|
}
|
|
|
|
ctx.status = 200
|
|
ctx.body = await quotas.addQuery(() => sdk.rows.search(searchParams), {
|
|
datasourceId: tableId,
|
|
})
|
|
}
|
|
|
|
export async function validate(ctx: Ctx) {
|
|
const tableId = utils.getTableId(ctx)
|
|
// external tables are hard to validate currently
|
|
if (isExternalTable(tableId)) {
|
|
ctx.body = { valid: true }
|
|
} else {
|
|
ctx.body = await utils.validate({
|
|
row: ctx.request.body,
|
|
tableId,
|
|
})
|
|
}
|
|
}
|
|
|
|
export async function fetchEnrichedRow(ctx: any) {
|
|
const tableId = utils.getTableId(ctx)
|
|
ctx.body = await quotas.addQuery(
|
|
() => pickApi(tableId).fetchEnrichedRow(ctx),
|
|
{
|
|
datasourceId: tableId,
|
|
}
|
|
)
|
|
}
|
|
|
|
export const exportRows = async (ctx: any) => {
|
|
const tableId = utils.getTableId(ctx)
|
|
|
|
const format = ctx.query.format
|
|
|
|
const { rows, columns, query } = ctx.request.body
|
|
if (typeof format !== "string" || !exporters.isFormat(format)) {
|
|
ctx.throw(
|
|
400,
|
|
`Format ${format} not valid. Valid values: ${Object.values(
|
|
exporters.Format
|
|
)}`
|
|
)
|
|
}
|
|
|
|
ctx.body = await quotas.addQuery(
|
|
async () => {
|
|
const { fileName, content } = await sdk.rows.exportRows({
|
|
tableId,
|
|
format,
|
|
rowIds: rows,
|
|
columns,
|
|
query,
|
|
})
|
|
ctx.attachment(fileName)
|
|
return apiFileReturn(content)
|
|
},
|
|
{
|
|
datasourceId: tableId,
|
|
}
|
|
)
|
|
}
|