1
0
Fork 0
mirror of synced 2024-10-04 03:54:37 +13:00

Delete row from view

This commit is contained in:
Adria Navarro 2023-07-31 16:14:14 +02:00
parent d1ad443d18
commit 3335c86a84
5 changed files with 100 additions and 7 deletions

View file

@ -166,13 +166,13 @@ async function deleteRow(ctx: UserCtx<DeleteRowRequest>) {
const appId = ctx.appId const appId = ctx.appId
const tableId = utils.getTableId(ctx) const tableId = utils.getTableId(ctx)
let resp = await quotas.addQuery<any>(() => pickApi(tableId).destroy(ctx), { const resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), {
datasourceId: tableId, datasourceId: tableId,
}) })
await quotas.removeRow() await quotas.removeRow()
ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, resp.row) ctx.eventEmitter && ctx.eventEmitter.emitRow(`row:delete`, appId, resp.row)
gridSocket?.emitRowDeletion(ctx, resp.row._id) gridSocket?.emitRowDeletion(ctx, resp.row._id!)
return resp return resp
} }

View file

@ -6,6 +6,7 @@ import { permissions } from "@budibase/backend-core"
import { internalSearchValidator } from "./utils/validators" import { internalSearchValidator } from "./utils/validators"
import noViewData from "../../middleware/noViewData" import noViewData from "../../middleware/noViewData"
import trimViewRowInfo from "../../middleware/trimViewRowInfo" import trimViewRowInfo from "../../middleware/trimViewRowInfo"
import * as utils from "../../db/utils"
const { PermissionType, PermissionLevel } = permissions const { PermissionType, PermissionLevel } = permissions
const router: Router = new Router() const router: Router = new Router()
@ -305,6 +306,14 @@ router
trimViewRowInfo, trimViewRowInfo,
rowController.save rowController.save
) )
/**
* @api {patch} /api/v2/views/:viewId/rows/:rowId Updates a row
* @apiName Update a row
* @apiGroup rows
* @apiPermission table write access
* @apiDescription This endpoint is identical to the row creation endpoint but instead it will
* error if an _id isn't provided, it will only function for existing rows.
*/
.patch( .patch(
"/api/v2/views/:viewId/rows/:rowId", "/api/v2/views/:viewId/rows/:rowId",
paramResource("viewId"), paramResource("viewId"),
@ -312,5 +321,38 @@ router
trimViewRowInfo, trimViewRowInfo,
rowController.patch rowController.patch
) )
/**
* @api {delete} /api/v2/views/:viewId/rows Delete rows for a view
* @apiName Delete rows for a view
* @apiGroup rows
* @apiPermission table write access
* @apiDescription This endpoint can delete a single row, or delete them in a bulk
* fashion.
*
* @apiParam {string} tableId The ID of the table the row is to be deleted from.
*
* @apiParam (Body) {object[]} [rows] If bulk deletion is desired then provide the rows in this
* key of the request body that are to be deleted.
* @apiParam (Body) {string} [_id] If deleting a single row then provide its ID in this field.
* @apiParam (Body) {string} [_rev] If deleting a single row from an internal table then provide its
* revision here.
*
* @apiSuccess {object[]|object} body If deleting bulk then the response body will be an array
* of the deleted rows, if deleting a single row then the body will contain a "row" property which
* is the deleted row.
*/
.delete(
"/api/v2/views/:viewId/rows",
paramResource("viewId"),
authorized(PermissionType.VIEW, PermissionLevel.WRITE),
// This is required as the implementation relies on the table id
(ctx, next) => {
ctx.params.tableId = utils.extractViewInfoFromID(
ctx.params.viewId
).tableId
next()
},
rowController.destroy
)
export default router export default router

View file

@ -16,6 +16,7 @@ import {
FieldType, FieldType,
SortType, SortType,
SortOrder, SortOrder,
DeleteRow,
} from "@budibase/types" } from "@budibase/types"
import { import {
expectAnyInternalColsAttributes, expectAnyInternalColsAttributes,
@ -1146,7 +1147,7 @@ describe("/rows", () => {
describe("patch", () => { describe("patch", () => {
it("should update only the view fields for a row", async () => { it("should update only the view fields for a row", async () => {
const table = await config.createTable(userTable()) const table = await config.createTable(userTable())
const tableId = config.table!._id! const tableId = table._id!
const view = await config.api.viewV2.create({ const view = await config.api.viewV2.create({
tableId, tableId,
columns: { columns: {
@ -1195,5 +1196,35 @@ describe("/rows", () => {
expect(route?.stack).toContainEqual(trimViewRowInfoMiddleware) expect(route?.stack).toContainEqual(trimViewRowInfoMiddleware)
}) })
}) })
describe("destroy", () => {
it("should be able to delete a row", async () => {
const table = await config.createTable(userTable())
const tableId = table._id!
const view = await config.api.viewV2.create({
tableId,
columns: {
name: { visible: true },
address: { visible: true },
},
})
const createdRow = await config.createRow()
const rowUsage = await getRowUsage()
const queryUsage = await getQueryUsage()
const body: DeleteRow = {
_id: createdRow._id!,
}
await config.api.viewV2.row.delete(view.id, body)
await assertRowUsage(rowUsage - 1)
await assertQueryUsage(queryUsage + 1)
await config.api.row.get(tableId, createdRow._id!, {
expectStatus: 404,
})
})
})
}) })
}) })

View file

@ -7,12 +7,19 @@ export class RowAPI extends TestAPI {
super(config) super(config)
} }
get = async (tableId: string, rowId: string) => { get = async (
return await this.request tableId: string,
rowId: string,
{ expectStatus } = { expectStatus: 200 }
) => {
const request = this.request
.get(`/api/${tableId}/rows/${rowId}`) .get(`/api/${tableId}/rows/${rowId}`)
.set(this.config.defaultHeaders()) .set(this.config.defaultHeaders())
.expect("Content-Type", /json/) .expect(expectStatus)
.expect(200) if (expectStatus !== 404) {
request.expect("Content-Type", /json/)
}
return request
} }
patch = async ( patch = async (

View file

@ -1,5 +1,6 @@
import { import {
CreateViewRequest, CreateViewRequest,
DeleteRowRequest,
PatchRowRequest, PatchRowRequest,
PatchRowResponse, PatchRowResponse,
Row, Row,
@ -130,5 +131,17 @@ export class ViewV2API extends TestAPI {
.expect(expectStatus) .expect(expectStatus)
return result.body as PatchRowResponse return result.body as PatchRowResponse
}, },
delete: async (
viewId: string,
body: DeleteRowRequest,
{ expectStatus } = { expectStatus: 200 }
): Promise<any> => {
const result = await this.request
.delete(`/api/v2/views/${viewId}/rows`)
.send(body)
.set(this.config.defaultHeaders())
.expect(expectStatus)
return result.body
},
} }
} }