From cc4169a94c7c5f5bf4d04f7b6e815b409a0a8192 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 21 Sep 2023 12:50:28 +0200 Subject: [PATCH] feat(utils): Provide an utils that allows to convert an array of fields to a complete remote query object (#5161) **What** For simplicity and compatibility with the front, the fields are stored as an array of strings containing the list of fields that should be selected by a query. In order to reduce the delta between this object shape and what is expected by the remoteQuery when passing an object, we built util to make the translation from fields to config. This will allow us to update the endpoint fields to specify what exactly needs to be selected and based on that we will be able to build the remote query object. Furthermore, it will allow us to drop back the functionality of custom fields and relations. we will still have to take into account the limit constraint of an url size including the parameters if a user want to select everything from a relation. In that case, we might maybe think about handling this case once the modules will export all available relations and fields so that the remote joiner would be able to pass them all automatically if the relation is present but a `*` is passed or no values in the fields during the translation with the util. But this is something we can come up in a separate iteration --- .changeset/lemon-spies-double.md | 5 + .../string-to-remote-query-object.ts | 81 ++++++++++++ .../common/string-to-remote-query-object.ts | 124 ++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 .changeset/lemon-spies-double.md create mode 100644 packages/utils/src/common/__tests__/string-to-remote-query-object.ts create mode 100644 packages/utils/src/common/string-to-remote-query-object.ts diff --git a/.changeset/lemon-spies-double.md b/.changeset/lemon-spies-double.md new file mode 100644 index 0000000000..ae3b7fd186 --- /dev/null +++ b/.changeset/lemon-spies-double.md @@ -0,0 +1,5 @@ +--- +"@medusajs/utils": patch +--- + +feat(utils): Provide an utils that allows to convert an array of fields to a complete remote query object diff --git a/packages/utils/src/common/__tests__/string-to-remote-query-object.ts b/packages/utils/src/common/__tests__/string-to-remote-query-object.ts new file mode 100644 index 0000000000..0314ba0268 --- /dev/null +++ b/packages/utils/src/common/__tests__/string-to-remote-query-object.ts @@ -0,0 +1,81 @@ +import { stringToRemoteQueryObject } from "../string-to-remote-query-object" + +const fields = [ + "id", + "created_at", + "updated_at", + "deleted_at", + "url", + "metadata", + "tags.id", + "tags.created_at", + "tags.updated_at", + "tags.deleted_at", + "tags.value", + "options.id", + "options.created_at", + "options.updated_at", + "options.deleted_at", + "options.title", + "options.product_id", + "options.metadata", + "options.values.id", + "options.values.created_at", + "options.values.updated_at", + "options.values.deleted_at", + "options.values.value", + "options.values.option_id", + "options.values.variant_id", + "options.values.metadata", +] + +describe("stringToRemoteQueryObject", function () { + it("should return a remote query object", function () { + const output = stringToRemoteQueryObject({ + entryPoint: "product", + variables: {}, + fields, + }) + + expect(output).toEqual({ + product: { + __args: {}, + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "url", + "metadata", + ], + tags: { + fields: ["id", "created_at", "updated_at", "deleted_at", "value"], + }, + + options: { + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "title", + "product_id", + "metadata", + ], + values: { + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "value", + "option_id", + "variant_id", + "metadata", + ], + }, + }, + }, + }) + }) +}) diff --git a/packages/utils/src/common/string-to-remote-query-object.ts b/packages/utils/src/common/string-to-remote-query-object.ts new file mode 100644 index 0000000000..cc76aed7b8 --- /dev/null +++ b/packages/utils/src/common/string-to-remote-query-object.ts @@ -0,0 +1,124 @@ +/** + * Convert a string fields array to a remote query object + * @param entryPoint + * @param variables + * @param fields + * + * @example + * const fields = [ + * "id", + * "created_at", + * "updated_at", + * "deleted_at", + * "url", + * "metadata", + * "tags.id", + * "tags.created_at", + * "tags.updated_at", + * "tags.deleted_at", + * "tags.value", + * "options.id", + * "options.created_at", + * "options.updated_at", + * "options.deleted_at", + * "options.title", + * "options.product_id", + * "options.metadata", + * "options.values.id", + * "options.values.created_at", + * "options.values.updated_at", + * "options.values.deleted_at", + * "options.values.value", + * "options.values.option_id", + * "options.values.variant_id", + * "options.values.metadata", + * ] + * + * const remoteQueryObject = stringToRemoteQueryObject({ + * entryPoint: "product", + * variables: {}, + * fields, + * }) + * + * console.log(remoteQueryObject) + * // { + * // product: { + * // __args: {}, + * // fields: [ + * // "id", + * // "created_at", + * // "updated_at", + * // "deleted_at", + * // "url", + * // "metadata", + * // ], + * // + * // tags: { + * // fields: ["id", "created_at", "updated_at", "deleted_at", "value"], + * // }, + * // + * // options: { + * // fields: [ + * // "id", + * // "created_at", + * // "updated_at", + * // "deleted_at", + * // "title", + * // "product_id", + * // "metadata", + * // ], + * // values: { + * // fields: [ + * // "id", + * // "created_at", + * // "updated_at", + * // "deleted_at", + * // "value", + * // "option_id", + * // "variant_id", + * // "metadata", + * // ], + * // }, + * // }, + * // }, + * // } + */ +export function stringToRemoteQueryObject({ + entryPoint, + variables, + fields, +}: { + entryPoint: string + variables?: any + fields: string[] +}): object { + const remoteJoinerConfig: object = { + [entryPoint]: { + fields: [], + }, + } + + if (variables) { + remoteJoinerConfig[entryPoint]["__args"] = variables + } + + for (const field of fields) { + if (!field.includes(".")) { + remoteJoinerConfig[entryPoint]["fields"].push(field) + continue + } + + const fieldSegments = field.split(".") + const fieldProperty = fieldSegments.pop() + + const deepConfigRef = fieldSegments.reduce((acc, curr) => { + acc[curr] ??= {} + return acc[curr] + }, remoteJoinerConfig[entryPoint]) + + deepConfigRef["fields"] ??= [] + deepConfigRef["fields"].push(fieldProperty) + } + + return remoteJoinerConfig +}