Merge branch 'master' of github.com:budibase/budibase into bigint-relationship-fix
This commit is contained in:
commit
866e9dcadd
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"version": "3.2.11",
|
"version": "3.2.12",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"concurrency": 20,
|
"concurrency": 20,
|
||||||
"command": {
|
"command": {
|
||||||
|
|
|
@ -25,11 +25,12 @@
|
||||||
"prettier": "2.8.8",
|
"prettier": "2.8.8",
|
||||||
"prettier-plugin-svelte": "^2.3.0",
|
"prettier-plugin-svelte": "^2.3.0",
|
||||||
"proper-lockfile": "^4.1.2",
|
"proper-lockfile": "^4.1.2",
|
||||||
"svelte": "^4.2.10",
|
"svelte": "4.2.19",
|
||||||
"svelte-eslint-parser": "^0.33.1",
|
"svelte-eslint-parser": "^0.33.1",
|
||||||
"typescript": "5.5.2",
|
"typescript": "5.5.2",
|
||||||
"typescript-eslint": "^7.3.1",
|
"typescript-eslint": "^7.3.1",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2",
|
||||||
|
"cross-spawn": "7.0.6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"get-past-client-version": "node scripts/getPastClientVersion.js",
|
"get-past-client-version": "node scripts/getPastClientVersion.js",
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bull": "4.10.1",
|
"bull": "4.10.1",
|
||||||
"correlation-id": "4.0.0",
|
"correlation-id": "4.0.0",
|
||||||
"dd-trace": "5.23.0",
|
"dd-trace": "5.26.0",
|
||||||
"dotenv": "16.0.1",
|
"dotenv": "16.0.1",
|
||||||
"google-auth-library": "^8.0.1",
|
"google-auth-library": "^8.0.1",
|
||||||
"google-spreadsheet": "npm:@budibase/google-spreadsheet@4.1.5",
|
"google-spreadsheet": "npm:@budibase/google-spreadsheet@4.1.5",
|
||||||
|
|
|
@ -190,7 +190,7 @@ export class DatabaseImpl implements Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async performCall<T>(call: DBCallback<T>): Promise<any> {
|
private async performCall<T>(call: DBCallback<T>): Promise<T> {
|
||||||
const db = this.getDb()
|
const db = this.getDb()
|
||||||
const fnc = await call(db)
|
const fnc = await call(db)
|
||||||
try {
|
try {
|
||||||
|
@ -467,7 +467,7 @@ export class DatabaseImpl implements Database {
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
// didn't exist, don't worry
|
// didn't exist, don't worry
|
||||||
if (err.statusCode === 404) {
|
if (err.statusCode === 404) {
|
||||||
return
|
return { ok: true }
|
||||||
} else {
|
} else {
|
||||||
throw new CouchDBError(err.message, err)
|
throw new CouchDBError(err.message, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
|
|
||||||
exists(docId?: string): Promise<boolean> {
|
exists(docId?: string): Promise<boolean> {
|
||||||
return tracer.trace("db.exists", span => {
|
return tracer.trace("db.exists", span => {
|
||||||
span?.addTags({ db_name: this.name, doc_id: docId })
|
span.addTags({ db_name: this.name, doc_id: docId })
|
||||||
if (docId) {
|
if (docId) {
|
||||||
return this.db.exists(docId)
|
return this.db.exists(docId)
|
||||||
}
|
}
|
||||||
|
@ -37,15 +37,17 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
|
|
||||||
get<T extends Document>(id?: string | undefined): Promise<T> {
|
get<T extends Document>(id?: string | undefined): Promise<T> {
|
||||||
return tracer.trace("db.get", span => {
|
return tracer.trace("db.get", span => {
|
||||||
span?.addTags({ db_name: this.name, doc_id: id })
|
span.addTags({ db_name: this.name, doc_id: id })
|
||||||
return this.db.get(id)
|
return this.db.get(id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
tryGet<T extends Document>(id?: string | undefined): Promise<T | undefined> {
|
tryGet<T extends Document>(id?: string | undefined): Promise<T | undefined> {
|
||||||
return tracer.trace("db.tryGet", span => {
|
return tracer.trace("db.tryGet", async span => {
|
||||||
span?.addTags({ db_name: this.name, doc_id: id })
|
span.addTags({ db_name: this.name, doc_id: id })
|
||||||
return this.db.tryGet(id)
|
const doc = await this.db.tryGet<T>(id)
|
||||||
|
span.addTags({ doc_found: doc !== undefined })
|
||||||
|
return doc
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +55,15 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
ids: string[],
|
ids: string[],
|
||||||
opts?: { allowMissing?: boolean | undefined } | undefined
|
opts?: { allowMissing?: boolean | undefined } | undefined
|
||||||
): Promise<T[]> {
|
): Promise<T[]> {
|
||||||
return tracer.trace("db.getMultiple", span => {
|
return tracer.trace("db.getMultiple", async span => {
|
||||||
span?.addTags({
|
span.addTags({
|
||||||
db_name: this.name,
|
db_name: this.name,
|
||||||
num_docs: ids.length,
|
num_docs: ids.length,
|
||||||
allow_missing: opts?.allowMissing,
|
allow_missing: opts?.allowMissing,
|
||||||
})
|
})
|
||||||
return this.db.getMultiple(ids, opts)
|
const docs = await this.db.getMultiple<T>(ids, opts)
|
||||||
|
span.addTags({ num_docs_found: docs.length })
|
||||||
|
return docs
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,12 +73,14 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
idOrDoc: string | Document,
|
idOrDoc: string | Document,
|
||||||
rev?: string
|
rev?: string
|
||||||
): Promise<DocumentDestroyResponse> {
|
): Promise<DocumentDestroyResponse> {
|
||||||
return tracer.trace("db.remove", span => {
|
return tracer.trace("db.remove", async span => {
|
||||||
span?.addTags({ db_name: this.name, doc_id: idOrDoc })
|
span.addTags({ db_name: this.name, doc_id: idOrDoc, rev })
|
||||||
const isDocument = typeof idOrDoc === "object"
|
const isDocument = typeof idOrDoc === "object"
|
||||||
const id = isDocument ? idOrDoc._id! : idOrDoc
|
const id = isDocument ? idOrDoc._id! : idOrDoc
|
||||||
rev = isDocument ? idOrDoc._rev : rev
|
rev = isDocument ? idOrDoc._rev : rev
|
||||||
return this.db.remove(id, rev)
|
const resp = await this.db.remove(id, rev)
|
||||||
|
span.addTags({ ok: resp.ok })
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +89,11 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
opts?: { silenceErrors?: boolean }
|
opts?: { silenceErrors?: boolean }
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return tracer.trace("db.bulkRemove", span => {
|
return tracer.trace("db.bulkRemove", span => {
|
||||||
span?.addTags({ db_name: this.name, num_docs: documents.length })
|
span.addTags({
|
||||||
|
db_name: this.name,
|
||||||
|
num_docs: documents.length,
|
||||||
|
silence_errors: opts?.silenceErrors,
|
||||||
|
})
|
||||||
return this.db.bulkRemove(documents, opts)
|
return this.db.bulkRemove(documents, opts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -92,15 +102,21 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
document: AnyDocument,
|
document: AnyDocument,
|
||||||
opts?: DatabasePutOpts | undefined
|
opts?: DatabasePutOpts | undefined
|
||||||
): Promise<DocumentInsertResponse> {
|
): Promise<DocumentInsertResponse> {
|
||||||
return tracer.trace("db.put", span => {
|
return tracer.trace("db.put", async span => {
|
||||||
span?.addTags({ db_name: this.name, doc_id: document._id })
|
span.addTags({
|
||||||
return this.db.put(document, opts)
|
db_name: this.name,
|
||||||
|
doc_id: document._id,
|
||||||
|
force: opts?.force,
|
||||||
|
})
|
||||||
|
const resp = await this.db.put(document, opts)
|
||||||
|
span.addTags({ ok: resp.ok })
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkDocs(documents: AnyDocument[]): Promise<DocumentBulkResponse[]> {
|
bulkDocs(documents: AnyDocument[]): Promise<DocumentBulkResponse[]> {
|
||||||
return tracer.trace("db.bulkDocs", span => {
|
return tracer.trace("db.bulkDocs", span => {
|
||||||
span?.addTags({ db_name: this.name, num_docs: documents.length })
|
span.addTags({ db_name: this.name, num_docs: documents.length })
|
||||||
return this.db.bulkDocs(documents)
|
return this.db.bulkDocs(documents)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -108,9 +124,15 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
allDocs<T extends Document | RowValue>(
|
allDocs<T extends Document | RowValue>(
|
||||||
params: DatabaseQueryOpts
|
params: DatabaseQueryOpts
|
||||||
): Promise<AllDocsResponse<T>> {
|
): Promise<AllDocsResponse<T>> {
|
||||||
return tracer.trace("db.allDocs", span => {
|
return tracer.trace("db.allDocs", async span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, ...params })
|
||||||
return this.db.allDocs(params)
|
const resp = await this.db.allDocs<T>(params)
|
||||||
|
span.addTags({
|
||||||
|
total_rows: resp.total_rows,
|
||||||
|
rows_length: resp.rows.length,
|
||||||
|
offset: resp.offset,
|
||||||
|
})
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,57 +140,75 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
viewName: string,
|
viewName: string,
|
||||||
params: DatabaseQueryOpts
|
params: DatabaseQueryOpts
|
||||||
): Promise<AllDocsResponse<T>> {
|
): Promise<AllDocsResponse<T>> {
|
||||||
return tracer.trace("db.query", span => {
|
return tracer.trace("db.query", async span => {
|
||||||
span?.addTags({ db_name: this.name, view_name: viewName })
|
span.addTags({ db_name: this.name, view_name: viewName, ...params })
|
||||||
return this.db.query(viewName, params)
|
const resp = await this.db.query<T>(viewName, params)
|
||||||
|
span.addTags({
|
||||||
|
total_rows: resp.total_rows,
|
||||||
|
rows_length: resp.rows.length,
|
||||||
|
offset: resp.offset,
|
||||||
|
})
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(): Promise<void | OkResponse> {
|
destroy(): Promise<OkResponse> {
|
||||||
return tracer.trace("db.destroy", span => {
|
return tracer.trace("db.destroy", async span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name })
|
||||||
return this.db.destroy()
|
const resp = await this.db.destroy()
|
||||||
|
span.addTags({ ok: resp.ok })
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
compact(): Promise<void | OkResponse> {
|
compact(): Promise<OkResponse> {
|
||||||
return tracer.trace("db.compact", span => {
|
return tracer.trace("db.compact", async span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name })
|
||||||
return this.db.compact()
|
const resp = await this.db.compact()
|
||||||
|
span.addTags({ ok: resp.ok })
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
dump(stream: Writable, opts?: DatabaseDumpOpts | undefined): Promise<any> {
|
dump(stream: Writable, opts?: DatabaseDumpOpts | undefined): Promise<any> {
|
||||||
return tracer.trace("db.dump", span => {
|
return tracer.trace("db.dump", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({
|
||||||
|
db_name: this.name,
|
||||||
|
batch_limit: opts?.batch_limit,
|
||||||
|
batch_size: opts?.batch_size,
|
||||||
|
style: opts?.style,
|
||||||
|
timeout: opts?.timeout,
|
||||||
|
num_doc_ids: opts?.doc_ids?.length,
|
||||||
|
view: opts?.view,
|
||||||
|
})
|
||||||
return this.db.dump(stream, opts)
|
return this.db.dump(stream, opts)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
load(...args: any[]): Promise<any> {
|
load(...args: any[]): Promise<any> {
|
||||||
return tracer.trace("db.load", span => {
|
return tracer.trace("db.load", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, num_args: args.length })
|
||||||
return this.db.load(...args)
|
return this.db.load(...args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
createIndex(...args: any[]): Promise<any> {
|
createIndex(...args: any[]): Promise<any> {
|
||||||
return tracer.trace("db.createIndex", span => {
|
return tracer.trace("db.createIndex", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, num_args: args.length })
|
||||||
return this.db.createIndex(...args)
|
return this.db.createIndex(...args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteIndex(...args: any[]): Promise<any> {
|
deleteIndex(...args: any[]): Promise<any> {
|
||||||
return tracer.trace("db.deleteIndex", span => {
|
return tracer.trace("db.deleteIndex", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, num_args: args.length })
|
||||||
return this.db.deleteIndex(...args)
|
return this.db.deleteIndex(...args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getIndexes(...args: any[]): Promise<any> {
|
getIndexes(...args: any[]): Promise<any> {
|
||||||
return tracer.trace("db.getIndexes", span => {
|
return tracer.trace("db.getIndexes", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, num_args: args.length })
|
||||||
return this.db.getIndexes(...args)
|
return this.db.getIndexes(...args)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -177,22 +217,27 @@ export class DDInstrumentedDatabase implements Database {
|
||||||
sql: string,
|
sql: string,
|
||||||
parameters?: SqlQueryBinding
|
parameters?: SqlQueryBinding
|
||||||
): Promise<T[]> {
|
): Promise<T[]> {
|
||||||
return tracer.trace("db.sql", span => {
|
return tracer.trace("db.sql", async span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name, num_bindings: parameters?.length })
|
||||||
return this.db.sql(sql, parameters)
|
const resp = await this.db.sql<T>(sql, parameters)
|
||||||
|
span.addTags({ num_rows: resp.length })
|
||||||
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlPurgeDocument(docIds: string[] | string): Promise<void> {
|
sqlPurgeDocument(docIds: string[] | string): Promise<void> {
|
||||||
return tracer.trace("db.sqlPurgeDocument", span => {
|
return tracer.trace("db.sqlPurgeDocument", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({
|
||||||
|
db_name: this.name,
|
||||||
|
num_docs: Array.isArray(docIds) ? docIds.length : 1,
|
||||||
|
})
|
||||||
return this.db.sqlPurgeDocument(docIds)
|
return this.db.sqlPurgeDocument(docIds)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlDiskCleanup(): Promise<void> {
|
sqlDiskCleanup(): Promise<void> {
|
||||||
return tracer.trace("db.sqlDiskCleanup", span => {
|
return tracer.trace("db.sqlDiskCleanup", span => {
|
||||||
span?.addTags({ db_name: this.name })
|
span.addTags({ db_name: this.name })
|
||||||
return this.db.sqlDiskCleanup()
|
return this.db.sqlDiskCleanup()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3b56ed03a562b7caa8da8962243efe9050b78e9d
|
Subproject commit 25dd40ee12b048307b558ebcedb36548d6e042cd
|
|
@ -63,6 +63,7 @@
|
||||||
"@bull-board/koa": "5.10.2",
|
"@bull-board/koa": "5.10.2",
|
||||||
"@elastic/elasticsearch": "7.10.0",
|
"@elastic/elasticsearch": "7.10.0",
|
||||||
"@google-cloud/firestore": "7.8.0",
|
"@google-cloud/firestore": "7.8.0",
|
||||||
|
"@koa/cors": "5.0.0",
|
||||||
"@koa/router": "13.1.0",
|
"@koa/router": "13.1.0",
|
||||||
"@socket.io/redis-adapter": "^8.2.1",
|
"@socket.io/redis-adapter": "^8.2.1",
|
||||||
"@types/xml2js": "^0.4.14",
|
"@types/xml2js": "^0.4.14",
|
||||||
|
@ -80,8 +81,8 @@
|
||||||
"cookies": "0.8.0",
|
"cookies": "0.8.0",
|
||||||
"csvtojson": "2.0.10",
|
"csvtojson": "2.0.10",
|
||||||
"curlconverter": "3.21.0",
|
"curlconverter": "3.21.0",
|
||||||
"dd-trace": "5.23.0",
|
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
|
"dd-trace": "5.26.0",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"global-agent": "3.0.0",
|
"global-agent": "3.0.0",
|
||||||
|
@ -131,6 +132,7 @@
|
||||||
"xml2js": "0.6.2"
|
"xml2js": "0.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.22.5",
|
||||||
"@babel/preset-env": "7.16.11",
|
"@babel/preset-env": "7.16.11",
|
||||||
"@jest/types": "^29.6.3",
|
"@jest/types": "^29.6.3",
|
||||||
"@swc/core": "1.3.71",
|
"@swc/core": "1.3.71",
|
||||||
|
@ -140,6 +142,7 @@
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
"@types/koa": "2.13.4",
|
"@types/koa": "2.13.4",
|
||||||
"@types/koa-send": "^4.1.6",
|
"@types/koa-send": "^4.1.6",
|
||||||
|
"@types/koa__cors": "5.0.0",
|
||||||
"@types/koa__router": "12.0.4",
|
"@types/koa__router": "12.0.4",
|
||||||
"@types/lodash": "4.14.200",
|
"@types/lodash": "4.14.200",
|
||||||
"@types/mssql": "9.1.5",
|
"@types/mssql": "9.1.5",
|
||||||
|
@ -172,8 +175,7 @@
|
||||||
"tsconfig-paths": "4.0.0",
|
"tsconfig-paths": "4.0.0",
|
||||||
"typescript": "5.5.2",
|
"typescript": "5.5.2",
|
||||||
"update-dotenv": "1.1.1",
|
"update-dotenv": "1.1.1",
|
||||||
"yargs": "13.2.4",
|
"yargs": "13.2.4"
|
||||||
"@babel/core": "^7.22.5"
|
|
||||||
},
|
},
|
||||||
"nx": {
|
"nx": {
|
||||||
"targets": {
|
"targets": {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,13 @@ components:
|
||||||
description: The ID of the table which this request is targeting.
|
description: The ID of the table which this request is targeting.
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
viewId:
|
||||||
|
in: path
|
||||||
|
name: viewId
|
||||||
|
required: true
|
||||||
|
description: The ID of the view which this request is targeting.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
rowId:
|
rowId:
|
||||||
in: path
|
in: path
|
||||||
name: rowId
|
name: rowId
|
||||||
|
@ -36,7 +43,7 @@ components:
|
||||||
required: true
|
required: true
|
||||||
description: The ID of the app which this request is targeting.
|
description: The ID of the app which this request is targeting.
|
||||||
schema:
|
schema:
|
||||||
default: "{{ appId }}"
|
default: "{{appId}}"
|
||||||
type: string
|
type: string
|
||||||
appIdUrl:
|
appIdUrl:
|
||||||
in: path
|
in: path
|
||||||
|
@ -44,7 +51,7 @@ components:
|
||||||
required: true
|
required: true
|
||||||
description: The ID of the app which this request is targeting.
|
description: The ID of the app which this request is targeting.
|
||||||
schema:
|
schema:
|
||||||
default: "{{ appId }}"
|
default: "{{appId}}"
|
||||||
type: string
|
type: string
|
||||||
queryId:
|
queryId:
|
||||||
in: path
|
in: path
|
||||||
|
@ -442,6 +449,74 @@ components:
|
||||||
# TYPE budibase_quota_limit_automations gauge
|
# TYPE budibase_quota_limit_automations gauge
|
||||||
|
|
||||||
budibase_quota_limit_automations 9007199254740991
|
budibase_quota_limit_automations 9007199254740991
|
||||||
|
view:
|
||||||
|
value:
|
||||||
|
data:
|
||||||
|
name: peopleView
|
||||||
|
tableId: ta_896a325f7e8147d2a2cda93c5d236511
|
||||||
|
schema:
|
||||||
|
name:
|
||||||
|
visible: true
|
||||||
|
readonly: false
|
||||||
|
order: 1
|
||||||
|
width: 300
|
||||||
|
age:
|
||||||
|
visible: true
|
||||||
|
readonly: true
|
||||||
|
order: 2
|
||||||
|
width: 200
|
||||||
|
salary:
|
||||||
|
visible: false
|
||||||
|
readonly: false
|
||||||
|
query:
|
||||||
|
logicalOperator: all
|
||||||
|
onEmptyFilter: none
|
||||||
|
groups:
|
||||||
|
- logicalOperator: any
|
||||||
|
filters:
|
||||||
|
- operator: string
|
||||||
|
field: name
|
||||||
|
value: John
|
||||||
|
- operator: range
|
||||||
|
field: age
|
||||||
|
value:
|
||||||
|
low: 18
|
||||||
|
high: 100
|
||||||
|
primaryDisplay: name
|
||||||
|
views:
|
||||||
|
value:
|
||||||
|
data:
|
||||||
|
- name: peopleView
|
||||||
|
tableId: ta_896a325f7e8147d2a2cda93c5d236511
|
||||||
|
schema:
|
||||||
|
name:
|
||||||
|
visible: true
|
||||||
|
readonly: false
|
||||||
|
order: 1
|
||||||
|
width: 300
|
||||||
|
age:
|
||||||
|
visible: true
|
||||||
|
readonly: true
|
||||||
|
order: 2
|
||||||
|
width: 200
|
||||||
|
salary:
|
||||||
|
visible: false
|
||||||
|
readonly: false
|
||||||
|
query:
|
||||||
|
logicalOperator: all
|
||||||
|
onEmptyFilter: none
|
||||||
|
groups:
|
||||||
|
- logicalOperator: any
|
||||||
|
filters:
|
||||||
|
- operator: string
|
||||||
|
field: name
|
||||||
|
value: John
|
||||||
|
- operator: range
|
||||||
|
field: age
|
||||||
|
value:
|
||||||
|
low: 18
|
||||||
|
high: 100
|
||||||
|
primaryDisplay: name
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
ApiKeyAuth:
|
ApiKeyAuth:
|
||||||
type: apiKey
|
type: apiKey
|
||||||
|
@ -761,7 +836,6 @@ components:
|
||||||
enum:
|
enum:
|
||||||
- static
|
- static
|
||||||
- dynamic
|
- dynamic
|
||||||
- ai
|
|
||||||
description: Defines whether this is a static or dynamic formula.
|
description: Defines whether this is a static or dynamic formula.
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -931,7 +1005,6 @@ components:
|
||||||
enum:
|
enum:
|
||||||
- static
|
- static
|
||||||
- dynamic
|
- dynamic
|
||||||
- ai
|
|
||||||
description: Defines whether this is a static or dynamic formula.
|
description: Defines whether this is a static or dynamic formula.
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -1108,7 +1181,6 @@ components:
|
||||||
enum:
|
enum:
|
||||||
- static
|
- static
|
||||||
- dynamic
|
- dynamic
|
||||||
- ai
|
|
||||||
description: Defines whether this is a static or dynamic formula.
|
description: Defines whether this is a static or dynamic formula.
|
||||||
- type: object
|
- type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -1704,6 +1776,644 @@ components:
|
||||||
- userIds
|
- userIds
|
||||||
required:
|
required:
|
||||||
- data
|
- data
|
||||||
|
view:
|
||||||
|
description: The view to be created/updated.
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- schema
|
||||||
|
- tableId
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The name of the view.
|
||||||
|
type: string
|
||||||
|
tableId:
|
||||||
|
description: The ID of the table this view is based on.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: The type of view - standard (empty value) or calculation.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- calculation
|
||||||
|
primaryDisplay:
|
||||||
|
type: string
|
||||||
|
description: A column used to display rows from this view - usually used when
|
||||||
|
rendered in tables.
|
||||||
|
query:
|
||||||
|
description: Search parameters for view
|
||||||
|
type: object
|
||||||
|
required: []
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
onEmptyFilter:
|
||||||
|
description: If no filters match, should the view return all rows, or no rows.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- none
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
sort:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- field
|
||||||
|
properties:
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table/view schema to sort on.
|
||||||
|
order:
|
||||||
|
type: string
|
||||||
|
description: The order in which to sort.
|
||||||
|
enum:
|
||||||
|
- ascending
|
||||||
|
- descending
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The type of sort to perform (by number, or by alphabetically).
|
||||||
|
enum:
|
||||||
|
- string
|
||||||
|
- number
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
visible:
|
||||||
|
type: boolean
|
||||||
|
description: Defines whether the column is visible or not - rows
|
||||||
|
retrieved/updated through this view will not be able to
|
||||||
|
access it.
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
description: "When used in combination with 'visible: true' the column will be
|
||||||
|
visible in row responses but cannot be updated."
|
||||||
|
order:
|
||||||
|
type: integer
|
||||||
|
description: A number defining where the column shows up in tables, lowest being
|
||||||
|
first.
|
||||||
|
width:
|
||||||
|
type: integer
|
||||||
|
description: A width for the column, defined in pixels - this affects rendering
|
||||||
|
in tables.
|
||||||
|
column:
|
||||||
|
type: array
|
||||||
|
description: If this is a relationship column, we can set the columns we wish to
|
||||||
|
include
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
calculationType:
|
||||||
|
type: string
|
||||||
|
description: This column should be built from a calculation, specifying a type
|
||||||
|
and field. It is important to note when a calculation is
|
||||||
|
configured all non-calculation columns will be used for
|
||||||
|
grouping.
|
||||||
|
enum:
|
||||||
|
- sum
|
||||||
|
- avg
|
||||||
|
- count
|
||||||
|
- min
|
||||||
|
- max
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table to perform the calculation on.
|
||||||
|
distinct:
|
||||||
|
type: boolean
|
||||||
|
description: Can be used in tandem with the count calculation type, to count
|
||||||
|
unique entries.
|
||||||
|
viewOutput:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
description: The view to be created/updated.
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- schema
|
||||||
|
- tableId
|
||||||
|
- id
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The name of the view.
|
||||||
|
type: string
|
||||||
|
tableId:
|
||||||
|
description: The ID of the table this view is based on.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: The type of view - standard (empty value) or calculation.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- calculation
|
||||||
|
primaryDisplay:
|
||||||
|
type: string
|
||||||
|
description: A column used to display rows from this view - usually used when
|
||||||
|
rendered in tables.
|
||||||
|
query:
|
||||||
|
description: Search parameters for view
|
||||||
|
type: object
|
||||||
|
required: []
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
onEmptyFilter:
|
||||||
|
description: If no filters match, should the view return all rows, or no rows.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- none
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
sort:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- field
|
||||||
|
properties:
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table/view schema to sort on.
|
||||||
|
order:
|
||||||
|
type: string
|
||||||
|
description: The order in which to sort.
|
||||||
|
enum:
|
||||||
|
- ascending
|
||||||
|
- descending
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The type of sort to perform (by number, or by alphabetically).
|
||||||
|
enum:
|
||||||
|
- string
|
||||||
|
- number
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
visible:
|
||||||
|
type: boolean
|
||||||
|
description: Defines whether the column is visible or not - rows
|
||||||
|
retrieved/updated through this view will not be able
|
||||||
|
to access it.
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
description: "When used in combination with 'visible: true' the column will be
|
||||||
|
visible in row responses but cannot be updated."
|
||||||
|
order:
|
||||||
|
type: integer
|
||||||
|
description: A number defining where the column shows up in tables, lowest being
|
||||||
|
first.
|
||||||
|
width:
|
||||||
|
type: integer
|
||||||
|
description: A width for the column, defined in pixels - this affects rendering
|
||||||
|
in tables.
|
||||||
|
column:
|
||||||
|
type: array
|
||||||
|
description: If this is a relationship column, we can set the columns we wish to
|
||||||
|
include
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
calculationType:
|
||||||
|
type: string
|
||||||
|
description: This column should be built from a calculation, specifying a type
|
||||||
|
and field. It is important to note when a calculation
|
||||||
|
is configured all non-calculation columns will be used
|
||||||
|
for grouping.
|
||||||
|
enum:
|
||||||
|
- sum
|
||||||
|
- avg
|
||||||
|
- count
|
||||||
|
- min
|
||||||
|
- max
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table to perform the calculation on.
|
||||||
|
distinct:
|
||||||
|
type: boolean
|
||||||
|
description: Can be used in tandem with the count calculation type, to count
|
||||||
|
unique entries.
|
||||||
|
id:
|
||||||
|
description: The ID of the view.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
viewSearch:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
data:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
description: The view to be created/updated.
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- schema
|
||||||
|
- tableId
|
||||||
|
- id
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: The name of the view.
|
||||||
|
type: string
|
||||||
|
tableId:
|
||||||
|
description: The ID of the table this view is based on.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: The type of view - standard (empty value) or calculation.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- calculation
|
||||||
|
primaryDisplay:
|
||||||
|
type: string
|
||||||
|
description: A column used to display rows from this view - usually used when
|
||||||
|
rendered in tables.
|
||||||
|
query:
|
||||||
|
description: Search parameters for view
|
||||||
|
type: object
|
||||||
|
required: []
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
onEmptyFilter:
|
||||||
|
description: If no filters match, should the view return all rows, or no rows.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- none
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
groups:
|
||||||
|
description: A grouping of filters to be applied.
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
logicalOperator:
|
||||||
|
description: When using groups this defines whether all of the filters must
|
||||||
|
match, or only one of them.
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- all
|
||||||
|
- any
|
||||||
|
filters:
|
||||||
|
description: A list of filters to apply
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
description: The type of search operation which is being performed.
|
||||||
|
enum:
|
||||||
|
- equal
|
||||||
|
- notEqual
|
||||||
|
- empty
|
||||||
|
- notEmpty
|
||||||
|
- fuzzy
|
||||||
|
- string
|
||||||
|
- contains
|
||||||
|
- notContains
|
||||||
|
- containsAny
|
||||||
|
- oneOf
|
||||||
|
- range
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field in the view to perform the search on.
|
||||||
|
value:
|
||||||
|
description: The value to search for - the type will depend on the operator in
|
||||||
|
use.
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: number
|
||||||
|
- type: boolean
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
sort:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- field
|
||||||
|
properties:
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table/view schema to sort on.
|
||||||
|
order:
|
||||||
|
type: string
|
||||||
|
description: The order in which to sort.
|
||||||
|
enum:
|
||||||
|
- ascending
|
||||||
|
- descending
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The type of sort to perform (by number, or by alphabetically).
|
||||||
|
enum:
|
||||||
|
- string
|
||||||
|
- number
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
oneOf:
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
visible:
|
||||||
|
type: boolean
|
||||||
|
description: Defines whether the column is visible or not - rows
|
||||||
|
retrieved/updated through this view will not be able
|
||||||
|
to access it.
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
description: "When used in combination with 'visible: true' the column will be
|
||||||
|
visible in row responses but cannot be updated."
|
||||||
|
order:
|
||||||
|
type: integer
|
||||||
|
description: A number defining where the column shows up in tables, lowest being
|
||||||
|
first.
|
||||||
|
width:
|
||||||
|
type: integer
|
||||||
|
description: A width for the column, defined in pixels - this affects rendering
|
||||||
|
in tables.
|
||||||
|
column:
|
||||||
|
type: array
|
||||||
|
description: If this is a relationship column, we can set the columns we wish to
|
||||||
|
include
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
readonly:
|
||||||
|
type: boolean
|
||||||
|
- type: object
|
||||||
|
properties:
|
||||||
|
calculationType:
|
||||||
|
type: string
|
||||||
|
description: This column should be built from a calculation, specifying a type
|
||||||
|
and field. It is important to note when a
|
||||||
|
calculation is configured all non-calculation
|
||||||
|
columns will be used for grouping.
|
||||||
|
enum:
|
||||||
|
- sum
|
||||||
|
- avg
|
||||||
|
- count
|
||||||
|
- min
|
||||||
|
- max
|
||||||
|
field:
|
||||||
|
type: string
|
||||||
|
description: The field from the table to perform the calculation on.
|
||||||
|
distinct:
|
||||||
|
type: boolean
|
||||||
|
description: Can be used in tandem with the count calculation type, to count
|
||||||
|
unique entries.
|
||||||
|
id:
|
||||||
|
description: The ID of the view.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- data
|
||||||
security:
|
security:
|
||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
paths:
|
paths:
|
||||||
|
@ -2136,6 +2846,32 @@ paths:
|
||||||
examples:
|
examples:
|
||||||
search:
|
search:
|
||||||
$ref: "#/components/examples/rows"
|
$ref: "#/components/examples/rows"
|
||||||
|
"/views/{viewId}/rows/search":
|
||||||
|
post:
|
||||||
|
operationId: rowViewSearch
|
||||||
|
summary: Search for rows in a view
|
||||||
|
tags:
|
||||||
|
- rows
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/viewId"
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/rowSearch"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The response will contain an array of rows that match the search
|
||||||
|
parameters.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/searchOutput"
|
||||||
|
examples:
|
||||||
|
search:
|
||||||
|
$ref: "#/components/examples/rows"
|
||||||
/tables:
|
/tables:
|
||||||
post:
|
post:
|
||||||
operationId: tableCreate
|
operationId: tableCreate
|
||||||
|
@ -2359,4 +3095,123 @@ paths:
|
||||||
examples:
|
examples:
|
||||||
users:
|
users:
|
||||||
$ref: "#/components/examples/users"
|
$ref: "#/components/examples/users"
|
||||||
|
/views:
|
||||||
|
post:
|
||||||
|
operationId: viewCreate
|
||||||
|
summary: Create a view
|
||||||
|
description: Create a view, this can be against an internal or external table.
|
||||||
|
tags:
|
||||||
|
- views
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/view"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns the created view, including the ID which has been generated
|
||||||
|
for it.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/viewOutput"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
"/views/{viewId}":
|
||||||
|
put:
|
||||||
|
operationId: viewUpdate
|
||||||
|
summary: Update a view
|
||||||
|
description: Update a view, this can be against an internal or external table.
|
||||||
|
tags:
|
||||||
|
- views
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/viewId"
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/view"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns the updated view.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/viewOutput"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
delete:
|
||||||
|
operationId: viewDestroy
|
||||||
|
summary: Delete a view
|
||||||
|
description: Delete a view, this can be against an internal or external table.
|
||||||
|
tags:
|
||||||
|
- views
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/viewId"
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns the deleted view.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/viewOutput"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
get:
|
||||||
|
operationId: viewGetById
|
||||||
|
summary: Retrieve a view
|
||||||
|
description: Lookup a view, this could be internal or external.
|
||||||
|
tags:
|
||||||
|
- views
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/viewId"
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns the retrieved view.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/viewOutput"
|
||||||
|
examples:
|
||||||
|
view:
|
||||||
|
$ref: "#/components/examples/view"
|
||||||
|
/views/search:
|
||||||
|
post:
|
||||||
|
operationId: viewSearch
|
||||||
|
summary: Search for views
|
||||||
|
description: Based on view properties (currently only name) search for views.
|
||||||
|
tags:
|
||||||
|
- views
|
||||||
|
parameters:
|
||||||
|
- $ref: "#/components/parameters/appId"
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/nameSearch"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Returns the found views, based on the search parameters.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/viewSearch"
|
||||||
|
examples:
|
||||||
|
views:
|
||||||
|
$ref: "#/components/examples/views"
|
||||||
tags: []
|
tags: []
|
||||||
|
|
|
@ -8,6 +8,16 @@ export const tableId = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const viewId = {
|
||||||
|
in: "path",
|
||||||
|
name: "viewId",
|
||||||
|
required: true,
|
||||||
|
description: "The ID of the view which this request is targeting.",
|
||||||
|
schema: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export const rowId = {
|
export const rowId = {
|
||||||
in: "path",
|
in: "path",
|
||||||
name: "rowId",
|
name: "rowId",
|
||||||
|
|
|
@ -6,6 +6,7 @@ import user from "./user"
|
||||||
import metrics from "./metrics"
|
import metrics from "./metrics"
|
||||||
import misc from "./misc"
|
import misc from "./misc"
|
||||||
import roles from "./roles"
|
import roles from "./roles"
|
||||||
|
import view from "./view"
|
||||||
|
|
||||||
export const examples = {
|
export const examples = {
|
||||||
...application.getExamples(),
|
...application.getExamples(),
|
||||||
|
@ -16,6 +17,7 @@ export const examples = {
|
||||||
...misc.getExamples(),
|
...misc.getExamples(),
|
||||||
...metrics.getExamples(),
|
...metrics.getExamples(),
|
||||||
...roles.getExamples(),
|
...roles.getExamples(),
|
||||||
|
...view.getExamples(),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
|
@ -26,4 +28,5 @@ export const schemas = {
|
||||||
...user.getSchemas(),
|
...user.getSchemas(),
|
||||||
...misc.getSchemas(),
|
...misc.getSchemas(),
|
||||||
...roles.getSchemas(),
|
...roles.getSchemas(),
|
||||||
|
...view.getSchemas(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
import { object } from "./utils"
|
import { object } from "./utils"
|
||||||
import Resource from "./utils/Resource"
|
import Resource from "./utils/Resource"
|
||||||
|
|
||||||
export default new Resource().setSchemas({
|
export const searchSchema = {
|
||||||
rowSearch: object(
|
|
||||||
{
|
|
||||||
query: {
|
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
allOr: {
|
allOr: {
|
||||||
|
@ -93,7 +90,12 @@ export default new Resource().setSchemas({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
|
||||||
|
export default new Resource().setSchemas({
|
||||||
|
rowSearch: object(
|
||||||
|
{
|
||||||
|
query: searchSchema,
|
||||||
paginate: {
|
paginate: {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
description: "Enables pagination, by default this is disabled.",
|
description: "Enables pagination, by default this is disabled.",
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
import { object } from "./utils"
|
||||||
|
import Resource from "./utils/Resource"
|
||||||
|
import {
|
||||||
|
ArrayOperator,
|
||||||
|
BasicOperator,
|
||||||
|
CalculationType,
|
||||||
|
RangeOperator,
|
||||||
|
SortOrder,
|
||||||
|
SortType,
|
||||||
|
} from "@budibase/types"
|
||||||
|
import { cloneDeep } from "lodash"
|
||||||
|
|
||||||
|
const view = {
|
||||||
|
name: "peopleView",
|
||||||
|
tableId: "ta_896a325f7e8147d2a2cda93c5d236511",
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
visible: true,
|
||||||
|
readonly: false,
|
||||||
|
order: 1,
|
||||||
|
width: 300,
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
visible: true,
|
||||||
|
readonly: true,
|
||||||
|
order: 2,
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
salary: {
|
||||||
|
visible: false,
|
||||||
|
readonly: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
logicalOperator: "all",
|
||||||
|
onEmptyFilter: "none",
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
logicalOperator: "any",
|
||||||
|
filters: [
|
||||||
|
{ operator: "string", field: "name", value: "John" },
|
||||||
|
{ operator: "range", field: "age", value: { low: 18, high: 100 } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
primaryDisplay: "name",
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseColumnDef = {
|
||||||
|
visible: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"Defines whether the column is visible or not - rows retrieved/updated through this view will not be able to access it.",
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"When used in combination with 'visible: true' the column will be visible in row responses but cannot be updated.",
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
type: "integer",
|
||||||
|
description:
|
||||||
|
"A number defining where the column shows up in tables, lowest being first.",
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: "integer",
|
||||||
|
description:
|
||||||
|
"A width for the column, defined in pixels - this affects rendering in tables.",
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
type: "array",
|
||||||
|
description:
|
||||||
|
"If this is a relationship column, we can set the columns we wish to include",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
readonly: {
|
||||||
|
type: "boolean",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const logicalOperator = {
|
||||||
|
description:
|
||||||
|
"When using groups this defines whether all of the filters must match, or only one of them.",
|
||||||
|
type: "string",
|
||||||
|
enum: ["all", "any"],
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterGroup = {
|
||||||
|
description: "A grouping of filters to be applied.",
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
logicalOperator,
|
||||||
|
filters: {
|
||||||
|
description: "A list of filters to apply",
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
operator: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The type of search operation which is being performed.",
|
||||||
|
enum: [
|
||||||
|
...Object.values(BasicOperator),
|
||||||
|
...Object.values(ArrayOperator),
|
||||||
|
...Object.values(RangeOperator),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: "string",
|
||||||
|
description: "The field in the view to perform the search on.",
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
description:
|
||||||
|
"The value to search for - the type will depend on the operator in use.",
|
||||||
|
oneOf: [
|
||||||
|
{ type: "string" },
|
||||||
|
{ type: "number" },
|
||||||
|
{ type: "boolean" },
|
||||||
|
{ type: "object" },
|
||||||
|
{ type: "array" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// have to clone to avoid constantly recursive structure - we can't represent this easily
|
||||||
|
const layeredFilterGroup: any = cloneDeep(filterGroup)
|
||||||
|
layeredFilterGroup.items.properties.groups = filterGroup
|
||||||
|
|
||||||
|
const viewQuerySchema = {
|
||||||
|
description: "Search parameters for view",
|
||||||
|
type: "object",
|
||||||
|
required: [],
|
||||||
|
properties: {
|
||||||
|
logicalOperator,
|
||||||
|
onEmptyFilter: {
|
||||||
|
description:
|
||||||
|
"If no filters match, should the view return all rows, or no rows.",
|
||||||
|
type: "string",
|
||||||
|
enum: ["all", "none"],
|
||||||
|
},
|
||||||
|
groups: layeredFilterGroup,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewSchema = {
|
||||||
|
description: "The view to be created/updated.",
|
||||||
|
type: "object",
|
||||||
|
required: ["name", "schema", "tableId"],
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
description: "The name of the view.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
tableId: {
|
||||||
|
description: "The ID of the table this view is based on.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
description: "The type of view - standard (empty value) or calculation.",
|
||||||
|
type: "string",
|
||||||
|
enum: ["calculation"],
|
||||||
|
},
|
||||||
|
primaryDisplay: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"A column used to display rows from this view - usually used when rendered in tables.",
|
||||||
|
},
|
||||||
|
query: viewQuerySchema,
|
||||||
|
sort: {
|
||||||
|
type: "object",
|
||||||
|
required: ["field"],
|
||||||
|
properties: {
|
||||||
|
field: {
|
||||||
|
type: "string",
|
||||||
|
description: "The field from the table/view schema to sort on.",
|
||||||
|
},
|
||||||
|
order: {
|
||||||
|
type: "string",
|
||||||
|
description: "The order in which to sort.",
|
||||||
|
enum: Object.values(SortOrder),
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The type of sort to perform (by number, or by alphabetically).",
|
||||||
|
enum: Object.values(SortType),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: {
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: baseColumnDef,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
calculationType: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"This column should be built from a calculation, specifying a type and field. It is important to note when a calculation is configured all non-calculation columns will be used for grouping.",
|
||||||
|
enum: Object.values(CalculationType),
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The field from the table to perform the calculation on.",
|
||||||
|
},
|
||||||
|
distinct: {
|
||||||
|
type: "boolean",
|
||||||
|
description:
|
||||||
|
"Can be used in tandem with the count calculation type, to count unique entries.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewOutputSchema = {
|
||||||
|
...viewSchema,
|
||||||
|
properties: {
|
||||||
|
...viewSchema.properties,
|
||||||
|
id: {
|
||||||
|
description: "The ID of the view.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [...viewSchema.required, "id"],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Resource()
|
||||||
|
.setExamples({
|
||||||
|
view: {
|
||||||
|
value: {
|
||||||
|
data: view,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
value: {
|
||||||
|
data: [view],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.setSchemas({
|
||||||
|
view: viewSchema,
|
||||||
|
viewOutput: object({
|
||||||
|
data: viewOutputSchema,
|
||||||
|
}),
|
||||||
|
viewSearch: object({
|
||||||
|
data: {
|
||||||
|
type: "array",
|
||||||
|
items: viewOutputSchema,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
|
@ -1,6 +1,7 @@
|
||||||
import { Application } from "./types"
|
import { Application } from "./types"
|
||||||
|
import { RequiredKeys } from "@budibase/types"
|
||||||
|
|
||||||
function application(body: any): Application {
|
function application(body: any): RequiredKeys<Application> {
|
||||||
let app = body?.application ? body.application : body
|
let app = body?.application ? body.application : body
|
||||||
return {
|
return {
|
||||||
_id: app.appId,
|
_id: app.appId,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import applications from "./applications"
|
||||||
import users from "./users"
|
import users from "./users"
|
||||||
import rows from "./rows"
|
import rows from "./rows"
|
||||||
import queries from "./queries"
|
import queries from "./queries"
|
||||||
|
import views from "./views"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...tables,
|
...tables,
|
||||||
|
@ -10,4 +11,5 @@ export default {
|
||||||
...users,
|
...users,
|
||||||
...rows,
|
...rows,
|
||||||
...queries,
|
...queries,
|
||||||
|
...views,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Query, ExecuteQuery } from "./types"
|
import { Query, ExecuteQuery } from "./types"
|
||||||
|
import { RequiredKeys } from "@budibase/types"
|
||||||
|
|
||||||
function query(body: any): Query {
|
function query(body: any): RequiredKeys<Query> {
|
||||||
return {
|
return {
|
||||||
_id: body._id,
|
_id: body._id,
|
||||||
datasourceId: body.datasourceId,
|
datasourceId: body.datasourceId,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Row, RowSearch } from "./types"
|
import { Row, RowSearch } from "./types"
|
||||||
|
import { RequiredKeys } from "@budibase/types"
|
||||||
|
|
||||||
function row(body: any): Row {
|
function row(body: any): RequiredKeys<Row> {
|
||||||
delete body._rev
|
delete body._rev
|
||||||
// have to input everything, since structure unknown
|
// have to input everything, since structure unknown
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Table } from "./types"
|
import { Table } from "./types"
|
||||||
|
import { RequiredKeys } from "@budibase/types"
|
||||||
|
|
||||||
function table(body: any): Table {
|
function table(body: any): RequiredKeys<Table> {
|
||||||
return {
|
return {
|
||||||
_id: body._id,
|
_id: body._id,
|
||||||
name: body.name,
|
name: body.name,
|
||||||
|
|
|
@ -9,6 +9,9 @@ export type CreateApplicationParams = components["schemas"]["application"]
|
||||||
export type Table = components["schemas"]["tableOutput"]["data"]
|
export type Table = components["schemas"]["tableOutput"]["data"]
|
||||||
export type CreateTableParams = components["schemas"]["table"]
|
export type CreateTableParams = components["schemas"]["table"]
|
||||||
|
|
||||||
|
export type View = components["schemas"]["viewOutput"]["data"]
|
||||||
|
export type CreateViewParams = components["schemas"]["view"]
|
||||||
|
|
||||||
export type Row = components["schemas"]["rowOutput"]["data"]
|
export type Row = components["schemas"]["rowOutput"]["data"]
|
||||||
export type RowSearch = components["schemas"]["searchOutput"]
|
export type RowSearch = components["schemas"]["searchOutput"]
|
||||||
export type CreateRowParams = components["schemas"]["row"]
|
export type CreateRowParams = components["schemas"]["row"]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { User } from "./types"
|
import { User } from "./types"
|
||||||
|
import { RequiredKeys } from "@budibase/types"
|
||||||
|
|
||||||
function user(body: any): User {
|
function user(body: any): RequiredKeys<User> {
|
||||||
return {
|
return {
|
||||||
_id: body._id,
|
_id: body._id,
|
||||||
email: body.email,
|
email: body.email,
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { View } from "./types"
|
||||||
|
import { ViewV2, Ctx, RequiredKeys } from "@budibase/types"
|
||||||
|
import { dataFilters } from "@budibase/shared-core"
|
||||||
|
|
||||||
|
function view(body: ViewV2): RequiredKeys<View> {
|
||||||
|
return {
|
||||||
|
id: body.id,
|
||||||
|
tableId: body.tableId,
|
||||||
|
type: body.type,
|
||||||
|
name: body.name,
|
||||||
|
schema: body.schema!,
|
||||||
|
primaryDisplay: body.primaryDisplay,
|
||||||
|
query: dataFilters.buildQuery(body.query),
|
||||||
|
sort: body.sort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapView(ctx: Ctx<{ data: ViewV2 }>): { data: View } {
|
||||||
|
return {
|
||||||
|
data: view(ctx.body.data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapViews(ctx: Ctx<{ data: ViewV2[] }>): { data: View[] } {
|
||||||
|
const views = ctx.body.data.map((body: ViewV2) => view(body))
|
||||||
|
return { data: views }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mapView,
|
||||||
|
mapViews,
|
||||||
|
}
|
|
@ -22,13 +22,13 @@ export function fixRow(row: Row, params: any) {
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search(ctx: UserCtx, next: Next) {
|
function buildSearchRequestBody(ctx: UserCtx) {
|
||||||
let { sort, paginate, bookmark, limit, query } = ctx.request.body
|
let { sort, paginate, bookmark, limit, query } = ctx.request.body
|
||||||
// update the body to the correct format of the internal search
|
// update the body to the correct format of the internal search
|
||||||
if (!sort) {
|
if (!sort) {
|
||||||
sort = {}
|
sort = {}
|
||||||
}
|
}
|
||||||
ctx.request.body = {
|
return {
|
||||||
sort: sort.column,
|
sort: sort.column,
|
||||||
sortType: sort.type,
|
sortType: sort.type,
|
||||||
sortOrder: sort.order,
|
sortOrder: sort.order,
|
||||||
|
@ -37,10 +37,23 @@ export async function search(ctx: UserCtx, next: Next) {
|
||||||
limit,
|
limit,
|
||||||
query,
|
query,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
|
ctx.request.body = buildSearchRequestBody(ctx)
|
||||||
await rowController.search(ctx)
|
await rowController.search(ctx)
|
||||||
await next()
|
await next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function viewSearch(ctx: UserCtx, next: Next) {
|
||||||
|
ctx.request.body = buildSearchRequestBody(ctx)
|
||||||
|
ctx.params = {
|
||||||
|
viewId: ctx.params.viewId,
|
||||||
|
}
|
||||||
|
await rowController.views.searchView(ctx)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
export async function create(ctx: UserCtx, next: Next) {
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
ctx.request.body = fixRow(ctx.request.body, ctx.params)
|
ctx.request.body = fixRow(ctx.request.body, ctx.params)
|
||||||
await rowController.save(ctx)
|
await rowController.save(ctx)
|
||||||
|
@ -79,4 +92,5 @@ export default {
|
||||||
update,
|
update,
|
||||||
destroy,
|
destroy,
|
||||||
search,
|
search,
|
||||||
|
viewSearch,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import { search as stringSearch } from "./utils"
|
||||||
|
import * as controller from "../view"
|
||||||
|
import { ViewV2, UserCtx, UISearchFilter, PublicAPIView } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
import { merge } from "lodash"
|
||||||
|
|
||||||
|
function viewRequest(view: PublicAPIView, params?: { viewId: string }) {
|
||||||
|
const viewV2: ViewV2 = view
|
||||||
|
if (!viewV2) {
|
||||||
|
return viewV2
|
||||||
|
}
|
||||||
|
if (params?.viewId) {
|
||||||
|
viewV2.id = params.viewId
|
||||||
|
}
|
||||||
|
if (!view.query) {
|
||||||
|
viewV2.query = {}
|
||||||
|
} else {
|
||||||
|
// public API only has one form of query
|
||||||
|
viewV2.queryUI = viewV2.query as UISearchFilter
|
||||||
|
}
|
||||||
|
viewV2.version = 2
|
||||||
|
return viewV2
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewResponse(view: ViewV2): PublicAPIView {
|
||||||
|
// remove our internal structure - always un-necessary
|
||||||
|
delete view.query
|
||||||
|
return {
|
||||||
|
...view,
|
||||||
|
query: view.queryUI,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewsResponse(views: ViewV2[]): PublicAPIView[] {
|
||||||
|
return views.map(viewResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
|
const { name } = ctx.request.body
|
||||||
|
await controller.v2.fetch(ctx)
|
||||||
|
ctx.body.data = viewsResponse(stringSearch(ctx.body.data, name))
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
|
ctx = merge(ctx, {
|
||||||
|
request: {
|
||||||
|
body: viewRequest(ctx.request.body),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await controller.v2.create(ctx)
|
||||||
|
ctx.body.data = viewResponse(ctx.body.data)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
|
ctx = merge(ctx, {
|
||||||
|
params: {
|
||||||
|
viewId: ctx.params.viewId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await controller.v2.get(ctx)
|
||||||
|
ctx.body.data = viewResponse(ctx.body.data)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
|
const viewId = ctx.params.viewId
|
||||||
|
ctx = merge(ctx, {
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
data: viewRequest(ctx.request.body, { viewId }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
viewId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await controller.v2.update(ctx)
|
||||||
|
ctx.body.data = viewResponse(ctx.body.data)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
|
await controller.v2.remove(ctx)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
create,
|
||||||
|
read,
|
||||||
|
update,
|
||||||
|
destroy,
|
||||||
|
search,
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ export async function searchView(
|
||||||
result.rows.forEach(r => (r._viewId = view.id))
|
result.rows.forEach(r => (r._viewId = view.id))
|
||||||
ctx.body = result
|
ctx.body = result
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSortOptions(request: SearchViewRowRequest, view: ViewV2) {
|
function getSortOptions(request: SearchViewRowRequest, view: ViewV2) {
|
||||||
if (request.sort) {
|
if (request.sort) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
RelationSchemaField,
|
RelationSchemaField,
|
||||||
ViewFieldMetadata,
|
ViewFieldMetadata,
|
||||||
CalculationType,
|
CalculationType,
|
||||||
|
ViewFetchResponseEnriched,
|
||||||
CountDistinctCalculationFieldMetadata,
|
CountDistinctCalculationFieldMetadata,
|
||||||
CountCalculationFieldMetadata,
|
CountCalculationFieldMetadata,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
@ -125,6 +126,12 @@ export async function get(ctx: Ctx<void, ViewResponseEnriched>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetch(ctx: Ctx<void, ViewFetchResponseEnriched>) {
|
||||||
|
ctx.body = {
|
||||||
|
data: await sdk.views.getAllEnriched(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
|
export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
|
||||||
const view = ctx.request.body
|
const view = ctx.request.body
|
||||||
const { tableId } = view
|
const { tableId } = view
|
||||||
|
|
|
@ -4,19 +4,21 @@ import queryEndpoints from "./queries"
|
||||||
import tableEndpoints from "./tables"
|
import tableEndpoints from "./tables"
|
||||||
import rowEndpoints from "./rows"
|
import rowEndpoints from "./rows"
|
||||||
import userEndpoints from "./users"
|
import userEndpoints from "./users"
|
||||||
|
import viewEndpoints from "./views"
|
||||||
import roleEndpoints from "./roles"
|
import roleEndpoints from "./roles"
|
||||||
import authorized from "../../../middleware/authorized"
|
import authorized from "../../../middleware/authorized"
|
||||||
import publicApi from "../../../middleware/publicApi"
|
import publicApi from "../../../middleware/publicApi"
|
||||||
import { paramResource, paramSubResource } from "../../../middleware/resourceId"
|
import { paramResource, paramSubResource } from "../../../middleware/resourceId"
|
||||||
import { PermissionType, PermissionLevel } from "@budibase/types"
|
import { PermissionLevel, PermissionType } from "@budibase/types"
|
||||||
import { CtxFn } from "./utils/Endpoint"
|
import { CtxFn } from "./utils/Endpoint"
|
||||||
import mapperMiddleware from "./middleware/mapper"
|
import mapperMiddleware from "./middleware/mapper"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
|
import { middleware, redis } from "@budibase/backend-core"
|
||||||
|
import { SelectableDatabase } from "@budibase/backend-core/src/redis/utils"
|
||||||
|
import cors from "@koa/cors"
|
||||||
// below imports don't have declaration files
|
// below imports don't have declaration files
|
||||||
const Router = require("@koa/router")
|
const Router = require("@koa/router")
|
||||||
const { RateLimit, Stores } = require("koa2-ratelimit")
|
const { RateLimit, Stores } = require("koa2-ratelimit")
|
||||||
import { middleware, redis } from "@budibase/backend-core"
|
|
||||||
import { SelectableDatabase } from "@budibase/backend-core/src/redis/utils"
|
|
||||||
|
|
||||||
interface KoaRateLimitOptions {
|
interface KoaRateLimitOptions {
|
||||||
socket: {
|
socket: {
|
||||||
|
@ -81,6 +83,7 @@ const publicRouter = new Router({
|
||||||
if (limiter && !env.isDev()) {
|
if (limiter && !env.isDev()) {
|
||||||
publicRouter.use(limiter)
|
publicRouter.use(limiter)
|
||||||
}
|
}
|
||||||
|
publicRouter.use(cors())
|
||||||
|
|
||||||
function addMiddleware(
|
function addMiddleware(
|
||||||
endpoints: any,
|
endpoints: any,
|
||||||
|
@ -149,6 +152,7 @@ applyAdminRoutes(metricEndpoints)
|
||||||
applyAdminRoutes(roleEndpoints)
|
applyAdminRoutes(roleEndpoints)
|
||||||
applyRoutes(appEndpoints, PermissionType.APP, "appId")
|
applyRoutes(appEndpoints, PermissionType.APP, "appId")
|
||||||
applyRoutes(tableEndpoints, PermissionType.TABLE, "tableId")
|
applyRoutes(tableEndpoints, PermissionType.TABLE, "tableId")
|
||||||
|
applyRoutes(viewEndpoints, PermissionType.VIEW, "viewId")
|
||||||
applyRoutes(userEndpoints, PermissionType.USER, "userId")
|
applyRoutes(userEndpoints, PermissionType.USER, "userId")
|
||||||
applyRoutes(queryEndpoints, PermissionType.QUERY, "queryId")
|
applyRoutes(queryEndpoints, PermissionType.QUERY, "queryId")
|
||||||
// needs to be applied last for routing purposes, don't override other endpoints
|
// needs to be applied last for routing purposes, don't override other endpoints
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Ctx } from "@budibase/types"
|
import { Ctx } from "@budibase/types"
|
||||||
import mapping from "../../../controllers/public/mapping"
|
import mapping from "../../../controllers/public/mapping"
|
||||||
|
|
||||||
enum Resources {
|
enum Resource {
|
||||||
APPLICATION = "applications",
|
APPLICATION = "applications",
|
||||||
TABLES = "tables",
|
TABLES = "tables",
|
||||||
|
VIEWS = "views",
|
||||||
ROWS = "rows",
|
ROWS = "rows",
|
||||||
USERS = "users",
|
USERS = "users",
|
||||||
QUERIES = "queries",
|
QUERIES = "queries",
|
||||||
|
@ -15,7 +16,7 @@ function isAttachment(ctx: Ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isArrayResponse(ctx: Ctx) {
|
function isArrayResponse(ctx: Ctx) {
|
||||||
return ctx.url.endsWith(Resources.SEARCH) || Array.isArray(ctx.body)
|
return ctx.url.endsWith(Resource.SEARCH) || Array.isArray(ctx.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
function noResponse(ctx: Ctx) {
|
function noResponse(ctx: Ctx) {
|
||||||
|
@ -38,6 +39,14 @@ function processTables(ctx: Ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function processViews(ctx: Ctx) {
|
||||||
|
if (isArrayResponse(ctx)) {
|
||||||
|
return mapping.mapViews(ctx)
|
||||||
|
} else {
|
||||||
|
return mapping.mapView(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function processRows(ctx: Ctx) {
|
function processRows(ctx: Ctx) {
|
||||||
if (isArrayResponse(ctx)) {
|
if (isArrayResponse(ctx)) {
|
||||||
return mapping.mapRowSearch(ctx)
|
return mapping.mapRowSearch(ctx)
|
||||||
|
@ -71,20 +80,27 @@ export default async (ctx: Ctx, next: any) => {
|
||||||
let body = {}
|
let body = {}
|
||||||
|
|
||||||
switch (urlParts[0]) {
|
switch (urlParts[0]) {
|
||||||
case Resources.APPLICATION:
|
case Resource.APPLICATION:
|
||||||
body = processApplications(ctx)
|
body = processApplications(ctx)
|
||||||
break
|
break
|
||||||
case Resources.TABLES:
|
case Resource.TABLES:
|
||||||
if (urlParts[2] === Resources.ROWS) {
|
if (urlParts[2] === Resource.ROWS) {
|
||||||
body = processRows(ctx)
|
body = processRows(ctx)
|
||||||
} else {
|
} else {
|
||||||
body = processTables(ctx)
|
body = processTables(ctx)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case Resources.USERS:
|
case Resource.VIEWS:
|
||||||
|
if (urlParts[2] === Resource.ROWS) {
|
||||||
|
body = processRows(ctx)
|
||||||
|
} else {
|
||||||
|
body = processViews(ctx)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case Resource.USERS:
|
||||||
body = processUsers(ctx)
|
body = processUsers(ctx)
|
||||||
break
|
break
|
||||||
case Resources.QUERIES:
|
case Resource.QUERIES:
|
||||||
body = processQueries(ctx)
|
body = processQueries(ctx)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import controller from "../../controllers/public/rows"
|
import controller, { viewSearch } from "../../controllers/public/rows"
|
||||||
import Endpoint from "./utils/Endpoint"
|
import Endpoint from "./utils/Endpoint"
|
||||||
import { externalSearchValidator } from "../utils/validators"
|
import { externalSearchValidator } from "../utils/validators"
|
||||||
|
|
||||||
|
@ -168,4 +168,40 @@ read.push(
|
||||||
).addMiddleware(externalSearchValidator())
|
).addMiddleware(externalSearchValidator())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views/{viewId}/rows/search:
|
||||||
|
* post:
|
||||||
|
* operationId: rowViewSearch
|
||||||
|
* summary: Search for rows in a view
|
||||||
|
* tags:
|
||||||
|
* - rows
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/viewId'
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/rowSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: The response will contain an array of rows that match the search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/searchOutput'
|
||||||
|
* examples:
|
||||||
|
* search:
|
||||||
|
* $ref: '#/components/examples/rows'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint(
|
||||||
|
"post",
|
||||||
|
"/views/:viewId/rows/search",
|
||||||
|
controller.viewSearch
|
||||||
|
).addMiddleware(externalSearchValidator())
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
import { User, Table, SearchFilters, Row } from "@budibase/types"
|
import {
|
||||||
|
User,
|
||||||
|
Table,
|
||||||
|
SearchFilters,
|
||||||
|
Row,
|
||||||
|
ViewV2Schema,
|
||||||
|
ViewV2,
|
||||||
|
ViewV2Type,
|
||||||
|
PublicAPIView,
|
||||||
|
} from "@budibase/types"
|
||||||
import { HttpMethod, MakeRequestResponse, generateMakeRequest } from "./utils"
|
import { HttpMethod, MakeRequestResponse, generateMakeRequest } from "./utils"
|
||||||
import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
|
import TestConfiguration from "../../../../tests/utilities/TestConfiguration"
|
||||||
import { Expectations } from "../../../../tests/utilities/api/base"
|
|
||||||
|
|
||||||
type RequestOpts = { internal?: boolean; appId?: string }
|
type RequestOpts = { internal?: boolean; appId?: string }
|
||||||
|
|
||||||
|
type Response<T> = { data: T }
|
||||||
|
|
||||||
export interface PublicAPIExpectations {
|
export interface PublicAPIExpectations {
|
||||||
status?: number
|
status?: number
|
||||||
body?: Record<string, any>
|
body?: Record<string, any>
|
||||||
|
headers?: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PublicAPIRequest {
|
export class PublicAPIRequest {
|
||||||
|
@ -15,6 +26,7 @@ export class PublicAPIRequest {
|
||||||
private appId: string | undefined
|
private appId: string | undefined
|
||||||
|
|
||||||
tables: PublicTableAPI
|
tables: PublicTableAPI
|
||||||
|
views: PublicViewAPI
|
||||||
rows: PublicRowAPI
|
rows: PublicRowAPI
|
||||||
apiKey: string
|
apiKey: string
|
||||||
|
|
||||||
|
@ -28,6 +40,7 @@ export class PublicAPIRequest {
|
||||||
this.appId = appId
|
this.appId = appId
|
||||||
this.tables = new PublicTableAPI(this)
|
this.tables = new PublicTableAPI(this)
|
||||||
this.rows = new PublicRowAPI(this)
|
this.rows = new PublicRowAPI(this)
|
||||||
|
this.views = new PublicViewAPI(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async init(config: TestConfiguration, user: User, opts?: RequestOpts) {
|
static async init(config: TestConfiguration, user: User, opts?: RequestOpts) {
|
||||||
|
@ -59,6 +72,12 @@ export class PublicAPIRequest {
|
||||||
if (expectations?.body) {
|
if (expectations?.body) {
|
||||||
expect(res.body).toEqual(expectations?.body)
|
expect(res.body).toEqual(expectations?.body)
|
||||||
}
|
}
|
||||||
|
if (expectations?.headers) {
|
||||||
|
for (let [header, value] of Object.entries(expectations.headers)) {
|
||||||
|
const found = res.headers[header]
|
||||||
|
expect(found?.toLowerCase()).toEqual(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
return res.body
|
return res.body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,9 +92,16 @@ export class PublicTableAPI {
|
||||||
async create(
|
async create(
|
||||||
table: Table,
|
table: Table,
|
||||||
expectations?: PublicAPIExpectations
|
expectations?: PublicAPIExpectations
|
||||||
): Promise<{ data: Table }> {
|
): Promise<Response<Table>> {
|
||||||
return this.request.send("post", "/tables", table, expectations)
|
return this.request.send("post", "/tables", table, expectations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async search(
|
||||||
|
name: string,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<Table[]>> {
|
||||||
|
return this.request.send("post", "/tables/search", { name }, expectations)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PublicRowAPI {
|
export class PublicRowAPI {
|
||||||
|
@ -85,11 +111,24 @@ export class PublicRowAPI {
|
||||||
this.request = request
|
this.request = request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
tableId: string,
|
||||||
|
row: Row,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<Row>> {
|
||||||
|
return this.request.send(
|
||||||
|
"post",
|
||||||
|
`/tables/${tableId}/rows`,
|
||||||
|
row,
|
||||||
|
expectations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async search(
|
async search(
|
||||||
tableId: string,
|
tableId: string,
|
||||||
query: SearchFilters,
|
query: SearchFilters,
|
||||||
expectations?: PublicAPIExpectations
|
expectations?: PublicAPIExpectations
|
||||||
): Promise<{ data: Row[] }> {
|
): Promise<Response<Row[]>> {
|
||||||
return this.request.send(
|
return this.request.send(
|
||||||
"post",
|
"post",
|
||||||
`/tables/${tableId}/rows/search`,
|
`/tables/${tableId}/rows/search`,
|
||||||
|
@ -99,4 +138,75 @@ export class PublicRowAPI {
|
||||||
expectations
|
expectations
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async viewSearch(
|
||||||
|
viewId: string,
|
||||||
|
query: SearchFilters,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<Row[]>> {
|
||||||
|
return this.request.send(
|
||||||
|
"post",
|
||||||
|
`/views/${viewId}/rows/search`,
|
||||||
|
{
|
||||||
|
query,
|
||||||
|
},
|
||||||
|
expectations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PublicViewAPI {
|
||||||
|
request: PublicAPIRequest
|
||||||
|
|
||||||
|
constructor(request: PublicAPIRequest) {
|
||||||
|
this.request = request
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
view: Omit<PublicAPIView, "id" | "version">,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<PublicAPIView>> {
|
||||||
|
return this.request.send("post", "/views", view, expectations)
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
viewId: string,
|
||||||
|
view: Omit<PublicAPIView, "id" | "version">,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<PublicAPIView>> {
|
||||||
|
return this.request.send("put", `/views/${viewId}`, view, expectations)
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy(
|
||||||
|
viewId: string,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<void> {
|
||||||
|
return this.request.send(
|
||||||
|
"delete",
|
||||||
|
`/views/${viewId}`,
|
||||||
|
undefined,
|
||||||
|
expectations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async find(
|
||||||
|
viewId: string,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<PublicAPIView>> {
|
||||||
|
return this.request.send("get", `/views/${viewId}`, undefined, expectations)
|
||||||
|
}
|
||||||
|
|
||||||
|
async search(
|
||||||
|
viewName: string,
|
||||||
|
expectations?: PublicAPIExpectations
|
||||||
|
): Promise<Response<PublicAPIView[]>> {
|
||||||
|
return this.request.send(
|
||||||
|
"post",
|
||||||
|
"/views/search",
|
||||||
|
{
|
||||||
|
name: viewName,
|
||||||
|
},
|
||||||
|
expectations
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as setup from "../../tests/utilities"
|
||||||
|
import { PublicAPIRequest } from "./Request"
|
||||||
|
|
||||||
|
describe("check public API security", () => {
|
||||||
|
const config = setup.getConfig()
|
||||||
|
let request: PublicAPIRequest
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.init()
|
||||||
|
request = await PublicAPIRequest.init(config, await config.globalUser())
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have Access-Control-Allow-Origin set to *", async () => {
|
||||||
|
await request.tables.search("", {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"access-control-allow-origin": "*",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,95 @@
|
||||||
|
import * as setup from "../../tests/utilities"
|
||||||
|
import { basicTable } from "../../../../tests/utilities/structures"
|
||||||
|
import { BasicOperator, Table, UILogicalOperator } from "@budibase/types"
|
||||||
|
import { PublicAPIRequest } from "./Request"
|
||||||
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
|
|
||||||
|
describe("check public API security", () => {
|
||||||
|
const config = setup.getConfig()
|
||||||
|
let request: PublicAPIRequest, table: Table
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.init()
|
||||||
|
request = await PublicAPIRequest.init(config, await config.globalUser())
|
||||||
|
table = (await request.tables.create(basicTable())).data
|
||||||
|
})
|
||||||
|
|
||||||
|
function baseView() {
|
||||||
|
return {
|
||||||
|
name: generator.word(),
|
||||||
|
tableId: table._id!,
|
||||||
|
query: {},
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
readonly: true,
|
||||||
|
visible: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should be able to create a view", async () => {
|
||||||
|
await request.views.create(baseView(), { status: 201 })
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to update a view", async () => {
|
||||||
|
const view = await request.views.create(baseView(), { status: 201 })
|
||||||
|
const response = await request.views.update(view.data.id, {
|
||||||
|
...view.data,
|
||||||
|
name: "new name",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to search views", async () => {
|
||||||
|
const viewName = "view to search for"
|
||||||
|
const view = await request.views.create(
|
||||||
|
{
|
||||||
|
...baseView(),
|
||||||
|
name: viewName,
|
||||||
|
},
|
||||||
|
{ status: 201 }
|
||||||
|
)
|
||||||
|
const results = await request.views.search(viewName, {
|
||||||
|
status: 200,
|
||||||
|
})
|
||||||
|
expect(results.data.length).toEqual(1)
|
||||||
|
expect(results.data[0].id).toEqual(view.data.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to delete a view", async () => {
|
||||||
|
const view = await request.views.create(baseView(), { status: 201 })
|
||||||
|
const result = await request.views.destroy(view.data.id, { status: 204 })
|
||||||
|
expect(result).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to search rows through a view", async () => {
|
||||||
|
const row1 = await request.rows.create(
|
||||||
|
table._id!,
|
||||||
|
{ name: "hello world" },
|
||||||
|
{ status: 200 }
|
||||||
|
)
|
||||||
|
await request.rows.create(table._id!, { name: "foo bar" }, { status: 200 })
|
||||||
|
const response = await request.views.create(
|
||||||
|
{
|
||||||
|
...baseView(),
|
||||||
|
query: {
|
||||||
|
logicalOperator: UILogicalOperator.ANY,
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
operator: BasicOperator.STRING,
|
||||||
|
field: "name",
|
||||||
|
value: "hello",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ status: 201 }
|
||||||
|
)
|
||||||
|
const results = await request.rows.viewSearch(response.data.id, {})
|
||||||
|
expect(results.data.length).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,165 @@
|
||||||
|
import controller from "../../controllers/public/views"
|
||||||
|
import Endpoint from "./utils/Endpoint"
|
||||||
|
import { viewValidator, nameValidator } from "../utils/validators"
|
||||||
|
|
||||||
|
const read = [],
|
||||||
|
write = []
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views:
|
||||||
|
* post:
|
||||||
|
* operationId: viewCreate
|
||||||
|
* summary: Create a view
|
||||||
|
* description: Create a view, this can be against an internal or external table.
|
||||||
|
* tags:
|
||||||
|
* - views
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/view'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the created view, including the ID which has been generated for it.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/viewOutput'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
*/
|
||||||
|
write.push(
|
||||||
|
new Endpoint("post", "/views", controller.create).addMiddleware(
|
||||||
|
viewValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views/{viewId}:
|
||||||
|
* put:
|
||||||
|
* operationId: viewUpdate
|
||||||
|
* summary: Update a view
|
||||||
|
* description: Update a view, this can be against an internal or external table.
|
||||||
|
* tags:
|
||||||
|
* - views
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/viewId'
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/view'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the updated view.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/viewOutput'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
*/
|
||||||
|
write.push(
|
||||||
|
new Endpoint("put", "/views/:viewId", controller.update).addMiddleware(
|
||||||
|
viewValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views/{viewId}:
|
||||||
|
* delete:
|
||||||
|
* operationId: viewDestroy
|
||||||
|
* summary: Delete a view
|
||||||
|
* description: Delete a view, this can be against an internal or external table.
|
||||||
|
* tags:
|
||||||
|
* - views
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/viewId'
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the deleted view.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/viewOutput'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
*/
|
||||||
|
write.push(new Endpoint("delete", "/views/:viewId", controller.destroy))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views/{viewId}:
|
||||||
|
* get:
|
||||||
|
* operationId: viewGetById
|
||||||
|
* summary: Retrieve a view
|
||||||
|
* description: Lookup a view, this could be internal or external.
|
||||||
|
* tags:
|
||||||
|
* - views
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/viewId'
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the retrieved view.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/viewOutput'
|
||||||
|
* examples:
|
||||||
|
* view:
|
||||||
|
* $ref: '#/components/examples/view'
|
||||||
|
*/
|
||||||
|
read.push(new Endpoint("get", "/views/:viewId", controller.read))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /views/search:
|
||||||
|
* post:
|
||||||
|
* operationId: viewSearch
|
||||||
|
* summary: Search for views
|
||||||
|
* description: Based on view properties (currently only name) search for views.
|
||||||
|
* tags:
|
||||||
|
* - views
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/nameSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the found views, based on the search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/viewSearch'
|
||||||
|
* examples:
|
||||||
|
* views:
|
||||||
|
* $ref: '#/components/examples/views'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint("post", "/views/search", controller.search).addMiddleware(
|
||||||
|
nameValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
export default { read, write }
|
|
@ -2592,6 +2592,33 @@ if (descriptions.length) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("fetch", () => {
|
||||||
|
let view: ViewV2, view2: ViewV2
|
||||||
|
let table: Table, table2: Table
|
||||||
|
beforeEach(async () => {
|
||||||
|
table = await config.api.table.save(saveTableRequest())
|
||||||
|
table2 = await config.api.table.save(saveTableRequest())
|
||||||
|
view = await config.api.viewV2.create({
|
||||||
|
tableId: table._id!,
|
||||||
|
name: generator.guid(),
|
||||||
|
schema: {},
|
||||||
|
})
|
||||||
|
view2 = await config.api.viewV2.create({
|
||||||
|
tableId: table2._id!,
|
||||||
|
name: generator.guid(),
|
||||||
|
schema: {},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to list views", async () => {
|
||||||
|
const response = await config.api.viewV2.fetch({
|
||||||
|
status: 200,
|
||||||
|
})
|
||||||
|
expect(response.data.find(v => v.id === view.id)).toBeDefined()
|
||||||
|
expect(response.data.find(v => v.id === view2.id)).toBeDefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("destroy", () => {
|
describe("destroy", () => {
|
||||||
const getRowUsage = async () => {
|
const getRowUsage = async () => {
|
||||||
const { total } = await config.doInContext(undefined, () =>
|
const { total } = await config.doInContext(undefined, () =>
|
||||||
|
|
|
@ -9,6 +9,13 @@ import {
|
||||||
Table,
|
Table,
|
||||||
WebhookActionType,
|
WebhookActionType,
|
||||||
BuiltinPermissionID,
|
BuiltinPermissionID,
|
||||||
|
ViewV2Type,
|
||||||
|
SortOrder,
|
||||||
|
SortType,
|
||||||
|
UILogicalOperator,
|
||||||
|
BasicOperator,
|
||||||
|
ArrayOperator,
|
||||||
|
RangeOperator,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import Joi, { CustomValidator } from "joi"
|
import Joi, { CustomValidator } from "joi"
|
||||||
import { ValidSnippetNameRegex, helpers } from "@budibase/shared-core"
|
import { ValidSnippetNameRegex, helpers } from "@budibase/shared-core"
|
||||||
|
@ -66,6 +73,66 @@ export function tableValidator() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function searchUIFilterValidator() {
|
||||||
|
const logicalOperator = Joi.string().valid(
|
||||||
|
...Object.values(UILogicalOperator)
|
||||||
|
)
|
||||||
|
const operators = [
|
||||||
|
...Object.values(BasicOperator),
|
||||||
|
...Object.values(ArrayOperator),
|
||||||
|
...Object.values(RangeOperator),
|
||||||
|
]
|
||||||
|
const filters = Joi.array().items(
|
||||||
|
Joi.object({
|
||||||
|
operator: Joi.string()
|
||||||
|
.valid(...operators)
|
||||||
|
.required(),
|
||||||
|
field: Joi.string().required(),
|
||||||
|
// could do with better validation of value based on operator
|
||||||
|
value: Joi.any().required(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
return Joi.object({
|
||||||
|
logicalOperator,
|
||||||
|
onEmptyFilter: Joi.string().valid(...Object.values(EmptyFilterOption)),
|
||||||
|
groups: Joi.array().items(
|
||||||
|
Joi.object({
|
||||||
|
logicalOperator,
|
||||||
|
filters,
|
||||||
|
groups: Joi.array().items(
|
||||||
|
Joi.object({
|
||||||
|
filters,
|
||||||
|
logicalOperator,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function viewValidator() {
|
||||||
|
return auth.joiValidator.body(
|
||||||
|
Joi.object({
|
||||||
|
id: OPTIONAL_STRING,
|
||||||
|
tableId: Joi.string().required(),
|
||||||
|
name: Joi.string().required(),
|
||||||
|
type: Joi.string().optional().valid(null, ViewV2Type.CALCULATION),
|
||||||
|
primaryDisplay: OPTIONAL_STRING,
|
||||||
|
schema: Joi.object().required(),
|
||||||
|
query: searchUIFilterValidator().optional(),
|
||||||
|
sort: Joi.object({
|
||||||
|
field: Joi.string().required(),
|
||||||
|
order: Joi.string()
|
||||||
|
.optional()
|
||||||
|
.valid(...Object.values(SortOrder)),
|
||||||
|
type: Joi.string()
|
||||||
|
.optional()
|
||||||
|
.valid(...Object.values(SortType)),
|
||||||
|
}).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function nameValidator() {
|
export function nameValidator() {
|
||||||
return auth.joiValidator.body(
|
return auth.joiValidator.body(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
|
@ -91,8 +158,7 @@ export function datasourceValidator() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterObject(opts?: { unknown: boolean }) {
|
function searchFiltersValidator() {
|
||||||
const { unknown = true } = opts || {}
|
|
||||||
const conditionalFilteringObject = () =>
|
const conditionalFilteringObject = () =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
conditions: Joi.array().items(Joi.link("#schema")).required(),
|
conditions: Joi.array().items(Joi.link("#schema")).required(),
|
||||||
|
@ -119,7 +185,14 @@ function filterObject(opts?: { unknown: boolean }) {
|
||||||
fuzzyOr: Joi.forbidden(),
|
fuzzyOr: Joi.forbidden(),
|
||||||
documentType: Joi.forbidden(),
|
documentType: Joi.forbidden(),
|
||||||
}
|
}
|
||||||
return Joi.object(filtersValidators).unknown(unknown).id("schema")
|
|
||||||
|
return Joi.object(filtersValidators)
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterObject(opts?: { unknown: boolean }) {
|
||||||
|
const { unknown = true } = opts || {}
|
||||||
|
|
||||||
|
return searchFiltersValidator().unknown(unknown).id("schema")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function internalSearchValidator() {
|
export function internalSearchValidator() {
|
||||||
|
|
|
@ -8,6 +8,11 @@ import { permissions } from "@budibase/backend-core"
|
||||||
const router: Router = new Router()
|
const router: Router = new Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
|
.get(
|
||||||
|
"/api/v2/views",
|
||||||
|
authorized(permissions.BUILDER),
|
||||||
|
viewController.v2.fetch
|
||||||
|
)
|
||||||
.get(
|
.get(
|
||||||
"/api/v2/views/:viewId",
|
"/api/v2/views/:viewId",
|
||||||
authorizedResource(
|
authorizedResource(
|
||||||
|
|
|
@ -65,6 +65,9 @@ export interface paths {
|
||||||
"/tables/{tableId}/rows/search": {
|
"/tables/{tableId}/rows/search": {
|
||||||
post: operations["rowSearch"];
|
post: operations["rowSearch"];
|
||||||
};
|
};
|
||||||
|
"/views/{viewId}/rows/search": {
|
||||||
|
post: operations["rowViewSearch"];
|
||||||
|
};
|
||||||
"/tables": {
|
"/tables": {
|
||||||
/** Create a table, this could be internal or external. */
|
/** Create a table, this could be internal or external. */
|
||||||
post: operations["tableCreate"];
|
post: operations["tableCreate"];
|
||||||
|
@ -93,6 +96,22 @@ export interface paths {
|
||||||
/** Based on user properties (currently only name) search for users. */
|
/** Based on user properties (currently only name) search for users. */
|
||||||
post: operations["userSearch"];
|
post: operations["userSearch"];
|
||||||
};
|
};
|
||||||
|
"/views": {
|
||||||
|
/** Create a view, this can be against an internal or external table. */
|
||||||
|
post: operations["viewCreate"];
|
||||||
|
};
|
||||||
|
"/views/{viewId}": {
|
||||||
|
/** Lookup a view, this could be internal or external. */
|
||||||
|
get: operations["viewGetById"];
|
||||||
|
/** Update a view, this can be against an internal or external table. */
|
||||||
|
put: operations["viewUpdate"];
|
||||||
|
/** Delete a view, this can be against an internal or external table. */
|
||||||
|
delete: operations["viewDestroy"];
|
||||||
|
};
|
||||||
|
"/views/search": {
|
||||||
|
/** Based on view properties (currently only name) search for views. */
|
||||||
|
post: operations["viewSearch"];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface components {
|
export interface components {
|
||||||
|
@ -813,10 +832,442 @@ export interface components {
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/** @description The view to be created/updated. */
|
||||||
|
view: {
|
||||||
|
/** @description The name of the view. */
|
||||||
|
name: string;
|
||||||
|
/** @description The ID of the table this view is based on. */
|
||||||
|
tableId: string;
|
||||||
|
/**
|
||||||
|
* @description The type of view - standard (empty value) or calculation.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "calculation";
|
||||||
|
/** @description A column used to display rows from this view - usually used when rendered in tables. */
|
||||||
|
primaryDisplay?: string;
|
||||||
|
/** @description Search parameters for view */
|
||||||
|
query?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/**
|
||||||
|
* @description If no filters match, should the view return all rows, or no rows.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
onEmptyFilter?: "all" | "none";
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
sort?: {
|
||||||
|
/** @description The field from the table/view schema to sort on. */
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* @description The order in which to sort.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
order?: "ascending" | "descending";
|
||||||
|
/**
|
||||||
|
* @description The type of sort to perform (by number, or by alphabetically).
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "string" | "number";
|
||||||
|
};
|
||||||
|
schema: {
|
||||||
|
[key: string]:
|
||||||
|
| {
|
||||||
|
/** @description Defines whether the column is visible or not - rows retrieved/updated through this view will not be able to access it. */
|
||||||
|
visible?: boolean;
|
||||||
|
/** @description When used in combination with 'visible: true' the column will be visible in row responses but cannot be updated. */
|
||||||
|
readonly?: boolean;
|
||||||
|
/** @description A number defining where the column shows up in tables, lowest being first. */
|
||||||
|
order?: number;
|
||||||
|
/** @description A width for the column, defined in pixels - this affects rendering in tables. */
|
||||||
|
width?: number;
|
||||||
|
/** @description If this is a relationship column, we can set the columns we wish to include */
|
||||||
|
column?: {
|
||||||
|
readonly?: boolean;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* @description This column should be built from a calculation, specifying a type and field. It is important to note when a calculation is configured all non-calculation columns will be used for grouping.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
calculationType?: "sum" | "avg" | "count" | "min" | "max";
|
||||||
|
/** @description The field from the table to perform the calculation on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description Can be used in tandem with the count calculation type, to count unique entries. */
|
||||||
|
distinct?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
viewOutput: {
|
||||||
|
/** @description The view to be created/updated. */
|
||||||
|
data: {
|
||||||
|
/** @description The name of the view. */
|
||||||
|
name: string;
|
||||||
|
/** @description The ID of the table this view is based on. */
|
||||||
|
tableId: string;
|
||||||
|
/**
|
||||||
|
* @description The type of view - standard (empty value) or calculation.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "calculation";
|
||||||
|
/** @description A column used to display rows from this view - usually used when rendered in tables. */
|
||||||
|
primaryDisplay?: string;
|
||||||
|
/** @description Search parameters for view */
|
||||||
|
query?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/**
|
||||||
|
* @description If no filters match, should the view return all rows, or no rows.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
onEmptyFilter?: "all" | "none";
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
sort?: {
|
||||||
|
/** @description The field from the table/view schema to sort on. */
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* @description The order in which to sort.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
order?: "ascending" | "descending";
|
||||||
|
/**
|
||||||
|
* @description The type of sort to perform (by number, or by alphabetically).
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "string" | "number";
|
||||||
|
};
|
||||||
|
schema: {
|
||||||
|
[key: string]:
|
||||||
|
| {
|
||||||
|
/** @description Defines whether the column is visible or not - rows retrieved/updated through this view will not be able to access it. */
|
||||||
|
visible?: boolean;
|
||||||
|
/** @description When used in combination with 'visible: true' the column will be visible in row responses but cannot be updated. */
|
||||||
|
readonly?: boolean;
|
||||||
|
/** @description A number defining where the column shows up in tables, lowest being first. */
|
||||||
|
order?: number;
|
||||||
|
/** @description A width for the column, defined in pixels - this affects rendering in tables. */
|
||||||
|
width?: number;
|
||||||
|
/** @description If this is a relationship column, we can set the columns we wish to include */
|
||||||
|
column?: {
|
||||||
|
readonly?: boolean;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* @description This column should be built from a calculation, specifying a type and field. It is important to note when a calculation is configured all non-calculation columns will be used for grouping.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
calculationType?: "sum" | "avg" | "count" | "min" | "max";
|
||||||
|
/** @description The field from the table to perform the calculation on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description Can be used in tandem with the count calculation type, to count unique entries. */
|
||||||
|
distinct?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description The ID of the view. */
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
viewSearch: {
|
||||||
|
data: {
|
||||||
|
/** @description The name of the view. */
|
||||||
|
name: string;
|
||||||
|
/** @description The ID of the table this view is based on. */
|
||||||
|
tableId: string;
|
||||||
|
/**
|
||||||
|
* @description The type of view - standard (empty value) or calculation.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "calculation";
|
||||||
|
/** @description A column used to display rows from this view - usually used when rendered in tables. */
|
||||||
|
primaryDisplay?: string;
|
||||||
|
/** @description Search parameters for view */
|
||||||
|
query?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/**
|
||||||
|
* @description If no filters match, should the view return all rows, or no rows.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
onEmptyFilter?: "all" | "none";
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
/** @description A grouping of filters to be applied. */
|
||||||
|
groups?: {
|
||||||
|
/**
|
||||||
|
* @description When using groups this defines whether all of the filters must match, or only one of them.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
logicalOperator?: "all" | "any";
|
||||||
|
/** @description A list of filters to apply */
|
||||||
|
filters?: {
|
||||||
|
/**
|
||||||
|
* @description The type of search operation which is being performed.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
operator?:
|
||||||
|
| "equal"
|
||||||
|
| "notEqual"
|
||||||
|
| "empty"
|
||||||
|
| "notEmpty"
|
||||||
|
| "fuzzy"
|
||||||
|
| "string"
|
||||||
|
| "contains"
|
||||||
|
| "notContains"
|
||||||
|
| "containsAny"
|
||||||
|
| "oneOf"
|
||||||
|
| "range";
|
||||||
|
/** @description The field in the view to perform the search on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description The value to search for - the type will depend on the operator in use. */
|
||||||
|
value?:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| { [key: string]: unknown }
|
||||||
|
| unknown[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
sort?: {
|
||||||
|
/** @description The field from the table/view schema to sort on. */
|
||||||
|
field: string;
|
||||||
|
/**
|
||||||
|
* @description The order in which to sort.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
order?: "ascending" | "descending";
|
||||||
|
/**
|
||||||
|
* @description The type of sort to perform (by number, or by alphabetically).
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
type?: "string" | "number";
|
||||||
|
};
|
||||||
|
schema: {
|
||||||
|
[key: string]:
|
||||||
|
| {
|
||||||
|
/** @description Defines whether the column is visible or not - rows retrieved/updated through this view will not be able to access it. */
|
||||||
|
visible?: boolean;
|
||||||
|
/** @description When used in combination with 'visible: true' the column will be visible in row responses but cannot be updated. */
|
||||||
|
readonly?: boolean;
|
||||||
|
/** @description A number defining where the column shows up in tables, lowest being first. */
|
||||||
|
order?: number;
|
||||||
|
/** @description A width for the column, defined in pixels - this affects rendering in tables. */
|
||||||
|
width?: number;
|
||||||
|
/** @description If this is a relationship column, we can set the columns we wish to include */
|
||||||
|
column?: {
|
||||||
|
readonly?: boolean;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/**
|
||||||
|
* @description This column should be built from a calculation, specifying a type and field. It is important to note when a calculation is configured all non-calculation columns will be used for grouping.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
calculationType?: "sum" | "avg" | "count" | "min" | "max";
|
||||||
|
/** @description The field from the table to perform the calculation on. */
|
||||||
|
field?: string;
|
||||||
|
/** @description Can be used in tandem with the count calculation type, to count unique entries. */
|
||||||
|
distinct?: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description The ID of the view. */
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
parameters: {
|
parameters: {
|
||||||
/** @description The ID of the table which this request is targeting. */
|
/** @description The ID of the table which this request is targeting. */
|
||||||
tableId: string;
|
tableId: string;
|
||||||
|
/** @description The ID of the view which this request is targeting. */
|
||||||
|
viewId: string;
|
||||||
/** @description The ID of the row which this request is targeting. */
|
/** @description The ID of the row which this request is targeting. */
|
||||||
rowId: string;
|
rowId: string;
|
||||||
/** @description The ID of the app which this request is targeting. */
|
/** @description The ID of the app which this request is targeting. */
|
||||||
|
@ -1213,6 +1664,31 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
rowViewSearch: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** The ID of the view which this request is targeting. */
|
||||||
|
viewId: components["parameters"]["viewId"];
|
||||||
|
};
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** The response will contain an array of rows that match the search parameters. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["searchOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["rowSearch"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/** Create a table, this could be internal or external. */
|
/** Create a table, this could be internal or external. */
|
||||||
tableCreate: {
|
tableCreate: {
|
||||||
parameters: {
|
parameters: {
|
||||||
|
@ -1409,6 +1885,118 @@ export interface operations {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/** Create a view, this can be against an internal or external table. */
|
||||||
|
viewCreate: {
|
||||||
|
parameters: {
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** Returns the created view, including the ID which has been generated for it. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["viewOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["view"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** Lookup a view, this could be internal or external. */
|
||||||
|
viewGetById: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** The ID of the view which this request is targeting. */
|
||||||
|
viewId: components["parameters"]["viewId"];
|
||||||
|
};
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** Returns the retrieved view. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["viewOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** Update a view, this can be against an internal or external table. */
|
||||||
|
viewUpdate: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** The ID of the view which this request is targeting. */
|
||||||
|
viewId: components["parameters"]["viewId"];
|
||||||
|
};
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** Returns the updated view. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["viewOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["view"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** Delete a view, this can be against an internal or external table. */
|
||||||
|
viewDestroy: {
|
||||||
|
parameters: {
|
||||||
|
path: {
|
||||||
|
/** The ID of the view which this request is targeting. */
|
||||||
|
viewId: components["parameters"]["viewId"];
|
||||||
|
};
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** Returns the deleted view. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["viewOutput"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** Based on view properties (currently only name) search for views. */
|
||||||
|
viewSearch: {
|
||||||
|
parameters: {
|
||||||
|
header: {
|
||||||
|
/** The ID of the app which this request is targeting. */
|
||||||
|
"x-budibase-app-id": components["parameters"]["appId"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** Returns the found views, based on the search parameters. */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["viewSearch"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["nameSearch"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface external {}
|
export interface external {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { constants, utils } from "@budibase/backend-core"
|
import { constants, utils } from "@budibase/backend-core"
|
||||||
import { BBContext } from "@budibase/types"
|
import { Ctx } from "@budibase/types"
|
||||||
|
|
||||||
export default function ({ requiresAppId }: { requiresAppId?: boolean } = {}) {
|
export default function ({ requiresAppId }: { requiresAppId?: boolean } = {}) {
|
||||||
return async (ctx: BBContext, next: any) => {
|
return async (ctx: Ctx, next: any) => {
|
||||||
const appId = await utils.getAppIdFromCtx(ctx)
|
const appId = await utils.getAppIdFromCtx(ctx)
|
||||||
if (requiresAppId && !appId) {
|
if (requiresAppId && !appId) {
|
||||||
ctx.throw(
|
ctx.throw(
|
||||||
|
|
|
@ -78,8 +78,11 @@ export async function getAllInternalTables(db?: Database): Promise<Table[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAllExternalTables(): Promise<Table[]> {
|
async function getAllExternalTables(): Promise<Table[]> {
|
||||||
|
// this is all datasources, we'll need to filter out internal
|
||||||
const datasources = await sdk.datasources.fetch({ enriched: true })
|
const datasources = await sdk.datasources.fetch({ enriched: true })
|
||||||
const allEntities = datasources.map(datasource => datasource.entities)
|
const allEntities = datasources
|
||||||
|
.filter(datasource => datasource._id !== INTERNAL_TABLE_SOURCE_ID)
|
||||||
|
.map(datasource => datasource.entities)
|
||||||
let final: Table[] = []
|
let final: Table[] = []
|
||||||
for (let entities of allEntities) {
|
for (let entities of allEntities) {
|
||||||
if (entities) {
|
if (entities) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { isExternalTableID } from "../../../integrations/utils"
|
||||||
import * as internal from "./internal"
|
import * as internal from "./internal"
|
||||||
import * as external from "./external"
|
import * as external from "./external"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
|
import { ensureQueryUISet } from "./utils"
|
||||||
|
|
||||||
function pickApi(tableId: any) {
|
function pickApi(tableId: any) {
|
||||||
if (isExternalTableID(tableId)) {
|
if (isExternalTableID(tableId)) {
|
||||||
|
@ -44,6 +45,24 @@ export async function getEnriched(viewId: string): Promise<ViewV2Enriched> {
|
||||||
return pickApi(tableId).getEnriched(viewId)
|
return pickApi(tableId).getEnriched(viewId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAllEnriched(): Promise<ViewV2Enriched[]> {
|
||||||
|
const tables = await sdk.tables.getAllTables()
|
||||||
|
let views: ViewV2Enriched[] = []
|
||||||
|
for (let table of tables) {
|
||||||
|
if (!table.views || Object.keys(table.views).length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const v2Views = Object.values(table.views).filter(isV2)
|
||||||
|
const enrichedViews = await Promise.all(
|
||||||
|
v2Views.map(view =>
|
||||||
|
enrichSchema(ensureQueryUISet(view), table.schema, tables)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
views = views.concat(enrichedViews)
|
||||||
|
}
|
||||||
|
return views
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTable(view: string | ViewV2): Promise<Table> {
|
export async function getTable(view: string | ViewV2): Promise<Table> {
|
||||||
const viewId = typeof view === "string" ? view : view.id
|
const viewId = typeof view === "string" ? view : view.id
|
||||||
const cached = context.getTableForView(viewId)
|
const cached = context.getTableForView(viewId)
|
||||||
|
@ -333,13 +352,19 @@ export function allowedFields(
|
||||||
|
|
||||||
export async function enrichSchema(
|
export async function enrichSchema(
|
||||||
view: ViewV2,
|
view: ViewV2,
|
||||||
tableSchema: TableSchema
|
tableSchema: TableSchema,
|
||||||
|
tables?: Table[]
|
||||||
): Promise<ViewV2Enriched> {
|
): Promise<ViewV2Enriched> {
|
||||||
async function populateRelTableSchema(
|
async function populateRelTableSchema(
|
||||||
tableId: string,
|
tableId: string,
|
||||||
viewFields: Record<string, RelationSchemaField>
|
viewFields: Record<string, RelationSchemaField>
|
||||||
) {
|
) {
|
||||||
const relTable = await sdk.tables.getTable(tableId)
|
let relTable = tables
|
||||||
|
? tables?.find(t => t._id === tableId)
|
||||||
|
: await sdk.tables.getTable(tableId)
|
||||||
|
if (!relTable) {
|
||||||
|
throw new Error("Cannot enrich relationship, table not found")
|
||||||
|
}
|
||||||
const result: Record<string, ViewV2ColumnEnriched> = {}
|
const result: Record<string, ViewV2ColumnEnriched> = {}
|
||||||
for (const relTableFieldName of Object.keys(relTable.schema)) {
|
for (const relTableFieldName of Object.keys(relTable.schema)) {
|
||||||
const relTableField = relTable.schema[relTableFieldName]
|
const relTableField = relTable.schema[relTableFieldName]
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
SearchViewRowRequest,
|
SearchViewRowRequest,
|
||||||
PaginatedSearchRowResponse,
|
PaginatedSearchRowResponse,
|
||||||
ViewResponseEnriched,
|
ViewResponseEnriched,
|
||||||
|
ViewFetchResponseEnriched,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { Expectations, TestAPI } from "./base"
|
import { Expectations, TestAPI } from "./base"
|
||||||
|
|
||||||
|
@ -49,6 +50,12 @@ export class ViewV2API extends TestAPI {
|
||||||
.data
|
.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetch = async (expectations?: Expectations) => {
|
||||||
|
return await this._get<ViewFetchResponseEnriched>(`/api/v2/views`, {
|
||||||
|
expectations,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
search = async (
|
search = async (
|
||||||
viewId: string,
|
viewId: string,
|
||||||
params?: SearchViewRowRequest,
|
params?: SearchViewRowRequest,
|
||||||
|
|
|
@ -9,6 +9,10 @@ export interface ViewResponseEnriched {
|
||||||
data: ViewV2Enriched
|
data: ViewV2Enriched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ViewFetchResponseEnriched {
|
||||||
|
data: ViewV2Enriched[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateViewRequest extends Omit<ViewV2, "version" | "id"> {}
|
export interface CreateViewRequest extends Omit<ViewV2, "version" | "id"> {}
|
||||||
|
|
||||||
export interface UpdateViewRequest extends ViewV2 {}
|
export interface UpdateViewRequest extends ViewV2 {}
|
||||||
|
|
|
@ -101,6 +101,10 @@ export interface ViewV2 {
|
||||||
schema?: ViewV2Schema
|
schema?: ViewV2Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PublicAPIView extends Omit<ViewV2, "query" | "queryUI"> {
|
||||||
|
query?: UISearchFilter
|
||||||
|
}
|
||||||
|
|
||||||
export type ViewV2Schema = Record<string, ViewFieldMetadata>
|
export type ViewV2Schema = Record<string, ViewFieldMetadata>
|
||||||
|
|
||||||
export type ViewSchema = ViewCountOrSumSchema | ViewStatisticsSchema
|
export type ViewSchema = ViewCountOrSumSchema | ViewStatisticsSchema
|
||||||
|
|
|
@ -8,7 +8,7 @@ export interface RowValue {
|
||||||
export interface RowResponse<T extends Document | RowValue> {
|
export interface RowResponse<T extends Document | RowValue> {
|
||||||
id: string
|
id: string
|
||||||
key: string
|
key: string
|
||||||
error: string
|
error?: string
|
||||||
value: T
|
value: T
|
||||||
doc?: T
|
doc?: T
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,8 +163,8 @@ export interface Database {
|
||||||
viewName: string,
|
viewName: string,
|
||||||
params: DatabaseQueryOpts
|
params: DatabaseQueryOpts
|
||||||
): Promise<AllDocsResponse<T>>
|
): Promise<AllDocsResponse<T>>
|
||||||
destroy(): Promise<Nano.OkResponse | void>
|
destroy(): Promise<Nano.OkResponse>
|
||||||
compact(): Promise<Nano.OkResponse | void>
|
compact(): Promise<Nano.OkResponse>
|
||||||
// these are all PouchDB related functions that are rarely used - in future
|
// these are all PouchDB related functions that are rarely used - in future
|
||||||
// should be replaced by better typed/non-pouch implemented methods
|
// should be replaced by better typed/non-pouch implemented methods
|
||||||
dump(stream: Writable, opts?: DatabaseDumpOpts): Promise<any>
|
dump(stream: Writable, opts?: DatabaseDumpOpts): Promise<any>
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
"bcrypt": "5.1.0",
|
"bcrypt": "5.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bull": "4.10.1",
|
"bull": "4.10.1",
|
||||||
"dd-trace": "5.23.0",
|
"dd-trace": "5.26.0",
|
||||||
"dotenv": "8.6.0",
|
"dotenv": "8.6.0",
|
||||||
"email-validator": "^2.0.4",
|
"email-validator": "^2.0.4",
|
||||||
"global-agent": "3.0.0",
|
"global-agent": "3.0.0",
|
||||||
|
|
165
yarn.lock
165
yarn.lock
|
@ -2210,7 +2210,7 @@
|
||||||
bcryptjs "2.4.3"
|
bcryptjs "2.4.3"
|
||||||
bull "4.10.1"
|
bull "4.10.1"
|
||||||
correlation-id "4.0.0"
|
correlation-id "4.0.0"
|
||||||
dd-trace "5.23.0"
|
dd-trace "5.26.0"
|
||||||
dotenv "16.0.1"
|
dotenv "16.0.1"
|
||||||
google-auth-library "^8.0.1"
|
google-auth-library "^8.0.1"
|
||||||
google-spreadsheet "npm:@budibase/google-spreadsheet@4.1.5"
|
google-spreadsheet "npm:@budibase/google-spreadsheet@4.1.5"
|
||||||
|
@ -2477,6 +2477,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@dagrejs/graphlib/-/graphlib-2.2.4.tgz#d77bfa9ff49e2307c0c6e6b8b26b5dd3c05816c4"
|
resolved "https://registry.yarnpkg.com/@dagrejs/graphlib/-/graphlib-2.2.4.tgz#d77bfa9ff49e2307c0c6e6b8b26b5dd3c05816c4"
|
||||||
integrity sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==
|
integrity sha512-mepCf/e9+SKYy1d02/UkvSy6+6MoyXhVxP8lLDfA7BPE1X1d4dR0sZznmbM8/XVJ1GPM+Svnx7Xj6ZweByWUkw==
|
||||||
|
|
||||||
|
"@datadog/libdatadog@^0.2.2":
|
||||||
|
version "0.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/libdatadog/-/libdatadog-0.2.2.tgz#ac02c76ac9a38250dca740727c7cdf00244ce3d3"
|
||||||
|
integrity sha512-rTWo96mEPTY5UbtGoFj8/wY0uKSViJhsPg/Z6aoFWBFXQ8b45Ix2e/yvf92AAwrhG+gPLTxEqTXh3kef2dP8Ow==
|
||||||
|
|
||||||
"@datadog/native-appsec@8.1.1":
|
"@datadog/native-appsec@8.1.1":
|
||||||
version "8.1.1"
|
version "8.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.1.1.tgz#76aa34697e6ecbd3d9ef7e6938d3cdcfa689b1f3"
|
resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.1.1.tgz#76aa34697e6ecbd3d9ef7e6938d3cdcfa689b1f3"
|
||||||
|
@ -2484,6 +2489,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
node-gyp-build "^3.9.0"
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
|
"@datadog/native-appsec@8.3.0":
|
||||||
|
version "8.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.3.0.tgz#91afd89d18d386be4da8a1b0e04500f2f8b5eb66"
|
||||||
|
integrity sha512-RYHbSJ/MwJcJaLzaCaZvUyNLUKFbMshayIiv4ckpFpQJDiq1T8t9iM2k7008s75g1vRuXfsRNX7MaLn4aoFuWA==
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
"@datadog/native-iast-rewriter@2.4.1":
|
"@datadog/native-iast-rewriter@2.4.1":
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.4.1.tgz#e8211f78c818906513fb96a549374da0382c7623"
|
resolved "https://registry.yarnpkg.com/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.4.1.tgz#e8211f78c818906513fb96a549374da0382c7623"
|
||||||
|
@ -2492,6 +2504,14 @@
|
||||||
lru-cache "^7.14.0"
|
lru-cache "^7.14.0"
|
||||||
node-gyp-build "^4.5.0"
|
node-gyp-build "^4.5.0"
|
||||||
|
|
||||||
|
"@datadog/native-iast-rewriter@2.5.0":
|
||||||
|
version "2.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/native-iast-rewriter/-/native-iast-rewriter-2.5.0.tgz#b613defe86e78168f750d1f1662d4ffb3cf002e6"
|
||||||
|
integrity sha512-WRu34A3Wwp6oafX8KWNAbedtDaaJO+nzfYQht7pcJKjyC2ggfPeF7SoP+eDo9wTn4/nQwEOscSR4hkJqTRlpXQ==
|
||||||
|
dependencies:
|
||||||
|
lru-cache "^7.14.0"
|
||||||
|
node-gyp-build "^4.5.0"
|
||||||
|
|
||||||
"@datadog/native-iast-taint-tracking@3.1.0":
|
"@datadog/native-iast-taint-tracking@3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-3.1.0.tgz#7b2ed7f8fad212d65e5ab03bcdea8b42a3051b2e"
|
resolved "https://registry.yarnpkg.com/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-3.1.0.tgz#7b2ed7f8fad212d65e5ab03bcdea8b42a3051b2e"
|
||||||
|
@ -2499,6 +2519,13 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
node-gyp-build "^3.9.0"
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
|
"@datadog/native-iast-taint-tracking@3.2.0":
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/native-iast-taint-tracking/-/native-iast-taint-tracking-3.2.0.tgz#9fb6823d82f934e12c06ea1baa7399ca80deb2ec"
|
||||||
|
integrity sha512-Mc6FzCoyvU5yXLMsMS9yKnEqJMWoImAukJXolNWCTm+JQYCMf2yMsJ8pBAm7KyZKliamM9rCn7h7Tr2H3lXwjA==
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
"@datadog/native-metrics@^2.0.0":
|
"@datadog/native-metrics@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-2.0.0.tgz#65bf03313ee419956361e097551db36173e85712"
|
resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-2.0.0.tgz#65bf03313ee419956361e097551db36173e85712"
|
||||||
|
@ -2507,6 +2534,14 @@
|
||||||
node-addon-api "^6.1.0"
|
node-addon-api "^6.1.0"
|
||||||
node-gyp-build "^3.9.0"
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
|
"@datadog/native-metrics@^3.0.1":
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-3.0.1.tgz#dc276c93785c0377a048e316f23b7c8ff3acfa84"
|
||||||
|
integrity sha512-0GuMyYyXf+Qpb/F+Fcekz58f2mO37lit9U3jMbWY/m8kac44gCPABzL5q3gWbdH+hWgqYfQoEYsdNDGSrKfwoQ==
|
||||||
|
dependencies:
|
||||||
|
node-addon-api "^6.1.0"
|
||||||
|
node-gyp-build "^3.9.0"
|
||||||
|
|
||||||
"@datadog/pprof@5.3.0":
|
"@datadog/pprof@5.3.0":
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219"
|
resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.3.0.tgz#c2f58d328ecced7f99887f1a559d7fe3aecb9219"
|
||||||
|
@ -2518,6 +2553,17 @@
|
||||||
pprof-format "^2.1.0"
|
pprof-format "^2.1.0"
|
||||||
source-map "^0.7.4"
|
source-map "^0.7.4"
|
||||||
|
|
||||||
|
"@datadog/pprof@5.4.1":
|
||||||
|
version "5.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-5.4.1.tgz#08c9bcf5d8efb2eeafdfc9f5bb5402f79fb41266"
|
||||||
|
integrity sha512-IvpL96e/cuh8ugP5O8Czdup7XQOLHeIDgM5pac5W7Lc1YzGe5zTtebKFpitvb1CPw1YY+1qFx0pWGgKP2kOfHg==
|
||||||
|
dependencies:
|
||||||
|
delay "^5.0.0"
|
||||||
|
node-gyp-build "<4.0"
|
||||||
|
p-limit "^3.1.0"
|
||||||
|
pprof-format "^2.1.0"
|
||||||
|
source-map "^0.7.4"
|
||||||
|
|
||||||
"@datadog/sketches-js@^2.1.0":
|
"@datadog/sketches-js@^2.1.0":
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@datadog/sketches-js/-/sketches-js-2.1.0.tgz#8c7e8028a5fc22ad102fa542b0a446c956830455"
|
resolved "https://registry.yarnpkg.com/@datadog/sketches-js/-/sketches-js-2.1.0.tgz#8c7e8028a5fc22ad102fa542b0a446c956830455"
|
||||||
|
@ -2846,6 +2892,11 @@
|
||||||
wrap-ansi "^8.1.0"
|
wrap-ansi "^8.1.0"
|
||||||
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
|
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
|
||||||
|
|
||||||
|
"@isaacs/ttlcache@^1.4.1":
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz#21fb23db34e9b6220c6ba023a0118a2dd3461ea2"
|
||||||
|
integrity sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==
|
||||||
|
|
||||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
|
||||||
|
@ -3428,6 +3479,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@jsep-plugin/regex/-/regex-1.0.4.tgz#cb2fc423220fa71c609323b9ba7f7d344a755fcc"
|
resolved "https://registry.yarnpkg.com/@jsep-plugin/regex/-/regex-1.0.4.tgz#cb2fc423220fa71c609323b9ba7f7d344a755fcc"
|
||||||
integrity sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==
|
integrity sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==
|
||||||
|
|
||||||
|
"@koa/cors@5.0.0":
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-5.0.0.tgz#0029b5f057fa0d0ae0e37dd2c89ece315a0daffd"
|
||||||
|
integrity sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==
|
||||||
|
dependencies:
|
||||||
|
vary "^1.1.2"
|
||||||
|
|
||||||
"@koa/router@13.1.0":
|
"@koa/router@13.1.0":
|
||||||
version "13.1.0"
|
version "13.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@koa/router/-/router-13.1.0.tgz#43f4c554444ea4f4a148a5735a9525c6d16fd1b5"
|
resolved "https://registry.yarnpkg.com/@koa/router/-/router-13.1.0.tgz#43f4c554444ea4f4a148a5735a9525c6d16fd1b5"
|
||||||
|
@ -5698,6 +5756,13 @@
|
||||||
"@types/koa-compose" "*"
|
"@types/koa-compose" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/koa__cors@5.0.0":
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-5.0.0.tgz#74567a045b599266e2cd3940cef96cedecc2ef1f"
|
||||||
|
integrity sha512-LCk/n25Obq5qlernGOK/2LUwa/2YJb2lxHUkkvYFDOpLXlVI6tKcdfCHRBQnOY4LwH6el5WOLs6PD/a8Uzau6g==
|
||||||
|
dependencies:
|
||||||
|
"@types/koa" "*"
|
||||||
|
|
||||||
"@types/koa__router@12.0.4":
|
"@types/koa__router@12.0.4":
|
||||||
version "12.0.4"
|
version "12.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@types/koa__router/-/koa__router-12.0.4.tgz#a1f9afec9dc7e7d9fa1252d1938c44b403e19a28"
|
resolved "https://registry.yarnpkg.com/@types/koa__router/-/koa__router-12.0.4.tgz#a1f9afec9dc7e7d9fa1252d1938c44b403e19a28"
|
||||||
|
@ -8920,6 +8985,15 @@ cron-validate@1.4.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
yup "0.32.9"
|
yup "0.32.9"
|
||||||
|
|
||||||
|
cross-spawn@7.0.6:
|
||||||
|
version "7.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||||
|
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||||
|
dependencies:
|
||||||
|
path-key "^3.1.0"
|
||||||
|
shebang-command "^2.0.0"
|
||||||
|
which "^2.0.1"
|
||||||
|
|
||||||
cross-spawn@^6.0.0:
|
cross-spawn@^6.0.0:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||||
|
@ -9292,6 +9366,44 @@ dd-trace@5.23.0:
|
||||||
shell-quote "^1.8.1"
|
shell-quote "^1.8.1"
|
||||||
tlhunter-sorted-set "^0.1.0"
|
tlhunter-sorted-set "^0.1.0"
|
||||||
|
|
||||||
|
dd-trace@5.26.0:
|
||||||
|
version "5.26.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dd-trace/-/dd-trace-5.26.0.tgz#cc55061f66742bf01d0d7dc9f75c0e4937c82f40"
|
||||||
|
integrity sha512-AQ4usxrbAG41f7CKUUe7fayZgfrh24D0L0vNzcU2mMJOmqQ3bXeDz9uSHkF3aFY8Epcsegrep3ifjRC0/zOxTw==
|
||||||
|
dependencies:
|
||||||
|
"@datadog/libdatadog" "^0.2.2"
|
||||||
|
"@datadog/native-appsec" "8.3.0"
|
||||||
|
"@datadog/native-iast-rewriter" "2.5.0"
|
||||||
|
"@datadog/native-iast-taint-tracking" "3.2.0"
|
||||||
|
"@datadog/native-metrics" "^3.0.1"
|
||||||
|
"@datadog/pprof" "5.4.1"
|
||||||
|
"@datadog/sketches-js" "^2.1.0"
|
||||||
|
"@isaacs/ttlcache" "^1.4.1"
|
||||||
|
"@opentelemetry/api" ">=1.0.0 <1.9.0"
|
||||||
|
"@opentelemetry/core" "^1.14.0"
|
||||||
|
crypto-randomuuid "^1.0.0"
|
||||||
|
dc-polyfill "^0.1.4"
|
||||||
|
ignore "^5.2.4"
|
||||||
|
import-in-the-middle "1.11.2"
|
||||||
|
int64-buffer "^0.1.9"
|
||||||
|
istanbul-lib-coverage "3.2.0"
|
||||||
|
jest-docblock "^29.7.0"
|
||||||
|
koalas "^1.0.2"
|
||||||
|
limiter "1.1.5"
|
||||||
|
lodash.sortby "^4.7.0"
|
||||||
|
lru-cache "^7.14.0"
|
||||||
|
module-details-from-path "^1.0.3"
|
||||||
|
msgpack-lite "^0.1.26"
|
||||||
|
opentracing ">=0.12.1"
|
||||||
|
path-to-regexp "^0.1.10"
|
||||||
|
pprof-format "^2.1.0"
|
||||||
|
protobufjs "^7.2.5"
|
||||||
|
retry "^0.13.1"
|
||||||
|
rfdc "^1.3.1"
|
||||||
|
semver "^7.5.4"
|
||||||
|
shell-quote "^1.8.1"
|
||||||
|
tlhunter-sorted-set "^0.1.0"
|
||||||
|
|
||||||
debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4:
|
debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4:
|
||||||
version "4.3.6"
|
version "4.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b"
|
||||||
|
@ -20147,16 +20259,7 @@ string-range@~1.2, string-range@~1.2.1:
|
||||||
resolved "https://registry.yarnpkg.com/string-range/-/string-range-1.2.2.tgz#a893ed347e72299bc83befbbf2a692a8d239d5dd"
|
resolved "https://registry.yarnpkg.com/string-range/-/string-range-1.2.2.tgz#a893ed347e72299bc83befbbf2a692a8d239d5dd"
|
||||||
integrity sha512-tYft6IFi8SjplJpxCUxyqisD3b+R2CSkomrtJYCkvuf1KuCAWgz7YXt4O0jip7efpfCemwHEzTEAO8EuOYgh3w==
|
integrity sha512-tYft6IFi8SjplJpxCUxyqisD3b+R2CSkomrtJYCkvuf1KuCAWgz7YXt4O0jip7efpfCemwHEzTEAO8EuOYgh3w==
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
||||||
version "4.2.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
|
||||||
dependencies:
|
|
||||||
emoji-regex "^8.0.0"
|
|
||||||
is-fullwidth-code-point "^3.0.0"
|
|
||||||
strip-ansi "^6.0.1"
|
|
||||||
|
|
||||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
|
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
|
@ -20248,7 +20351,7 @@ stringify-object@^3.2.1:
|
||||||
is-obj "^1.0.1"
|
is-obj "^1.0.1"
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
|
@ -20262,13 +20365,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex "^4.1.0"
|
ansi-regex "^4.1.0"
|
||||||
|
|
||||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^5.0.1"
|
|
||||||
|
|
||||||
strip-ansi@^7.0.1:
|
strip-ansi@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
|
||||||
|
@ -20517,6 +20613,26 @@ svelte-spa-router@^4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
regexparam "2.0.2"
|
regexparam "2.0.2"
|
||||||
|
|
||||||
|
svelte@4.2.19:
|
||||||
|
version "4.2.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-4.2.19.tgz#4e6e84a8818e2cd04ae0255fcf395bc211e61d4c"
|
||||||
|
integrity sha512-IY1rnGr6izd10B0A8LqsBfmlT5OILVuZ7XsI0vdGPEvuonFV7NYEUK4dAkm9Zg2q0Um92kYjTpS1CAP3Nh/KWw==
|
||||||
|
dependencies:
|
||||||
|
"@ampproject/remapping" "^2.2.1"
|
||||||
|
"@jridgewell/sourcemap-codec" "^1.4.15"
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.18"
|
||||||
|
"@types/estree" "^1.0.1"
|
||||||
|
acorn "^8.9.0"
|
||||||
|
aria-query "^5.3.0"
|
||||||
|
axobject-query "^4.0.0"
|
||||||
|
code-red "^1.0.3"
|
||||||
|
css-tree "^2.3.1"
|
||||||
|
estree-walker "^3.0.3"
|
||||||
|
is-reference "^3.0.1"
|
||||||
|
locate-character "^3.0.0"
|
||||||
|
magic-string "^0.30.4"
|
||||||
|
periscopic "^3.1.0"
|
||||||
|
|
||||||
svelte@^4.2.10:
|
svelte@^4.2.10:
|
||||||
version "4.2.12"
|
version "4.2.12"
|
||||||
resolved "https://registry.yarnpkg.com/svelte/-/svelte-4.2.12.tgz#13d98d2274d24d3ad216c8fdc801511171c70bb1"
|
resolved "https://registry.yarnpkg.com/svelte/-/svelte-4.2.12.tgz#13d98d2274d24d3ad216c8fdc801511171c70bb1"
|
||||||
|
@ -22054,7 +22170,7 @@ worker-farm@1.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
errno "~0.1.7"
|
errno "~0.1.7"
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
|
@ -22072,15 +22188,6 @@ wrap-ansi@^5.1.0:
|
||||||
string-width "^3.0.0"
|
string-width "^3.0.0"
|
||||||
strip-ansi "^5.0.0"
|
strip-ansi "^5.0.0"
|
||||||
|
|
||||||
wrap-ansi@^7.0.0:
|
|
||||||
version "7.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.0.0"
|
|
||||||
string-width "^4.1.0"
|
|
||||||
strip-ansi "^6.0.0"
|
|
||||||
|
|
||||||
wrap-ansi@^8.1.0:
|
wrap-ansi@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||||
|
|
Loading…
Reference in New Issue