@directus/api
Version:
Directus is a real-time API and App dashboard for managing SQL database content
112 lines (110 loc) • 7.06 kB
JavaScript
import { DiffKind } from "../../packages/types/dist/index.js";
import { SNAPSHOT_VERSION } from "../../constants.js";
import { sanitizeCollection, sanitizeField, sanitizeRelation, sanitizeSystemField } from "../sanitize-schema.js";
import { isChanged } from "./is-changed.js";
import { isDeleteAllowed } from "./is-delete-allowed.js";
import { isInScope } from "./is-in-scope.js";
import deepDiff from "deep-diff";
//#region src/utils/schema/get-snapshot-diff.ts
function getSnapshotDiff(current, after, options) {
const isPartial = after.version === SNAPSHOT_VERSION.PARTIAL;
const scope = isPartial ? new Set([
...(after.collections ?? []).map((collection) => collection.collection),
...(after.fields ?? []).map((field) => field.collection),
...(after.relations ?? []).map((relation) => relation.collection)
]) : null;
const systemFieldScope = isPartial ? new Set((after.systemFields ?? []).map((field) => field.collection)) : null;
const diffedSnapshot = {
collections: [...current.collections.map((currentCollection) => {
const afterCollection = after.collections.find((afterCollection$1) => afterCollection$1.collection === currentCollection.collection);
const afterCollectionSanitized = afterCollection ? sanitizeCollection(afterCollection) : void 0;
return {
collection: currentCollection.collection,
diff: deepDiff.diff(sanitizeCollection(currentCollection), afterCollectionSanitized)
};
}), ...after.collections.filter((afterCollection) => {
return !!current.collections.find((currentCollection) => currentCollection.collection === afterCollection.collection) === false;
}).map((afterCollection) => ({
collection: afterCollection.collection,
diff: deepDiff.diff(void 0, sanitizeCollection(afterCollection))
}))].filter((obj) => isChanged(obj) && isDeleteAllowed(obj, options?.mode) && isInScope(obj, scope)),
fields: [...current.fields.map((currentField) => {
const afterField = after.fields.find((afterField$1) => afterField$1.collection === currentField.collection && afterField$1.field === currentField.field);
const isAutoIncrementPrimaryKey = !!currentField.schema?.is_primary_key && !!currentField.schema?.has_auto_increment;
if (afterField && currentField.type !== afterField.type && (currentField.type === "alias" || afterField.type === "alias")) return {
collection: currentField.collection,
field: currentField.field,
diff: deepDiff.diff(sanitizeField(currentField, isAutoIncrementPrimaryKey), void 0)
};
const afterFieldSanitized = afterField ? sanitizeField(afterField, isAutoIncrementPrimaryKey) : void 0;
return {
collection: currentField.collection,
field: currentField.field,
diff: deepDiff.diff(sanitizeField(currentField, isAutoIncrementPrimaryKey), afterFieldSanitized)
};
}), ...after.fields.filter((afterField) => {
let currentField = current.fields.find((currentField$1) => currentField$1.collection === afterField.collection && afterField.field === currentField$1.field);
if (currentField && currentField.type !== afterField.type && (currentField.type === "alias" || afterField.type === "alias")) currentField = void 0;
return !!currentField === false;
}).map((afterField) => ({
collection: afterField.collection,
field: afterField.field,
diff: deepDiff.diff(void 0, sanitizeField(afterField))
}))].filter((obj) => isChanged(obj) && isDeleteAllowed(obj, options?.mode) && isInScope(obj, scope)),
systemFields: [...(current.systemFields ?? []).map((currentSystemField) => {
const afterSystemField = (after.systemFields ?? []).find((afterSystemField$1) => afterSystemField$1.collection === currentSystemField.collection && afterSystemField$1.field === currentSystemField.field);
const afterSystemFieldSanitized = afterSystemField ? sanitizeSystemField(afterSystemField) : invertIndexed(currentSystemField);
return {
collection: currentSystemField.collection,
field: currentSystemField.field,
diff: deepDiff.diff(sanitizeSystemField(currentSystemField), afterSystemFieldSanitized)
};
}), ...(after.systemFields ?? []).filter((afterSystemField) => {
if (!afterSystemField.schema.is_indexed) return false;
const currentSystemField = (current.systemFields ?? []).find((currentSystemField$1) => currentSystemField$1.collection === afterSystemField.collection && afterSystemField.field === currentSystemField$1.field);
return Boolean(currentSystemField) === false;
}).map((afterSystemField) => {
const currentSystemField = (current.systemFields ?? []).find((currentSystemField$1) => currentSystemField$1.collection === afterSystemField.collection && currentSystemField$1.field === afterSystemField.field);
const currentSystemFieldSanitized = currentSystemField ? sanitizeSystemField(currentSystemField) : invertIndexed(afterSystemField);
return {
collection: afterSystemField.collection,
field: afterSystemField.field,
diff: deepDiff.diff(currentSystemFieldSanitized, sanitizeSystemField(afterSystemField))
};
})].filter((obj) => isChanged(obj) && isDeleteAllowed(obj, options?.mode) && isInScope(obj, systemFieldScope)),
relations: [...current.relations.map((currentRelation) => {
const afterRelation = after.relations.find((afterRelation$1) => afterRelation$1.collection === currentRelation.collection && afterRelation$1.field === currentRelation.field);
const afterRelationSanitized = afterRelation ? sanitizeRelation(afterRelation) : void 0;
return {
collection: currentRelation.collection,
field: currentRelation.field,
related_collection: currentRelation.related_collection,
diff: deepDiff.diff(sanitizeRelation(currentRelation), afterRelationSanitized)
};
}), ...after.relations.filter((afterRelation) => {
return !!current.relations.find((currentRelation) => currentRelation.collection === afterRelation.collection && afterRelation.field === currentRelation.field) === false;
}).map((afterRelation) => ({
collection: afterRelation.collection,
field: afterRelation.field,
related_collection: afterRelation.related_collection,
diff: deepDiff.diff(void 0, sanitizeRelation(afterRelation))
}))].filter((obj) => isChanged(obj) && isDeleteAllowed(obj, options?.mode) && isInScope(obj, scope))
};
/**
* When you delete a collection, we don't have to individually drop all the fields/relations as well
*/
const deletedCollections = diffedSnapshot.collections.filter((collection) => collection.diff?.[0]?.kind === DiffKind.DELETE).map(({ collection }) => collection);
diffedSnapshot.fields = diffedSnapshot.fields.filter((field) => deletedCollections.includes(field.collection) === false);
diffedSnapshot.relations = diffedSnapshot.relations.filter((relation) => deletedCollections.includes(relation.collection) === false);
return diffedSnapshot;
}
function invertIndexed(field) {
const newSchema = { ...field.schema };
if ("is_indexed" in field.schema) newSchema.is_indexed = !field.schema.is_indexed;
return {
...field,
schema: newSchema
};
}
//#endregion
export { getSnapshotDiff };