Merge pull request #11785 from Budibase/BUDI-7455/populate_user_refs_on_get
Populate user refs on get
This commit is contained in:
commit
b63c88fc36
|
@ -1,6 +1,6 @@
|
|||
import { cache } from "@budibase/backend-core"
|
||||
import { utils } from "@budibase/shared-core"
|
||||
import { Document, FieldSubtype } from "@budibase/types"
|
||||
import { FieldSubtype } from "@budibase/types"
|
||||
import { InvalidBBRefError } from "./errors"
|
||||
|
||||
export async function processInputBBReferences(
|
||||
|
@ -39,3 +39,36 @@ export async function processInputBBReferences(
|
|||
|
||||
return result.join(",")
|
||||
}
|
||||
|
||||
export async function processOutputBBReferences(
|
||||
value: string,
|
||||
subtype: FieldSubtype
|
||||
) {
|
||||
if (typeof value !== "string") {
|
||||
// Already processed or nothing to process
|
||||
return value
|
||||
}
|
||||
|
||||
const result = []
|
||||
|
||||
const validIds = value.split(",").filter(id => !!id)
|
||||
|
||||
switch (subtype) {
|
||||
case FieldSubtype.USER:
|
||||
for (const id of validIds) {
|
||||
try {
|
||||
const user = await cache.user.getUser(id)
|
||||
if (user) {
|
||||
result.push(user)
|
||||
}
|
||||
} catch {
|
||||
// If user cannot be found, we just strip it
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw utils.unreachable(subtype)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@ import { InternalTables } from "../../db/utils"
|
|||
import { TYPE_TRANSFORM_MAP } from "./map"
|
||||
import { FieldSubtype, Row, RowAttachment, Table } from "@budibase/types"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { processInputBBReferences } from "./bbReferenceProcessor"
|
||||
import {
|
||||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
} from "./bbReferenceProcessor"
|
||||
export * from "./utils"
|
||||
|
||||
type AutoColumnProcessingOpts = {
|
||||
|
@ -224,6 +227,16 @@ export async function outputProcessing<T extends Row[] | Row>(
|
|||
attachment.url = objectStore.getAppFileUrl(attachment.key)
|
||||
})
|
||||
}
|
||||
} else if (column.type == FieldTypes.BB_REFERENCE) {
|
||||
for (let row of enriched) {
|
||||
if (!row[property]) {
|
||||
continue
|
||||
}
|
||||
row[property] = await processOutputBBReferences(
|
||||
row[property],
|
||||
column.subtype as FieldSubtype
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts.squash) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import * as backendCore from "@budibase/backend-core"
|
||||
import { FieldSubtype, User } from "@budibase/types"
|
||||
import { processInputBBReferences } from "../bbReferenceProcessor"
|
||||
import {
|
||||
processInputBBReferences,
|
||||
processOutputBBReferences,
|
||||
} from "../bbReferenceProcessor"
|
||||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
import { InvalidBBRefError } from "../errors"
|
||||
|
||||
|
@ -57,7 +60,7 @@ describe("bbReferenceProcessor", () => {
|
|||
const userIds: string[] = []
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const userId = generator.guid()
|
||||
const user = structures.users.user({ _id: userId, userId })
|
||||
const user = structures.users.user({ _id: userId })
|
||||
mockedCacheGetUser.mockResolvedValueOnce(user)
|
||||
userIds.push(userId)
|
||||
}
|
||||
|
@ -128,4 +131,44 @@ describe("bbReferenceProcessor", () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("processOutputBBReferences", () => {
|
||||
describe("subtype user", () => {
|
||||
it("fetches user given a valid string id", async () => {
|
||||
const userId = generator.guid()
|
||||
|
||||
const userFromCache = structures.users.user()
|
||||
mockedCacheGetUser.mockResolvedValueOnce(userFromCache)
|
||||
|
||||
const result = await processOutputBBReferences(
|
||||
userId,
|
||||
FieldSubtype.USER
|
||||
)
|
||||
|
||||
expect(result).toEqual([userFromCache])
|
||||
expect(mockedCacheGetUser).toBeCalledTimes(1)
|
||||
expect(mockedCacheGetUser).toBeCalledWith(userId)
|
||||
})
|
||||
|
||||
it("fetches user given a valid string id csv", async () => {
|
||||
const userId1 = generator.guid()
|
||||
const userId2 = generator.guid()
|
||||
|
||||
const userFromCache1 = structures.users.user({ _id: userId1 })
|
||||
const userFromCache2 = structures.users.user({ _id: userId2 })
|
||||
mockedCacheGetUser.mockResolvedValueOnce(userFromCache1)
|
||||
mockedCacheGetUser.mockResolvedValueOnce(userFromCache2)
|
||||
|
||||
const result = await processOutputBBReferences(
|
||||
[userId1, userId2].join(","),
|
||||
FieldSubtype.USER
|
||||
)
|
||||
|
||||
expect(result).toEqual([userFromCache1, userFromCache2])
|
||||
expect(mockedCacheGetUser).toBeCalledTimes(2)
|
||||
expect(mockedCacheGetUser).toBeCalledWith(userId1)
|
||||
expect(mockedCacheGetUser).toBeCalledWith(userId2)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -5,6 +5,7 @@ import * as bbReferenceProcessor from "../bbReferenceProcessor"
|
|||
|
||||
jest.mock("../bbReferenceProcessor", (): typeof bbReferenceProcessor => ({
|
||||
processInputBBReferences: jest.fn(),
|
||||
processOutputBBReferences: jest.fn(),
|
||||
}))
|
||||
|
||||
describe("rowProcessor - inputProcessing", () => {
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
import {
|
||||
FieldSubtype,
|
||||
FieldType,
|
||||
FieldTypeSubtypes,
|
||||
Table,
|
||||
} from "@budibase/types"
|
||||
import { outputProcessing } from ".."
|
||||
import { generator, structures } from "@budibase/backend-core/tests"
|
||||
import * as bbReferenceProcessor from "../bbReferenceProcessor"
|
||||
|
||||
jest.mock("../bbReferenceProcessor", (): typeof bbReferenceProcessor => ({
|
||||
processInputBBReferences: jest.fn(),
|
||||
processOutputBBReferences: jest.fn(),
|
||||
}))
|
||||
|
||||
describe("rowProcessor - outputProcessing", () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
const processOutputBBReferencesMock =
|
||||
bbReferenceProcessor.processOutputBBReferences as jest.Mock
|
||||
|
||||
it("fetches bb user references given a populated field", async () => {
|
||||
const table: Table = {
|
||||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
name: "name",
|
||||
constraints: {
|
||||
presence: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const row = {
|
||||
name: "Jack",
|
||||
user: "123",
|
||||
}
|
||||
|
||||
const user = structures.users.user()
|
||||
processOutputBBReferencesMock.mockResolvedValue(user)
|
||||
|
||||
const result = await outputProcessing(table, row, { squash: false })
|
||||
|
||||
expect(result).toEqual({ name: "Jack", user })
|
||||
|
||||
expect(bbReferenceProcessor.processOutputBBReferences).toBeCalledTimes(1)
|
||||
expect(bbReferenceProcessor.processOutputBBReferences).toBeCalledWith(
|
||||
"123",
|
||||
FieldSubtype.USER
|
||||
)
|
||||
})
|
||||
|
||||
it("does not fetch bb references when fields are empty", async () => {
|
||||
const table: Table = {
|
||||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
name: "name",
|
||||
constraints: {
|
||||
presence: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
user: {
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const row = {
|
||||
name: "Jack",
|
||||
}
|
||||
|
||||
const result = await outputProcessing(table, row, { squash: false })
|
||||
|
||||
expect(result).toEqual({ name: "Jack" })
|
||||
|
||||
expect(bbReferenceProcessor.processOutputBBReferences).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("does not fetch bb references when not in the schema", async () => {
|
||||
const table: Table = {
|
||||
_id: generator.guid(),
|
||||
name: "TestTable",
|
||||
type: "table",
|
||||
schema: {
|
||||
name: {
|
||||
type: FieldType.STRING,
|
||||
name: "name",
|
||||
constraints: {
|
||||
presence: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
user: {
|
||||
type: FieldType.NUMBER,
|
||||
name: "user",
|
||||
constraints: {
|
||||
presence: false,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const row = {
|
||||
name: "Jack",
|
||||
user: "123",
|
||||
}
|
||||
|
||||
const result = await outputProcessing(table, row, { squash: false })
|
||||
|
||||
expect(result).toEqual({ name: "Jack", user: "123" })
|
||||
|
||||
expect(bbReferenceProcessor.processOutputBBReferences).not.toBeCalled()
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue