more relation events, events are now not triggered on sync changes

This commit is contained in:
azivner 2018-08-15 22:06:49 +02:00
parent df9acd0504
commit 0f106fb96f
8 changed files with 117 additions and 55 deletions

View File

@ -6,6 +6,9 @@ const protectedSessionService = require('../services/protected_session');
const repository = require('../services/repository');
const dateUtils = require('../services/date_utils');
const LABEL = 'label';
const RELATION = 'relation';
class Note extends Entity {
static get tableName() { return "notes"; }
static get primaryKeyName() { return "noteId"; }
@ -78,6 +81,14 @@ class Note extends Entity {
return this.__attributeCache;
}
async getLabels() {
return (await this.getAttributes()).filter(attr => attr.type === LABEL);
}
async getRelations() {
return (await this.getAttributes()).filter(attr => attr.type === RELATION);
}
invalidateAttributeCache() {
this.__attributeCache = null;
}
@ -145,55 +156,55 @@ class Note extends Entity {
this.__attributeCache = filteredAttributes;
}
async hasLabel(name) {
return !!await this.getLabel(name);
async hasAttribute(type, name) {
return !!await this.getAttribute(type, name);
}
// WARNING: this doesn't take into account the possibility to have multi-valued labels!
async getLabel(name) {
async getAttribute(type, name) {
const attributes = await this.getAttributes();
return attributes.find(attr => attr.type === 'label' && attr.name === name);
return attributes.find(attr => attr.type === type && attr.name === name);
}
async getLabelValue(name) {
const label = await this.getLabel(name);
async getAttributeValue(type, name) {
const attr = await this.getAttribute(type, name);
return label ? label.value : null;
return attr ? attr.value : null;
}
async toggleLabel(enabled, name, value = "") {
async toggleAttribute(type, enabled, name, value = "") {
if (enabled) {
await this.setLabel(name, value);
await this.setAttribute(type, name, value);
}
else {
await this.removeLabel(name, value);
await this.removeAttribute(type, name, value);
}
}
async setLabel(name, value = "") {
async setAttribute(type, name, value = "") {
const attributes = await this.getOwnedAttributes();
let label = attributes.find(attr => attr.type === 'label' && attr.value === value);
let attr = attributes.find(attr => attr.type === type && attr.value === value);
if (!label) {
label = new Attribute({
if (!attr) {
attr = new Attribute({
noteId: this.noteId,
type: 'label',
type: type,
name: name,
value: value
});
await label.save();
await attr.save();
this.invalidateAttributeCache();
}
}
async removeLabel(name, value = "") {
async removeAttribute(type, name, value = "") {
const attributes = await this.getOwnedAttributes();
for (const attribute of attributes) {
if (attribute.type === 'label' && (!value || value === attribute.value)) {
if (attribute.type === type && (!value || value === attribute.value)) {
attribute.isDeleted = true;
await attribute.save();
@ -202,6 +213,24 @@ class Note extends Entity {
}
}
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
async getLabel(name) { return await this.getAttribute(LABEL, name); }
async getRelation(name) { return await this.getAttribute(RELATION, name); }
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
async toggleLabel(enabled, name, value = "") { return await this.toggleAttribute(LABEL, enabled, name, value); }
async toggleRelation(enabled, name, value = "") { return await this.toggleAttribute(RELATION, enabled, name, value); }
async setLabel(name, value = "") { return await this.setAttribute(LABEL, name, value); }
async setRelation(name, value = "") { return await this.setAttribute(RELATION, name, value); }
async removeLabel(name, value = "") { return await this.removeAttribute(LABEL, name, value); }
async removeRelation(name, value = "") { return await this.removeAttribute(RELATION, name, value); }
async getRevisions() {
return await repository.getEntities("SELECT * FROM note_revisions WHERE noteId = ?", [this.noteId]);
}

View File

@ -19,7 +19,11 @@ const BUILTIN_ATTRIBUTES = [
// relation names
{ type: 'relation', name: 'runOnNoteView' },
{ type: 'relation', name: 'runOnNoteCreation' },
{ type: 'relation', name: 'runOnNoteTitleChange' },
{ type: 'relation', name: 'runOnNoteChange' },
{ type: 'relation', name: 'runOnChildNoteCreation' },
{ type: 'relation', name: 'runOnAttributeCreation' },
{ type: 'relation', name: 'runOnAttributeChange' },
{ type: 'relation', name: 'inheritAttributes' }
];
@ -59,20 +63,19 @@ async function createAttribute(attribute) {
}
async function getAttributeNames(type, nameLike) {
let names;
nameLike = nameLike.toLowerCase();
if (!nameLike) {
names = BUILTIN_ATTRIBUTES
.filter(attribute => attribute.type === type)
.map(attribute => attribute.name);
}
else {
names = await sql.getColumn(
`SELECT DISTINCT name
const names = await sql.getColumn(
`SELECT DISTINCT name
FROM attributes
WHERE isDeleted = 0
AND type = ?
AND name LIKE '%${utils.sanitizeSql(nameLike)}%'`, [type]);
for (const attr of BUILTIN_ATTRIBUTES) {
if (attr.type === type && attr.name.toLowerCase().includes(nameLike) && !names.includes(attr.name)) {
names.push(attr.name);
}
}
names.sort();

View File

@ -2,7 +2,9 @@ const log = require('./log');
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 CHILD_NOTE_CREATED = "CHILD_NOTE_CREATED";
const eventListeners = {};
@ -33,5 +35,7 @@ module.exports = {
// event types:
NOTE_TITLE_CHANGED,
ENTER_PROTECTED_SESSION,
ENTITY_CHANGED
ENTITY_CREATED,
ENTITY_CHANGED,
CHILD_NOTE_CREATED
};

View File

@ -2,12 +2,10 @@ const eventService = require('./events');
const scriptService = require('./script');
const treeService = require('./tree');
const messagingService = require('./messaging');
const repository = require('./repository');
const log = require('./log');
async function runAttachedRelations(note, relationName, originEntity) {
const attributes = await note.getAttributes();
const runRelations = attributes.filter(relation => relation.type === 'relation' && relation.name === relationName);
const runRelations = (await note.getRelations()).filter(relation => relation.name === relationName);
for (const relation of runRelations) {
const scriptNote = await relation.getTargetNote();
@ -37,10 +35,24 @@ eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
}
});
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityId, entityName }) => {
eventService.subscribe(eventService.ENTITY_CHANGED, async ({ entityName, entity }) => {
if (entityName === 'attributes') {
const attribute = await repository.getEntityFromName(entityName, entityId);
await runAttachedRelations(await attribute.getNote(), 'runOnAttributeChange', attribute);
await runAttachedRelations(await entity.getNote(), 'runOnAttributeChange', entity);
}
else if (entityName === 'notes') {
await runAttachedRelations(entity, 'runOnNoteChange', entity);
}
});
eventService.subscribe(eventService.ENTITY_CREATED, async ({ entityName, entity }) => {
if (entityName === 'attributes') {
await runAttachedRelations(await entity.getNote(), 'runOnAttributeCreation', entity);
}
else if (entityName === 'notes') {
await runAttachedRelations(entity, 'runOnNoteCreation', entity);
}
});
eventService.subscribe(eventService.CHILD_NOTE_CREATED, async ({ parentNote, childNote }) => {
await runAttachedRelations(parentNote, 'runOnChildNoteCreation', childNote);
});

View File

@ -228,13 +228,13 @@ function getNotePath(noteId) {
}
}
eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId}) => {
eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entity}) => {
if (!loaded) {
return;
}
if (entityName === 'notes') {
const note = await repository.getNote(entityId);
const note = entity;
if (note.isDeleted) {
delete noteTitles[note.noteId];
@ -245,7 +245,7 @@ eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId
}
}
else if (entityName === 'branches') {
const branch = await repository.getBranch(entityId);
const branch = entity;
if (childToParent[branch.noteId]) {
childToParent[branch.noteId] = childToParent[branch.noteId].filter(noteId => noteId !== branch.parentNoteId)
@ -266,7 +266,7 @@ eventService.subscribe(eventService.ENTITY_CHANGED, async ({entityName, entityId
}
}
else if (entityName === 'attributes') {
const attribute = await repository.getAttribute(entityId);
const attribute = entity;
if (attribute.type === 'label' && attribute.name === 'archived') {
// we're not using label object directly, since there might be other non-deleted archived label

View File

@ -35,6 +35,10 @@ async function getNewNotePosition(parentNoteId, noteData) {
return newNotePos;
}
async function triggerChildNoteCreated(childNote, parentNote) {
await eventService.emit(eventService.CHILD_NOTE_CREATED, { childNote, parentNote });
}
async function triggerNoteTitleChanged(note) {
await eventService.emit(eventService.NOTE_TITLE_CHANGED, note);
}
@ -42,12 +46,10 @@ async function triggerNoteTitleChanged(note) {
async function createNewNote(parentNoteId, noteData) {
const newNotePos = await getNewNotePosition(parentNoteId, noteData);
if (parentNoteId !== 'root') {
const parent = await repository.getNote(parentNoteId);
const parentNote = await repository.getNote(parentNoteId);
noteData.type = noteData.type || parent.type;
noteData.mime = noteData.mime || parent.mime;
}
noteData.type = noteData.type || parentNote.type;
noteData.mime = noteData.mime || parentNote.mime;
const note = await new Note({
title: noteData.title,
@ -66,6 +68,7 @@ async function createNewNote(parentNoteId, noteData) {
}).save();
await triggerNoteTitleChanged(note);
await triggerChildNoteCreated(note, parentNote);
return {
note,

View File

@ -2,6 +2,7 @@
const sql = require('./sql');
const syncTableService = require('../services/sync_table');
const eventService = require('./events');
let entityConstructor;
@ -56,6 +57,11 @@ async function getOption(name) {
}
async function updateEntity(entity) {
const entityName = entity.constructor.tableName;
const primaryKeyName = entity.constructor.primaryKeyName;
const isNewEntity = !entity[primaryKeyName];
if (entity.beforeSaving) {
await entity.beforeSaving();
}
@ -75,12 +81,24 @@ async function updateEntity(entity) {
}
await sql.transactional(async () => {
await sql.replace(entity.constructor.tableName, clone);
await sql.replace(entityName, clone);
const primaryKey = entity[entity.constructor.primaryKeyName];
const primaryKey = entity[primaryKeyName];
if (entity.isChanged && (entity.constructor.tableName !== 'options' || entity.isSynced)) {
await syncTableService.addEntitySync(entity.constructor.tableName, primaryKey);
if (entity.isChanged && (entityName !== 'options' || entity.isSynced)) {
await syncTableService.addEntitySync(entityName, primaryKey);
if (isNewEntity) {
await eventService.emit(eventService.ENTITY_CREATED, {
entityName,
entity
});
}
await eventService.emit(eventService.ENTITY_CHANGED, {
entityName,
entity
});
}
});
}

View File

@ -3,7 +3,6 @@ const sourceIdService = require('./source_id');
const dateUtils = require('./date_utils');
const log = require('./log');
const cls = require('./cls');
const eventService = require('./events');
async function addNoteSync(noteId, sourceId) {
await addEntitySync("notes", noteId, sourceId)
@ -52,11 +51,6 @@ async function addEntitySync(entityName, entityId, sourceId) {
syncDate: dateUtils.nowDate(),
sourceId: sourceId || cls.getSourceId() || sourceIdService.getCurrentSourceId()
});
await eventService.emit(eventService.ENTITY_CHANGED, {
entityName,
entityId
});
}
async function cleanupSyncRowsForMissingEntities(entityName, entityKey) {
@ -116,6 +110,5 @@ module.exports = {
addAttributeSync,
addApiTokenSync,
addEntitySync,
cleanupSyncRowsForMissingEntities,
fillAllSyncRows
};