1
0
Fork 0
mirror of synced 2024-09-06 12:41:24 +12:00

Validate and return csv

This commit is contained in:
Adria Navarro 2023-09-15 12:07:25 +02:00
parent 2f9843bd4c
commit f1a1cf74bc
3 changed files with 64 additions and 21 deletions

View file

@ -1,27 +1,34 @@
import { cache } from "@budibase/backend-core" import { cache } from "@budibase/backend-core"
import { utils } from "@budibase/shared-core" import { utils } from "@budibase/shared-core"
import { FieldSubtype } from "@budibase/types" import { Document, FieldSubtype } from "@budibase/types"
import { InvalidBBRefError } from "./errors"
export async function processInputBBReferences( export async function processInputBBReferences(
value: string, value: string | string[] | { _id: string } | { _id: string }[],
subtype: FieldSubtype subtype: FieldSubtype
) { ): Promise<string> {
const result = [] const result: string[] = []
const ids = value.split(",").map((id: string) => id.trim())
switch (subtype) { switch (subtype) {
case FieldSubtype.USER: case FieldSubtype.USER:
for (const id of ids) { if (Array.isArray(value)) {
result.push(await cache.user.getUser(id)) result.push(...value.map(x => (typeof x === "string" ? x : x._id)))
} else if (typeof value !== "string") {
result.push(value._id)
} else {
result.push(...value.split(",").map((id: string) => id.trim()))
}
for (const id of result) {
const user = await cache.user.getUser(id)
if (!user) {
throw new InvalidBBRefError(id, FieldSubtype.USER)
}
} }
break break
default: default:
utils.unreachable(subtype) throw utils.unreachable(subtype)
} }
if (result.length > 1) { return result.join(",")
return result
}
return result[0]
} }

View file

@ -0,0 +1,7 @@
import { FieldSubtype } from "@budibase/types"
export class InvalidBBRefError extends Error {
constructor(id: string, subtype: FieldSubtype) {
super(`Id "${id}" is not valid for the subtype "${subtype}"`)
}
}

View file

@ -2,6 +2,7 @@ import * as backendCore from "@budibase/backend-core"
import { FieldSubtype, User } from "@budibase/types" import { FieldSubtype, User } from "@budibase/types"
import { processInputBBReferences } from "../bbReferenceProcessor" import { processInputBBReferences } from "../bbReferenceProcessor"
import { generator, structures } from "@budibase/backend-core/tests" import { generator, structures } from "@budibase/backend-core/tests"
import { InvalidBBRefError } from "../errors"
jest.mock("@budibase/backend-core", (): typeof backendCore => { jest.mock("@budibase/backend-core", (): typeof backendCore => {
const actual = jest.requireActual("@budibase/backend-core") const actual = jest.requireActual("@budibase/backend-core")
@ -26,7 +27,7 @@ describe("bbReferenceProcessor", () => {
describe("processInputBBReferences", () => { describe("processInputBBReferences", () => {
describe("subtype user", () => { describe("subtype user", () => {
it("fetches by user id", async () => { it("validate valid string id", async () => {
const input = generator.guid() const input = generator.guid()
const userFromCache = structures.users.user() const userFromCache = structures.users.user()
@ -34,29 +35,57 @@ describe("bbReferenceProcessor", () => {
const result = await processInputBBReferences(input, FieldSubtype.USER) const result = await processInputBBReferences(input, FieldSubtype.USER)
expect(result).toEqual(userFromCache) expect(result).toEqual(input)
expect(mockedCacheGetUser).toBeCalledTimes(1) expect(mockedCacheGetUser).toBeCalledTimes(1)
expect(mockedCacheGetUser).toBeCalledWith(input) expect(mockedCacheGetUser).toBeCalledWith(input)
}) })
it("fetches by user id when send as csv", async () => { it("throws an error given an invalid id", async () => {
const users: Record<string, User> = {} const input = generator.guid()
await expect(
processInputBBReferences(input, FieldSubtype.USER)
).rejects.toThrowError(new InvalidBBRefError(input, FieldSubtype.USER))
})
it("validates valid user ids as csv", async () => {
const userIds: string[] = []
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const userId = generator.guid() const userId = generator.guid()
const user = structures.users.user({ _id: userId, userId }) const user = structures.users.user({ _id: userId, userId })
mockedCacheGetUser.mockResolvedValueOnce(user) mockedCacheGetUser.mockResolvedValueOnce(user)
users[userId] = user userIds.push(userId)
} }
const input = Object.keys(users).join(" , ") const input = userIds.join(" , ")
const result = await processInputBBReferences(input, FieldSubtype.USER) const result = await processInputBBReferences(input, FieldSubtype.USER)
expect(result).toEqual(Object.values(users)) expect(result).toEqual(userIds.join(","))
expect(mockedCacheGetUser).toBeCalledTimes(5) expect(mockedCacheGetUser).toBeCalledTimes(5)
Object.keys(users).forEach(userId => { userIds.forEach(userId => {
expect(mockedCacheGetUser).toBeCalledWith(userId) expect(mockedCacheGetUser).toBeCalledWith(userId)
}) })
}) })
it("throws an error given an invalid id in a csv", async () => {
const userId1 = generator.guid()
const userId2 = generator.guid()
const userId3 = generator.guid()
mockedCacheGetUser.mockResolvedValueOnce(
structures.users.user({ _id: userId1 })
)
mockedCacheGetUser.mockResolvedValueOnce(
structures.users.user({ _id: userId2 })
)
const input = [userId1, userId2, userId3].join(" , ")
await expect(
processInputBBReferences(input, FieldSubtype.USER)
).rejects.toThrowError(
new InvalidBBRefError(userId3, FieldSubtype.USER)
)
})
}) })
}) })
}) })