Fixing response types of DS+ query function.

This commit is contained in:
mike12345567 2024-02-26 17:56:28 +00:00
parent 45d2e67905
commit cb19e1f24c
10 changed files with 67 additions and 25 deletions

View File

@ -332,7 +332,7 @@ export class ExternalRequest<T extends Operation> {
endpoint: getEndpoint(table._id!, Operation.READ),
filters: buildFilters(rowId, {}, table),
})
if (response.length > 0) {
if (Array.isArray(response)) {
return response[0]
} else {
throw new Error(`Cannot fetch row by ID "${rowId}"`)
@ -646,7 +646,7 @@ export class ExternalRequest<T extends Operation> {
},
})
// this is the response from knex if no rows found
const rows: Row[] = !response[0].read ? response : []
const rows: Row[] = response?.[0].read ? [] : (response as Row[])
const storeTo = isMany ? field.throughFrom || linkPrimaryKey : fieldName
related[storeTo] = { rows, isMany, tableId }
}
@ -899,15 +899,16 @@ export class ExternalRequest<T extends Operation> {
response = await getDatasourceAndQuery(json)
}
const responseRows = Array.isArray(response) ? response : []
// handle many-to-many relationships now if we know the ID (could be auto increment)
if (operation !== Operation.READ) {
await this.handleManyRelationships(
table._id || "",
response[0],
responseRows[0],
processed.manyRelationships
)
}
const output = this.outputProcessing(response, table, relationships)
const output = this.outputProcessing(responseRows, table, relationships)
// if reading it'll just be an array of rows, return whole thing
if (operation === Operation.READ) {
return (

View File

@ -1,4 +1,10 @@
import { QueryJson, SearchFilters, Table, Row } from "@budibase/types"
import {
QueryJson,
SearchFilters,
Table,
Row,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils"
import { cloneDeep } from "lodash"
@ -68,9 +74,8 @@ export default class AliasTables {
return map
}
async queryWithAliasing(json: QueryJson) {
async queryWithAliasing(json: QueryJson): DatasourcePlusQueryResponse {
json = cloneDeep(json)
const aliasField = (field: string) => this.aliasField(field)
const aliasTable = (table: Table) => ({
...table,
name: this.getAlias(table.name),
@ -78,7 +83,7 @@ export default class AliasTables {
// run through the query json to update anywhere a table may be used
if (json.resource?.fields) {
json.resource.fields = json.resource.fields.map(field =>
aliasField(field)
this.aliasField(field)
)
}
if (json.filters) {
@ -88,7 +93,7 @@ export default class AliasTables {
}
const aliasedFilters: typeof filter = {}
for (let key of Object.keys(filter)) {
aliasedFilters[aliasField(key)] = filter[key]
aliasedFilters[this.aliasField(key)] = filter[key]
}
json.filters[filterKey as keyof SearchFilters] = aliasedFilters
}
@ -120,6 +125,10 @@ export default class AliasTables {
}
json.tableAliases = invertedTableAliases
const response = await getDatasourceAndQuery(json)
if (Array.isArray(response)) {
return this.reverse(response)
} else {
return response
}
}
}

View File

@ -1,11 +1,15 @@
import { QueryJson, Datasource } from "@budibase/types"
import {
QueryJson,
Datasource,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import { getIntegration } from "../index"
import sdk from "../../sdk"
export async function makeExternalQuery(
datasource: Datasource,
json: QueryJson
) {
): DatasourcePlusQueryResponse {
datasource = await sdk.datasources.enrich(datasource)
const Integration = await getIntegration(datasource.source)
// query is the opinionated function

View File

@ -16,6 +16,7 @@ import {
Table,
TableRequest,
TableSourceType,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import { OAuth2Client } from "google-auth-library"
import {
@ -334,7 +335,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
return { tables: externalTables, errors }
}
async query(json: QueryJson) {
async query(json: QueryJson): DatasourcePlusQueryResponse {
const sheet = json.endpoint.entityId
switch (json.endpoint.operation) {
case Operation.CREATE:
@ -384,7 +385,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
}
try {
await this.connect()
return await this.client.addSheet({ title: name, headerValues: [name] })
await this.client.addSheet({ title: name, headerValues: [name] })
} catch (err) {
console.error("Error creating new table in google sheets", err)
throw err
@ -450,7 +451,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
try {
await this.connect()
const sheetToDelete = this.client.sheetsByTitle[sheet]
return await sheetToDelete.delete()
await sheetToDelete.delete()
} catch (err) {
console.error("Error deleting table in google sheets", err)
throw err

View File

@ -13,6 +13,7 @@ import {
SourceName,
Schema,
TableSourceType,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import {
getSqlQuery,
@ -493,7 +494,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus {
return response.recordset || [{ deleted: true }]
}
async query(json: QueryJson) {
async query(json: QueryJson): DatasourcePlusQueryResponse {
const schema = this.config.schema
await this.connect()
if (schema && schema !== DEFAULT_SCHEMA && json?.endpoint) {

View File

@ -12,7 +12,7 @@ import {
SourceName,
Schema,
TableSourceType,
FieldType,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import {
getSqlQuery,
@ -381,7 +381,7 @@ class MySQLIntegration extends Sql implements DatasourcePlus {
return results.length ? results : [{ deleted: true }]
}
async query(json: QueryJson) {
async query(json: QueryJson): DatasourcePlusQueryResponse {
await this.connect()
try {
const queryFn = (query: any) =>

View File

@ -12,6 +12,8 @@ import {
ConnectionInfo,
Schema,
TableSourceType,
Row,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import {
buildExternalTableId,
@ -420,7 +422,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
: [{ deleted: true }]
}
async query(json: QueryJson) {
async query(json: QueryJson): DatasourcePlusQueryResponse {
const operation = this._operation(json)
const input = this._query(json, { disableReturning: true })
if (Array.isArray(input)) {
@ -444,7 +446,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
if (deletedRows?.rows?.length) {
return deletedRows.rows
} else if (response.rows?.length) {
return response.rows
return response.rows as Row[]
} else {
// get the last row that was updated
if (
@ -455,7 +457,7 @@ class OracleIntegration extends Sql implements DatasourcePlus {
const lastRow = await this.internalQuery({
sql: `SELECT * FROM \"${json.endpoint.entityId}\" WHERE ROWID = '${response.lastRowid}'`,
})
return lastRow.rows
return lastRow.rows as Row[]
} else {
return [{ [operation.toLowerCase()]: true }]
}

View File

@ -12,6 +12,7 @@ import {
SourceName,
Schema,
TableSourceType,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import {
getSqlQuery,
@ -419,7 +420,7 @@ class PostgresIntegration extends Sql implements DatasourcePlus {
return response.rows.length ? response.rows : [{ deleted: true }]
}
async query(json: QueryJson) {
async query(json: QueryJson): DatasourcePlusQueryResponse {
const operation = this._operation(json).toLowerCase()
const input = this._query(json)
if (Array.isArray(input)) {

View File

@ -1,12 +1,21 @@
import cloneDeep from "lodash/cloneDeep"
import validateJs from "validate.js"
import { FieldType, QueryJson, Row, Table, TableSchema } from "@budibase/types"
import {
FieldType,
QueryJson,
Row,
Table,
TableSchema,
DatasourcePlusQueryResponse,
} from "@budibase/types"
import { makeExternalQuery } from "../../../integrations/base/query"
import { Format } from "../../../api/controllers/view/exporters"
import sdk from "../.."
import { isRelationshipColumn } from "../../../db/utils"
export async function getDatasourceAndQuery(json: QueryJson) {
export async function getDatasourceAndQuery(
json: QueryJson
): DatasourcePlusQueryResponse {
const datasourceId = json.endpoint.datasourceId
const datasource = await sdk.datasources.get(datasourceId)
return makeExternalQuery(datasource, json)

View File

@ -1,4 +1,5 @@
import { Table } from "../documents"
import { Table, Row } from "../documents"
import { QueryJson } from "./search"
export const PASSWORD_REPLACEMENT = "--secret-value--"
@ -180,11 +181,24 @@ export interface Schema {
errors: Record<string, string>
}
// return these when an operation occurred but we got no response
enum DSPlusOperation {
CREATE = "create",
READ = "read",
UPDATE = "update",
DELETE = "delete",
}
export type DatasourcePlusQueryResponse = Promise<
Row[] | Record<DSPlusOperation, boolean>[] | void
>
export interface DatasourcePlus extends IntegrationBase {
// if the datasource supports the use of bindings directly (to protect against SQL injection)
// this returns the format of the identifier
getBindingIdentifier(): string
getStringConcat(parts: string[]): string
query(json: QueryJson): DatasourcePlusQueryResponse
buildSchema(
datasourceId: string,
entities: Record<string, Table>