diff --git a/.idea/dataSources/a2c75661-f9e2-478f-a69f-6a9409e69997.xml b/.idea/dataSources/a2c75661-f9e2-478f-a69f-6a9409e69997.xml
index 6c23a85af..7d07bfbef 100644
--- a/.idea/dataSources/a2c75661-f9e2-478f-a69f-6a9409e69997.xml
+++ b/.idea/dataSources/a2c75661-f9e2-478f-a69f-6a9409e69997.xml
@@ -388,10 +388,14 @@ imageId
2
TEXT|0s
+ 1
+ "unnamed"
3
TEXT|0s
+ 1
+ ""
4
diff --git a/db/main_branches.sql b/db/main_branches.sql
index ca48ff98b..5b32f5a4d 100644
--- a/db/main_branches.sql
+++ b/db/main_branches.sql
@@ -1,3 +1,4 @@
+INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, dateModified) VALUES ('root', 'root', 'none', 0, null, 1, 0, '2018-01-01T00:00:00.000Z');
INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, dateModified) VALUES ('dLgtLUFn3GoN', '1Heh2acXfPNt', 'root', 21, null, 1, 0, '2017-12-23T00:46:39.304Z');
INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, dateModified) VALUES ('QLfS835GSfIh', '3RkyK9LI18dO', '1Heh2acXfPNt', 1, null, 1, 0, '2017-12-23T01:20:04.181Z');
INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, dateModified) VALUES ('QJAcYJ1gGUh9', 'L1Ox40M1aEyy', '3RkyK9LI18dO', 0, null, 0, 0, '2017-12-23T01:20:45.365Z');
diff --git a/db/migrations/0089__add_root_branch.sql b/db/migrations/0089__add_root_branch.sql
new file mode 100644
index 000000000..0c88be74a
--- /dev/null
+++ b/db/migrations/0089__add_root_branch.sql
@@ -0,0 +1,5 @@
+INSERT INTO branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, dateModified)
+ VALUES ('root', 'root', 'none', 0, null, 1, '2018-01-01T00:00:00.000Z');
+
+INSERT INTO sync (entityName, entityId, sourceId, syncDate)
+ VALUES ('branches' ,'root', 'SYNC_FILL', '2018-01-01T00:00:00.000Z');
\ No newline at end of file
diff --git a/db/migrations/0090__branch_index.sql b/db/migrations/0090__branch_index.sql
new file mode 100644
index 000000000..88d396a74
--- /dev/null
+++ b/db/migrations/0090__branch_index.sql
@@ -0,0 +1 @@
+CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
\ No newline at end of file
diff --git a/db/migrations/0091__drop_isDeleted_index.sql b/db/migrations/0091__drop_isDeleted_index.sql
new file mode 100644
index 000000000..4d547394b
--- /dev/null
+++ b/db/migrations/0091__drop_isDeleted_index.sql
@@ -0,0 +1,2 @@
+-- index confuses planner and is mostly useless anyway since we're mostly used in non-deleted notes (which are presumably majority)
+DROP INDEX IDX_notes_isDeleted;
\ No newline at end of file
diff --git a/src/public/javascripts/services/link.js b/src/public/javascripts/services/link.js
index 7fa74cb34..89d37bdc4 100644
--- a/src/public/javascripts/services/link.js
+++ b/src/public/javascripts/services/link.js
@@ -75,7 +75,7 @@ function goToLink(e) {
}
function addLinkToEditor(linkTitle, linkHref) {
- const editor = noteDetailText.getEditor();
+ const editor = noteDetailText.getEditor();Rum
editor.model.change( writer => {
const insertPosition = editor.model.document.selection.getFirstPosition();
diff --git a/src/routes/api/tree.js b/src/routes/api/tree.js
index 0bd0372d4..7322e0b40 100644
--- a/src/routes/api/tree.js
+++ b/src/routes/api/tree.js
@@ -3,56 +3,46 @@
const sql = require('../../services/sql');
const optionService = require('../../services/options');
const protectedSessionService = require('../../services/protected_session');
+const utils = require('../../services/utils');
async function getTree() {
const branches = await sql.getRows(`
- SELECT
- branchId,
- noteId,
- parentNoteId,
- notePosition,
- prefix,
- isExpanded
- FROM
- branches
- WHERE
- isDeleted = 0
- ORDER BY
- notePosition`);
+ WITH RECURSIVE
+ tree(branchId, noteId, isExpanded) AS (
+ SELECT branchId, noteId, isExpanded FROM branches WHERE branchId = 'root'
+ UNION ALL
+ SELECT branches.branchId, branches.noteId, branches.isExpanded FROM branches
+ JOIN tree ON branches.parentNoteId = tree.noteId
+ WHERE tree.isExpanded = 1 AND branches.isDeleted = 0
+ )
+ SELECT branches.* FROM tree JOIN branches USING(branchId);`);
- const notes = [{
- noteId: 'root',
- title: 'root',
- isProtected: false,
- type: 'none',
- mime: 'none'
- }].concat(await sql.getRows(`
- SELECT
- notes.noteId,
- notes.title,
- notes.isProtected,
- notes.type,
- notes.mime,
- hideInAutocomplete.labelId AS 'hideInAutocomplete'
- FROM
- notes
- LEFT JOIN labels AS hideInAutocomplete ON hideInAutocomplete.noteId = notes.noteId
- AND hideInAutocomplete.name = 'hideInAutocomplete'
- AND hideInAutocomplete.isDeleted = 0
- WHERE
- notes.isDeleted = 0`));
+ const noteIds = branches.map(b => b.noteId);
+ const questionMarks = branches.map(() => "?").join(",");
+
+ const notes = await sql.getRows(`
+ SELECT noteId, title, isProtected, type, mime
+ FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
protectedSessionService.decryptNotes(notes);
- notes.forEach(note => {
- note.hideInAutocomplete = !!note.hideInAutocomplete;
- note.isProtected = !!note.isProtected;
- });
+ notes.forEach(note => note.isProtected = !!note.isProtected);
+
+ const relationships = await sql.getRows(`SELECT noteId, parentNoteId FROM branches WHERE isDeleted = 0
+ AND parentNoteId IN (${questionMarks})`, noteIds);
+
+ const parentToChild = {};
+
+ for (const rel of relationships) {
+ parentToChild[rel.parentNoteId] = parentToChild[rel.parentNoteId] || [];
+ parentToChild[rel.parentNoteId].push(rel.noteId);
+ }
return {
startNotePath: await optionService.getOption('startNotePath'),
branches: branches,
- notes: notes
+ notes: notes,
+ parentToChild
};
}
diff --git a/src/services/app_info.js b/src/services/app_info.js
index 3c2a5cd6b..c8433345f 100644
--- a/src/services/app_info.js
+++ b/src/services/app_info.js
@@ -3,7 +3,7 @@
const build = require('./build');
const packageJson = require('../../package');
-const APP_DB_VERSION = 88;
+const APP_DB_VERSION = 91;
module.exports = {
appVersion: packageJson.version,
diff --git a/src/services/consistency_checks.js b/src/services/consistency_checks.js
index bc764db3f..d8b0921c3 100644
--- a/src/services/consistency_checks.js
+++ b/src/services/consistency_checks.js
@@ -116,7 +116,7 @@ async function runAllChecks() {
WHERE
notes.isDeleted = 1
AND branches.isDeleted = 0`,
- "Note tree is not deleted even though main note is deleted for following branch IDs", errorList);
+ "Branch is not deleted even though main note is deleted for following branch IDs", errorList);
await runCheck(`
SELECT
@@ -125,12 +125,12 @@ async function runAllChecks() {
branches AS child
WHERE
child.isDeleted = 0
- AND child.parentNoteId != 'root'
+ AND child.parentNoteId != 'none'
AND (SELECT COUNT(*) FROM branches AS parent WHERE parent.noteId = child.parentNoteId
AND parent.isDeleted = 0) = 0`,
- "All parent branches are deleted but child note tree is not for these child note tree IDs", errorList);
+ "All parent branches are deleted but child branch is not for these child branch IDs", errorList);
- // we do extra JOIN to eliminate orphan notes without note tree (which are reported separately)
+ // we do extra JOIN to eliminate orphan notes without branches (which are reported separately)
await runCheck(`
SELECT
DISTINCT noteId
@@ -150,7 +150,7 @@ async function runAllChecks() {
LEFT JOIN branches AS parent ON parent.noteId = child.parentNoteId
WHERE
parent.noteId IS NULL
- AND child.parentNoteId != 'root'`,
+ AND child.parentNoteId != 'none'`,
"Not existing parent in the following parent > child relations", errorList);
await runCheck(`
diff --git a/src/tools/generate_document.js b/src/tools/generate_document.js
index 7933615c8..ab58d9fde 100644
--- a/src/tools/generate_document.js
+++ b/src/tools/generate_document.js
@@ -58,7 +58,7 @@ async function start() {
}
// we'll create clones for 20% of notes
- for (let i = 0; i < (noteCount / 5); i++) {
+ for (let i = 0; i < (noteCount / 50); i++) {
const noteIdToClone = getRandomParentNoteId();
const parentNoteId = getRandomParentNoteId();
const prefix = Math.random() > 0.8 ? "prefix" : null;