Work in progress - this is the scaffolding for views to be added to the public API.
This commit is contained in:
parent
a9279b35d5
commit
f8f9c4da8e
|
@ -0,0 +1,193 @@
|
||||||
|
import { FieldType, FormulaType, RelationshipType } from "@budibase/types"
|
||||||
|
import { object } from "./utils"
|
||||||
|
import Resource from "./utils/Resource"
|
||||||
|
|
||||||
|
const view = {
|
||||||
|
_id: "ta_5b1649e42a5b41dea4ef7742a36a7a70",
|
||||||
|
name: "People",
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
name: "name",
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
type: "number",
|
||||||
|
name: "age",
|
||||||
|
},
|
||||||
|
relationship: {
|
||||||
|
type: "link",
|
||||||
|
name: "relationship",
|
||||||
|
tableId: "ta_...",
|
||||||
|
fieldName: "relatedColumn",
|
||||||
|
relationshipType: "many-to-many",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseColumnDef = {
|
||||||
|
type: {
|
||||||
|
type: "string",
|
||||||
|
enum: Object.values(FieldType),
|
||||||
|
description:
|
||||||
|
"Defines the type of the column, most explain themselves, a link column is a relationship.",
|
||||||
|
},
|
||||||
|
constraints: {
|
||||||
|
type: "object",
|
||||||
|
description:
|
||||||
|
"A constraint can be applied to the column which will be validated against when a row is saved.",
|
||||||
|
properties: {
|
||||||
|
type: {
|
||||||
|
type: "string",
|
||||||
|
enum: ["string", "number", "object", "boolean"],
|
||||||
|
},
|
||||||
|
presence: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Defines whether the column is required or not.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
description: "The name of the column.",
|
||||||
|
},
|
||||||
|
autocolumn: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Defines whether the column is automatically generated.",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewSchema = {
|
||||||
|
description: "The table to be created/updated.",
|
||||||
|
type: "object",
|
||||||
|
required: ["name", "schema"],
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
description: "The name of the table.",
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
primaryDisplay: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The name of the column which should be used in relationship tags when relating to this table.",
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
additionalProperties: {
|
||||||
|
oneOf: [
|
||||||
|
// relationship
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
...baseColumnDef,
|
||||||
|
type: {
|
||||||
|
type: "string",
|
||||||
|
enum: [FieldType.LINK],
|
||||||
|
description: "A relationship column.",
|
||||||
|
},
|
||||||
|
fieldName: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The name of the column which a relationship column is related to in another table.",
|
||||||
|
},
|
||||||
|
tableId: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"The ID of the table which a relationship column is related to.",
|
||||||
|
},
|
||||||
|
relationshipType: {
|
||||||
|
type: "string",
|
||||||
|
enum: Object.values(RelationshipType),
|
||||||
|
description:
|
||||||
|
"Defines the type of relationship that this column will be used for.",
|
||||||
|
},
|
||||||
|
through: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"When using a SQL table that contains many to many relationships this defines the table the relationships are linked through.",
|
||||||
|
},
|
||||||
|
foreignKey: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"When using a SQL table that contains a one to many relationship this defines the foreign key.",
|
||||||
|
},
|
||||||
|
throughFrom: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"When using a SQL table that utilises a through table, this defines the primary key in the through table for this table.",
|
||||||
|
},
|
||||||
|
throughTo: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"When using a SQL table that utilises a through table, this defines the primary key in the through table for the related table.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
...baseColumnDef,
|
||||||
|
type: {
|
||||||
|
type: "string",
|
||||||
|
enum: [FieldType.FORMULA],
|
||||||
|
description: "A formula column.",
|
||||||
|
},
|
||||||
|
formula: {
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"Defines a Handlebars or JavaScript formula to use, note that Javascript formulas are expected to be provided in the base64 format.",
|
||||||
|
},
|
||||||
|
formulaType: {
|
||||||
|
type: "string",
|
||||||
|
enum: Object.values(FormulaType),
|
||||||
|
description:
|
||||||
|
"Defines whether this is a static or dynamic formula.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: baseColumnDef,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { search as stringSearch } from "./utils"
|
||||||
|
import * as controller from "../view"
|
||||||
|
import { ViewV2, UserCtx } from "@budibase/types"
|
||||||
|
import { Next } from "koa"
|
||||||
|
|
||||||
|
function fixView(view: ViewV2, params: any) {
|
||||||
|
if (!params || !view) {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
if (params.viewId) {
|
||||||
|
view.id = params.viewId
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function search(ctx: UserCtx, next: Next) {
|
||||||
|
const { name } = ctx.request.body
|
||||||
|
// TODO: need a view search endpoint
|
||||||
|
// await controller.v2.fetch(ctx)
|
||||||
|
ctx.body = stringSearch(ctx.body, name)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function create(ctx: UserCtx, next: Next) {
|
||||||
|
await controller.v2.create(ctx)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function read(ctx: UserCtx, next: Next) {
|
||||||
|
await controller.v2.get(ctx)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function update(ctx: UserCtx, next: Next) {
|
||||||
|
// TODO: this is more complex - no rev on views
|
||||||
|
// ctx.request.body = await addRev(
|
||||||
|
// fixView(ctx.request.body, ctx.params),
|
||||||
|
// ctx.params.tableId
|
||||||
|
// )
|
||||||
|
await controller.v2.update(ctx)
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function destroy(ctx: UserCtx, next: Next) {
|
||||||
|
await controller.v2.remove(ctx)
|
||||||
|
ctx.body = ctx.table
|
||||||
|
await next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
create,
|
||||||
|
read,
|
||||||
|
update,
|
||||||
|
destroy,
|
||||||
|
search,
|
||||||
|
}
|
|
@ -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/viewSearch'
|
||||||
|
* 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 }
|
|
@ -66,6 +66,10 @@ export function tableValidator() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function viewValidator() {
|
||||||
|
return auth.joiValidator.body(Joi.object())
|
||||||
|
}
|
||||||
|
|
||||||
export function nameValidator() {
|
export function nameValidator() {
|
||||||
return auth.joiValidator.body(
|
return auth.joiValidator.body(
|
||||||
Joi.object({
|
Joi.object({
|
||||||
|
|
Loading…
Reference in New Issue