diff --git a/db/migrations/0226__rename_noteSize_label.sql b/db/migrations/0226__rename_noteSize_label.sql new file mode 100644 index 000000000..cd2239af4 --- /dev/null +++ b/db/migrations/0226__rename_noteSize_label.sql @@ -0,0 +1 @@ +UPDATE attributes SET value = 'contentAndAttachmentsAndRevisionsSize' WHERE name = 'orderBy' AND value = 'noteSize'; diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 1f05b4001..3e04f5f10 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -132,11 +132,17 @@ class BNote extends AbstractBeccaEntity { */ this.contentSize = null; /** - * size of the content and note revision contents in bytes + * size of the note content, attachment contents in bytes * @type {int|null} * @private */ - this.noteSize = null; + this.contentAndAttachmentsSize = null; + /** + * size of the note content, attachment contents and revision contents in bytes + * @type {int|null} + * @private + */ + this.contentAndAttachmentsAndRevisionsSize = null; /** * number of note revisions for this note * @type {int|null} diff --git a/src/etapi/etapi.openapi.yaml b/src/etapi/etapi.openapi.yaml index a8bb6a8d8..09149397c 100644 --- a/src/etapi/etapi.openapi.yaml +++ b/src/etapi/etapi.openapi.yaml @@ -127,7 +127,8 @@ paths: - targetRelationCount - targetRelationCountIncludingLinks - contentSize - - noteSize + - contentAndAttachmentsSize + - contentAndAttachmentsAndRevisionsSize - revisionCount - name: orderDirection in: query diff --git a/src/public/app/widgets/search_options/order_by.js b/src/public/app/widgets/search_options/order_by.js index 8e2085fd4..100311fee 100644 --- a/src/public/app/widgets/search_options/order_by.js +++ b/src/public/app/widgets/search_options/order_by.js @@ -14,7 +14,8 @@ const TPL = ` - + + diff --git a/src/services/app_info.js b/src/services/app_info.js index 45d560ce4..98bc9d59b 100644 --- a/src/services/app_info.js +++ b/src/services/app_info.js @@ -4,7 +4,7 @@ const build = require('./build'); const packageJson = require('../../package'); const {TRILIUM_DATA_DIR} = require('./data_dir'); -const APP_DB_VERSION = 225; +const APP_DB_VERSION = 226; const SYNC_VERSION = 31; const CLIPPER_PROTOCOL_VERSION = "1.0"; diff --git a/src/services/search/expressions/order_by_and_limit.js b/src/services/search/expressions/order_by_and_limit.js index 8e8352f6d..2de6547ed 100644 --- a/src/services/search/expressions/order_by_and_limit.js +++ b/src/services/search/expressions/order_by_and_limit.js @@ -56,9 +56,9 @@ class OrderByAndLimitExp extends Expression { if (!valA && !valB) { // the attribute value is empty/zero in both notes so continue to the next order definition continue; - } else if (!valB || valA < valB) { + } else if (valA < valB) { return smaller; - } else if (!valA || valA > valB) { + } else if (valA > valB) { return larger; } // else the values are equal and continue to next order definition diff --git a/src/services/search/expressions/property_comparison.js b/src/services/search/expressions/property_comparison.js index c506cf995..f4183988e 100644 --- a/src/services/search/expressions/property_comparison.js +++ b/src/services/search/expressions/property_comparison.js @@ -31,7 +31,8 @@ const PROP_MAPPING = { "targetrelationcount": "targetRelationCount", "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", "contentsize": "contentSize", - "notesize": "noteSize", + "contentandattachmentssize": "contentAndAttachmentsSize", + "contentandattachmentsandrevisionssize": "contentAndAttachmentsAndRevisionsSize", "revisioncount": "revisionCount" }; @@ -48,7 +49,7 @@ class PropertyComparisonExp extends Expression { this.comparedValue = comparedValue; // for DEBUG mode this.comparator = buildComparator(operator, comparedValue); - if (['contentsize', 'notesize', 'revisioncount'].includes(this.propertyName)) { + if (['contentsize', 'contentandattachmentssize', 'contentandattachmentsandrevisionssize', 'revisioncount'].includes(this.propertyName)) { searchContext.dbLoadNeeded = true; } } diff --git a/src/services/search/services/search.js b/src/services/search/services/search.js index cda20b94d..25b8bc848 100644 --- a/src/services/search/services/search.js +++ b/src/services/search/services/search.js @@ -92,48 +92,87 @@ function searchFromRelation(note, relationName) { function loadNeededInfoFromDatabase() { const sql = require('../../sql'); - for (const noteId in becca.notes) { - becca.notes[noteId].contentSize = 0; - becca.notes[noteId].noteSize = 0; - becca.notes[noteId].revisionCount = 0; - } + const noteBlobs = {}; const noteContentLengths = sql.getRows(` SELECT noteId, + blobId, LENGTH(content) AS length FROM notes JOIN blobs USING(blobId) WHERE notes.isDeleted = 0`); - for (const {noteId, length} of noteContentLengths) { + for (const {noteId, blobId, length} of noteContentLengths) { if (!(noteId in becca.notes)) { - log.error(`Note ${noteId} not found in becca.`); + log.error(`Note '${noteId}' not found in becca.`); continue; } becca.notes[noteId].contentSize = length; - becca.notes[noteId].noteSize = length; + becca.notes[noteId].revisionCount = 0; + + noteBlobs[noteId] = { [blobId]: length }; + } + + const attachmentContentLengths = sql.getRows(` + SELECT + ownerId AS noteId, + attachments.blobId, + LENGTH(content) AS length + FROM attachments + JOIN notes ON attachments.ownerId = notes.noteId + JOIN blobs ON attachments.blobId = blobs.blobId + WHERE attachments.isDeleted = 0 + AND notes.isDeleted = 0`); + + for (const {noteId, blobId, length} of attachmentContentLengths) { + if (!(noteId in becca.notes)) { + log.error(`Note '${noteId}' not found in becca.`); + continue; + } + + if (!(noteId in noteBlobs)) { + log.error(`Did not find a '${noteId}' in the noteBlobs.`); + continue; + } + + noteBlobs[noteId][blobId] = length; + } + + for (const noteId in noteBlobs) { + becca.notes[noteId].contentAndAttachmentsSize = Object.values(noteBlobs[noteId]).reduce((acc, size) => acc + size, 0); } const revisionContentLengths = sql.getRows(` SELECT noteId, + revisions.blobId, LENGTH(content) AS length FROM notes - JOIN revisions USING(noteId) - JOIN blobs USING(blobId) + JOIN revisions USING(noteId) + JOIN blobs ON revisions.blobId = blobs.blobId WHERE notes.isDeleted = 0`); - for (const {noteId, length} of revisionContentLengths) { + for (const {noteId, blobId, length} of revisionContentLengths) { if (!(noteId in becca.notes)) { - log.error(`Note ${noteId} not found in becca.`); + log.error(`Note '${noteId}' not found in becca.`); continue; } - becca.notes[noteId].noteSize += length; + if (!(noteId in noteBlobs)) { + log.error(`Did not find a '${noteId}' in the noteBlobs.`); + continue; + } + + noteBlobs[noteId][blobId] = length; + becca.notes[noteId].revisionCount++; } + + for (const noteId in noteBlobs) { + becca.notes[noteId].contentAndAttachmentsAndRevisionsSize = Object.values(noteBlobs[noteId]).reduce((acc, size) => acc + size, 0); + } } /** diff --git a/src/services/search/value_extractor.js b/src/services/search/value_extractor.js index 633666d29..27aff0e6c 100644 --- a/src/services/search/value_extractor.js +++ b/src/services/search/value_extractor.js @@ -27,7 +27,8 @@ const PROP_MAPPING = { "targetrelationcount": "targetRelationCount", "targetrelationcountincludinglinks": "targetRelationCountIncludingLinks", "contentsize": "contentSize", - "notesize": "noteSize", + "contentandattachmentssize": "contentAndAttachmentsSize", + "contentandattachmentsandrevisionssize": "contentAndAttachmentsAndRevisionsSize", "revisioncount": "revisionCount" }; @@ -42,7 +43,7 @@ class ValueExtractor { this.propertyPath = ['note', 'relations', this.propertyPath[0].substr(1), ...this.propertyPath.slice(1, this.propertyPath.length)]; } - if (['contentsize', 'notesize', 'revisioncount'].includes(this.propertyPath[this.propertyPath.length - 1])) { + if (['contentsize', 'contentandattachmentssize', 'contentandattachmentsandrevisionssize', 'revisioncount'].includes(this.propertyPath[this.propertyPath.length - 1])) { searchContext.dbLoadNeeded = true; } }