Adding controllers for row, query and applications public APIs.
This commit is contained in:
parent
8685abf99e
commit
8f6e55e65b
|
@ -32,11 +32,10 @@ const populateFromDB = async (userId, tenantId) => {
|
|||
* @param {*} populateUser function to provide the user for re-caching. default to couch db
|
||||
* @returns
|
||||
*/
|
||||
exports.getUser = async (
|
||||
userId,
|
||||
tenantId = null,
|
||||
populateUser = populateFromDB
|
||||
) => {
|
||||
exports.getUser = async (userId, tenantId = null, populateUser = null) => {
|
||||
if (!populateUser) {
|
||||
populateUser = populateFromDB
|
||||
}
|
||||
if (!tenantId) {
|
||||
try {
|
||||
tenantId = getTenantId()
|
||||
|
|
|
@ -68,6 +68,7 @@ function getDocParams(docType, docId = null, otherProps = {}) {
|
|||
endkey: `${docType}${SEPARATOR}${docId}${UNICODE_MAX}`,
|
||||
}
|
||||
}
|
||||
exports.getDocParams = getDocParams
|
||||
|
||||
/**
|
||||
* Generates a new workspace ID.
|
||||
|
|
|
@ -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": {
|
||||
"value": {
|
||||
"user": {
|
||||
|
@ -1144,14 +1180,42 @@
|
|||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"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": {
|
||||
"query": {
|
||||
"$ref": "#/components/examples/query"
|
||||
"REST": {
|
||||
"$ref": "#/components/examples/restResponse"
|
||||
},
|
||||
"SQL": {
|
||||
"$ref": "#/components/examples/sqlResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,6 +242,28 @@ components:
|
|||
type: string
|
||||
transformer: return data
|
||||
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:
|
||||
value:
|
||||
user:
|
||||
|
@ -804,12 +826,33 @@ paths:
|
|||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
type: object
|
||||
properties:
|
||||
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:
|
||||
query:
|
||||
$ref: "#/components/examples/query"
|
||||
REST:
|
||||
$ref: "#/components/examples/restResponse"
|
||||
SQL:
|
||||
$ref: "#/components/examples/sqlResponse"
|
||||
"/tables/{tableId}/rows/search":
|
||||
post:
|
||||
summary: Used to search for rows within a table.
|
||||
|
|
|
@ -36,6 +36,44 @@ const query = {
|
|||
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({})
|
||||
|
||||
module.exports = new Resource()
|
||||
|
@ -50,6 +88,8 @@ module.exports = new Resource()
|
|||
queries: [query],
|
||||
},
|
||||
},
|
||||
restResponse,
|
||||
sqlResponse,
|
||||
})
|
||||
.setSchemas({
|
||||
query: querySchema,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
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
|
||||
// the call to be correct
|
||||
|
@ -22,14 +23,27 @@ exports.search = async ctx => {
|
|||
await rowController.search(ctx)
|
||||
}
|
||||
|
||||
exports.create = ctx => {
|
||||
exports.create = async ctx => {
|
||||
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 => {
|
||||
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 }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -46,10 +46,10 @@ function applyRoutes(endpoints, permType, resource, subResource = null) {
|
|||
addToRouter(endpoints.write)
|
||||
}
|
||||
|
||||
applyRoutes(rowEndpoints, PermissionTypes.TABLE, "tableId", "rowId")
|
||||
applyRoutes(appEndpoints, PermissionTypes.APP, "appId")
|
||||
applyRoutes(tableEndpoints, PermissionTypes.TABLE, "tableId")
|
||||
applyRoutes(userEndpoints, PermissionTypes.USER, "userId")
|
||||
applyRoutes(queryEndpoints, PermissionTypes.QUERY, "queryId")
|
||||
//applyRoutes(rowEndpoints, PermissionTypes.TABLE, "tableId", "rowId")
|
||||
|
||||
module.exports = publicRouter
|
||||
|
|
|
@ -53,12 +53,34 @@ read.push(new Endpoint("post", "/queries/search", controller.search))
|
|||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* type: object
|
||||
* properties:
|
||||
* 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:
|
||||
* query:
|
||||
* $ref: '#/components/examples/query'
|
||||
* REST:
|
||||
* $ref: '#/components/examples/restResponse'
|
||||
* SQL:
|
||||
* $ref: '#/components/examples/sqlResponse'
|
||||
*
|
||||
*/
|
||||
write.push(new Endpoint("post", "/queries/:queryId", controller.execute))
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ function request(ctx, request) {
|
|||
delete request.body
|
||||
}
|
||||
if (ctx && ctx.headers) {
|
||||
request.headers.cookie = ctx.headers.cookie
|
||||
request.headers = ctx.headers
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue