use bulk cache in processInputBBReferences

This commit is contained in:
Adria Navarro 2023-09-20 10:05:52 +02:00
parent 63ab14865a
commit 58d9d3e8e8
2 changed files with 77 additions and 77 deletions

View File

@ -19,19 +19,12 @@ export async function processInputBBReferences(
result.push(...value.split(",").map((id: string) => id.trim()))
}
for (const id of result) {
try {
const user = await cache.user.getUser(id)
if (!user) {
throw new InvalidBBRefError(id, FieldSubtype.USER)
}
} catch (err: any) {
if (err != null && err.status === 404 && err.error === "not_found") {
throw new InvalidBBRefError(id, FieldSubtype.USER)
}
throw err
}
const { notFoundIds } = await cache.user.getUsers(result)
if (notFoundIds?.length) {
throw new InvalidBBRefError(notFoundIds[0], FieldSubtype.USER)
}
break
default:
throw utils.unreachable(subtype)

View File

@ -1,133 +1,140 @@
import _ from "lodash"
import * as backendCore from "@budibase/backend-core"
import { FieldSubtype, User } from "@budibase/types"
import {
processInputBBReferences,
processOutputBBReferences,
} from "../bbReferenceProcessor"
import { generator, structures } from "@budibase/backend-core/tests"
import {
DBTestConfiguration,
generator,
structures,
} from "@budibase/backend-core/tests"
import { InvalidBBRefError } from "../errors"
jest.mock("@budibase/backend-core", (): typeof backendCore => {
const actual = jest.requireActual("@budibase/backend-core")
const actual: typeof backendCore = jest.requireActual(
"@budibase/backend-core"
)
return {
...actual,
cache: {
...actual.cache,
user: {
getUser: jest.fn(),
invalidateUser: jest.fn(),
...actual.cache.user,
getUsers: jest.fn(actual.cache.user.getUsers),
},
},
}
})
const config = new DBTestConfiguration()
describe("bbReferenceProcessor", () => {
const mockedCacheGetUser = backendCore.cache.user.getUser as jest.Mock
const cacheGetUsersSpy = backendCore.cache.user
.getUsers as jest.MockedFunction<typeof backendCore.cache.user.getUsers>
const users: User[] = []
beforeAll(async () => {
const userCount = 10
const userIds = generator.arrayOf(() => generator.guid(), {
min: userCount,
max: userCount,
})
await config.doInTenant(async () => {
const db = backendCore.context.getGlobalDB()
for (const userId of userIds) {
const user = structures.users.user({ _id: userId })
await db.put(user)
users.push(user)
}
})
})
beforeEach(() => {
jest.resetAllMocks()
jest.clearAllMocks()
})
describe("processInputBBReferences", () => {
describe("subtype user", () => {
it("validate valid string id", async () => {
const userId = generator.guid()
const user = _.sample(users)
const userId = user!._id!
const userFromCache = structures.users.user()
mockedCacheGetUser.mockResolvedValueOnce(userFromCache)
const result = await processInputBBReferences(userId, FieldSubtype.USER)
const result = await config.doInTenant(() =>
processInputBBReferences(userId, FieldSubtype.USER)
)
expect(result).toEqual(userId)
expect(mockedCacheGetUser).toBeCalledTimes(1)
expect(mockedCacheGetUser).toBeCalledWith(userId)
expect(cacheGetUsersSpy).toBeCalledTimes(1)
expect(cacheGetUsersSpy).toBeCalledWith([userId])
})
it("throws an error given an invalid id", async () => {
const userId = generator.guid()
mockedCacheGetUser.mockRejectedValue({
status: 404,
error: "not_found",
})
await expect(
config.doInTenant(() =>
processInputBBReferences(userId, FieldSubtype.USER)
)
).rejects.toThrowError(new InvalidBBRefError(userId, FieldSubtype.USER))
expect(cacheGetUsersSpy).toBeCalledTimes(1)
expect(cacheGetUsersSpy).toBeCalledWith([userId])
})
it("validates valid user ids as csv", async () => {
const userIds: string[] = []
for (let i = 0; i < 5; i++) {
const userId = generator.guid()
const user = structures.users.user({ _id: userId })
mockedCacheGetUser.mockResolvedValueOnce(user)
userIds.push(userId)
}
const userIds = _.sampleSize(users, 5).map(x => x._id!)
const userIdCsv = userIds.join(" , ")
const result = await processInputBBReferences(
userIdCsv,
FieldSubtype.USER
const result = await config.doInTenant(() =>
processInputBBReferences(userIdCsv, FieldSubtype.USER)
)
expect(result).toEqual(userIds.join(","))
expect(mockedCacheGetUser).toBeCalledTimes(5)
userIds.forEach(userId => {
expect(mockedCacheGetUser).toBeCalledWith(userId)
})
expect(cacheGetUsersSpy).toBeCalledTimes(1)
expect(cacheGetUsersSpy).toBeCalledWith(userIds)
})
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 expectedUsers = _.sampleSize(users, 2).map(x => x._id!)
const wrongId = generator.guid()
const userIdCsv = [userId1, userId2, userId3].join(" , ")
const userIdCsv = [expectedUsers[0], wrongId, expectedUsers[1]].join(
" , "
)
await expect(
config.doInTenant(() =>
processInputBBReferences(userIdCsv, FieldSubtype.USER)
)
).rejects.toThrowError(
new InvalidBBRefError(userId3, FieldSubtype.USER)
new InvalidBBRefError(wrongId, FieldSubtype.USER)
)
})
it("validate valid user object", async () => {
const userId = generator.guid()
const userId = _.sample(users)!._id!
const userFromCache = structures.users.user()
mockedCacheGetUser.mockResolvedValueOnce(userFromCache)
const result = await processInputBBReferences(
{ _id: userId },
FieldSubtype.USER
const result = await config.doInTenant(() =>
processInputBBReferences({ _id: userId }, FieldSubtype.USER)
)
expect(result).toEqual(userId)
expect(mockedCacheGetUser).toBeCalledTimes(1)
expect(mockedCacheGetUser).toBeCalledWith(userId)
expect(cacheGetUsersSpy).toBeCalledTimes(1)
expect(cacheGetUsersSpy).toBeCalledWith([userId])
})
it("validate valid user object array", async () => {
const users = Array.from({ length: 3 }, () => ({
_id: generator.guid(),
}))
const userIds = _.sampleSize(users, 3).map(x => x._id!)
mockedCacheGetUser.mockResolvedValue(structures.users.user())
const result = await config.doInTenant(() =>
processInputBBReferences(userIds, FieldSubtype.USER)
)
const result = await processInputBBReferences(users, FieldSubtype.USER)
expect(result).toEqual(users.map(x => x._id).join(","))
expect(mockedCacheGetUser).toBeCalledTimes(3)
for (const user of users) {
expect(mockedCacheGetUser).toBeCalledWith(user._id)
}
expect(result).toEqual(userIds.join(","))
expect(cacheGetUsersSpy).toBeCalledTimes(1)
expect(cacheGetUsersSpy).toBeCalledWith(userIds)
})
})
})