Comparing version 1.11.4 to 1.11.5
{ | ||
".": "1.11.4" | ||
".": "1.11.5" | ||
} |
# Changelog | ||
## [1.11.5](https://github.com/mathematic-inc/ts-japi/compare/v1.11.4...v1.11.5) (2025-01-14) | ||
### Bug Fixes | ||
* issue [#98](https://github.com/mathematic-inc/ts-japi/issues/98) by improving performance of recurseRelators ([#99](https://github.com/mathematic-inc/ts-japi/issues/99)) ([e92de4d](https://github.com/mathematic-inc/ts-japi/commit/e92de4d2720bf80ec9ebae00562e5713c3c7635e)) | ||
## [1.11.4](https://github.com/mathematic-inc/ts-japi/compare/v1.11.3...v1.11.4) (2024-05-13) | ||
@@ -4,0 +11,0 @@ |
@@ -51,3 +51,3 @@ import { RelatorOptions } from '../interfaces/relator.interface'; | ||
constructor(fetch: (data: PrimaryType) => Promise<RelatedType | RelatedType[] | nullish>, serializer: () => Serializer<RelatedType>, options: Partial<RelatorOptions<PrimaryType, RelatedType>> & Required<Pick<RelatorOptions<PrimaryType, RelatedType>, 'relatedName'>>); | ||
private get serializer(); | ||
get serializer(): Serializer<RelatedType>; | ||
/** @internal Gets related data from primary data. */ | ||
@@ -54,0 +54,0 @@ getRelatedData: (data: PrimaryType) => Promise<RelatedType | RelatedType[] | nullish>; |
@@ -8,9 +8,4 @@ "use strict"; | ||
const relator_1 = __importDefault(require("../classes/relator")); | ||
async function recurseRelators(data, relators, include, keys, relatorDataCache) { | ||
async function recurseRelatorsDepth(data, relators, depth, keys, relatorDataCache) { | ||
const included = []; | ||
let depth = typeof include === 'number' | ||
? include | ||
: Array.isArray(include) | ||
? Math.max(...include.map((i) => i.split('.').length)) | ||
: 0; | ||
let curRelatorDataCache = relatorDataCache || new Map(); | ||
@@ -31,21 +26,61 @@ // Required to support backwards compatability where the first dataCache may | ||
} | ||
let currentDepth = 0; | ||
while (depth-- > 0 && curRelatorDataCache.size > 0) { | ||
const newRelatorDataCache = new Map(); | ||
const includeFields = Array.isArray(include) | ||
? include | ||
.map((i) => i.split('.')) | ||
.filter((i) => i[currentDepth]) | ||
.map((i) => ({ field: i[currentDepth], hasMore: i.length > currentDepth + 1 })) | ||
: undefined; | ||
for (const [relator, cache] of curRelatorDataCache) { | ||
for (let i = 0; i < cache.length; i++) { | ||
const shouldBuildRelatedCache = (!includeFields || | ||
includeFields | ||
?.filter((i) => i.field === relator.relatedName) | ||
?.some((i) => i.hasMore)) ?? | ||
false; | ||
const resource = await relator.getRelatedResource(cache[i], undefined, undefined, | ||
// Only build the cache for the next iteration if needed. | ||
shouldBuildRelatedCache ? newRelatorDataCache : undefined); | ||
const resource = await relator.getRelatedResource(cache[i], undefined, undefined, newRelatorDataCache); | ||
const key = resource.getKey(); | ||
if (!keys.includes(key)) { | ||
keys.push(key); | ||
included.push(resource); | ||
} | ||
} | ||
} | ||
curRelatorDataCache = newRelatorDataCache; | ||
} | ||
return included; | ||
} | ||
async function recurseRelators(data, relators, include, keys, relatorDataCache) { | ||
if (include === undefined || typeof include === 'number') { | ||
return recurseRelatorsDepth(data, relators, include ?? 0, keys, relatorDataCache); | ||
} | ||
const included = []; | ||
let curRelatorDataCache = relatorDataCache || new Map(); | ||
// Required to support backwards compatability where the first dataCache may | ||
// not be passed in. All subsequent iterations will contain a dataCache | ||
if (!relatorDataCache && include.length > 0) { | ||
for (const name in relators) { | ||
const cache = curRelatorDataCache.get(relators[name]) || []; | ||
curRelatorDataCache.set(relators[name], cache); | ||
for (const datum of data) { | ||
const relatedData = await relators[name].getRelatedData(datum); | ||
if (relatedData !== null) { | ||
cache.push(...(Array.isArray(relatedData) ? relatedData : [relatedData])); | ||
} | ||
} | ||
} | ||
} | ||
const maxDepth = Math.max(...include.map((i) => i.split('.').length)); | ||
let currentDepth = 0; | ||
while (currentDepth < maxDepth) { | ||
const newRelatorDataCache = new Map(); | ||
const includeFields = include | ||
.map((i) => i.split('.')) | ||
.filter((i) => i[currentDepth]) | ||
.map((i) => ({ field: i[currentDepth], hasMore: i.length > currentDepth + 1 })) | ||
.reduce((acc, i) => { | ||
const match = acc.find((j) => j.field === i.field); | ||
if (match) { | ||
match.hasMore = match.hasMore || i.hasMore; | ||
} | ||
else { | ||
acc.push(i); | ||
} | ||
return acc; | ||
}, []); | ||
for (const [relator, cache] of curRelatorDataCache) { | ||
const shouldBuildRelatedCache = (!includeFields || | ||
includeFields?.filter((i) => i.field === relator.relatedName)?.some((i) => i.hasMore)) ?? | ||
false; | ||
for (let i = 0; i < cache.length; i++) { | ||
// Include if, | ||
@@ -55,4 +90,8 @@ // - includeFields !== undefined | ||
if (!includeFields || includeFields.map((i) => i.field).includes(relator.relatedName)) { | ||
const key = resource.getKey(); | ||
const key = `${relator.serializer.collectionName}:${cache[i].id}`; | ||
if (!keys.includes(key)) { | ||
// const key = resource.getKey(); | ||
const resource = await relator.getRelatedResource(cache[i], undefined, undefined, | ||
// Only build the cache for the next iteration if needed. | ||
shouldBuildRelatedCache ? newRelatorDataCache : undefined); | ||
keys.push(key); | ||
@@ -59,0 +98,0 @@ included.push(resource); |
{ | ||
"name": "ts-japi", | ||
"version": "1.11.4", | ||
"version": "1.11.5", | ||
"description": "A highly-modular (typescript-friendly)-framework agnostic library for serializing data to the JSON:API specification", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
242713
3548