processInputBBReference vs processInputBBReferences

This commit is contained in:
Adria Navarro 2024-05-02 16:51:48 +01:00
parent f9d738c393
commit 1767650337
3 changed files with 160 additions and 149 deletions

View File

@ -10,39 +10,57 @@ import { InvalidBBRefError } from "./errors"
const ROW_PREFIX = DocumentType.ROW + SEPARATOR const ROW_PREFIX = DocumentType.ROW + SEPARATOR
export function processInputBBReferences( export async function processInputBBReference(
value: string | { _id: string }, value: string | { _id: string },
type: FieldType.BB_REFERENCE_SINGLE subtype: BBReferenceFieldSubType.USER
): Promise<string | null> ): Promise<string | null> {
export function processInputBBReferences( if (value && Array.isArray(value)) {
value: string | string[] | { _id: string } | { _id: string }[], throw "BB_REFERENCE_SINGLE cannot be an array"
type: FieldType.BB_REFERENCE, }
subtype: BBReferenceFieldSubType let id = typeof value === "string" ? value : value?._id
): Promise<string | null>
if (!id) {
return null
}
switch (subtype) {
case BBReferenceFieldSubType.USER: {
if (id.startsWith(ROW_PREFIX)) {
id = dbCore.getGlobalIDFromUserMetadataID(id)
}
try {
await cache.user.getUser(id)
return id
} catch (e: any) {
if (e.statusCode === 404) {
throw new InvalidBBRefError(id, BBReferenceFieldSubType.USER)
}
throw e
}
}
default:
throw utils.unreachable(subtype)
}
}
export async function processInputBBReferences( export async function processInputBBReferences(
value: string | string[] | { _id: string } | { _id: string }[], value: string | string[] | { _id: string }[],
type: FieldType.BB_REFERENCE | FieldType.BB_REFERENCE_SINGLE, subtype: BBReferenceFieldSubType
subtype?: BBReferenceFieldSubType ): Promise<string[] | null> {
): Promise<string | string[] | null> { if (!value || !value[0]) {
switch (type) { return null
case FieldType.BB_REFERENCE: { }
let referenceIds: string[] = []
if (Array.isArray(value)) { let referenceIds
referenceIds.push( if (typeof value === "string") {
...value.map(idOrDoc => referenceIds = value
typeof idOrDoc === "string" ? idOrDoc : idOrDoc._id
)
)
} else if (typeof value !== "string") {
referenceIds.push(value._id)
} else {
referenceIds.push(
...value
.split(",") .split(",")
.filter(x => x) .map(u => u.trim())
.map((id: string) => id.trim()) .filter(u => !!u)
} else {
referenceIds = value.map(idOrDoc =>
typeof idOrDoc === "string" ? idOrDoc : idOrDoc._id
) )
} }
@ -75,35 +93,11 @@ export async function processInputBBReferences(
return null return null
} }
if (subtype === BBReferenceFieldSubType.USERS) {
return referenceIds return referenceIds
} }
return referenceIds.join(",")
}
default: default:
throw utils.unreachable(subtype) throw utils.unreachable(subtype)
} }
}
case FieldType.BB_REFERENCE_SINGLE: {
if (value && Array.isArray(value)) {
throw "BB_REFERENCE_SINGLE cannot be an array"
}
const id = typeof value === "string" ? value : value._id
const user = await cache.user.getUser(id)
if (!user) {
throw new InvalidBBRefError(id, BBReferenceFieldSubType.USER)
}
return user._id!
}
default:
throw utils.unreachable(type)
}
} }
interface UserReferenceInfo { interface UserReferenceInfo {

View File

@ -12,6 +12,7 @@ import {
} from "@budibase/types" } from "@budibase/types"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { import {
processInputBBReference,
processInputBBReferences, processInputBBReferences,
processOutputBBReferences, processOutputBBReferences,
} from "./bbReferenceProcessor" } from "./bbReferenceProcessor"
@ -161,13 +162,9 @@ export async function inputProcessing(
delete clonedRow[key].url delete clonedRow[key].url
} }
} else if (field.type === FieldType.BB_REFERENCE && value) { } else if (field.type === FieldType.BB_REFERENCE && value) {
clonedRow[key] = await processInputBBReferences( clonedRow[key] = await processInputBBReferences(value, field.subtype)
value,
field.type,
field.subtype
)
} else if (field.type === FieldType.BB_REFERENCE_SINGLE && value) { } else if (field.type === FieldType.BB_REFERENCE_SINGLE && value) {
clonedRow[key] = await processInputBBReferences(value, field.type) clonedRow[key] = await processInputBBReference(value, field.subtype)
} }
} }

View File

@ -2,6 +2,7 @@ import _ from "lodash"
import * as backendCore from "@budibase/backend-core" import * as backendCore from "@budibase/backend-core"
import { BBReferenceFieldSubType, FieldType, User } from "@budibase/types" import { BBReferenceFieldSubType, FieldType, User } from "@budibase/types"
import { import {
processInputBBReference,
processInputBBReferences, processInputBBReferences,
processOutputBBReferences, processOutputBBReferences,
} from "../bbReferenceProcessor" } from "../bbReferenceProcessor"
@ -22,6 +23,7 @@ jest.mock("@budibase/backend-core", (): typeof backendCore => {
...actual.cache, ...actual.cache,
user: { user: {
...actual.cache.user, ...actual.cache.user,
getUser: jest.fn(actual.cache.user.getUser),
getUsers: jest.fn(actual.cache.user.getUsers), getUsers: jest.fn(actual.cache.user.getUsers),
}, },
}, },
@ -31,9 +33,6 @@ jest.mock("@budibase/backend-core", (): typeof backendCore => {
const config = new DBTestConfiguration() const config = new DBTestConfiguration()
describe("bbReferenceProcessor", () => { describe("bbReferenceProcessor", () => {
const cacheGetUsersSpy = backendCore.cache.user
.getUsers as jest.MockedFunction<typeof backendCore.cache.user.getUsers>
const users: User[] = [] const users: User[] = []
beforeAll(async () => { beforeAll(async () => {
const userCount = 10 const userCount = 10
@ -56,21 +55,81 @@ describe("bbReferenceProcessor", () => {
jest.clearAllMocks() jest.clearAllMocks()
}) })
describe("processInputBBReferences", () => { describe("processInputBBReference", () => {
describe("subtype user", () => { describe("subtype user", () => {
const cacheGetUserSpy = backendCore.cache.user
.getUser as jest.MockedFunction<typeof backendCore.cache.user.getUser>
it("validate valid string id", async () => { it("validate valid string id", async () => {
const user = _.sample(users) const user = _.sample(users)
const userId = user!._id! const userId = user!._id!
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReference(userId, BBReferenceFieldSubType.USER)
userId,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
expect(result).toEqual(userId) expect(result).toEqual(userId)
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
})
it("throws an error given an invalid id", async () => {
const userId = generator.guid()
await expect(
config.doInTenant(() =>
processInputBBReference(userId, BBReferenceFieldSubType.USER)
)
).rejects.toThrow(
new InvalidBBRefError(userId, BBReferenceFieldSubType.USER)
)
})
it("validate valid user object", async () => {
const userId = _.sample(users)!._id!
const result = await config.doInTenant(() =>
processInputBBReference({ _id: userId }, BBReferenceFieldSubType.USER)
)
expect(result).toEqual(userId)
expect(cacheGetUserSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUserSpy).toHaveBeenCalledWith(userId)
})
it("empty strings will return null", async () => {
const result = await config.doInTenant(() =>
processInputBBReference("", BBReferenceFieldSubType.USER)
)
expect(result).toEqual(null)
})
it("should convert user medata IDs to global IDs", async () => {
const userId = _.sample(users)!._id!
const userMetadataId = backendCore.db.generateUserMetadataID(userId)
const result = await config.doInTenant(() =>
processInputBBReference(userMetadataId, BBReferenceFieldSubType.USER)
)
expect(result).toBe(userId)
})
})
})
describe("processInputBBReferences", () => {
describe("subtype user", () => {
const cacheGetUsersSpy = backendCore.cache.user
.getUsers as jest.MockedFunction<typeof backendCore.cache.user.getUsers>
it("validate valid string id", async () => {
const user = _.sample(users)
const userId = user!._id!
const result = await config.doInTenant(() =>
processInputBBReferences(userId, BBReferenceFieldSubType.USER)
)
expect(result).toEqual([userId])
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1) expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUsersSpy).toHaveBeenCalledWith([userId]) expect(cacheGetUsersSpy).toHaveBeenCalledWith([userId])
}) })
@ -80,11 +139,7 @@ describe("bbReferenceProcessor", () => {
await expect( await expect(
config.doInTenant(() => config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(userId, BBReferenceFieldSubType.USER)
userId,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
).rejects.toThrow( ).rejects.toThrow(
new InvalidBBRefError(userId, BBReferenceFieldSubType.USER) new InvalidBBRefError(userId, BBReferenceFieldSubType.USER)
@ -98,14 +153,10 @@ describe("bbReferenceProcessor", () => {
const userIdCsv = userIds.join(" , ") const userIdCsv = userIds.join(" , ")
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
userIdCsv,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
expect(result).toEqual(userIds.join(",")) expect(result).toEqual(userIds)
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1) expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds) expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds)
}) })
@ -122,45 +173,22 @@ describe("bbReferenceProcessor", () => {
await expect( await expect(
config.doInTenant(() => config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
userIdCsv,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
).rejects.toThrow( ).rejects.toThrow(
new InvalidBBRefError(wrongId, BBReferenceFieldSubType.USER) new InvalidBBRefError(wrongId, BBReferenceFieldSubType.USER)
) )
}) })
it("validate valid user object", async () => {
const userId = _.sample(users)!._id!
const result = await config.doInTenant(() =>
processInputBBReferences(
{ _id: userId },
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
)
expect(result).toEqual(userId)
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUsersSpy).toHaveBeenCalledWith([userId])
})
it("validate valid user object array", async () => { it("validate valid user object array", async () => {
const userIds = _.sampleSize(users, 3).map(x => x._id!) const inputUsers = _.sampleSize(users, 3).map(u => ({ _id: u._id! }))
const userIds = inputUsers.map(u => u._id)
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(inputUsers, BBReferenceFieldSubType.USER)
userIds,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
expect(result).toEqual(userIds.join(",")) expect(result).toEqual(userIds)
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1) expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds) expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds)
}) })
@ -169,7 +197,7 @@ describe("bbReferenceProcessor", () => {
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(
"", "",
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER BBReferenceFieldSubType.USER
) )
) )
@ -179,11 +207,7 @@ describe("bbReferenceProcessor", () => {
it("empty arrays will return null", async () => { it("empty arrays will return null", async () => {
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReferences([], BBReferenceFieldSubType.USER)
[],
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
)
) )
expect(result).toEqual(null) expect(result).toEqual(null)
@ -193,13 +217,9 @@ describe("bbReferenceProcessor", () => {
const userId = _.sample(users)!._id! const userId = _.sample(users)!._id!
const userMetadataId = backendCore.db.generateUserMetadataID(userId) const userMetadataId = backendCore.db.generateUserMetadataID(userId)
const result = await config.doInTenant(() => const result = await config.doInTenant(() =>
processInputBBReferences( processInputBBReferences(userMetadataId, BBReferenceFieldSubType.USER)
userMetadataId,
FieldType.BB_REFERENCE,
BBReferenceFieldSubType.USER
) )
) expect(result).toEqual([userId])
expect(result).toBe(userId)
}) })
}) })
}) })