Create/delete, save to table

This commit is contained in:
Adria Navarro 2023-07-19 15:43:21 +02:00
parent b82876b147
commit 76f89e10d3
7 changed files with 90 additions and 54 deletions

View File

@ -15,27 +15,19 @@ export async function find(ctx: Ctx<void, ViewResponse>) {
} }
export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) { export async function create(ctx: Ctx<CreateViewRequest, ViewResponse>) {
const { tableId } = ctx.params
const view = ctx.request.body const view = ctx.request.body
const result = await sdk.views.create(view) const result = await sdk.views.create(tableId, view)
ctx.status = 201 ctx.status = 201
ctx.body = { ctx.body = {
data: { data: result,
...view,
...result,
},
} }
} }
export async function remove(ctx: Ctx) { export async function remove(ctx: Ctx) {
const { viewId } = ctx.params const { tableId, viewId } = ctx.params
const doc = await sdk.views.get(viewId)
if (!doc) {
ctx.throw(404)
}
const { _rev } = doc await sdk.views.remove(tableId, viewId)
await sdk.views.remove(viewId, _rev!)
ctx.status = 204 ctx.status = 204
} }

View File

@ -1,5 +1,12 @@
import * as setup from "./utilities" import * as setup from "./utilities"
import { FieldType, SortOrder, SortType, Table, ViewV2 } from "@budibase/types" import {
CreateViewRequest,
FieldType,
SortOrder,
SortType,
Table,
ViewV2,
} from "@budibase/types"
import { generator, structures } from "@budibase/backend-core/tests" import { generator, structures } from "@budibase/backend-core/tests"
function priceTable(): Table { function priceTable(): Table {
@ -26,7 +33,7 @@ function priceTable(): Table {
describe("/v2/views", () => { describe("/v2/views", () => {
const config = setup.getConfig() const config = setup.getConfig()
const viewFilters: Omit<ViewV2, "name" | "tableId"> = { const viewFilters: Omit<CreateViewRequest, "name" | "tableId"> = {
query: { allOr: false, equal: { field: "value" } }, query: { allOr: false, equal: { field: "value" } },
sort: { sort: {
field: "fieldToSort", field: "fieldToSort",
@ -46,20 +53,20 @@ describe("/v2/views", () => {
describe("getView", () => { describe("getView", () => {
let view: ViewV2 let view: ViewV2
beforeAll(async () => { beforeAll(async () => {
view = await config.api.viewV2.create({ view = await config.api.viewV2.create(config.table?._id, {
query: { allOr: false, notEqual: { field: "value" } }, query: { allOr: false, notEqual: { field: "value" } },
}) })
}) })
it("can fetch the expected view", async () => { it("can fetch the expected view", async () => {
const res = await config.api.viewV2.get(view._id!) const res = await config.api.viewV2.get(view.id)
expect(res.status).toBe(200) expect(res.status).toBe(200)
expect(res.body).toEqual({ expect(res.body).toEqual({
data: { data: {
...view, ...view,
_id: view._id, _id: view._id,
_rev: view._rev, _rev: expect.any(String),
createdAt: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String), updatedAt: expect.any(String),
}, },
@ -75,32 +82,38 @@ describe("/v2/views", () => {
describe("create", () => { describe("create", () => {
it("persist the view when the view is successfully created", async () => { it("persist the view when the view is successfully created", async () => {
const newView: ViewV2 = { const newView: CreateViewRequest = {
name: generator.name(), name: generator.name(),
tableId: config.table!._id!, tableId: config.table!._id!,
} }
const res = await config.api.viewV2.create(newView) const res = await config.api.viewV2.create(config.table?._id, newView)
expect(res).toEqual({ expect(res).toEqual({
...newView, ...newView,
id: expect.any(String),
version: 2,
_id: expect.any(String), _id: expect.any(String),
_rev: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String),
}) })
}) })
it("can persist views with queries", async () => { it("can persist views with queries", async () => {
const newView: ViewV2 = { const newView: CreateViewRequest = {
name: generator.name(), name: generator.name(),
tableId: config.table!._id!, tableId: config.table!._id!,
...viewFilters, ...viewFilters,
} }
const res = await config.api.viewV2.create(newView) const res = await config.api.viewV2.create(config.table!._id!, newView)
expect(res).toEqual({ expect(res).toEqual({
...newView, ...newView,
...viewFilters, ...viewFilters,
id: expect.any(String),
version: 2,
_id: expect.any(String), _id: expect.any(String),
_rev: expect.any(String), createdAt: expect.any(String),
updatedAt: expect.any(String),
}) })
}) })
}) })
@ -114,11 +127,11 @@ describe("/v2/views", () => {
}) })
it("can delete an existing view", async () => { it("can delete an existing view", async () => {
await config.api.viewV2.get(view._id!, { expectStatus: 200 }) await config.api.viewV2.get(view.id, { expectStatus: 200 })
await config.api.viewV2.delete(view._id!) await config.api.viewV2.delete(config.table?._id!, view.id)
await config.api.viewV2.get(view._id!, { expectStatus: 404 }) await config.api.viewV2.get(view.id, { expectStatus: 404 })
}) })
}) })
}) })

View File

@ -14,12 +14,12 @@ router
viewController.v2.find viewController.v2.find
) )
.post( .post(
"/api/v2/views", "/api/v2/views/:tableId",
authorized(permissions.BUILDER), authorized(permissions.BUILDER),
viewController.v2.create viewController.v2.create
) )
.delete( .delete(
`/api/v2/views/:viewId`, `/api/v2/views/:tableId/:viewId`,
authorized(permissions.BUILDER), authorized(permissions.BUILDER),
viewController.v2.remove viewController.v2.remove
) )

View File

@ -1,6 +1,8 @@
import { context } from "@budibase/backend-core" import { HTTPError, context } from "@budibase/backend-core"
import { ViewV2 } from "@budibase/types" import { ViewV2 } from "@budibase/types"
import * as utils from "../../../db/utils" import * as utils from "../../../db/utils"
import sdk from "../../../sdk"
import { utils as coreUtils } from "@budibase/backend-core"
export async function get(viewId: string): Promise<ViewV2 | undefined> { export async function get(viewId: string): Promise<ViewV2 | undefined> {
const db = context.getAppDB() const db = context.getAppDB()
@ -16,24 +18,45 @@ export async function get(viewId: string): Promise<ViewV2 | undefined> {
} }
} }
export async function create(view: ViewV2): Promise<ViewV2> { export async function create(
const db = context.getAppDB() tableId: string,
viewRequest: Omit<ViewV2, "id" | "version">
const response = await db.put( ): Promise<ViewV2> {
{ const view: ViewV2 = {
_id: utils.generateViewID(view.tableId), ...viewRequest,
...view, id: coreUtils.newid(),
}, version: 2,
{}
)
return {
...view,
_id: response.id,
_rev: response.rev,
} }
view._id = view.id
const db = context.getAppDB()
await db.put(view, {})
const table = await sdk.tables.getTable(tableId)
table.views ??= {}
// @ts-ignore: TODO
table.views[view.name] = view
await db.put(table)
return view
} }
export async function remove(viewId: string, rev: string): Promise<void> { function isV2(view: object): view is ViewV2 {
const db = context.getAppDB() return (view as ViewV2).version === 2
await db.remove(viewId, rev) }
export async function remove(tableId: string, viewId: string): Promise<void> {
const db = context.getAppDB()
const doc = await sdk.views.get(viewId)
await db.remove(viewId, doc!._rev)
const table = await sdk.tables.getTable(tableId)
const view = Object.values(table.views!).find(v => isV2(v) && v.id === viewId)
if (!view) {
throw new HTTPError(`View ${viewId} not found in table ${tableId}`, 404)
}
delete table.views![view?.name]
await db.put(table)
} }

View File

@ -10,19 +10,21 @@ export class ViewV2API extends TestAPI {
} }
create = async ( create = async (
tableId?: string,
viewData?: Partial<ViewV2>, viewData?: Partial<ViewV2>,
{ expectStatus } = { expectStatus: 201 } { expectStatus } = { expectStatus: 201 }
) => { ): Promise<ViewV2> => {
if (!this.config.table) { if (!tableId && !this.config.table) {
throw "Test requires table to be configured." throw "Test requires table to be configured."
} }
tableId = this.config.table!._id!
const view = { const view = {
tableId: this.config.table._id, tableId,
name: generator.guid(), name: generator.guid(),
...viewData, ...viewData,
} }
const result = await this.request const result = await this.request
.post(`/api/v2/views`) .post(`/api/v2/views/${tableId}`)
.send(view) .send(view)
.set(this.config.defaultHeaders()) .set(this.config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
@ -41,9 +43,13 @@ export class ViewV2API extends TestAPI {
.expect(expectStatus) .expect(expectStatus)
} }
delete = async (viewId: string, { expectStatus } = { expectStatus: 204 }) => { delete = async (
tableId: string,
viewId: string,
{ expectStatus } = { expectStatus: 204 }
) => {
return this.request return this.request
.delete(`/api/v2/views/${viewId}`) .delete(`/api/v2/views/${tableId}/${viewId}`)
.set(this.config.defaultHeaders()) .set(this.config.defaultHeaders())
.expect(expectStatus) .expect(expectStatus)
} }

View File

@ -6,5 +6,5 @@ export interface ViewResponse {
export type CreateViewRequest = Omit< export type CreateViewRequest = Omit<
ViewV2, ViewV2,
"_id" | "_rev" | "createdAt" | "updatedAt" "_id" | "_rev" | "createdAt" | "updatedAt" | "version" | "id"
> >

View File

@ -15,6 +15,8 @@ export interface View {
} }
export interface ViewV2 extends Document { export interface ViewV2 extends Document {
version: 2
id: string
name: string name: string
tableId: string tableId: string
query?: SearchFilters query?: SearchFilters