Persist as object instead of array

This commit is contained in:
Adria Navarro 2024-07-11 16:57:32 +02:00
parent de04a6f76d
commit 17fc605e4f
8 changed files with 85 additions and 94 deletions

View File

@ -1,6 +1,7 @@
import { import {
CreateRowActionRequest, CreateRowActionRequest,
Ctx, Ctx,
RowActionResponse,
RowActionsResponse, RowActionsResponse,
} from "@budibase/types" } from "@budibase/types"
import sdk from "../../../sdk" import sdk from "../../../sdk"
@ -20,7 +21,7 @@ export async function find(ctx: Ctx<void, RowActionsResponse>) {
if (!(await sdk.rowActions.docExists(table._id!))) { if (!(await sdk.rowActions.docExists(table._id!))) {
ctx.body = { ctx.body = {
tableId: table._id!, tableId: table._id!,
actions: [], actions: {},
} }
return return
} }
@ -33,15 +34,19 @@ export async function find(ctx: Ctx<void, RowActionsResponse>) {
} }
export async function create( export async function create(
ctx: Ctx<CreateRowActionRequest, RowActionsResponse> ctx: Ctx<CreateRowActionRequest, RowActionResponse>
) { ) {
const table = await getTable(ctx) const table = await getTable(ctx)
const created = await sdk.rowActions.create(table._id!, ctx.request.body) const { id, ...createdAction } = await sdk.rowActions.create(
table._id!,
ctx.request.body
)
ctx.body = { ctx.body = {
tableId: table._id!, tableId: table._id!,
...created, actionId: id,
...createdAction,
} }
ctx.status = 201 ctx.status = 201
} }

View File

@ -1,7 +1,7 @@
import _ from "lodash" import _ from "lodash"
import tk from "timekeeper" import tk from "timekeeper"
import { CreateRowActionRequest } from "@budibase/types" import { CreateRowActionRequest, RowActionResponse } from "@budibase/types"
import * as setup from "./utilities" import * as setup from "./utilities"
import { generator } from "@budibase/backend-core/tests" import { generator } from "@budibase/backend-core/tests"
import { Expectations } from "src/tests/utilities/api/base" import { Expectations } from "src/tests/utilities/api/base"
@ -46,6 +46,12 @@ describe("/rowsActions", () => {
} }
} }
function createRowActionRequests(count: number): CreateRowActionRequest[] {
return generator
.unique(() => generator.word(), count)
.map(name => ({ name }))
}
function unauthorisedTests() { function unauthorisedTests() {
it("returns unauthorised (401) for unauthenticated requests", async () => { it("returns unauthorised (401) for unauthenticated requests", async () => {
await createRowAction( await createRowAction(
@ -84,83 +90,47 @@ describe("/rowsActions", () => {
it("creates new row actions for tables without existing actions", async () => { it("creates new row actions for tables without existing actions", async () => {
const rowAction = createRowActionRequest() const rowAction = createRowActionRequest()
const res = await createRowAction(tableId, rowAction, {
const res = await createRowAction(tableId, rowAction, { status: 201 }) status: 201,
})
expect(res).toEqual({ expect(res).toEqual({
tableId: tableId,
actionId: expect.stringMatching(/^row_action_\w+/),
...rowAction,
})
expect(await config.api.rowAction.find(tableId)).toEqual({
_id: `ra_${tableId}`, _id: `ra_${tableId}`,
_rev: expect.stringMatching(/^1-\w+/), _rev: expect.stringMatching(/^1-\w+/),
actions: [
{
id: expect.any(String),
name: rowAction.name,
},
],
tableId: tableId, tableId: tableId,
actions: {
[res.actionId]: rowAction,
},
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}) })
}) })
it("can create multiple row actions for the same table", async () => { it("can create multiple row actions for the same table", async () => {
const rowActions = generator.unique(() => createRowActionRequest(), 3) const rowActions = createRowActionRequests(3)
const responses: RowActionResponse[] = []
for (const action of rowActions) {
responses.push(await createRowAction(tableId, action))
}
await createRowAction(tableId, rowActions[0]) expect(await config.api.rowAction.find(tableId)).toEqual({
await createRowAction(tableId, rowActions[1])
const res = await createRowAction(tableId, rowActions[2])
expect(res).toEqual({
_id: `ra_${tableId}`, _id: `ra_${tableId}`,
_rev: expect.stringMatching(/^3-\w+/), _rev: expect.stringMatching(/^3-\w+/),
actions: rowActions.map(a => ({ actions: {
id: expect.any(String), [responses[0].actionId]: rowActions[0],
...a, [responses[1].actionId]: rowActions[1],
})), [responses[2].actionId]: rowActions[2],
tableId: tableId,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
})
})
it("can create row actions for different tables", async () => {
const otherTable = await config.api.table.save(
setup.structures.basicTable()
)
const otherTableId = otherTable._id!
const rowAction1 = createRowActionRequest()
const rowAction2 = createRowActionRequest()
const res1 = await createRowAction(tableId, rowAction1)
const res2 = await createRowAction(otherTableId, rowAction2)
expect(res1).toEqual({
_id: `ra_${tableId}`,
_rev: expect.stringMatching(/^1-\w+/),
actions: [
{
id: expect.any(String),
...rowAction1,
}, },
],
tableId: tableId, tableId: tableId,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}) })
expect(res2).toEqual({
_id: `ra_${otherTableId}`,
_rev: expect.stringMatching(/^1-\w+/),
actions: [
{
id: expect.any(String),
...rowAction2,
},
],
tableId: otherTableId,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
})
}) })
it("rejects with bad request when creating with no name", async () => { it("rejects with bad request when creating with no name", async () => {
@ -181,25 +151,25 @@ describe("/rowsActions", () => {
unauthorisedTests() unauthorisedTests()
it("returns only the actions for the requested table", async () => { it("returns only the actions for the requested table", async () => {
const rowActions = generator.unique(() => createRowActionRequest(), 5) const rowActions: RowActionResponse[] = []
for (const rowAction of rowActions) { for (const action of createRowActionRequests(3)) {
await createRowAction(tableId, rowAction) rowActions.push(await createRowAction(tableId, action))
} }
const otherTable = await config.api.table.save( const otherTable = await config.api.table.save(
setup.structures.basicTable() setup.structures.basicTable()
) )
const otherTableId = otherTable._id! await createRowAction(otherTable._id!, createRowActionRequest())
await createRowAction(otherTableId, createRowActionRequest())
const response = await config.api.rowAction.find(tableId) const response = await config.api.rowAction.find(tableId)
expect(response).toEqual( expect(response).toEqual(
expect.objectContaining({ expect.objectContaining({
tableId, tableId,
actions: rowActions.map(a => ({ actions: {
id: expect.any(String), [rowActions[0].actionId]: expect.any(Object),
...a, [rowActions[1].actionId]: expect.any(Object),
})), [rowActions[2].actionId]: expect.any(Object),
},
}) })
) )
}) })
@ -209,7 +179,7 @@ describe("/rowsActions", () => {
expect(response).toEqual( expect(response).toEqual(
expect.objectContaining({ expect.objectContaining({
tableId, tableId,
actions: [], actions: {},
}) })
) )
}) })

View File

@ -1,7 +1,11 @@
import { context, utils } from "@budibase/backend-core" import { context, utils } from "@budibase/backend-core"
import { generateRowActionsID } from "../../db/utils" import { generateRowActionsID } from "../../db/utils"
import { TableRowActions } from "@budibase/types" import {
SEPARATOR,
TableRowActions,
VirtualDocumentType,
} from "@budibase/types"
export async function create(tableId: string, rowAction: { name: string }) { export async function create(tableId: string, rowAction: { name: string }) {
const db = context.getAppDB() const db = context.getAppDB()
@ -14,16 +18,17 @@ export async function create(tableId: string, rowAction: { name: string }) {
throw e throw e
} }
doc = { _id: rowActionsId, actions: [] } doc = { _id: rowActionsId, actions: {} }
} }
doc.actions.push({ const newId = `${VirtualDocumentType.ROW_ACTION}${SEPARATOR}${utils.newid()}`
id: utils.newid(), doc.actions[newId] = rowAction
...rowAction,
})
await db.put(doc) await db.put(doc)
return await get(tableId) return {
id: newId,
...rowAction,
}
} }
export async function get(tableId: string) { export async function get(tableId: string) {

View File

@ -1,4 +1,8 @@
import { CreateRowActionRequest, RowActionsResponse } from "@budibase/types" import {
CreateRowActionRequest,
RowActionResponse,
RowActionsResponse,
} from "@budibase/types"
import { Expectations, TestAPI } from "./base" import { Expectations, TestAPI } from "./base"
export class RowActionAPI extends TestAPI { export class RowActionAPI extends TestAPI {
@ -8,7 +12,7 @@ export class RowActionAPI extends TestAPI {
expectations?: Expectations, expectations?: Expectations,
config?: { publicUser?: boolean } config?: { publicUser?: boolean }
) => { ) => {
return await this._post<RowActionsResponse>( return await this._post<RowActionResponse>(
`/api/tables/${tableId}/actions`, `/api/tables/${tableId}/actions`,
{ {
body: rowAction, body: rowAction,

View File

@ -1,11 +1,15 @@
export interface CreateRowActionRequest { export interface CreateRowActionRequest extends RowActionData {}
name: string
export interface RowActionResponse extends RowActionData {
tableId: string
actionId: string
} }
export interface RowActionsResponse { export interface RowActionsResponse {
tableId: string tableId: string
actions: { actions: Record<string, RowActionData>
id: string }
name: string
}[] interface RowActionData {
name: string
} }

View File

@ -16,4 +16,4 @@ export * from "./links"
export * from "./component" export * from "./component"
export * from "./sqlite" export * from "./sqlite"
export * from "./snippet" export * from "./snippet"
export * from "./rowActions" export * from "./rowAction"

View File

@ -2,8 +2,10 @@ import { Document } from "../document"
export interface TableRowActions extends Document { export interface TableRowActions extends Document {
_id: string _id: string
actions: { actions: Record<
id: string string,
{
name: string name: string
}[] }
>
} }

View File

@ -69,6 +69,7 @@ export enum InternalTable {
// documents or enriched into existence as part of get requests // documents or enriched into existence as part of get requests
export enum VirtualDocumentType { export enum VirtualDocumentType {
VIEW = "view", VIEW = "view",
ROW_ACTION = "row_action",
} }
export interface Document { export interface Document {