diff --git a/docs/backend_api/Note.html b/docs/backend_api/Note.html
index dabe2ae48..c76b51f48 100644
--- a/docs/backend_api/Note.html
+++ b/docs/backend_api/Note.html
@@ -557,7 +557,7 @@
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ (optional) attribute type to filter |
+
+
+
+
name |
@@ -963,7 +996,7 @@
- attribute name to filter |
+ (optional) attribute name to filter |
@@ -1004,7 +1037,7 @@
Source:
@@ -1062,7 +1095,7 @@
- (async) getAttributeValue(type, name) → {Promise.<string>}
+ (async) getAttributeValue(type, name) → {Promise.<(string|null)>}
@@ -1182,7 +1215,7 @@
Source:
@@ -1222,7 +1255,7 @@
-Promise.<string>
+Promise.<(string|null)>
@@ -1288,7 +1321,7 @@
Source:
@@ -1390,7 +1423,7 @@
Source:
@@ -1496,7 +1529,7 @@
Source:
@@ -1704,7 +1737,7 @@
Source:
@@ -1937,7 +1970,7 @@
Source:
@@ -2135,7 +2168,7 @@
Source:
@@ -2333,7 +2366,7 @@
Source:
@@ -2489,7 +2522,7 @@
- (async) getLabel(name) → {Promise.<Attribute>}
+ (async) getLabel(name) → {Promise.<(Attribute|null)>}
@@ -2586,7 +2619,7 @@
Source:
@@ -2626,7 +2659,7 @@
-Promise.<Attribute>
+Promise.<(Attribute|null)>
@@ -2753,7 +2786,7 @@
Source:
@@ -2920,7 +2953,7 @@
Source:
@@ -2978,7 +3011,7 @@
- (async) getLabelValue(name) → {Promise.<string>}
+ (async) getLabelValue(name) → {Promise.<(string|null)>}
@@ -3075,7 +3108,7 @@
Source:
@@ -3115,7 +3148,7 @@
-Promise.<string>
+Promise.<(string|null)>
@@ -3187,7 +3220,7 @@
Source:
@@ -3289,7 +3322,7 @@
Source:
@@ -3349,13 +3382,17 @@ This method can be significantly faster than the getAttribute()
- (async) getOwnedAttributes() → {Promise.<Array.<Attribute>>}
+ (async) getOwnedAttributes(typeopt, nameopt) → {Promise.<Array.<Attribute>>}
+
+ This method is a faster variant of getAttributes() which looks for only owned attributes.
+Use when inheritance is not needed and/or in batch/performance sensitive operations.
+
@@ -3365,6 +3402,101 @@ This method can be significantly faster than the getAttribute()
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ (optional) attribute type to filter |
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ (optional) attribute name to filter |
+
+
+
+
+
+
+
+
@@ -3397,7 +3529,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -3426,9 +3558,7 @@ This method can be significantly faster than the getAttribute()
- attributes belonging to this specific note (excludes inherited attributes)
-
-This method can be significantly faster than the getAttributes()
+ note's "owned" attributes - excluding inherited ones
@@ -3457,7 +3587,7 @@ This method can be significantly faster than the getAttributes()
- (async) getParentNotes() → {Promise.<Array.<Note>>}
+ (async) getOwnedAttributeValue(type, name) → {Promise.<(string|null)>}
@@ -3472,6 +3602,78 @@ This method can be significantly faster than the getAttributes()
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ attribute type (label, relation, etc.) |
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ attribute name |
+
+
+
+
+
+
+
@@ -3505,7 +3707,7 @@ This method can be significantly faster than the getAttributes()
Source:
@@ -3534,7 +3736,7 @@ This method can be significantly faster than the getAttributes()
- parent notes of this note (note can have multiple parents because of cloning)
+ attribute value of given type and name or null if no such attribute exists.
@@ -3545,7 +3747,7 @@ This method can be significantly faster than the getAttributes()
-Promise.<Array.<Note>>
+Promise.<(string|null)>
@@ -3563,7 +3765,484 @@ This method can be significantly faster than the getAttributes()
- (async) getRelation(name) → {Promise.<Attribute>}
+ (async) getOwnedLabel(name) → {Promise.<(Attribute|null)>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ label name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ label if it exists, null otherwise
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<(Attribute|null)>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedLabels(nameopt) → {Promise.<Array.<Attribute>>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ label name to filter |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ all note's labels (attributes with type label), excluding inherited ones
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<Array.<Attribute>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedLabelValue(name) → {Promise.<(string|null)>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ label name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ label value if label exists, null otherwise
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<(string|null)>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedRelation(name) → {Promise.<(Attribute|null)>}
@@ -3660,7 +4339,7 @@ This method can be significantly faster than the getAttributes()
Source:
@@ -3700,7 +4379,748 @@ This method can be significantly faster than the getAttributes()
-Promise.<Attribute>
+Promise.<(Attribute|null)>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedRelations(nameopt) → {Promise.<Array.<Attribute>>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ relation name to filter |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ all note's relations (attributes with type relation), excluding inherited ones
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<Array.<Attribute>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedRelationTarget(name) → {Promise.<Note>|null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ target note of the relation or null (if target is empty or note was not found)
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<Note>
+|
+
+null
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getOwnedRelationValue(name) → {Promise.<(string|null)>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ relation name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ relation value if relation exists, null otherwise
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<(string|null)>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getParentNotes() → {Promise.<Array.<Note>>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ parent notes of this note (note can have multiple parents because of cloning)
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<Array.<Note>>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) getRelation(name) → {Promise.<(Attribute|null)>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ relation name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ relation if it exists, null otherwise
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<(Attribute|null)>
@@ -3827,7 +5247,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -3994,7 +5414,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4149,7 +5569,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4319,7 +5739,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4373,7 +5793,7 @@ This method can be significantly faster than the getAttributes()
- (async) getRelationValue(name) → {Promise.<string>}
+ (async) getRelationValue(name) → {Promise.<(string|null)>}
@@ -4470,7 +5890,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4510,7 +5930,7 @@ This method can be significantly faster than the getAttributes()
-
-Promise.<string>
+Promise.<(string|null)>
@@ -4580,7 +6000,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4788,7 +6208,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -4966,7 +6386,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -5072,7 +6492,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -5227,7 +6647,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -5285,6 +6705,494 @@ This method can be significantly faster than the getAttributes()
+ (async) hasOwnedAttribute(type, name) → {Promise.<boolean>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ attribute type (label, relation, etc.) |
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ attribute name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if note has an attribute with given type and name (excluding inherited)
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) hasOwnedLabel(name) → {Promise.<boolean>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ label name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if label exists (excluding inherited)
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (async) hasOwnedRelation(name) → {Promise.<boolean>}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+ relation name |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ true if relation exists (excluding inherited)
+
+
+
+
+
+ -
+ Type
+
+ -
+
+Promise.<boolean>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(async) hasRelation(name) → {Promise.<boolean>}
@@ -5382,7 +7290,7 @@ This method can be significantly faster than the getAttributes()
- Source:
@@ -5493,7 +7401,7 @@ Cache is note instance scoped.
- Source:
@@ -5621,7 +7529,7 @@ Cache is note instance scoped.
- Source:
@@ -6257,7 +8165,7 @@ Cache is note instance scoped.
- Source:
@@ -6486,7 +8394,7 @@ Cache is note instance scoped.
- Source:
@@ -6684,7 +8592,7 @@ Cache is note instance scoped.
- Source:
@@ -6882,7 +8790,7 @@ Cache is note instance scoped.
- Source:
@@ -7111,7 +9019,7 @@ Cache is note instance scoped.
- Source:
@@ -7513,7 +9421,7 @@ Cache is note instance scoped.
- Source:
@@ -7711,7 +9619,7 @@ Cache is note instance scoped.
- Source:
@@ -7971,7 +9879,7 @@ Cache is note instance scoped.
- Source:
@@ -8200,7 +10108,7 @@ Cache is note instance scoped.
- Source:
@@ -8429,7 +10337,7 @@ Cache is note instance scoped.
- Source:
diff --git a/docs/backend_api/entities_note.js.html b/docs/backend_api/entities_note.js.html
index 9f32a00ee..cbe5cd3ef 100644
--- a/docs/backend_api/entities_note.js.html
+++ b/docs/backend_api/entities_note.js.html
@@ -224,26 +224,36 @@ class Note extends Entity {
return null;
}
+ async loadOwnedAttributesToCache() {
+ this.__ownedAttributeCache = await repository.getEntities(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`, [this.noteId]);
+ return this.__ownedAttributeCache;
+ }
+
/**
- * @returns {Promise<Attribute[]>} attributes belonging to this specific note (excludes inherited attributes)
+ * This method is a faster variant of getAttributes() which looks for only owned attributes.
+ * Use when inheritance is not needed and/or in batch/performance sensitive operations.
*
- * This method can be significantly faster than the getAttributes()
+ * @param {string} [type] - (optional) attribute type to filter
+ * @param {string} [name] - (optional) attribute name to filter
+ * @returns {Promise<Attribute[]>} note's "owned" attributes - excluding inherited ones
*/
async getOwnedAttributes(type, name) {
- let query = `SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`;
- const params = [this.noteId];
-
- if (type) {
- query += ` AND type = ?`;
- params.push(type);
+ if (!this.__ownedAttributeCache) {
+ await this.loadOwnedAttributesToCache();
}
- if (name) {
- query += ` AND name = ?`;
- params.push(name);
+ if (type && name) {
+ return this.__ownedAttributeCache.filter(attr => attr.type === type && attr.name === name);
+ }
+ else if (type) {
+ return this.__ownedAttributeCache.filter(attr => attr.type === type);
+ }
+ else if (name) {
+ return this.__ownedAttributeCache.filter(attr => attr.name === name);
+ }
+ else {
+ return this.__ownedAttributeCache.slice();
}
-
- return await repository.getEntities(query, params);
}
/**
@@ -265,19 +275,26 @@ class Note extends Entity {
}
/**
- * @param {string} [name] - attribute name to filter
+ * @param {string} [type] - (optional) attribute type to filter
+ * @param {string} [name] - (optional) attribute name to filter
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
*/
- async getAttributes(name) {
+ async getAttributes(type, name) {
if (!this.__attributeCache) {
await this.loadAttributesToCache();
}
- if (name) {
+ if (type && name) {
+ return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
+ }
+ else if (type) {
+ return this.__attributeCache.filter(attr => attr.type === type);
+ }
+ else if (name) {
return this.__attributeCache.filter(attr => attr.name === name);
}
else {
- return this.__attributeCache;
+ return this.__attributeCache.slice();
}
}
@@ -286,7 +303,15 @@ class Note extends Entity {
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
*/
async getLabels(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
+ return await this.getAttributes(LABEL, name);
+ }
+
+ /**
+ * @param {string} [name] - label name to filter
+ * @returns {Promise<Attribute[]>} all note's labels (attributes with type label), excluding inherited ones
+ */
+ async getOwnedLabels(name) {
+ return await this.getOwnedAttributes(LABEL, name);
}
/**
@@ -294,7 +319,7 @@ class Note extends Entity {
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
*/
async getLabelDefinitions(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
+ return await this.getAttributes(LABEL_DEFINITION, name);
}
/**
@@ -302,7 +327,15 @@ class Note extends Entity {
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
*/
async getRelations(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
+ return await this.getAttributes(RELATION, name);
+ }
+
+ /**
+ * @param {string} [name] - relation name to filter
+ * @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), excluding inherited ones
+ */
+ async getOwnedRelations(name) {
+ return await this.getOwnedAttributes(RELATION, name);
}
/**
@@ -325,7 +358,7 @@ class Note extends Entity {
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
*/
async getRelationDefinitions(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
+ return await this.getAttributes(RELATION_DEFINITION, name);
}
/**
@@ -334,6 +367,7 @@ class Note extends Entity {
*/
invalidateAttributeCache() {
this.__attributeCache = null;
+ this.__ownedAttributeCache = null;
}
/** @returns {Promise<void>} */
@@ -343,11 +377,10 @@ class Note extends Entity {
tree(noteId, level) AS (
SELECT ?, 0
UNION
- SELECT branches.parentNoteId, tree.level + 1 FROM branches
+ SELECT branches.parentNoteId, tree.level + 1
+ FROM branches
JOIN tree ON branches.noteId = tree.noteId
- JOIN notes ON notes.noteId = branches.parentNoteId
- WHERE notes.isDeleted = 0
- AND branches.isDeleted = 0
+ WHERE branches.isDeleted = 0
),
treeWithAttrs(noteId, level) AS (
SELECT * FROM tree
@@ -366,6 +399,11 @@ class Note extends Entity {
// we order by noteId so that attributes from same note stay together. Actual noteId ordering doesn't matter.
const filteredAttributes = attributes.filter((attr, index) => {
+ // if this exact attribute already appears then don't include it (can happen via cloning)
+ if (attributes.findIndex(it => it.attributeId === attr.attributeId) !== index) {
+ return false;
+ }
+
if (attr.isDefinition()) {
const firstDefinitionIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name);
@@ -409,6 +447,15 @@ class Note extends Entity {
return !!await this.getAttribute(type, name);
}
+ /**
+ * @param {string} type - attribute type (label, relation, etc.)
+ * @param {string} name - attribute name
+ * @returns {Promise<boolean>} true if note has an attribute with given type and name (excluding inherited)
+ */
+ async hasOwnedAttribute(type, name) {
+ return !!await this.getOwnedAttribute(type, name);
+ }
+
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
@@ -423,7 +470,7 @@ class Note extends Entity {
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
- * @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
+ * @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
*/
async getAttributeValue(type, name) {
const attr = await this.getAttribute(type, name);
@@ -431,6 +478,17 @@ class Note extends Entity {
return attr ? attr.value : null;
}
+ /**
+ * @param {string} type - attribute type (label, relation, etc.)
+ * @param {string} name - attribute name
+ * @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
+ */
+ async getOwnedAttributeValue(type, name) {
+ const attr = await this.getOwnedAttribute(type, name);
+
+ return attr ? attr.value : null;
+ }
+
/**
* Based on enabled, attribute is either set or removed.
*
@@ -458,7 +516,7 @@ class Note extends Entity {
* @returns {Promise<void>}
*/
async setAttribute(type, name, value) {
- const attributes = await this.getOwnedAttributes();
+ const attributes = await this.loadOwnedAttributesToCache();
let attr = attributes.find(attr => attr.type === type && attr.name === name);
if (attr) {
@@ -492,7 +550,7 @@ class Note extends Entity {
* @returns {Promise<void>}
*/
async removeAttribute(type, name, value) {
- const attributes = await this.getOwnedAttributes();
+ const attributes = await this.loadOwnedAttributesToCache();
for (const attribute of attributes) {
if (attribute.type === type && (value === undefined || value === attribute.value)) {
@@ -536,36 +594,72 @@ class Note extends Entity {
*/
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
+ /**
+ * @param {string} name - label name
+ * @returns {Promise<boolean>} true if label exists (excluding inherited)
+ */
+ async hasOwnedLabel(name) { return await this.hasOwnedAttribute(LABEL, name); }
+
/**
* @param {string} name - relation name
* @returns {Promise<boolean>} true if relation exists (including inherited)
*/
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {Promise<boolean>} true if relation exists (excluding inherited)
+ */
+ async hasOwnedRelation(name) { return await this.hasOwnedAttribute(RELATION, name); }
+
/**
* @param {string} name - label name
- * @returns {Promise<Attribute>} label if it exists, null otherwise
+ * @returns {Promise<Attribute|null>} label if it exists, null otherwise
*/
async getLabel(name) { return await this.getAttribute(LABEL, name); }
+ /**
+ * @param {string} name - label name
+ * @returns {Promise<Attribute|null>} label if it exists, null otherwise
+ */
+ async getOwnedLabel(name) { return await this.getOwnedAttribute(LABEL, name); }
+
/**
* @param {string} name - relation name
- * @returns {Promise<Attribute>} relation if it exists, null otherwise
+ * @returns {Promise<Attribute|null>} relation if it exists, null otherwise
*/
async getRelation(name) { return await this.getAttribute(RELATION, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {Promise<Attribute|null>} relation if it exists, null otherwise
+ */
+ async getOwnedRelation(name) { return await this.getOwnedAttribute(RELATION, name); }
+
/**
* @param {string} name - label name
- * @returns {Promise<string>} label value if label exists, null otherwise
+ * @returns {Promise<string|null>} label value if label exists, null otherwise
*/
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
+ /**
+ * @param {string} name - label name
+ * @returns {Promise<string|null>} label value if label exists, null otherwise
+ */
+ async getOwnedLabelValue(name) { return await this.getOwnedAttributeValue(LABEL, name); }
+
/**
* @param {string} name - relation name
- * @returns {Promise<string>} relation value if relation exists, null otherwise
+ * @returns {Promise<string|null>} relation value if relation exists, null otherwise
*/
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
+ /**
+ * @param {string} name - relation name
+ * @returns {Promise<string|null>} relation value if relation exists, null otherwise
+ */
+ async getOwnedRelationValue(name) { return await this.getOwnedAttributeValue(RELATION, name); }
+
/**
* @param {string} name
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
@@ -576,6 +670,16 @@ class Note extends Entity {
return relation ? await repository.getNote(relation.value) : null;
}
+ /**
+ * @param {string} name
+ * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
+ */
+ async getOwnedRelationTarget(name) {
+ const relation = await this.getOwnedRelation(name);
+
+ return relation ? await repository.getNote(relation.value) : null;
+ }
+
/**
* Based on enabled, label is either set or removed.
*
diff --git a/docs/backend_api/global.html b/docs/backend_api/global.html
index 907f6a8ca..7f36be767 100644
--- a/docs/backend_api/global.html
+++ b/docs/backend_api/global.html
@@ -596,6 +596,480 @@
+
+CreateNoteAttribute
+
+
+
+
+
+
+ Type:
+
+
+
+
+
+
+ Properties:
+
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+
+ |
+
+
+
+
+ attribute type - label, relation etc. |
+
+
+
+
+
+
+ name |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+
+
+ |
+
+
+
+
+ attribute name |
+
+
+
+
+
+
+ value |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+ attribute value |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Type:
+
+
+
+
+
+
+ Properties:
+
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+ Default |
+
+
+ Description |
+
+
+
+
+
+
+
+
+ json |
+
+
+
+
+
+boolean
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+
+ false
+
+ |
+
+
+ should the note be JSON |
+
+
+
+
+
+
+ isProtected |
+
+
+
+
+
+boolean
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+
+ false
+
+ |
+
+
+ should the note be protected |
+
+
+
+
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+
+ 'text'
+
+ |
+
+
+ note type |
+
+
+
+
+
+
+ mime |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+
+ 'text/html'
+
+ |
+
+
+ MIME type of the note |
+
+
+
+
+
+
+ attributes |
+
+
+
+
+
+Array.<CreateNoteAttribute>
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+ |
+
+
+
+
+
+ []
+
+ |
+
+
+ attributes to be created for this note |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/backend_api/services_backend_script_api.js.html b/docs/backend_api/services_backend_script_api.js.html
index de1512b05..8c76aa124 100644
--- a/docs/backend_api/services_backend_script_api.js.html
+++ b/docs/backend_api/services_backend_script_api.js.html
@@ -258,6 +258,65 @@ function BackendScriptApi(currentNote, apiParams) {
*/
this.createNewNote = noteService.createNewNote;
+ /**
+ * @typedef {object} CreateNoteAttribute
+ * @property {string} type - attribute type - label, relation etc.
+ * @property {string} name - attribute name
+ * @property {string} [value] - attribute value
+ */
+
+ /**
+ * @typedef {object} CreateNoteExtraOptions
+ * @property {boolean} [json=false] - should the note be JSON
+ * @property {boolean} [isProtected=false] - should the note be protected
+ * @property {string} [type='text'] - note type
+ * @property {string} [mime='text/html'] - MIME type of the note
+ * @property {CreateNoteAttribute[]} [attributes=[]] - attributes to be created for this note
+ */
+
+ /**
+ * @method
+ *
+ * @param {string} parentNoteId - create new note under this parent
+ * @param {string} title
+ * @param {string} [content=""]
+ * @param {CreateNoteExtraOptions} [extraOptions={}]
+ * @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
+ */
+ this.createNote = async (parentNoteId, title, content = "", extraOptions= {}) => {
+ extraOptions.parentNoteId = parentNoteId;
+ extraOptions.title = title;
+
+ const parentNote = await repository.getNote(parentNoteId);
+
+ // code note type can be inherited, otherwise text is default
+ extraOptions.type = parentNote.type === 'code' ? 'code' : 'text';
+ extraOptions.mime = parentNote.type === 'code' ? parentNote.mime : 'text/html';
+
+ if (extraOptions.json) {
+ extraOptions.content = JSON.stringify(content || {}, null, '\t');
+ extraOptions.type = 'code';
+ extraOptions.mime = 'application/json';
+ }
+ else {
+ extraOptions.content = content;
+ }
+
+ const {note, branch} = await noteService.createNewNote(extraOptions);
+
+ for (const attr of extraOptions.attributes || []) {
+ await attributeService.createAttribute({
+ noteId: note.noteId,
+ type: attr.type,
+ name: attr.name,
+ value: attr.value,
+ isInheritable: !!attr.isInheritable
+ });
+ }
+
+ return {note, branch};
+ };
+
/**
* Log given message to trilium logs.
*
diff --git a/docs/frontend_api/NoteShort.html b/docs/frontend_api/NoteShort.html
index 6e3561286..e4766ce54 100644
--- a/docs/frontend_api/NoteShort.html
+++ b/docs/frontend_api/NoteShort.html
@@ -1220,7 +1220,7 @@
- Source:
@@ -1278,7 +1278,7 @@
- (async) getAttributes(nameopt) → {Promise.<Array.<Attribute>>}
+ (async) getAttributes(typeopt, nameopt) → {Promise.<Array.<Attribute>>}
@@ -1318,6 +1318,39 @@
+
+
+ type |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ (optional) attribute type to filter |
+
+
+
+
name |
@@ -1346,7 +1379,7 @@
- attribute name to filter |
+ (optional) attribute name to filter |
@@ -1387,7 +1420,7 @@
- Source:
@@ -1415,6 +1448,10 @@
Returns:
+
+ all note's attributes, including inherited ones
+
+
@@ -1561,7 +1598,7 @@
- Source:
@@ -2124,7 +2161,7 @@
- Source:
@@ -2291,7 +2328,7 @@
- Source:
@@ -2458,7 +2495,7 @@
- Source:
@@ -2613,7 +2650,7 @@
- Source:
@@ -2972,7 +3009,7 @@
- Source:
@@ -3139,7 +3176,7 @@
- Source:
@@ -3306,7 +3343,7 @@
- Source:
@@ -3461,7 +3498,7 @@
- Source:
@@ -3631,7 +3668,7 @@
- Source:
@@ -3782,7 +3819,7 @@
- Source:
@@ -3892,7 +3929,7 @@
- Source:
@@ -4066,7 +4103,7 @@
- Source:
@@ -4323,7 +4360,7 @@
- Source:
@@ -4478,7 +4515,7 @@
- Source:
@@ -4536,7 +4573,7 @@
- invalidateAttributeCache()
+ invalidate__attributeCache()
@@ -4589,7 +4626,7 @@ Cache is note instance scoped.
- Source:
diff --git a/docs/frontend_api/entities_note_short.js.html b/docs/frontend_api/entities_note_short.js.html
index ed9603318..ebb24d8b2 100644
--- a/docs/frontend_api/entities_note_short.js.html
+++ b/docs/frontend_api/entities_note_short.js.html
@@ -182,20 +182,27 @@ class NoteShort {
}
/**
- * @param {string} [name] - attribute name to filter
- * @returns {Promise<Attribute[]>}
+ * @param {string} [type] - (optional) attribute type to filter
+ * @param {string} [name] - (optional) attribute name to filter
+ * @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
*/
- async getAttributes(name) {
- if (!this.attributeCache) {
- this.attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
+ async getAttributes(type, name) {
+ if (!this.__attributeCache) {
+ this.__attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
.map(attrRow => new Attribute(this.treeCache, attrRow));
}
- if (name) {
- return this.attributeCache.filter(attr => attr.name === name);
+ if (type && name) {
+ return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
+ }
+ else if (type) {
+ return this.__attributeCache.filter(attr => attr.type === type);
+ }
+ else if (name) {
+ return this.__attributeCache.filter(attr => attr.name === name);
}
else {
- return this.attributeCache;
+ return this.__attributeCache.slice();
}
}
@@ -204,7 +211,7 @@ class NoteShort {
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
*/
async getLabels(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
+ return await this.getAttributes(LABEL, name);
}
/**
@@ -212,7 +219,7 @@ class NoteShort {
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
*/
async getLabelDefinitions(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
+ return await this.getAttributes(LABEL_DEFINITION, name);
}
/**
@@ -220,7 +227,7 @@ class NoteShort {
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
*/
async getRelations(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
+ return await this.getAttributes(RELATION, name);
}
/**
@@ -228,7 +235,7 @@ class NoteShort {
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
*/
async getRelationDefinitions(name) {
- return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
+ return await this.getAttributes(RELATION_DEFINITION, name);
}
/**
@@ -327,8 +334,8 @@ class NoteShort {
* Clear note's attributes cache to force fresh reload for next attribute request.
* Cache is note instance scoped.
*/
- invalidateAttributeCache() {
- this.attributeCache = null;
+ invalidate__attributeCache() {
+ this.__attributeCache = null;
}
/**
@@ -349,7 +356,7 @@ class NoteShort {
const dto = Object.assign({}, this);
delete dto.treeCache;
delete dto.archived;
- delete dto.attributeCache;
+ delete dto.__attributeCache;
return dto;
}