@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
82 lines (81 loc) • 3.87 kB
JavaScript
import { isPlainObject } from 'lodash-es';
import assert from 'node:assert';
import { getRelationInfo } from '../get-relation-info.js';
import { InvalidQueryError } from '@directus/errors';
/**
* Allows to deep map the data like a response or delta changes with collection, field and relation context for each entry.
* Bottom to Top depth first mapping of values.
*/
export function deepMapWithSchema(object, callback, context, options) {
const collection = context.schema.collections[context.collection];
assert(isPlainObject(object) && typeof object === 'object' && object !== null, `DeepMapResponse only works on objects, received ${JSON.stringify(object)}`);
let fields;
if (options?.mapNonExistentFields) {
fields = Object.entries(collection.fields);
}
else {
fields = Object.keys(object).map((key) => [key, collection.fields[key]]);
}
return Object.fromEntries(fields
.map(([key, field]) => {
let value = object[key];
if (!field)
return [key, value];
const relationInfo = getRelationInfo(context.schema.relations, collection.collection, field.field);
let leaf = true;
if (relationInfo.relation && typeof value === 'object' && value !== null && isPlainObject(object)) {
switch (relationInfo.relationType) {
case 'm2o':
value = deepMapWithSchema(value, callback, {
schema: context.schema,
collection: relationInfo.relation.related_collection,
relationInfo,
}, options);
leaf = false;
break;
case 'o2m': {
function map(childValue) {
if (isPlainObject(childValue) && typeof childValue === 'object' && childValue !== null) {
leaf = false;
return deepMapWithSchema(childValue, callback, {
schema: context.schema,
collection: relationInfo.relation.collection,
relationInfo,
}, options);
}
else
return childValue;
}
if (Array.isArray(value)) {
value = value.map(map);
}
else if (options?.detailedUpdateSyntax && isPlainObject(value)) {
value = {
create: value['create']?.map(map),
update: value['update']?.map(map),
delete: value['delete']?.map(map),
};
}
break;
}
case 'a2o': {
const related_collection = object[relationInfo.relation.meta.one_collection_field];
if (!related_collection) {
throw new InvalidQueryError({
reason: `When selecting '${collection.collection}.${field.field}', the field '${collection.collection}.${relationInfo.relation.meta.one_collection_field}' has to be selected when using versioning and m2a relations `,
});
}
value = deepMapWithSchema(value, callback, {
schema: context.schema,
collection: related_collection,
relationInfo,
}, options);
leaf = false;
break;
}
}
}
return callback([key, value], { collection, field, ...relationInfo, leaf, object });
})
.filter((f) => f));
}