diff --git a/docs/backend_api/ApiToken.html b/docs/backend_api/ApiToken.html index 2faeafef3..8f0026765 100644 --- a/docs/backend_api/ApiToken.html +++ b/docs/backend_api/ApiToken.html @@ -287,7 +287,7 @@
diff --git a/docs/backend_api/Attribute.html b/docs/backend_api/Attribute.html index 378b1db05..dfdc8ead7 100644 --- a/docs/backend_api/Attribute.html +++ b/docs/backend_api/Attribute.html @@ -744,7 +744,7 @@
diff --git a/docs/backend_api/BackendScriptApi.html b/docs/backend_api/BackendScriptApi.html index 2d62dd248..09ccf7808 100644 --- a/docs/backend_api/BackendScriptApi.html +++ b/docs/backend_api/BackendScriptApi.html @@ -81,7 +81,7 @@
Source:
@@ -131,6 +131,116 @@ +

axios

+ + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
Axios + + +axios + + + + library for HTTP requests. See https://axios-http.com/ for documentation
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + +

currentNote

@@ -223,7 +333,117 @@
Source:
+ + + + + + + + + + + + + + + + +

dayjs

+ + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
day.js + + +dayjs + + + + library for date manipulation. See https://day.js.org/ for documentation
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -333,7 +553,117 @@
Source:
+ + + + + + + +
+ + + + + + + + +

sql

+ + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sql + + +module:sql + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -443,7 +773,117 @@
Source:
+ + + + + + + +
+ + + + + + + + +

xml2js

+ + + + + + + + + + +
Properties:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
xml2js + + +axios + + + + library for XML parsing. See https://github.com/Leonidas-from-XIV/node-xml2js for documentation
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
@@ -619,7 +1059,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -647,6 +1087,10 @@ JSON MIME type. See also createNewNote() for more options.
Returns:
+
+ object having "note" and "branch" keys representing respective objects +
+
@@ -782,7 +1226,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1068,7 +1512,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1273,7 +1717,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1301,6 +1745,10 @@ JSON MIME type. See also createNewNote() for more options.
Returns:
+
+ - object having "note" and "branch" keys representing respective objects +
+
@@ -1451,7 +1899,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1652,7 +2100,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1706,6 +2154,161 @@ JSON MIME type. See also createNewNote() for more options. +

escapeHtml(string) → {string}

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
string + + +string + + + + to escape
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ escaped string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + +

getAppInfo() → {Object|*}

@@ -1754,7 +2357,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -1912,7 +2515,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -2066,7 +2669,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -2224,7 +2827,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -2401,7 +3004,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -2579,7 +3182,7 @@ JSON MIME type. See also createNewNote() for more options.
Source:
@@ -2689,7 +3292,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -2847,7 +3450,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3001,7 +3604,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3202,7 +3805,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3400,7 +4003,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3509,7 +4112,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3618,7 +4221,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3799,7 +4402,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3957,7 +4560,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4110,7 +4713,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4140,6 +4743,165 @@ if some action needs to happen on only one specific instance. + + + + + + +

randomString(length) → {string}

+ + + + + + +
+ Return randomly generated string of given length. This random string generation is NOT cryptographically secure. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
length + + +number + + + + of the string
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ random string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + @@ -4196,7 +4958,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4334,7 +5096,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4536,7 +5298,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -4745,7 +5507,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
Source:
@@ -4781,7 +5543,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look -

sortNotesAlphabetically(parentNoteId)

+

sortNotesByTitle(parentNoteId)

@@ -4878,7 +5640,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
Source:
@@ -5084,7 +5846,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
Source:
@@ -5240,7 +6002,7 @@ exists, then we'll use that transaction.
Source:
@@ -5293,6 +6055,161 @@ exists, then we'll use that transaction. + + + + + +

unescapeHtml(string) → {string}

+ + + + + + + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
string + + +string + + + + to unescape
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ unescaped string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + @@ -5308,7 +6225,7 @@ exists, then we'll use that transaction.
diff --git a/docs/backend_api/Branch.html b/docs/backend_api/Branch.html index cb92ae68c..407a6edef 100644 --- a/docs/backend_api/Branch.html +++ b/docs/backend_api/Branch.html @@ -643,7 +643,7 @@ Each note can have multiple (at least one) branches, meaning it can be placed in
diff --git a/docs/backend_api/Entity.html b/docs/backend_api/Entity.html index 10330a6af..b9dbd11e2 100644 --- a/docs/backend_api/Entity.html +++ b/docs/backend_api/Entity.html @@ -212,7 +212,7 @@
diff --git a/docs/backend_api/Note.html b/docs/backend_api/Note.html index ed874bc30..0f075977c 100644 --- a/docs/backend_api/Note.html +++ b/docs/backend_api/Note.html @@ -537,7 +537,7 @@
Source:
@@ -639,7 +639,7 @@
Source:
@@ -817,7 +817,7 @@
Source:
@@ -1017,7 +1017,7 @@
Source:
@@ -1195,7 +1195,7 @@
Source:
@@ -1304,7 +1304,7 @@
Source:
@@ -1406,7 +1406,7 @@
Source:
@@ -1512,7 +1512,7 @@
Source:
@@ -1618,7 +1618,7 @@
Source:
@@ -1720,7 +1720,7 @@
Source:
@@ -1822,7 +1822,7 @@
Source:
@@ -2055,7 +2055,7 @@
Source:
@@ -2253,7 +2253,7 @@
Source:
@@ -2451,7 +2451,7 @@
Source:
@@ -2553,7 +2553,7 @@
Source:
@@ -2704,7 +2704,7 @@
Source:
@@ -2874,7 +2874,7 @@
Source:
@@ -3029,7 +3029,7 @@
Source:
@@ -3144,7 +3144,7 @@
Source:
@@ -3246,7 +3246,7 @@
Source:
@@ -3453,7 +3453,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -3631,7 +3631,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -3789,7 +3789,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -3959,7 +3959,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4114,7 +4114,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4272,7 +4272,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4442,7 +4442,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4597,7 +4597,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4755,7 +4755,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -4864,7 +4864,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5019,7 +5019,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5189,7 +5189,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5344,7 +5344,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5514,7 +5514,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5665,7 +5665,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5778,7 +5778,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5880,7 +5880,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -5986,7 +5986,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6164,7 +6164,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6270,7 +6270,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6425,7 +6425,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6603,7 +6603,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6758,7 +6758,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -6913,7 +6913,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -7068,7 +7068,7 @@ Use when inheritance is not needed and/or in batch/performance sensitive operati
Source:
@@ -7179,7 +7179,7 @@ Cache is note instance scoped.
Source:
@@ -7307,7 +7307,7 @@ Cache is note instance scoped.
Source:
@@ -7413,7 +7413,7 @@ Cache is note instance scoped.
Source:
@@ -7519,7 +7519,7 @@ Cache is note instance scoped.
Source:
@@ -7625,7 +7625,7 @@ Cache is note instance scoped.
Source:
@@ -7731,7 +7731,7 @@ Cache is note instance scoped.
Source:
@@ -7837,7 +7837,7 @@ Cache is note instance scoped.
Source:
@@ -8070,7 +8070,7 @@ Cache is note instance scoped.
Source:
@@ -8250,7 +8250,7 @@ Cache is note instance scoped.
Source:
@@ -8430,7 +8430,7 @@ Cache is note instance scoped.
Source:
@@ -8641,7 +8641,7 @@ Cache is note instance scoped.
Source:
@@ -8821,7 +8821,7 @@ Cache is note instance scoped.
Source:
@@ -8857,7 +8857,7 @@ Cache is note instance scoped. -

setRelation(name, valueopt)

+

setRelation(name, value)

@@ -8889,8 +8889,6 @@ Cache is note instance scoped. Type - Attributes - @@ -8916,14 +8914,6 @@ Cache is note instance scoped. - - - - - - - - @@ -8947,16 +8937,6 @@ Cache is note instance scoped. - - - <optional>
- - - - - - - @@ -9001,7 +8981,7 @@ Cache is note instance scoped.
Source:
@@ -9243,7 +9223,7 @@ Cache is note instance scoped.
Source:
@@ -9454,7 +9434,7 @@ Cache is note instance scoped.
Source:
@@ -9665,7 +9645,7 @@ Cache is note instance scoped.
Source:
@@ -9711,7 +9691,7 @@ Cache is note instance scoped.
diff --git a/docs/backend_api/NoteRevision.html b/docs/backend_api/NoteRevision.html index fdaa8cb45..12ab87c6e 100644 --- a/docs/backend_api/NoteRevision.html +++ b/docs/backend_api/NoteRevision.html @@ -660,7 +660,7 @@
diff --git a/docs/backend_api/Option.html b/docs/backend_api/Option.html index b65e9eb5e..2ecb34751 100644 --- a/docs/backend_api/Option.html +++ b/docs/backend_api/Option.html @@ -310,7 +310,7 @@
diff --git a/docs/backend_api/RecentNote.html b/docs/backend_api/RecentNote.html index e3bea9753..6831a401d 100644 --- a/docs/backend_api/RecentNote.html +++ b/docs/backend_api/RecentNote.html @@ -264,7 +264,7 @@
diff --git a/docs/backend_api/entities_api_token.js.html b/docs/backend_api/entities_api_token.js.html index 0d4db291c..01d3dd10a 100644 --- a/docs/backend_api/entities_api_token.js.html +++ b/docs/backend_api/entities_api_token.js.html @@ -69,7 +69,7 @@ module.exports = ApiToken;
diff --git a/docs/backend_api/entities_attribute.js.html b/docs/backend_api/entities_attribute.js.html index 0e833e283..4485a8aa5 100644 --- a/docs/backend_api/entities_attribute.js.html +++ b/docs/backend_api/entities_attribute.js.html @@ -160,7 +160,7 @@ module.exports = Attribute;
diff --git a/docs/backend_api/entities_branch.js.html b/docs/backend_api/entities_branch.js.html index c71894b9d..6c28da4f8 100644 --- a/docs/backend_api/entities_branch.js.html +++ b/docs/backend_api/entities_branch.js.html @@ -113,7 +113,7 @@ module.exports = Branch;
diff --git a/docs/backend_api/entities_entity.js.html b/docs/backend_api/entities_entity.js.html index 78a82ea00..c6a8b1dcb 100644 --- a/docs/backend_api/entities_entity.js.html +++ b/docs/backend_api/entities_entity.js.html @@ -69,7 +69,7 @@ class Entity { } getUtcDateChanged() { - return this.utcDateModified; + return this.utcDateModified || this.utcDateCreated; } get repository() { @@ -98,7 +98,7 @@ module.exports = Entity;
diff --git a/docs/backend_api/entities_note.js.html b/docs/backend_api/entities_note.js.html index 778234c83..ab5ec0443 100644 --- a/docs/backend_api/entities_note.js.html +++ b/docs/backend_api/entities_note.js.html @@ -77,7 +77,12 @@ class Note extends Entity { this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable(); if (this.isContentAvailable) { - this.title = protectedSessionService.decryptString(this.title); + try { + this.title = protectedSessionService.decryptString(this.title); + } + catch (e) { + throw new Error(`Could not decrypt title of note ${this.noteId}: ${e.message} ${e.stack}`) + } } else { this.title = "[protected]"; @@ -184,14 +189,14 @@ class Note extends Entity { sql.upsert("note_contents", "noteId", pojo); - const hash = utils.hash(this.noteId + "|" + content.toString()); + const hash = utils.hash(this.noteId + "|" + pojo.content.toString()); entityChangesService.addEntityChange({ entityName: 'note_contents', entityId: this.noteId, hash: hash, isErased: false, - utcDateChanged: this.getUtcDateChanged() + utcDateChanged: pojo.utcDateModified }, null); } @@ -393,7 +398,6 @@ class Note extends Entity { WHERE attributes.isDeleted = 0 AND attributes.type = 'relation' AND attributes.name = 'template' - AND (treeWithAttrs.level = 0 OR attributes.isInheritable = 1) ) SELECT attributes.* FROM attributes JOIN treeWithAttrs ON attributes.noteId = treeWithAttrs.noteId WHERE attributes.isDeleted = 0 AND (attributes.isInheritable = 1 OR treeWithAttrs.level = 0) @@ -709,7 +713,7 @@ class Note extends Entity { * Update's given relation's value or creates it if it doesn't exist * * @param {string} name - relation name - * @param {string} [value] - relation value (noteId) + * @param {string} value - relation value (noteId) */ setRelation(name, value) { return this.setAttribute(RELATION, name, value); } @@ -974,7 +978,7 @@ module.exports = Note;
diff --git a/docs/backend_api/entities_note_revision.js.html b/docs/backend_api/entities_note_revision.js.html index 371bc3c06..f42910fcc 100644 --- a/docs/backend_api/entities_note_revision.js.html +++ b/docs/backend_api/entities_note_revision.js.html @@ -189,7 +189,7 @@ module.exports = NoteRevision;
diff --git a/docs/backend_api/entities_option.js.html b/docs/backend_api/entities_option.js.html index c1bbab9ff..7ee1a2d7f 100644 --- a/docs/backend_api/entities_option.js.html +++ b/docs/backend_api/entities_option.js.html @@ -75,7 +75,7 @@ module.exports = Option;
diff --git a/docs/backend_api/entities_recent_note.js.html b/docs/backend_api/entities_recent_note.js.html index 7af54b3ae..0efca547d 100644 --- a/docs/backend_api/entities_recent_note.js.html +++ b/docs/backend_api/entities_recent_note.js.html @@ -64,7 +64,7 @@ module.exports = RecentNote;
diff --git a/docs/backend_api/global.html b/docs/backend_api/global.html index bfb7edec3..7bf9e2d7a 100644 --- a/docs/backend_api/global.html +++ b/docs/backend_api/global.html @@ -391,7 +391,7 @@
Source:
@@ -579,7 +579,7 @@
Source:
@@ -767,7 +767,7 @@
Source:
@@ -1053,7 +1053,7 @@
Source:
@@ -1083,7 +1083,7 @@
diff --git a/docs/backend_api/index.html b/docs/backend_api/index.html index 4051b8b8f..16d0a14a7 100644 --- a/docs/backend_api/index.html +++ b/docs/backend_api/index.html @@ -50,7 +50,7 @@
diff --git a/docs/backend_api/module-sql.html b/docs/backend_api/module-sql.html new file mode 100644 index 000000000..290599ca1 --- /dev/null +++ b/docs/backend_api/module-sql.html @@ -0,0 +1,1267 @@ + + + + + JSDoc: Module: sql + + + + + + + + + + +
+ +

Module: sql

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) execute(query, paramsopt)

+ + + + + + +
+ Execute SQL +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(static) getColumn(query, paramsopt) → {Array.<object>}

+ + + + + + +
+ Get a first column in an array. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - array of first column of all returned rows +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

(static) getMap(query, paramsopt) → {object}

+ + + + + + +
+ Get a map of first column mapping to second column. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - map of first column to second column +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

(static) getRow(query, paramsopt) → {object}

+ + + + + + +
+ Get first returned row. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - map of column name to column value +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +

(static) getRows(query, paramsopt) → {Array.<object>}

+ + + + + + +
+ Get all returned rows. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - array of all rows, each row is a map of column name to column value +
+ + + +
+
+ Type +
+
+ +Array.<object> + + +
+
+ + + + + + + + + + + + + +

(static) getValue(query, paramsopt)

+ + + + + + +
+ Get single value from the given query - first column from first returned row. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
query + + +string + + + + + + + + + + SQL query with ? used as parameter placeholder
params + + +Array.<object> + + + + + + <optional>
+ + + + + +
array of params if needed
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ [object] - single value +
+ + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/docs/backend_api/services_backend_script_api.js.html b/docs/backend_api/services_backend_script_api.js.html index 98bf9c0fd..cb310abc5 100644 --- a/docs/backend_api/services_backend_script_api.js.html +++ b/docs/backend_api/services_backend_script_api.js.html @@ -37,6 +37,7 @@ const config = require('./config'); const repository = require('./repository'); const axios = require('axios'); const dayjs = require('dayjs'); +const xml2js = require('xml2js'); const cloningService = require('./cloning'); const appInfo = require('./app_info'); const searchService = require('./search/services/search'); @@ -60,9 +61,14 @@ function BackendScriptApi(currentNote, apiParams) { this[key] = apiParams[key]; } + /** @property {axios} Axios library for HTTP requests. See https://axios-http.com/ for documentation */ this.axios = axios; + /** @property {dayjs} day.js library for date manipulation. See https://day.js.org/ for documentation */ this.dayjs = dayjs; + /** @property {axios} xml2js library for XML parsing. See https://github.com/Leonidas-from-XIV/node-xml2js for documentation */ + this.xml2js = xml2js; + // DEPRECATED - use direct api.unescapeHtml this.utils = { unescapeHtml: utils.unescapeHtml }; @@ -128,6 +134,10 @@ function BackendScriptApi(currentNote, apiParams) { searchParams.includeArchivedNotes = true; } + if (searchParams.ignoreHoistedNote === undefined) { + searchParams.ignoreHoistedNote = true; + } + const noteIds = searchService.findNotesWithQuery(query, new SearchContext(searchParams)) .map(sr => sr.noteId); @@ -214,7 +224,7 @@ function BackendScriptApi(currentNote, apiParams) { * @param {string} parentNoteId * @param {string} title * @param {string} content - * @return {{note: Note, branch: Branch}} + * @return {{note: Note, branch: Branch}} - object having "note" and "branch" keys representing respective objects */ this.createTextNote = (parentNoteId, title, content = '') => noteService.createNewNote({ parentNoteId, @@ -230,7 +240,7 @@ function BackendScriptApi(currentNote, apiParams) { * @param {string} parentNoteId * @param {string} title * @param {object} content - * @return {{note: Note, branch: Branch}} + * @return {{note: Note, branch: Branch}} object having "note" and "branch" keys representing respective objects */ this.createDataNote = (parentNoteId, title, content = {}) => noteService.createNewNote({ parentNoteId, @@ -387,7 +397,7 @@ function BackendScriptApi(currentNote, apiParams) { * @method * @param {string} parentNoteId - this note's child notes will be sorted */ - this.sortNotesAlphabetically = treeService.sortNotesAlphabetically; + this.sortNotesByTitle = treeService.sortNotesByTitle; /** * This method finds note by its noteId and prefix and either sets it to the given parentNoteId @@ -413,6 +423,32 @@ function BackendScriptApi(currentNote, apiParams) { */ this.transactional = sql.transactional; + /** + * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. + * + * @method + * @param {number} length of the string + * @returns {string} random string + */ + this.randomString = utils.randomString; + + /** + * @method + * @param {string} string to escape + * @returns {string} escaped string + */ + this.escapeHtml = utils.escapeHtml; + + /** + * @method + * @param {string} string to unescape + * @returns {string} unescaped string + */ + this.unescapeHtml = utils.unescapeHtml; + + /** + * @property {module:sql} sql + */ this.sql = sql; /** @@ -438,7 +474,7 @@ module.exports = BackendScriptApi;
diff --git a/docs/backend_api/services_sql.js.html b/docs/backend_api/services_sql.js.html new file mode 100644 index 000000000..6ad8e618a --- /dev/null +++ b/docs/backend_api/services_sql.js.html @@ -0,0 +1,399 @@ + + + + + JSDoc: Source: services/sql.js + + + + + + + + + + +
+ +

Source: services/sql.js

+ + + + + + +
+
+
"use strict";
+
+/**
+ * @module sql
+ */
+
+const log = require('./log');
+const Database = require('better-sqlite3');
+const dataDir = require('./data_dir');
+const cls = require('./cls');
+
+const dbConnection = new Database(dataDir.DOCUMENT_PATH);
+dbConnection.pragma('journal_mode = WAL');
+
+[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `SIGTERM`].forEach(eventType => {
+    process.on(eventType, () => {
+        if (dbConnection) {
+            // closing connection is especially important to fold -wal file into the main DB file
+            // (see https://sqlite.org/tempfiles.html for details)
+            dbConnection.close();
+        }
+    });
+});
+
+function insert(tableName, rec, replace = false) {
+    const keys = Object.keys(rec);
+    if (keys.length === 0) {
+        log.error("Can't insert empty object into table " + tableName);
+        return;
+    }
+
+    const columns = keys.join(", ");
+    const questionMarks = keys.map(p => "?").join(", ");
+
+    const query = "INSERT " + (replace ? "OR REPLACE" : "") + " INTO " + tableName + "(" + columns + ") VALUES (" + questionMarks + ")";
+
+    const res = execute(query, Object.values(rec));
+
+    return res ? res.lastInsertRowid : null;
+}
+
+function replace(tableName, rec) {
+    return insert(tableName, rec, true);
+}
+
+function upsert(tableName, primaryKey, rec) {
+    const keys = Object.keys(rec);
+    if (keys.length === 0) {
+        log.error("Can't upsert empty object into table " + tableName);
+        return;
+    }
+
+    const columns = keys.join(", ");
+
+    const questionMarks = keys.map(colName => "@" + colName).join(", ");
+
+    const updateMarks = keys.map(colName => `${colName} = @${colName}`).join(", ");
+
+    const query = `INSERT INTO ${tableName} (${columns}) VALUES (${questionMarks}) 
+                   ON CONFLICT (${primaryKey}) DO UPDATE SET ${updateMarks}`;
+
+    for (const idx in rec) {
+        if (rec[idx] === true || rec[idx] === false) {
+            rec[idx] = rec[idx] ? 1 : 0;
+        }
+    }
+
+    execute(query, rec);
+}
+
+const statementCache = {};
+
+function stmt(sql) {
+    if (!(sql in statementCache)) {
+        statementCache[sql] = dbConnection.prepare(sql);
+    }
+
+    return statementCache[sql];
+}
+
+function getRow(query, params = []) {
+    return wrap(query, s => s.get(params));
+}
+
+function getRowOrNull(query, params = []) {
+    const all = getRows(query, params);
+
+    return all.length > 0 ? all[0] : null;
+}
+
+function getValue(query, params = []) {
+    const row = getRowOrNull(query, params);
+
+    if (!row) {
+        return null;
+    }
+
+    return row[Object.keys(row)[0]];
+}
+
+// smaller values can result in better performance due to better usage of statement cache
+const PARAM_LIMIT = 100;
+
+function getManyRows(query, params) {
+    let results = [];
+
+    while (params.length > 0) {
+        const curParams = params.slice(0, Math.min(params.length, PARAM_LIMIT));
+        params = params.slice(curParams.length);
+
+        const curParamsObj = {};
+
+        let j = 1;
+        for (const param of curParams) {
+            curParamsObj['param' + j++] = param;
+        }
+
+        let i = 1;
+        const questionMarks = curParams.map(() => ":param" + i++).join(",");
+        const curQuery = query.replace(/\?\?\?/g, questionMarks);
+
+        const statement = curParams.length === PARAM_LIMIT
+            ? stmt(curQuery)
+            : dbConnection.prepare(curQuery);
+
+        const subResults = statement.all(curParamsObj);
+        results = results.concat(subResults);
+    }
+
+    return results;
+}
+
+function getRows(query, params = []) {
+    return wrap(query, s => s.all(params));
+}
+
+function iterateRows(query, params = []) {
+    return stmt(query).iterate(params);
+}
+
+function getMap(query, params = []) {
+    const map = {};
+    const results = getRows(query, params);
+
+    for (const row of results) {
+        const keys = Object.keys(row);
+
+        map[row[keys[0]]] = row[keys[1]];
+    }
+
+    return map;
+}
+
+function getColumn(query, params = []) {
+    const list = [];
+    const result = getRows(query, params);
+
+    if (result.length === 0) {
+        return list;
+    }
+
+    const key = Object.keys(result[0])[0];
+
+    for (const row of result) {
+        list.push(row[key]);
+    }
+
+    return list;
+}
+
+function execute(query, params = []) {
+    return wrap(query, s => s.run(params));
+}
+
+function executeWithoutTransaction(query, params = []) {
+    dbConnection.run(query, params);
+}
+
+function executeMany(query, params) {
+    while (params.length > 0) {
+        const curParams = params.slice(0, Math.min(params.length, PARAM_LIMIT));
+        params = params.slice(curParams.length);
+
+        const curParamsObj = {};
+
+        let j = 1;
+        for (const param of curParams) {
+            curParamsObj['param' + j++] = param;
+        }
+
+        let i = 1;
+        const questionMarks = curParams.map(() => ":param" + i++).join(",");
+        const curQuery = query.replace(/\?\?\?/g, questionMarks);
+
+        dbConnection.prepare(curQuery).run(curParamsObj);
+    }
+}
+
+function executeScript(query) {
+    return dbConnection.exec(query);
+}
+
+function wrap(query, func) {
+    const startTimestamp = Date.now();
+    let result;
+
+    try {
+        result = func(stmt(query));
+    }
+    catch (e) {
+        if (e.message.includes("The database connection is not open")) {
+            // this often happens on killing the app which puts these alerts in front of user
+            // in these cases error should be simply ignored.
+            console.log(e.message);
+
+            return null
+        }
+
+        throw e;
+    }
+
+    const milliseconds = Date.now() - startTimestamp;
+
+    if (milliseconds >= 20) {
+        if (query.includes("WITH RECURSIVE")) {
+            log.info(`Slow recursive query took ${milliseconds}ms.`);
+        }
+        else {
+            log.info(`Slow query took ${milliseconds}ms: ${query.trim().replace(/\s+/g, " ")}`);
+        }
+    }
+
+    return result;
+}
+
+function transactional(func) {
+    try {
+        const ret = dbConnection.transaction(func).deferred();
+
+        if (!dbConnection.inTransaction) { // i.e. transaction was really committed (and not just savepoint released)
+            require('./ws.js').sendTransactionEntityChangesToAllClients();
+        }
+
+        return ret;
+    }
+    catch (e) {
+        cls.clearEntityChanges();
+
+        throw e;
+    }
+}
+
+function fillParamList(paramIds, truncate = true) {
+    if (paramIds.length === 0) {
+        return;
+    }
+
+    if (truncate) {
+        execute("DELETE FROM param_list");
+    }
+
+    paramIds = Array.from(new Set(paramIds));
+
+    if (paramIds.length > 30000) {
+        fillParamList(paramIds.slice(30000), false);
+
+        paramIds = paramIds.slice(0, 30000);
+    }
+
+    // doing it manually to avoid this showing up on the sloq query list
+    const s = stmt(`INSERT INTO param_list VALUES ` + paramIds.map(paramId => `(?)`).join(','), paramIds);
+
+    s.run(paramIds);
+}
+
+module.exports = {
+    dbConnection,
+    insert,
+    replace,
+
+    /**
+     * Get single value from the given query - first column from first returned row.
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     * @return [object] - single value
+     */
+    getValue,
+
+    /**
+     * Get first returned row.
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     * @return {object} - map of column name to column value
+     */
+    getRow,
+    getRowOrNull,
+
+    /**
+     * Get all returned rows.
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     * @return {object[]} - array of all rows, each row is a map of column name to column value
+     */
+    getRows,
+    iterateRows,
+    getManyRows,
+
+    /**
+     * Get a map of first column mapping to second column.
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     * @return {object} - map of first column to second column
+     */
+    getMap,
+
+    /**
+     * Get a first column in an array.
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     * @return {object[]} - array of first column of all returned rows
+     */
+    getColumn,
+
+    /**
+     * Execute SQL
+     *
+     * @method
+     * @param {string} query - SQL query with ? used as parameter placeholder
+     * @param {object[]} [params] - array of params if needed
+     */
+    execute,
+    executeWithoutTransaction,
+    executeMany,
+    executeScript,
+    transactional,
+    upsert,
+    fillParamList
+};
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/docs/frontend_api/FrontendScriptApi.html b/docs/frontend_api/FrontendScriptApi.html index 2b0aac448..7dabc35d2 100644 --- a/docs/frontend_api/FrontendScriptApi.html +++ b/docs/frontend_api/FrontendScriptApi.html @@ -81,7 +81,7 @@
Source:
@@ -223,7 +223,7 @@
Source:
@@ -329,7 +329,7 @@
Source:
@@ -435,7 +435,7 @@
Source:
@@ -545,7 +545,7 @@
Source:
@@ -658,7 +658,7 @@
Source:
@@ -768,7 +768,7 @@
Source:
@@ -874,7 +874,7 @@
Source:
@@ -980,7 +980,7 @@
Source:
@@ -1109,7 +1109,7 @@
Source:
@@ -1264,7 +1264,7 @@
Source:
@@ -1419,7 +1419,7 @@
Source:
@@ -1556,7 +1556,7 @@
Source:
@@ -1712,7 +1712,7 @@
Source:
@@ -2033,7 +2033,7 @@
Source:
@@ -2166,7 +2166,7 @@
Source:
@@ -2272,7 +2272,7 @@
Source:
@@ -2378,7 +2378,7 @@
Source:
@@ -2532,7 +2532,7 @@
Source:
@@ -2669,7 +2669,7 @@
Source:
@@ -2776,7 +2776,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -2931,7 +2931,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3087,7 +3087,7 @@ if some action needs to happen on only one specific instance.
Source:
@@ -3288,7 +3288,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -3394,7 +3394,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -3549,7 +3549,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -3727,7 +3727,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -3878,7 +3878,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -3986,7 +3986,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4142,7 +4142,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4298,7 +4298,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4328,6 +4328,165 @@ otherwise (by e.g. createNoteLink()) + + + + + + +

randomString(length) → {string}

+ + + + + + +
+ Return randomly generated string of given length. This random string generation is NOT cryptographically secure. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
length + + +number + + + + of the string
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ random string +
+ + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + @@ -4430,7 +4589,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4516,7 +4675,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4653,7 +4812,7 @@ otherwise (by e.g. createNoteLink())
Source:
@@ -4814,7 +4973,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -4922,7 +5081,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5060,7 +5219,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5216,7 +5375,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5371,7 +5530,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5522,7 +5681,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5659,7 +5818,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5796,7 +5955,7 @@ Internally this serializes the anonymous function into string and sends it to ba
Source:
@@ -5888,7 +6047,7 @@ Typical use case is when new note has been created, we should wait until it is s
Source:
diff --git a/docs/frontend_api/NoteShort.html b/docs/frontend_api/NoteShort.html index 89045666e..72ad5005e 100644 --- a/docs/frontend_api/NoteShort.html +++ b/docs/frontend_api/NoteShort.html @@ -167,7 +167,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -267,7 +267,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -335,7 +335,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -403,7 +403,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -461,7 +461,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -519,7 +519,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -577,7 +577,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -635,7 +635,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -703,7 +703,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -771,7 +771,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -839,7 +839,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -897,7 +897,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -955,7 +955,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1103,7 +1103,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1303,7 +1303,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1481,7 +1481,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1587,7 +1587,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1689,7 +1689,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1791,7 +1791,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1893,7 +1893,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -1995,7 +1995,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2146,7 +2146,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2313,7 +2313,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2468,7 +2468,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2578,7 +2578,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2752,7 +2752,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -2952,7 +2952,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3130,7 +3130,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3285,7 +3285,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3452,7 +3452,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3607,7 +3607,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3762,7 +3762,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -3929,7 +3929,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4084,7 +4084,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4190,7 +4190,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4292,7 +4292,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4443,7 +4443,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4610,7 +4610,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4765,7 +4765,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -4935,7 +4935,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5086,7 +5086,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5196,7 +5196,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5302,7 +5302,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5404,7 +5404,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5578,7 +5578,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5684,7 +5684,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -5835,7 +5835,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -6013,7 +6013,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -6168,7 +6168,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -6323,7 +6323,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -6478,7 +6478,7 @@ This note's representation is used in note tree and is kept in TreeCache.
Source:
@@ -6589,7 +6589,7 @@ Cache is note instance scoped.
Source:
@@ -6673,7 +6673,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 c81f0b014..69f2d1dc9 100644 --- a/docs/frontend_api/entities_note_short.js.html +++ b/docs/frontend_api/entities_note_short.js.html @@ -30,6 +30,7 @@ import noteAttributeCache from "../services/note_attribute_cache.js"; import ws from "../services/ws.js"; import options from "../services/options.js"; +import treeCache from "../services/tree_cache.js"; const LABEL = 'label'; const RELATION = 'relation'; @@ -186,6 +187,26 @@ class NoteShort { return this.treeCache.getNotesFromCache(this.parents); } + // will sort the parents so that non-search & non-archived are first and archived at the end + // this is done so that non-search & non-archived paths are always explored as first when looking for note path + resortParents() { + this.parents.sort((aNoteId, bNoteId) => { + const aBranchId = this.parentToBranch[aNoteId]; + + if (aBranchId && aBranchId.startsWith('virt-')) { + return 1; + } + + const aNote = this.treeCache.getNoteFromCache([aNoteId]); + + if (aNote.hasLabel('archived')) { + return 1; + } + + return -1; + }); + } + /** @returns {string[]} */ getChildNoteIds() { return this.children; @@ -261,6 +282,72 @@ class NoteShort { return noteAttributeCache.attributes[this.noteId]; } + getAllNotePaths(encounteredNoteIds = null) { + if (this.noteId === 'root') { + return [['root']]; + } + + if (!encounteredNoteIds) { + encounteredNoteIds = new Set(); + } + + encounteredNoteIds.add(this.noteId); + + const parentNotes = this.getParentNotes(); + let paths; + + if (parentNotes.length === 1) { // optimization for the most common case + if (encounteredNoteIds.has(parentNotes[0].noteId)) { + return []; + } + else { + paths = parentNotes[0].getAllNotePaths(encounteredNoteIds); + } + } + else { + paths = []; + + for (const parentNote of parentNotes) { + if (encounteredNoteIds.has(parentNote.noteId)) { + continue; + } + + const newSet = new Set(encounteredNoteIds); + + paths.push(...parentNote.getAllNotePaths(newSet)); + } + } + + for (const path of paths) { + path.push(this.noteId); + } + + return paths; + } + + getSortedNotePaths(hoistedNotePath = 'root') { + const notePaths = this.getAllNotePaths().map(path => ({ + notePath: path, + isInHoistedSubTree: path.includes(hoistedNotePath), + isArchived: path.find(noteId => treeCache.notes[noteId].hasLabel('archived')), + isSearch: path.find(noteId => treeCache.notes[noteId].type === 'search') + })); + + notePaths.sort((a, b) => { + if (a.isInHoistedSubTree !== b.isInHoistedSubTree) { + return a.isInHoistedSubTree ? -1 : 1; + } else if (a.isSearch !== b.isSearch) { + return a.isSearch ? 1 : -1; + } else if (a.isArchived !== b.isArchived) { + return a.isArchived ? 1 : -1; + } else { + return a.notePath.length - b.notePath.length; + } + }); + + return notePaths; + } + __filterAttrs(attributes, type, name) { if (!type && !name) { return attributes; @@ -300,7 +387,7 @@ class NoteShort { const workspaceIconClass = this.getWorkspaceIconClass(); if (iconClassLabels.length > 0) { - return iconClassLabels.map(l => l.value).join(' '); + return iconClassLabels[0].value; } else if (workspaceIconClass) { return workspaceIconClass; @@ -550,7 +637,7 @@ class NoteShort { }); } - hasAncestor(ancestorNote, visitedNoteIds) { + hasAncestor(ancestorNote, visitedNoteIds = null) { if (this.noteId === ancestorNote.noteId) { return true; } diff --git a/docs/frontend_api/global.html b/docs/frontend_api/global.html index c0139c144..7fe7edd24 100644 --- a/docs/frontend_api/global.html +++ b/docs/frontend_api/global.html @@ -572,7 +572,7 @@ separately but should behave uniformly for the user.
Source:
diff --git a/docs/frontend_api/services_frontend_script_api.js.html b/docs/frontend_api/services_frontend_script_api.js.html index 55df0a765..d16aeadcc 100644 --- a/docs/frontend_api/services_frontend_script_api.js.html +++ b/docs/frontend_api/services_frontend_script_api.js.html @@ -34,6 +34,7 @@ import treeCache from './tree_cache.js'; import noteTooltipService from './note_tooltip.js'; import protectedSessionService from './protected_session.js'; import dateNotesService from './date_notes.js'; +import searchService from './search.js'; import CollapsibleWidget from '../widgets/collapsible_widget.js'; import ws from "./ws.js"; import appContext from "./app_context.js"; @@ -110,7 +111,10 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain await ws.waitForMaxKnownEntityChangeId(); await appContext.tabManager.openTabWithNote(notePath, activate); - appContext.triggerEvent('focusAndSelectTitle'); + + if (activate) { + appContext.triggerEvent('focusAndSelectTitle'); + } }; /** @@ -129,9 +133,18 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain this.addButtonToToolbar = opts => { const buttonId = "toolbar-button-" + opts.title.replace(/\s/g, "-"); - const button = $('<button class="noborder">') - .addClass("btn btn-sm") - .on('click', opts.action); + let button; + if (utils.isMobile()) { + $('#plugin-buttons-placeholder').remove(); + button = $('<a class="dropdown-item" href="#">') + .on('click', () => { + setTimeout(() => $pluginButtons.dropdown('hide'), 0); + }); + } else { + button = $('<button class="noborder">') + .addClass("btn btn-sm"); + } + button = button.on('click', opts.action); if (opts.icon) { button.append($("<span>").addClass("bx bx-" + opts.icon)) @@ -191,8 +204,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain }, "script"); if (ret.success) { - // wait until all the changes done in the script has been synced to frontend before continuing - await ws.waitForEntityChangeId(ret.maxEntityChangeId); + await ws.waitForMaxKnownEntityChangeId(); return ret.executionResult; } @@ -216,11 +228,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain * @returns {Promise<NoteShort[]>} */ this.searchForNotes = async searchString => { - const noteIds = await this.runOnBackend( - searchString => api.searchForNotes(searchString).map(note => note.noteId), - [searchString]); - - return await treeCache.getNotes(noteIds); + return await searchService.searchForNotes(searchString); }; /** @@ -457,6 +465,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain * @param includedNoteId - noteId of the included note */ this.refreshIncludedNote = includedNoteId => appContext.triggerEvent('refreshIncludedNote', {noteId: includedNoteId}); + + /** + * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. + * + * @method + * @param {number} length of the string + * @returns {string} random string + */ + this.randomString = utils.randomString; } export default FrontendScriptApi; diff --git a/package.json b/package.json index c20ab4f1d..d5307d4bf 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "start-server": "cross-env TRILIUM_ENV=dev node ./src/www", "start-electron": "cross-env TRILIUM_ENV=dev electron --inspect=5858 .", - "build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js", + "build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js src/services/sql.js", "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js", "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", "webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js", @@ -87,7 +87,7 @@ "jsdoc": "3.6.6", "lorem-ipsum": "2.0.3", "rcedit": "3.0.0", - "webpack": "5.30.0", + "webpack": "5.31.0", "webpack-cli": "4.6.0" }, "optionalDependencies": { diff --git a/src/public/app/services/frontend_script_api.js b/src/public/app/services/frontend_script_api.js index f396b1274..935c6b819 100644 --- a/src/public/app/services/frontend_script_api.js +++ b/src/public/app/services/frontend_script_api.js @@ -437,6 +437,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain * @param includedNoteId - noteId of the included note */ this.refreshIncludedNote = includedNoteId => appContext.triggerEvent('refreshIncludedNote', {noteId: includedNoteId}); + + /** + * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. + * + * @method + * @param {number} length of the string + * @returns {string} random string + */ + this.randomString = utils.randomString; } export default FrontendScriptApi; diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js index 45f60f2b0..527b5d98f 100644 --- a/src/services/backend_script_api.js +++ b/src/services/backend_script_api.js @@ -33,10 +33,14 @@ function BackendScriptApi(currentNote, apiParams) { this[key] = apiParams[key]; } + /** @property {axios} Axios library for HTTP requests. See https://axios-http.com/ for documentation */ this.axios = axios; + /** @property {dayjs} day.js library for date manipulation. See https://day.js.org/ for documentation */ this.dayjs = dayjs; + /** @property {axios} xml2js library for XML parsing. See https://github.com/Leonidas-from-XIV/node-xml2js for documentation */ this.xml2js = xml2js; + // DEPRECATED - use direct api.unescapeHtml this.utils = { unescapeHtml: utils.unescapeHtml }; @@ -192,7 +196,7 @@ function BackendScriptApi(currentNote, apiParams) { * @param {string} parentNoteId * @param {string} title * @param {string} content - * @return {{note: Note, branch: Branch}} + * @return {{note: Note, branch: Branch}} - object having "note" and "branch" keys representing respective objects */ this.createTextNote = (parentNoteId, title, content = '') => noteService.createNewNote({ parentNoteId, @@ -208,7 +212,7 @@ function BackendScriptApi(currentNote, apiParams) { * @param {string} parentNoteId * @param {string} title * @param {object} content - * @return {{note: Note, branch: Branch}} + * @return {{note: Note, branch: Branch}} object having "note" and "branch" keys representing respective objects */ this.createDataNote = (parentNoteId, title, content = {}) => noteService.createNewNote({ parentNoteId, @@ -391,6 +395,32 @@ function BackendScriptApi(currentNote, apiParams) { */ this.transactional = sql.transactional; + /** + * Return randomly generated string of given length. This random string generation is NOT cryptographically secure. + * + * @method + * @param {number} length of the string + * @returns {string} random string + */ + this.randomString = utils.randomString; + + /** + * @method + * @param {string} string to escape + * @returns {string} escaped string + */ + this.escapeHtml = utils.escapeHtml; + + /** + * @method + * @param {string} string to unescape + * @returns {string} unescaped string + */ + this.unescapeHtml = utils.unescapeHtml; + + /** + * @property {module:sql} sql + */ this.sql = sql; /** diff --git a/src/services/sql.js b/src/services/sql.js index a043898ef..3768624b4 100644 --- a/src/services/sql.js +++ b/src/services/sql.js @@ -1,5 +1,9 @@ "use strict"; +/** + * @module sql + */ + const log = require('./log'); const Database = require('better-sqlite3'); const dataDir = require('./data_dir'); @@ -273,14 +277,67 @@ module.exports = { dbConnection, insert, replace, + + /** + * Get single value from the given query - first column from first returned row. + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + * @return [object] - single value + */ getValue, + + /** + * Get first returned row. + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + * @return {object} - map of column name to column value + */ getRow, getRowOrNull, + + /** + * Get all returned rows. + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + * @return {object[]} - array of all rows, each row is a map of column name to column value + */ getRows, iterateRows, getManyRows, + + /** + * Get a map of first column mapping to second column. + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + * @return {object} - map of first column to second column + */ getMap, + + /** + * Get a first column in an array. + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + * @return {object[]} - array of first column of all returned rows + */ getColumn, + + /** + * Execute SQL + * + * @method + * @param {string} query - SQL query with ? used as parameter placeholder + * @param {object[]} [params] - array of params if needed + */ execute, executeWithoutTransaction, executeMany,