Validate and return csv
This commit is contained in:
parent
2f9843bd4c
commit
f1a1cf74bc
3 changed files with 64 additions and 21 deletions
|
@ -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]
|
|
||||||
}
|
}
|
||||||
|
|
7
packages/server/src/utilities/rowProcessor/errors.ts
Normal file
7
packages/server/src/utilities/rowProcessor/errors.ts
Normal 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}"`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue