processInputBBReference vs processInputBBReferences
This commit is contained in:
parent
f9d738c393
commit
1767650337
|
@ -10,99 +10,93 @@ import { InvalidBBRefError } from "./errors"
|
|||
|
||||
const ROW_PREFIX = DocumentType.ROW + SEPARATOR
|
||||
|
||||
export function processInputBBReferences(
|
||||
export async function processInputBBReference(
|
||||
value: string | { _id: string },
|
||||
type: FieldType.BB_REFERENCE_SINGLE
|
||||
): Promise<string | null>
|
||||
export function processInputBBReferences(
|
||||
value: string | string[] | { _id: string } | { _id: string }[],
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: BBReferenceFieldSubType
|
||||
): Promise<string | null>
|
||||
subtype: BBReferenceFieldSubType.USER
|
||||
): Promise<string | null> {
|
||||
if (value && Array.isArray(value)) {
|
||||
throw "BB_REFERENCE_SINGLE cannot be an array"
|
||||
}
|
||||
let id = typeof value === "string" ? value : value?._id
|
||||
|
||||
export async function processInputBBReferences(
|
||||
value: string | string[] | { _id: string } | { _id: string }[],
|
||||
type: FieldType.BB_REFERENCE | FieldType.BB_REFERENCE_SINGLE,
|
||||
subtype?: BBReferenceFieldSubType
|
||||
): Promise<string | string[] | null> {
|
||||
switch (type) {
|
||||
case FieldType.BB_REFERENCE: {
|
||||
let referenceIds: string[] = []
|
||||
if (!id) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
referenceIds.push(
|
||||
...value.map(idOrDoc =>
|
||||
typeof idOrDoc === "string" ? idOrDoc : idOrDoc._id
|
||||
)
|
||||
)
|
||||
} else if (typeof value !== "string") {
|
||||
referenceIds.push(value._id)
|
||||
} else {
|
||||
referenceIds.push(
|
||||
...value
|
||||
.split(",")
|
||||
.filter(x => x)
|
||||
.map((id: string) => id.trim())
|
||||
)
|
||||
switch (subtype) {
|
||||
case BBReferenceFieldSubType.USER: {
|
||||
if (id.startsWith(ROW_PREFIX)) {
|
||||
id = dbCore.getGlobalIDFromUserMetadataID(id)
|
||||
}
|
||||
|
||||
// make sure all reference IDs are correct global user IDs
|
||||
// they may be user metadata references (start with row prefix)
|
||||
// and these need to be converted to global IDs
|
||||
referenceIds = referenceIds.map(id => {
|
||||
if (id?.startsWith(ROW_PREFIX)) {
|
||||
return dbCore.getGlobalIDFromUserMetadataID(id)
|
||||
} else {
|
||||
return id
|
||||
try {
|
||||
await cache.user.getUser(id)
|
||||
return id
|
||||
} catch (e: any) {
|
||||
if (e.statusCode === 404) {
|
||||
throw new InvalidBBRefError(id, BBReferenceFieldSubType.USER)
|
||||
}
|
||||
})
|
||||
|
||||
switch (subtype) {
|
||||
case undefined:
|
||||
throw "Subtype must be defined"
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS: {
|
||||
const { notFoundIds } = await cache.user.getUsers(referenceIds)
|
||||
|
||||
if (notFoundIds?.length) {
|
||||
throw new InvalidBBRefError(
|
||||
notFoundIds[0],
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
}
|
||||
|
||||
if (!referenceIds?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (subtype === BBReferenceFieldSubType.USERS) {
|
||||
return referenceIds
|
||||
}
|
||||
|
||||
return referenceIds.join(",")
|
||||
}
|
||||
default:
|
||||
throw utils.unreachable(subtype)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
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)
|
||||
throw utils.unreachable(subtype)
|
||||
}
|
||||
}
|
||||
export async function processInputBBReferences(
|
||||
value: string | string[] | { _id: string }[],
|
||||
subtype: BBReferenceFieldSubType
|
||||
): Promise<string[] | null> {
|
||||
if (!value || !value[0]) {
|
||||
return null
|
||||
}
|
||||
|
||||
let referenceIds
|
||||
if (typeof value === "string") {
|
||||
referenceIds = value
|
||||
.split(",")
|
||||
.map(u => u.trim())
|
||||
.filter(u => !!u)
|
||||
} else {
|
||||
referenceIds = value.map(idOrDoc =>
|
||||
typeof idOrDoc === "string" ? idOrDoc : idOrDoc._id
|
||||
)
|
||||
}
|
||||
|
||||
// make sure all reference IDs are correct global user IDs
|
||||
// they may be user metadata references (start with row prefix)
|
||||
// and these need to be converted to global IDs
|
||||
referenceIds = referenceIds.map(id => {
|
||||
if (id?.startsWith(ROW_PREFIX)) {
|
||||
return dbCore.getGlobalIDFromUserMetadataID(id)
|
||||
} else {
|
||||
return id
|
||||
}
|
||||
})
|
||||
|
||||
switch (subtype) {
|
||||
case undefined:
|
||||
throw "Subtype must be defined"
|
||||
case BBReferenceFieldSubType.USER:
|
||||
case BBReferenceFieldSubType.USERS: {
|
||||
const { notFoundIds } = await cache.user.getUsers(referenceIds)
|
||||
|
||||
if (notFoundIds?.length) {
|
||||
throw new InvalidBBRefError(
|
||||
notFoundIds[0],
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
}
|
||||
|
||||
if (!referenceIds?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return referenceIds
|
||||
}
|
||||
default:
|
||||
throw utils.unreachable(subtype)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
} from "@budibase/types"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import {
|
||||
processInputBBReference,
|
||||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
} from "./bbReferenceProcessor"
|
||||
|
@ -161,13 +162,9 @@ export async function inputProcessing(
|
|||
delete clonedRow[key].url
|
||||
}
|
||||
} else if (field.type === FieldType.BB_REFERENCE && value) {
|
||||
clonedRow[key] = await processInputBBReferences(
|
||||
value,
|
||||
field.type,
|
||||
field.subtype
|
||||
)
|
||||
clonedRow[key] = await processInputBBReferences(value, field.subtype)
|
||||
} else if (field.type === FieldType.BB_REFERENCE_SINGLE && value) {
|
||||
clonedRow[key] = await processInputBBReferences(value, field.type)
|
||||
clonedRow[key] = await processInputBBReference(value, field.subtype)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import _ from "lodash"
|
|||
import * as backendCore from "@budibase/backend-core"
|
||||
import { BBReferenceFieldSubType, FieldType, User } from "@budibase/types"
|
||||
import {
|
||||
processInputBBReference,
|
||||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
} from "../bbReferenceProcessor"
|
||||
|
@ -22,6 +23,7 @@ jest.mock("@budibase/backend-core", (): typeof backendCore => {
|
|||
...actual.cache,
|
||||
user: {
|
||||
...actual.cache.user,
|
||||
getUser: jest.fn(actual.cache.user.getUser),
|
||||
getUsers: jest.fn(actual.cache.user.getUsers),
|
||||
},
|
||||
},
|
||||
|
@ -31,9 +33,6 @@ jest.mock("@budibase/backend-core", (): typeof backendCore => {
|
|||
const config = new DBTestConfiguration()
|
||||
|
||||
describe("bbReferenceProcessor", () => {
|
||||
const cacheGetUsersSpy = backendCore.cache.user
|
||||
.getUsers as jest.MockedFunction<typeof backendCore.cache.user.getUsers>
|
||||
|
||||
const users: User[] = []
|
||||
beforeAll(async () => {
|
||||
const userCount = 10
|
||||
|
@ -56,21 +55,81 @@ describe("bbReferenceProcessor", () => {
|
|||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe("processInputBBReferences", () => {
|
||||
describe("processInputBBReference", () => {
|
||||
describe("subtype user", () => {
|
||||
const cacheGetUserSpy = backendCore.cache.user
|
||||
.getUser as jest.MockedFunction<typeof backendCore.cache.user.getUser>
|
||||
|
||||
it("validate valid string id", async () => {
|
||||
const user = _.sample(users)
|
||||
const userId = user!._id!
|
||||
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
userId,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReference(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
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).toHaveBeenCalledWith([userId])
|
||||
})
|
||||
|
@ -80,11 +139,7 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
await expect(
|
||||
config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
userId,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences(userId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
).rejects.toThrow(
|
||||
new InvalidBBRefError(userId, BBReferenceFieldSubType.USER)
|
||||
|
@ -98,14 +153,10 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
const userIdCsv = userIds.join(" , ")
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
userIdCsv,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userIds.join(","))
|
||||
expect(result).toEqual(userIds)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds)
|
||||
})
|
||||
|
@ -122,45 +173,22 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
await expect(
|
||||
config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
userIdCsv,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences(userIdCsv, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
).rejects.toThrow(
|
||||
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 () => {
|
||||
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(() =>
|
||||
processInputBBReferences(
|
||||
userIds,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences(inputUsers, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(userIds.join(","))
|
||||
expect(result).toEqual(userIds)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledTimes(1)
|
||||
expect(cacheGetUsersSpy).toHaveBeenCalledWith(userIds)
|
||||
})
|
||||
|
@ -169,7 +197,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
"",
|
||||
FieldType.BB_REFERENCE,
|
||||
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
)
|
||||
|
@ -179,11 +207,7 @@ describe("bbReferenceProcessor", () => {
|
|||
|
||||
it("empty arrays will return null", async () => {
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
[],
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences([], BBReferenceFieldSubType.USER)
|
||||
)
|
||||
|
||||
expect(result).toEqual(null)
|
||||
|
@ -193,13 +217,9 @@ describe("bbReferenceProcessor", () => {
|
|||
const userId = _.sample(users)!._id!
|
||||
const userMetadataId = backendCore.db.generateUserMetadataID(userId)
|
||||
const result = await config.doInTenant(() =>
|
||||
processInputBBReferences(
|
||||
userMetadataId,
|
||||
FieldType.BB_REFERENCE,
|
||||
BBReferenceFieldSubType.USER
|
||||
)
|
||||
processInputBBReferences(userMetadataId, BBReferenceFieldSubType.USER)
|
||||
)
|
||||
expect(result).toBe(userId)
|
||||
expect(result).toEqual([userId])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue