Adding controllers for row, query and applications public APIs.

This commit is contained in:
mike12345567 2022-02-23 18:31:32 +00:00
parent 8685abf99e
commit 8f6e55e65b
12 changed files with 310 additions and 33 deletions

View File

@ -32,11 +32,10 @@ const populateFromDB = async (userId, tenantId) => {
* @param {*} populateUser function to provide the user for re-caching. default to couch db * @param {*} populateUser function to provide the user for re-caching. default to couch db
* @returns * @returns
*/ */
exports.getUser = async ( exports.getUser = async (userId, tenantId = null, populateUser = null) => {
userId, if (!populateUser) {
tenantId = null, populateUser = populateFromDB
populateUser = populateFromDB }
) => {
if (!tenantId) { if (!tenantId) {
try { try {
tenantId = getTenantId() tenantId = getTenantId()

View File

@ -68,6 +68,7 @@ function getDocParams(docType, docId = null, otherProps = {}) {
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`, endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
} }
} }
exports.getDocParams = getDocParams
/** /**
* Generates a new workspace ID. * Generates a new workspace ID.

View File

@ -335,6 +335,42 @@
] ]
} }
}, },
"restResponse": {
"value": {
"data": [
{
"value": "<html lang='en-GB'></html>"
}
],
"pagination": {
"cursor": "2"
},
"raw": "<html lang='en-GB'></html>",
"headers": {
"content-type": "text/html; charset=ISO-8859-1"
}
}
},
"sqlResponse": {
"value": {
"data": [
{
"personid": 1,
"lastname": "Hughes",
"firstname": "Mike",
"address": "123 Fake Street",
"city": "Belfast"
},
{
"personid": 2,
"lastname": "Smith",
"firstname": "John",
"address": "64 Updown Road",
"city": "Dublin"
}
]
}
},
"user": { "user": {
"value": { "value": {
"user": { "user": {
@ -1144,14 +1180,42 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "array", "type": "object",
"items": { "properties": {
"type": "object" "data": {
"type": "array",
"description": "The data retrieved from the query.",
"items": {
"type": "object",
"description": "The structure of the returned data will be an object, if it is just a string then this will be an object containing \"value\"."
}
},
"pagination": {
"type": "object",
"description": "For supported query types this returns pagination information.",
"properties": {
"cursor": {
"type": "string",
"description": "The pagination cursor location."
}
}
},
"raw": {
"type": "string",
"description": "The raw query response."
},
"headers": {
"type": "object",
"description": "For REST queries the headers in the response will be returned here."
}
} }
}, },
"examples": { "examples": {
"query": { "REST": {
"$ref": "#/components/examples/query" "$ref": "#/components/examples/restResponse"
},
"SQL": {
"$ref": "#/components/examples/sqlResponse"
} }
} }
} }

View File

@ -242,6 +242,28 @@ components:
type: string type: string
transformer: return data transformer: return data
readable: true readable: true
restResponse:
value:
data:
- value: <html lang='en-GB'></html>
pagination:
cursor: "2"
raw: <html lang='en-GB'></html>
headers:
content-type: text/html; charset=ISO-8859-1
sqlResponse:
value:
data:
- personid: 1
lastname: Hughes
firstname: Mike
address: 123 Fake Street
city: Belfast
- personid: 2
lastname: Smith
firstname: John
address: 64 Updown Road
city: Dublin
user: user:
value: value:
user: user:
@ -804,12 +826,33 @@ paths:
content: content:
application/json: application/json:
schema: schema:
type: array type: object
items: properties:
type: object data:
type: array
description: The data retrieved from the query.
items:
type: object
description: The structure of the returned data will be an object, if it is just
a string then this will be an object containing "value".
pagination:
type: object
description: For supported query types this returns pagination information.
properties:
cursor:
type: string
description: The pagination cursor location.
raw:
type: string
description: The raw query response.
headers:
type: object
description: For REST queries the headers in the response will be returned here.
examples: examples:
query: REST:
$ref: "#/components/examples/query" $ref: "#/components/examples/restResponse"
SQL:
$ref: "#/components/examples/sqlResponse"
"/tables/{tableId}/rows/search": "/tables/{tableId}/rows/search":
post: post:
summary: Used to search for rows within a table. summary: Used to search for rows within a table.

View File

@ -36,6 +36,44 @@ const query = {
readable: true, readable: true,
} }
const restResponse = {
value: {
data: [
{
value: "<html lang='en-GB'></html>",
},
],
pagination: {
cursor: "2",
},
raw: "<html lang='en-GB'></html>",
headers: {
"content-type": "text/html; charset=ISO-8859-1",
},
},
}
const sqlResponse = {
value: {
data: [
{
personid: 1,
lastname: "Hughes",
firstname: "Mike",
address: "123 Fake Street",
city: "Belfast",
},
{
personid: 2,
lastname: "Smith",
firstname: "John",
address: "64 Updown Road",
city: "Dublin",
},
],
},
}
const querySchema = object({}) const querySchema = object({})
module.exports = new Resource() module.exports = new Resource()
@ -50,6 +88,8 @@ module.exports = new Resource()
queries: [query], queries: [query],
}, },
}, },
restResponse,
sqlResponse,
}) })
.setSchemas({ .setSchemas({
query: querySchema, query: querySchema,

View File

@ -1,9 +1,45 @@
exports.search = () => {} const { search } = require("./utils")
const { getAllApps } = require("@budibase/backend-core/db")
const { updateAppId } = require("@budibase/backend-core/context")
const controller = require("../application")
exports.create = () => {} async function setResponseApp(ctx) {
if (ctx.body && ctx.body.appId && (!ctx.params || !ctx.params.appId)) {
ctx.params = { appId: ctx.body.appId }
}
await controller.fetchAppPackage(ctx)
}
exports.read = () => {} exports.search = async ctx => {
const { name } = ctx.request.body
const apps = await getAllApps({ all: true })
ctx.body = {
applications: search(apps, "name", name),
}
}
exports.update = () => {} exports.create = async ctx => {
await controller.create(ctx)
await setResponseApp(ctx)
}
exports.delete = () => {} exports.read = async ctx => {
updateAppId(ctx.params.appId)
await setResponseApp(ctx)
}
exports.update = async ctx => {
updateAppId(ctx.params.appId)
await controller.update(ctx)
await setResponseApp(ctx)
}
exports.delete = async ctx => {
updateAppId(ctx.params.appId)
// get the app before deleting it
await setResponseApp(ctx)
const body = ctx.body
await controller.delete(ctx)
// overwrite the body again
ctx.body = body
}

View File

@ -1,3 +1,14 @@
exports.search = () => {} const { searchDocs } = require("./utils")
const { DocumentTypes } = require("../../../db/utils")
const queryController = require("../query")
exports.execute = () => {} exports.search = async ctx => {
const { name } = ctx.request.body
ctx.body = {
queries: await searchDocs(DocumentTypes.QUERY, "name", name),
}
}
exports.execute = async ctx => {
await queryController.executeV2(ctx)
}

View File

@ -1,4 +1,5 @@
const rowController = require("../row") const rowController = require("../row")
const { addRev } = require("./utils")
// makes sure that the user doesn't need to pass in the type, tableId or _id params for // makes sure that the user doesn't need to pass in the type, tableId or _id params for
// the call to be correct // the call to be correct
@ -22,14 +23,27 @@ exports.search = async ctx => {
await rowController.search(ctx) await rowController.search(ctx)
} }
exports.create = ctx => { exports.create = async ctx => {
ctx.request.body = fixRow(ctx.request.body, ctx.params) ctx.request.body = fixRow(ctx.request.body, ctx.params)
await rowController.save(ctx)
ctx.body = { row: ctx.body }
} }
exports.read = () => {} exports.read = async ctx => {
await rowController.find(ctx)
ctx.body = { row: ctx.body }
}
exports.update = async ctx => { exports.update = async ctx => {
ctx.request.body = fixRow(ctx.request.body, ctx.params) ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params))
ctx.body = { row: ctx.body }
} }
exports.delete = () => {} exports.delete = async ctx => {
// set the body as expected, with the _id and _rev fields
ctx.request.body = await addRev({ _id: ctx.params.rowId })
await rowController.destroy(ctx)
// destroy controller doesn't currently return the row as the body, need to adjust this
// in the public API to be correct
ctx.body = { row: ctx.row }
}

View File

@ -0,0 +1,47 @@
const { getAppDB } = require("@budibase/backend-core/context")
const { getDocParams } = require("@budibase/backend-core/db")
exports.addRev = async body => {
if (!body._id) {
return body
}
const db = getAppDB()
const dbDoc = await db.get(body._id)
body._rev = dbDoc._rev
return body
}
exports.search = (docs, key, value) => {
if (!value || typeof value !== "string") {
return docs
}
value = value.toLowerCase()
const filtered = []
for (let doc of docs) {
if (typeof doc[key] !== "string") {
continue
}
const toTest = doc[key].toLowerCase()
if (toTest.startsWith(value)) {
filtered.push(doc)
}
}
return filtered
}
/**
* Performs a case insensitive search on a document type, using the
* provided key and value. This will be a string based search,
* using the startsWith function.
*/
exports.searchDocs = async (docType, key, value) => {
const db = getAppDB()
const docs = (
await db.allDocs(
getDocParams(docType, null, {
include_docs: true,
})
)
).rows.map(row => row.doc)
return exports.search(docs, key, value)
}

View File

@ -46,10 +46,10 @@ function applyRoutes(endpoints, permType, resource, subResource = null) {
addToRouter(endpoints.write) addToRouter(endpoints.write)
} }
applyRoutes(rowEndpoints, PermissionTypes.TABLE, "tableId", "rowId")
applyRoutes(appEndpoints, PermissionTypes.APP, "appId") applyRoutes(appEndpoints, PermissionTypes.APP, "appId")
applyRoutes(tableEndpoints, PermissionTypes.TABLE, "tableId") applyRoutes(tableEndpoints, PermissionTypes.TABLE, "tableId")
applyRoutes(userEndpoints, PermissionTypes.USER, "userId") applyRoutes(userEndpoints, PermissionTypes.USER, "userId")
applyRoutes(queryEndpoints, PermissionTypes.QUERY, "queryId") applyRoutes(queryEndpoints, PermissionTypes.QUERY, "queryId")
//applyRoutes(rowEndpoints, PermissionTypes.TABLE, "tableId", "rowId")
module.exports = publicRouter module.exports = publicRouter

View File

@ -53,12 +53,34 @@ read.push(new Endpoint("post", "/queries/search", controller.search))
* content: * content:
* application/json: * application/json:
* schema: * schema:
* type: array * type: object
* items: * properties:
* type: object * data:
* type: array
* description: The data retrieved from the query.
* items:
* type: object
* description: The structure of the returned data will be an object,
* if it is just a string then this will be an object containing "value".
* pagination:
* type: object
* description: For supported query types this returns pagination information.
* properties:
* cursor:
* type: string
* description: The pagination cursor location.
* raw:
* type: string
* description: The raw query response.
* headers:
* type: object
* description: For REST queries the headers in the response will be returned here.
* examples: * examples:
* query: * REST:
* $ref: '#/components/examples/query' * $ref: '#/components/examples/restResponse'
* SQL:
* $ref: '#/components/examples/sqlResponse'
*
*/ */
write.push(new Endpoint("post", "/queries/:queryId", controller.execute)) write.push(new Endpoint("post", "/queries/:queryId", controller.execute))

View File

@ -26,7 +26,7 @@ function request(ctx, request) {
delete request.body delete request.body
} }
if (ctx && ctx.headers) { if (ctx && ctx.headers) {
request.headers.cookie = ctx.headers.cookie request.headers = ctx.headers
} }
return request return request
} }