From 08e2cd0153b6b0d1a0f9d3f4ab967fb5efba2c02 Mon Sep 17 00:00:00 2001 From: Jiri Lojda Date: Wed, 6 Dec 2023 12:23:18 +0100 Subject: [PATCH] Add taxonomy ids into context --- src/commands/import.ts | 4 ++- .../entities/taxonomies.ts | 27 +++++++++++++---- .../importExportEntities/entityDefinition.ts | 4 +++ src/utils/array.ts | 29 +++++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/utils/array.ts diff --git a/src/commands/import.ts b/src/commands/import.ts index 364efe33..ee0925e0 100644 --- a/src/commands/import.ts +++ b/src/commands/import.ts @@ -57,7 +57,9 @@ const importEntities = async (params: ImportEntitiesParams) => { let context: ImportContext = { collectionIdsByOldIds: new Map(), - languageIdsByOldIds: new Map() + languageIdsByOldIds: new Map(), + taxonomyGroupIdsByOldIds: new Map(), + taxonomyTermIdsByOldIds: new Map(), }; await serially(entityDefinitions.map(def => async () => { diff --git a/src/commands/importExportEntities/entities/taxonomies.ts b/src/commands/importExportEntities/entities/taxonomies.ts index acb86ee4..5b705f70 100644 --- a/src/commands/importExportEntities/entities/taxonomies.ts +++ b/src/commands/importExportEntities/entities/taxonomies.ts @@ -1,5 +1,6 @@ import { TaxonomyContracts } from "@kontent-ai/management-sdk"; +import { zip } from "../../../utils/array.js"; import { serially } from "../../../utils/requests.js"; import { EntityDefinition } from "../entityDefinition.js"; @@ -7,12 +8,21 @@ export const taxonomiesEntity: EntityDefinition client.listTaxonomies().toAllPromise().then(res => res.data.items.map(t => t._raw)), serializeEntities: taxonomies => JSON.stringify(taxonomies), - importEntities: async (client, fileTaxonomies) => { - await serially(fileTaxonomies.map(taxonomy => () => - client - .addTaxonomy() - .withData(addExternalIds(taxonomy)) - .toPromise())); + importEntities: async (client, fileTaxonomies, context) => { + const projectTaxonomies = await serially Promise>>( + fileTaxonomies.map(taxonomy => () => + client + .addTaxonomy() + .withData(addExternalIds(taxonomy)) + .toPromise() + .then(res => res.data._raw)) + ); + + return { + ...context, + taxonomyGroupIdsByOldIds: new Map(zip(fileTaxonomies.map(t => t.id), projectTaxonomies.map(t => t.id))), + taxonomyTermIdsByOldIds: new Map(zip(fileTaxonomies.flatMap(t => t.terms), projectTaxonomies.flatMap(t => t.terms)).flatMap(extractTermIdsEntries)), + }; }, deserializeEntities: JSON.parse, }; @@ -22,3 +32,8 @@ const addExternalIds = (taxonomy: TaxonomyContracts.ITaxonomyContract): Taxonomy external_id: taxonomy.external_id ?? taxonomy.codename, terms: taxonomy.terms.map(addExternalIds), }); + +const extractTermIdsEntries = ([fileTaxonomy, projectTaxonomy]: readonly [TaxonomyContracts.ITaxonomyContract, TaxonomyContracts.ITaxonomyContract]): ReadonlyArray => [ + [fileTaxonomy.id, projectTaxonomy.id] as const, + ...zip(fileTaxonomy.terms, projectTaxonomy.terms).flatMap(extractTermIdsEntries), +]; diff --git a/src/commands/importExportEntities/entityDefinition.ts b/src/commands/importExportEntities/entityDefinition.ts index d8946b75..5653f369 100644 --- a/src/commands/importExportEntities/entityDefinition.ts +++ b/src/commands/importExportEntities/entityDefinition.ts @@ -13,4 +13,8 @@ export type EntityDefinition = Readonly<{ export type ImportContext = Readonly<{ collectionIdsByOldIds: ReadonlyMap; languageIdsByOldIds: ReadonlyMap; + taxonomyGroupIdsByOldIds: IdsMap; + taxonomyTermIdsByOldIds: IdsMap; }>; + +type IdsMap = ReadonlyMap; diff --git a/src/utils/array.ts b/src/utils/array.ts new file mode 100644 index 00000000..779d4b10 --- /dev/null +++ b/src/utils/array.ts @@ -0,0 +1,29 @@ +export const zip = , T2 extends ReadonlyArray>(arr1: T1, arr2: T2): Zip => + arr1 + .slice(0, Math.min(arr1.length, arr2.length)) + .map((el1, i) => [el1, arr2[i]] as const) as unknown as Zip; + +type Zip, T2 extends ReadonlyArray> = + true extends IsEmptyTuple | IsEmptyTuple + ? readonly [] + : [IsNonEmptyTuple, IsNonEmptyTuple] extends [true, true] + ? ZipTuples + : ZipArrays; + +type IsEmptyTuple> = T extends readonly [] ? true : false; + +type IsNonEmptyTuple> = T extends readonly [any, ...ReadonlyArray] ? true : false; + +/** + * Handles zip of two types where at least one is an array of unknown length. +*/ +type ZipArrays, T2 extends ReadonlyArray> = ReadonlyArray; + +/** + * Handles zip of two tuples (arrays of known length and exact types for different positions). + * This type expects two tuples and doesn't work well with arrays of unknown length. +*/ +type ZipTuples, T2 extends ReadonlyArray, Accum extends ReadonlyArray = readonly []> = + [T1, T2] extends [readonly [infer First1, ...infer Rest1 extends ReadonlyArray], readonly [infer First2, ...infer Rest2 extends ReadonlyArray]] + ? ZipTuples + : Accum;