use bulk cache in processInputBBReferences
This commit is contained in:
parent
63ab14865a
commit
58d9d3e8e8
|
@ -19,19 +19,12 @@ export async function processInputBBReferences(
|
||||||
result.push(...value.split(",").map((id: string) => id.trim()))
|
result.push(...value.split(",").map((id: string) => id.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const id of result) {
|
const { notFoundIds } = await cache.user.getUsers(result)
|
||||||
try {
|
|
||||||
const user = await cache.user.getUser(id)
|
if (notFoundIds?.length) {
|
||||||
if (!user) {
|
throw new InvalidBBRefError(notFoundIds[0], FieldSubtype.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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
throw utils.unreachable(subtype)
|
throw utils.unreachable(subtype)
|
||||||
|
|
|
@ -1,133 +1,140 @@
|
||||||
|
import _ from "lodash"
|
||||||
import * as backendCore from "@budibase/backend-core"
|
import * as backendCore from "@budibase/backend-core"
|
||||||
import { FieldSubtype, User } from "@budibase/types"
|
import { FieldSubtype, User } from "@budibase/types"
|
||||||
import {
|
import {
|
||||||
processInputBBReferences,
|
processInputBBReferences,
|
||||||
processOutputBBReferences,
|
processOutputBBReferences,
|
||||||
} from "../bbReferenceProcessor"
|
} from "../bbReferenceProcessor"
|
||||||
import { generator, structures } from "@budibase/backend-core/tests"
|
import {
|
||||||
|
DBTestConfiguration,
|
||||||
|
generator,
|
||||||
|
structures,
|
||||||
|
} from "@budibase/backend-core/tests"
|
||||||
import { InvalidBBRefError } from "../errors"
|
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: typeof backendCore = jest.requireActual(
|
||||||
|
"@budibase/backend-core"
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
...actual,
|
...actual,
|
||||||
cache: {
|
cache: {
|
||||||
...actual.cache,
|
...actual.cache,
|
||||||
user: {
|
user: {
|
||||||
getUser: jest.fn(),
|
...actual.cache.user,
|
||||||
invalidateUser: jest.fn(),
|
getUsers: jest.fn(actual.cache.user.getUsers),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const config = new DBTestConfiguration()
|
||||||
|
|
||||||
describe("bbReferenceProcessor", () => {
|
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(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks()
|
jest.clearAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("processInputBBReferences", () => {
|
describe("processInputBBReferences", () => {
|
||||||
describe("subtype user", () => {
|
describe("subtype user", () => {
|
||||||
it("validate valid string id", async () => {
|
it("validate valid string id", async () => {
|
||||||
const userId = generator.guid()
|
const user = _.sample(users)
|
||||||
|
const userId = user!._id!
|
||||||
|
|
||||||
const userFromCache = structures.users.user()
|
const result = await config.doInTenant(() =>
|
||||||
mockedCacheGetUser.mockResolvedValueOnce(userFromCache)
|
processInputBBReferences(userId, FieldSubtype.USER)
|
||||||
|
)
|
||||||
const result = await processInputBBReferences(userId, FieldSubtype.USER)
|
|
||||||
|
|
||||||
expect(result).toEqual(userId)
|
expect(result).toEqual(userId)
|
||||||
expect(mockedCacheGetUser).toBeCalledTimes(1)
|
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
||||||
expect(mockedCacheGetUser).toBeCalledWith(userId)
|
expect(cacheGetUsersSpy).toBeCalledWith([userId])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("throws an error given an invalid id", async () => {
|
it("throws an error given an invalid id", async () => {
|
||||||
const userId = generator.guid()
|
const userId = generator.guid()
|
||||||
|
|
||||||
mockedCacheGetUser.mockRejectedValue({
|
|
||||||
status: 404,
|
|
||||||
error: "not_found",
|
|
||||||
})
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
processInputBBReferences(userId, FieldSubtype.USER)
|
config.doInTenant(() =>
|
||||||
|
processInputBBReferences(userId, FieldSubtype.USER)
|
||||||
|
)
|
||||||
).rejects.toThrowError(new InvalidBBRefError(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 () => {
|
it("validates valid user ids as csv", async () => {
|
||||||
const userIds: string[] = []
|
const userIds = _.sampleSize(users, 5).map(x => x._id!)
|
||||||
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 userIdCsv = userIds.join(" , ")
|
const userIdCsv = userIds.join(" , ")
|
||||||
const result = await processInputBBReferences(
|
const result = await config.doInTenant(() =>
|
||||||
userIdCsv,
|
processInputBBReferences(userIdCsv, FieldSubtype.USER)
|
||||||
FieldSubtype.USER
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result).toEqual(userIds.join(","))
|
expect(result).toEqual(userIds.join(","))
|
||||||
expect(mockedCacheGetUser).toBeCalledTimes(5)
|
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
||||||
userIds.forEach(userId => {
|
expect(cacheGetUsersSpy).toBeCalledWith(userIds)
|
||||||
expect(mockedCacheGetUser).toBeCalledWith(userId)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("throws an error given an invalid id in a csv", async () => {
|
it("throws an error given an invalid id in a csv", async () => {
|
||||||
const userId1 = generator.guid()
|
const expectedUsers = _.sampleSize(users, 2).map(x => x._id!)
|
||||||
const userId2 = generator.guid()
|
const wrongId = generator.guid()
|
||||||
const userId3 = generator.guid()
|
|
||||||
mockedCacheGetUser.mockResolvedValueOnce(
|
|
||||||
structures.users.user({ _id: userId1 })
|
|
||||||
)
|
|
||||||
mockedCacheGetUser.mockResolvedValueOnce(
|
|
||||||
structures.users.user({ _id: userId2 })
|
|
||||||
)
|
|
||||||
|
|
||||||
const userIdCsv = [userId1, userId2, userId3].join(" , ")
|
const userIdCsv = [expectedUsers[0], wrongId, expectedUsers[1]].join(
|
||||||
|
" , "
|
||||||
|
)
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
processInputBBReferences(userIdCsv, FieldSubtype.USER)
|
config.doInTenant(() =>
|
||||||
|
processInputBBReferences(userIdCsv, FieldSubtype.USER)
|
||||||
|
)
|
||||||
).rejects.toThrowError(
|
).rejects.toThrowError(
|
||||||
new InvalidBBRefError(userId3, FieldSubtype.USER)
|
new InvalidBBRefError(wrongId, FieldSubtype.USER)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validate valid user object", async () => {
|
it("validate valid user object", async () => {
|
||||||
const userId = generator.guid()
|
const userId = _.sample(users)!._id!
|
||||||
|
|
||||||
const userFromCache = structures.users.user()
|
const result = await config.doInTenant(() =>
|
||||||
mockedCacheGetUser.mockResolvedValueOnce(userFromCache)
|
processInputBBReferences({ _id: userId }, FieldSubtype.USER)
|
||||||
|
|
||||||
const result = await processInputBBReferences(
|
|
||||||
{ _id: userId },
|
|
||||||
FieldSubtype.USER
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result).toEqual(userId)
|
expect(result).toEqual(userId)
|
||||||
expect(mockedCacheGetUser).toBeCalledTimes(1)
|
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
||||||
expect(mockedCacheGetUser).toBeCalledWith(userId)
|
expect(cacheGetUsersSpy).toBeCalledWith([userId])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validate valid user object array", async () => {
|
it("validate valid user object array", async () => {
|
||||||
const users = Array.from({ length: 3 }, () => ({
|
const userIds = _.sampleSize(users, 3).map(x => x._id!)
|
||||||
_id: generator.guid(),
|
|
||||||
}))
|
|
||||||
|
|
||||||
mockedCacheGetUser.mockResolvedValue(structures.users.user())
|
const result = await config.doInTenant(() =>
|
||||||
|
processInputBBReferences(userIds, FieldSubtype.USER)
|
||||||
|
)
|
||||||
|
|
||||||
const result = await processInputBBReferences(users, FieldSubtype.USER)
|
expect(result).toEqual(userIds.join(","))
|
||||||
|
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
||||||
expect(result).toEqual(users.map(x => x._id).join(","))
|
expect(cacheGetUsersSpy).toBeCalledWith(userIds)
|
||||||
expect(mockedCacheGetUser).toBeCalledTimes(3)
|
|
||||||
for (const user of users) {
|
|
||||||
expect(mockedCacheGetUser).toBeCalledWith(user._id)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue