From 5c9e289c4d1b8872191dd84d8ca1483d33b135c7 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Fri, 11 Oct 2024 18:03:58 +0200 Subject: [PATCH] fix(utils): build query conversion breaking the underlying API operator map (#9533) --- packages/core/types/src/common/common.ts | 4 +- .../modules-sdk/__tests__/build-query.spec.ts | 97 +++++++++++++++++++ .../core/utils/src/modules-sdk/build-query.ts | 5 +- 3 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 packages/core/utils/src/modules-sdk/__tests__/build-query.spec.ts diff --git a/packages/core/types/src/common/common.ts b/packages/core/types/src/common/common.ts index 761ffdee3f..d4ea7207dd 100644 --- a/packages/core/types/src/common/common.ts +++ b/packages/core/types/src/common/common.ts @@ -80,9 +80,7 @@ export interface FindConfig { * An object used to specify how to sort the returned records. Its keys are the names of attributes of the entity, and a key's value can either be `ASC` * to sort retrieved records in an ascending order, or `DESC` to sort retrieved records in a descending order. */ - order?: { - [K: string]: "ASC" | "DESC" - } + order?: Record /** * A boolean indicating whether deleted records should also be retrieved as part of the result. This only works if the entity extends the diff --git a/packages/core/utils/src/modules-sdk/__tests__/build-query.spec.ts b/packages/core/utils/src/modules-sdk/__tests__/build-query.spec.ts new file mode 100644 index 0000000000..dbd0da8bcf --- /dev/null +++ b/packages/core/utils/src/modules-sdk/__tests__/build-query.spec.ts @@ -0,0 +1,97 @@ +import { buildQuery } from "../build-query" +import { SoftDeletableFilterKey } from "../../dal/mikro-orm/mikro-orm-soft-deletable-filter" + +describe("buildQuery", () => { + test("should return empty where and basic options when no filters or config provided", () => { + const result = buildQuery() + expect(result).toEqual({ + where: {}, + options: { + populate: [], + fields: undefined, + limit: undefined, + offset: undefined, + }, + }) + }) + + test("should build basic where clause", () => { + const filters = { name: "test", age: 25 } + const result = buildQuery(filters) + expect(result.where).toEqual(filters) + }) + + test("should handle array values in filters", () => { + const filters = { id: [1, 2, 3, 3] } + const result = buildQuery(filters) + expect(result.where).toEqual({ id: [1, 2, 3] }) // Deduplication + }) + + test("should handle nested object filters", () => { + const filters = { user: { name: "John", age: 30 } } + const result = buildQuery(filters) + expect(result.where).toEqual(filters) + }) + + test("should handle $or operator", () => { + const filters = { $or: [{ name: "John" }, { age: 30 }] } + const result = buildQuery(filters) + expect(result.where).toEqual(filters) + }) + + test("should handle $and operator", () => { + const filters = { $and: [{ name: "John" }, { age: 30 }] } + const result = buildQuery(filters) + expect(result.where).toEqual(filters) + }) + + test("should apply config options", () => { + const config = { + relations: ["user", "order"], + select: ["id", "name"], + take: 10, + skip: 5, + order: { createdAt: "DESC" }, + } + const result = buildQuery({}, config) + expect(result.options).toMatchObject({ + populate: ["user", "order"], + fields: ["id", "name"], + limit: 10, + offset: 5, + orderBy: { createdAt: "DESC" }, + }) + }) + + test("should handle withDeleted flag", () => { + const filters = { deleted_at: "some-value" } + const result = buildQuery(filters) + expect(result.options.filters).toHaveProperty(SoftDeletableFilterKey) + expect(result.options.filters?.[SoftDeletableFilterKey]).toEqual({ + withDeleted: true, + }) + }) + + test("should apply additional filters from config", () => { + const config = { + filters: { + customFilter: { someOption: true }, + }, + } + const result = buildQuery({}, config) + expect(result.options.filters).toHaveProperty("customFilter") + expect(result.options.filters?.["customFilter"]).toEqual({ + someOption: true, + }) + }) + + test("should merge options from config", () => { + const config = { + options: { + customOption: "value", + }, + } + const result = buildQuery({}, config) + expect(result.options).toHaveProperty("customOption", "value") + }) +}) diff --git a/packages/core/utils/src/modules-sdk/build-query.ts b/packages/core/utils/src/modules-sdk/build-query.ts index b6dd21afa9..63da37fa6e 100644 --- a/packages/core/utils/src/modules-sdk/build-query.ts +++ b/packages/core/utils/src/modules-sdk/build-query.ts @@ -13,7 +13,7 @@ type FilterFlags = { export function buildQuery( filters: Record = {}, config: FindConfig & { primaryKeyFields?: string | string[] } = {} -): DAL.FindOptions { +): Required> { const where: DAL.FilterQuery = {} const filterFlags: FilterFlags = {} buildWhere(filters, where, filterFlags) @@ -73,8 +73,7 @@ function buildWhere( } if (Array.isArray(value)) { - value = deduplicate(value) - where[prop] = ["$in", "$nin"].includes(prop) ? value : { $in: value } + where[prop] = deduplicate(value) continue }