mirror of
https://github.com/zadam/trilium.git
synced 2025-11-18 03:00:41 +01:00
implemented mirror relations
This commit is contained in:
@@ -5,6 +5,7 @@ const sqlInit = require('./sql_init');
|
||||
const log = require('./log');
|
||||
const messagingService = require('./messaging');
|
||||
const syncMutexService = require('./sync_mutex');
|
||||
const repository = require('./repository.js');
|
||||
const cls = require('./cls');
|
||||
|
||||
async function runCheck(query, errorText, errorList) {
|
||||
@@ -89,6 +90,17 @@ async function runSyncRowChecks(table, key, errorList) {
|
||||
`Missing ${table} records for existing sync rows`, errorList);
|
||||
}
|
||||
|
||||
async function fixEmptyRelationTargets(errorList) {
|
||||
const emptyRelations = await repository.getEntities("SELECT * FROM attributes WHERE isDeleted = 0 AND type = 'relation' AND value = ''");
|
||||
|
||||
for (const relation of emptyRelations) {
|
||||
relation.isDeleted = true;
|
||||
await relation.save();
|
||||
|
||||
errorList.push(`Relation ${relation.attributeId} of name "${relation.name} has empty target. Autofixed.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function runAllChecks() {
|
||||
const errorList = [];
|
||||
|
||||
@@ -221,6 +233,8 @@ async function runAllChecks() {
|
||||
await checkTreeCycles(errorList);
|
||||
}
|
||||
|
||||
await fixEmptyRelationTargets(errorList);
|
||||
|
||||
return errorList;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const NOTE_TITLE_CHANGED = "NOTE_TITLE_CHANGED";
|
||||
const ENTER_PROTECTED_SESSION = "ENTER_PROTECTED_SESSION";
|
||||
const ENTITY_CREATED = "ENTITY_CREATED";
|
||||
const ENTITY_CHANGED = "ENTITY_CHANGED";
|
||||
const ENTITY_DELETED = "ENTITY_DELETED";
|
||||
const CHILD_NOTE_CREATED = "CHILD_NOTE_CREATED";
|
||||
|
||||
const eventListeners = {};
|
||||
@@ -37,5 +38,6 @@ module.exports = {
|
||||
ENTER_PROTECTED_SESSION,
|
||||
ENTITY_CREATED,
|
||||
ENTITY_CHANGED,
|
||||
ENTITY_DELETED,
|
||||
CHILD_NOTE_CREATED
|
||||
};
|
||||
@@ -3,9 +3,10 @@ const scriptService = require('./script');
|
||||
const treeService = require('./tree');
|
||||
const messagingService = require('./messaging');
|
||||
const log = require('./log');
|
||||
const Attribute = require('../entities/attribute');
|
||||
|
||||
async function runAttachedRelations(note, relationName, originEntity) {
|
||||
const runRelations = (await note.getRelations()).filter(relation => relation.name === relationName);
|
||||
const runRelations = await note.getRelations(relationName);
|
||||
|
||||
for (const relation of runRelations) {
|
||||
const scriptNote = await relation.getTargetNote();
|
||||
@@ -56,4 +57,54 @@ eventService.subscribe(eventService.ENTITY_CREATED, async ({ entityName, entity
|
||||
|
||||
eventService.subscribe(eventService.CHILD_NOTE_CREATED, async ({ parentNote, childNote }) => {
|
||||
await runAttachedRelations(parentNote, 'runOnChildNoteCreation', childNote);
|
||||
});
|
||||
|
||||
async function processMirrorRelations(entityName, entity, handler) {
|
||||
if (entityName === 'attributes' && entity.type === 'relation') {
|
||||
const note = await entity.getNote();
|
||||
const attributes = (await note.getAttributes(entity.name)).filter(relation => relation.type === 'relation-definition');
|
||||
|
||||
for (const attribute of attributes) {
|
||||
const definition = attribute.value;
|
||||
|
||||
if (definition.mirrorRelation && definition.mirrorRelation.trim()) {
|
||||
const targetNote = await entity.getTargetNote();
|
||||
|
||||
await handler(definition, note, targetNote);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityName, entity }) => {
|
||||
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
||||
// we need to make sure that also target's mirror attribute exists and if note, then create it
|
||||
if (!await targetNote.hasRelation(definition.mirrorRelation)) {
|
||||
await new Attribute({
|
||||
noteId: targetNote.noteId,
|
||||
type: 'relation',
|
||||
name: definition.mirrorRelation,
|
||||
value: note.noteId,
|
||||
isInheritable: entity.isInheritable
|
||||
}).save();
|
||||
|
||||
targetNote.invalidateAttributeCache();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
eventService.subscribe(eventService.ENTITY_DELETED, async ({ entityName, entity }) => {
|
||||
await processMirrorRelations(entityName, entity, async (definition, note, targetNote) => {
|
||||
// if one mirror attribute is deleted then the other should be deleted as well
|
||||
const relations = await targetNote.getRelations(definition.mirrorRelation);
|
||||
|
||||
for (const relation of relations) {
|
||||
relation.isDeleted = true;
|
||||
await relation.save();
|
||||
}
|
||||
|
||||
if (relations.length > 0) {
|
||||
targetNote.invalidateAttributeCache();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -96,20 +96,17 @@ async function updateEntity(entity) {
|
||||
if (entity.isChanged && (entityName !== 'options' || entity.isSynced)) {
|
||||
await syncTableService.addEntitySync(entityName, primaryKey);
|
||||
|
||||
if (isNewEntity) {
|
||||
await eventService.emit(eventService.ENTITY_CREATED, {
|
||||
entityName,
|
||||
entity
|
||||
});
|
||||
const eventPayload = {
|
||||
entityName,
|
||||
entity
|
||||
};
|
||||
|
||||
if (isNewEntity && !entity.isDeleted) {
|
||||
await eventService.emit(eventService.ENTITY_CREATED, eventPayload);
|
||||
}
|
||||
|
||||
// it seems to be better to handle deletion with a separate event
|
||||
if (!entity.isDeleted) {
|
||||
await eventService.emit(eventService.ENTITY_CHANGED, {
|
||||
entityName,
|
||||
entity
|
||||
});
|
||||
}
|
||||
// it seems to be better to handle deletion and update separately
|
||||
await eventService.emit(entity.isDeleted ? eventService.ENTITY_DELETED : eventService.ENTITY_CHANGED, eventPayload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user