Query API typing.
This commit is contained in:
parent
3446b1c678
commit
23d9808cb6
|
@ -4,26 +4,38 @@ import { save as saveDatasource } from "../datasource"
|
||||||
import { RestImporter } from "./import"
|
import { RestImporter } from "./import"
|
||||||
import { invalidateCachedVariable } from "../../../threads/utils"
|
import { invalidateCachedVariable } from "../../../threads/utils"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { events, context, utils, constants } from "@budibase/backend-core"
|
import { constants, context, events, utils } from "@budibase/backend-core"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
import { QueryEvent, QueryEventParameters } from "../../../threads/definitions"
|
import { QueryEvent, QueryEventParameters } from "../../../threads/definitions"
|
||||||
import {
|
import {
|
||||||
ConfigType,
|
ConfigType,
|
||||||
Query,
|
CreateDatasourceRequest,
|
||||||
UserCtx,
|
Datasource,
|
||||||
SessionCookie,
|
|
||||||
JsonFieldSubType,
|
|
||||||
QueryResponse,
|
|
||||||
QuerySchema,
|
|
||||||
FieldType,
|
|
||||||
ExecuteQueryRequest,
|
ExecuteQueryRequest,
|
||||||
ExecuteQueryResponse,
|
ExecuteV2QueryResponse,
|
||||||
|
ExecuteV1QueryResponse,
|
||||||
|
FetchQueriesResponse,
|
||||||
|
FieldType,
|
||||||
|
FindQueryResponse,
|
||||||
|
ImportRestQueryRequest,
|
||||||
|
ImportRestQueryResponse,
|
||||||
|
JsonFieldSubType,
|
||||||
PreviewQueryRequest,
|
PreviewQueryRequest,
|
||||||
PreviewQueryResponse,
|
PreviewQueryResponse,
|
||||||
|
Query,
|
||||||
|
QueryResponse,
|
||||||
|
QuerySchema,
|
||||||
|
SaveQueryRequest,
|
||||||
|
SaveQueryResponse,
|
||||||
|
SessionCookie,
|
||||||
|
SourceName,
|
||||||
|
UserCtx,
|
||||||
|
DeleteQueryResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { ValidQueryNameRegex, utils as JsonUtils } from "@budibase/shared-core"
|
import { utils as JsonUtils, ValidQueryNameRegex } from "@budibase/shared-core"
|
||||||
import { findHBSBlocks } from "@budibase/string-templates"
|
import { findHBSBlocks } from "@budibase/string-templates"
|
||||||
import { ObjectId } from "mongodb"
|
import { ObjectId } from "mongodb"
|
||||||
|
import { merge } from "lodash"
|
||||||
|
|
||||||
const Runner = new Thread(ThreadType.QUERY, {
|
const Runner = new Thread(ThreadType.QUERY, {
|
||||||
timeoutMs: env.QUERY_THREAD_TIMEOUT,
|
timeoutMs: env.QUERY_THREAD_TIMEOUT,
|
||||||
|
@ -43,11 +55,13 @@ function validateQueryInputs(parameters: QueryEventParameters) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetch(ctx: UserCtx) {
|
export async function fetch(ctx: UserCtx<void, FetchQueriesResponse>) {
|
||||||
ctx.body = await sdk.queries.fetch()
|
ctx.body = await sdk.queries.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
const _import = async (ctx: UserCtx) => {
|
const _import = async (
|
||||||
|
ctx: UserCtx<ImportRestQueryRequest, ImportRestQueryResponse>
|
||||||
|
) => {
|
||||||
const body = ctx.request.body
|
const body = ctx.request.body
|
||||||
const data = body.data
|
const data = body.data
|
||||||
|
|
||||||
|
@ -58,9 +72,9 @@ const _import = async (ctx: UserCtx) => {
|
||||||
if (!body.datasourceId) {
|
if (!body.datasourceId) {
|
||||||
// construct new datasource
|
// construct new datasource
|
||||||
const info: any = await importer.getInfo()
|
const info: any = await importer.getInfo()
|
||||||
let datasource = {
|
let datasource: Datasource = {
|
||||||
type: "datasource",
|
type: "datasource",
|
||||||
source: "REST",
|
source: SourceName.REST,
|
||||||
config: {
|
config: {
|
||||||
url: info.url,
|
url: info.url,
|
||||||
defaultHeaders: [],
|
defaultHeaders: [],
|
||||||
|
@ -69,8 +83,14 @@ const _import = async (ctx: UserCtx) => {
|
||||||
name: info.name,
|
name: info.name,
|
||||||
}
|
}
|
||||||
// save the datasource
|
// save the datasource
|
||||||
const datasourceCtx = { ...ctx }
|
const datasourceCtx: UserCtx<CreateDatasourceRequest> = merge(ctx, {
|
||||||
datasourceCtx.request.body.datasource = datasource
|
request: {
|
||||||
|
body: {
|
||||||
|
datasource,
|
||||||
|
tablesFilter: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
await saveDatasource(datasourceCtx)
|
await saveDatasource(datasourceCtx)
|
||||||
datasourceId = datasourceCtx.body.datasource._id
|
datasourceId = datasourceCtx.body.datasource._id
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,7 +108,7 @@ const _import = async (ctx: UserCtx) => {
|
||||||
}
|
}
|
||||||
export { _import as import }
|
export { _import as import }
|
||||||
|
|
||||||
export async function save(ctx: UserCtx<Query, Query>) {
|
export async function save(ctx: UserCtx<SaveQueryRequest, SaveQueryResponse>) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const query: Query = ctx.request.body
|
const query: Query = ctx.request.body
|
||||||
|
|
||||||
|
@ -119,10 +139,9 @@ export async function save(ctx: UserCtx<Query, Query>) {
|
||||||
query._rev = response.rev
|
query._rev = response.rev
|
||||||
|
|
||||||
ctx.body = query
|
ctx.body = query
|
||||||
ctx.message = `Query ${query.name} saved successfully.`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function find(ctx: UserCtx) {
|
export async function find(ctx: UserCtx<void, FindQueryResponse>) {
|
||||||
const queryId = ctx.params.queryId
|
const queryId = ctx.params.queryId
|
||||||
ctx.body = await sdk.queries.find(queryId)
|
ctx.body = await sdk.queries.find(queryId)
|
||||||
}
|
}
|
||||||
|
@ -335,7 +354,7 @@ export async function preview(
|
||||||
async function execute(
|
async function execute(
|
||||||
ctx: UserCtx<
|
ctx: UserCtx<
|
||||||
ExecuteQueryRequest,
|
ExecuteQueryRequest,
|
||||||
ExecuteQueryResponse | Record<string, any>[]
|
ExecuteV2QueryResponse | ExecuteV1QueryResponse
|
||||||
>,
|
>,
|
||||||
opts: any = { rowsOnly: false, isAutomation: false }
|
opts: any = { rowsOnly: false, isAutomation: false }
|
||||||
) {
|
) {
|
||||||
|
@ -390,19 +409,21 @@ async function execute(
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeV1(
|
export async function executeV1(
|
||||||
ctx: UserCtx<ExecuteQueryRequest, Record<string, any>[]>
|
ctx: UserCtx<ExecuteQueryRequest, ExecuteV1QueryResponse>
|
||||||
) {
|
) {
|
||||||
return execute(ctx, { rowsOnly: true, isAutomation: false })
|
return execute(ctx, { rowsOnly: true, isAutomation: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeV2(
|
export async function executeV2(
|
||||||
ctx: UserCtx<
|
ctx: UserCtx<ExecuteQueryRequest, ExecuteV2QueryResponse>
|
||||||
ExecuteQueryRequest,
|
|
||||||
ExecuteQueryResponse | Record<string, any>[]
|
|
||||||
>,
|
|
||||||
{ isAutomation }: { isAutomation?: boolean } = {}
|
|
||||||
) {
|
) {
|
||||||
return execute(ctx, { rowsOnly: false, isAutomation })
|
return execute(ctx, { rowsOnly: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function executeV2AsAutomation(
|
||||||
|
ctx: UserCtx<ExecuteQueryRequest, ExecuteV2QueryResponse>
|
||||||
|
) {
|
||||||
|
return execute(ctx, { rowsOnly: false, isAutomation: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeDynamicVariables = async (queryId: string) => {
|
const removeDynamicVariables = async (queryId: string) => {
|
||||||
|
@ -426,14 +447,14 @@ const removeDynamicVariables = async (queryId: string) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function destroy(ctx: UserCtx) {
|
export async function destroy(ctx: UserCtx<void, DeleteQueryResponse>) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const queryId = ctx.params.queryId as string
|
const queryId = ctx.params.queryId as string
|
||||||
await removeDynamicVariables(queryId)
|
await removeDynamicVariables(queryId)
|
||||||
const query = await db.get<Query>(queryId)
|
const query = await db.get<Query>(queryId)
|
||||||
const datasource = await sdk.datasources.get(query.datasourceId)
|
const datasource = await sdk.datasources.get(query.datasourceId)
|
||||||
await db.remove(ctx.params.queryId, ctx.params.revId)
|
await db.remove(ctx.params.queryId, ctx.params.revId)
|
||||||
ctx.message = `Query deleted.`
|
ctx.body = { message: `Query deleted.` }
|
||||||
ctx.status = 200
|
ctx.status = 200
|
||||||
await events.query.deleted(datasource, query)
|
await events.query.deleted(datasource, query)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ router
|
||||||
"/api/v2/queries/:queryId",
|
"/api/v2/queries/:queryId",
|
||||||
paramResource("queryId"),
|
paramResource("queryId"),
|
||||||
authorized(PermissionType.QUERY, PermissionLevel.WRITE),
|
authorized(PermissionType.QUERY, PermissionLevel.WRITE),
|
||||||
queryController.executeV2 as any
|
queryController.executeV2
|
||||||
)
|
)
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
ExecuteQueryStepInputs,
|
ExecuteQueryStepInputs,
|
||||||
ExecuteQueryStepOutputs,
|
ExecuteQueryStepOutputs,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
import { executeV2AsAutomation } from "../../api/controllers/query"
|
||||||
|
|
||||||
export const definition: AutomationStepDefinition = {
|
export const definition: AutomationStepDefinition = {
|
||||||
name: "External Data Connector",
|
name: "External Data Connector",
|
||||||
|
@ -94,7 +95,7 @@ export async function run({
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await queryController.executeV2(ctx, { isAutomation: true })
|
await queryController.executeV2AsAutomation(ctx)
|
||||||
const { data, ...rest } = ctx.body
|
const { data, ...rest } = ctx.body
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {
|
import {
|
||||||
Query,
|
Query,
|
||||||
ExecuteQueryRequest,
|
ExecuteQueryRequest,
|
||||||
ExecuteQueryResponse,
|
ExecuteV2QueryResponse,
|
||||||
PreviewQueryRequest,
|
PreviewQueryRequest,
|
||||||
PreviewQueryResponse,
|
PreviewQueryResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
@ -17,8 +17,8 @@ export class QueryAPI extends TestAPI {
|
||||||
queryId: string,
|
queryId: string,
|
||||||
body?: ExecuteQueryRequest,
|
body?: ExecuteQueryRequest,
|
||||||
expectations?: Expectations
|
expectations?: Expectations
|
||||||
): Promise<ExecuteQueryResponse> => {
|
): Promise<ExecuteV2QueryResponse> => {
|
||||||
return await this._post<ExecuteQueryResponse>(
|
return await this._post<ExecuteV2QueryResponse>(
|
||||||
`/api/v2/queries/${queryId}`,
|
`/api/v2/queries/${queryId}`,
|
||||||
{
|
{
|
||||||
body,
|
body,
|
||||||
|
|
|
@ -12,3 +12,4 @@ export * from "./automation"
|
||||||
export * from "./component"
|
export * from "./component"
|
||||||
export * from "./integration"
|
export * from "./integration"
|
||||||
export * from "./metadata"
|
export * from "./metadata"
|
||||||
|
export * from "./query"
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import {
|
||||||
|
Datasource,
|
||||||
|
Query,
|
||||||
|
QueryPreview,
|
||||||
|
QuerySchema,
|
||||||
|
} from "../../../documents"
|
||||||
|
|
||||||
|
export type FetchQueriesResponse = Query[]
|
||||||
|
|
||||||
|
export interface SaveQueryRequest extends Query {}
|
||||||
|
export interface SaveQueryResponse extends Query {}
|
||||||
|
|
||||||
|
export interface ImportRestQueryRequest {
|
||||||
|
datasourceId: string
|
||||||
|
data: string
|
||||||
|
datasource: Datasource
|
||||||
|
}
|
||||||
|
export interface ImportRestQueryResponse {
|
||||||
|
errorQueries: Query[]
|
||||||
|
queries: Query[]
|
||||||
|
datasourceId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FindQueryResponse extends Query {}
|
||||||
|
|
||||||
|
export interface PreviewQueryRequest extends QueryPreview {}
|
||||||
|
|
||||||
|
export interface PreviewQueryResponse {
|
||||||
|
rows: any[]
|
||||||
|
nestedSchemaFields: { [key: string]: { [key: string]: string | QuerySchema } }
|
||||||
|
schema: { [key: string]: string | QuerySchema }
|
||||||
|
info: any
|
||||||
|
extra: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteQueryRequest {
|
||||||
|
parameters?: Record<string, string>
|
||||||
|
pagination?: any
|
||||||
|
}
|
||||||
|
export type ExecuteV1QueryResponse = Record<string, any>[]
|
||||||
|
export interface ExecuteV2QueryResponse {
|
||||||
|
data: Record<string, any>[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeleteQueryResponse {
|
||||||
|
message: string
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ export * from "./searchFilter"
|
||||||
export * from "./cookies"
|
export * from "./cookies"
|
||||||
export * from "./automation"
|
export * from "./automation"
|
||||||
export * from "./layout"
|
export * from "./layout"
|
||||||
export * from "./query"
|
|
||||||
export * from "./role"
|
export * from "./role"
|
||||||
export * from "./plugins"
|
export * from "./plugins"
|
||||||
export * from "./apikeys"
|
export * from "./apikeys"
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
import { QueryPreview, QuerySchema } from "../../documents"
|
|
||||||
|
|
||||||
export interface PreviewQueryRequest extends QueryPreview {}
|
|
||||||
|
|
||||||
export interface PreviewQueryResponse {
|
|
||||||
rows: any[]
|
|
||||||
nestedSchemaFields: { [key: string]: { [key: string]: string | QuerySchema } }
|
|
||||||
schema: { [key: string]: string | QuerySchema }
|
|
||||||
info: any
|
|
||||||
extra: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecuteQueryRequest {
|
|
||||||
parameters?: Record<string, string>
|
|
||||||
pagination?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecuteQueryResponse {
|
|
||||||
data: Record<string, any>[]
|
|
||||||
}
|
|
Loading…
Reference in New Issue