Delete row from view
This commit is contained in:
parent
d1ad443d18
commit
3335c86a84
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue