Link entity migrated to Attribute, WIP

This commit is contained in:
zadam
2019-08-19 20:12:00 +02:00
parent fd9b79e115
commit 3cb421143f
22 changed files with 172 additions and 174 deletions

View File

@@ -4,8 +4,8 @@ const build = require('./build');
const packageJson = require('../../package');
const {TRILIUM_DATA_DIR} = require('./data_dir');
const APP_DB_VERSION = 136;
const SYNC_VERSION = 9;
const APP_DB_VERSION = 137;
const SYNC_VERSION = 10;
const CLIPPER_PROTOCOL_VERSION = "1.0";
module.exports = {

View File

@@ -12,7 +12,6 @@ const Attribute = require('../entities/attribute');
const NoteRevision = require('../entities/note_revision');
const RecentNote = require('../entities/recent_note');
const Option = require('../entities/option');
const Link = require('../entities/link');
async function getHash(tableName, primaryKeyName, whereBranch) {
// subselect is necessary to have correct ordering in GROUP_CONCAT
@@ -40,7 +39,6 @@ async function getHashes() {
options: await getHash(Option.entityName, Option.primaryKeyName, "isSynced = 1"),
attributes: await getHash(Attribute.entityName, Attribute.primaryKeyName),
api_tokens: await getHash(ApiToken.entityName, ApiToken.primaryKeyName),
links: await getHash(Link.entityName, Link.primaryKeyName)
};
const elapseTimeMs = Date.now() - startTime.getTime();

View File

@@ -115,12 +115,6 @@ async function exportToTar(exportContext, branch, format, res) {
isInheritable: attribute.isInheritable,
position: attribute.position
};
}),
links: (await note.getLinks()).map(link => {
return {
type: link.type,
targetNoteId: link.targetNoteId
}
})
};
@@ -220,9 +214,8 @@ async function exportToTar(exportContext, branch, format, res) {
};
for (const noteMeta of Object.values(noteIdToMeta)) {
// filter out relations and links which are not inside this export
// filter out relations which are not inside this export
noteMeta.attributes = noteMeta.attributes.filter(attr => attr.type !== 'relation' || attr.value in noteIdToMeta);
noteMeta.links = noteMeta.links.filter(link => link.targetNoteId in noteIdToMeta);
}
if (!metaFile.files[0]) { // corner case of disabled export for exported note

View File

@@ -1,7 +1,6 @@
"use strict";
const Attribute = require('../../entities/attribute');
const Link = require('../../entities/link');
const utils = require('../../services/utils');
const log = require('../../services/log');
const repository = require('../../services/repository');
@@ -26,7 +25,6 @@ async function importTar(importContext, fileBuffer, importRootNote) {
// maps from original noteId (in tar file) to newly generated noteId
const noteIdMap = {};
const attributes = [];
const links = [];
// path => noteId
const createdPaths = { '/': importRootNote.noteId, '\\': importRootNote.noteId };
const mdReader = new commonmark.Parser();
@@ -146,7 +144,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
return { type, mime };
}
async function saveAttributesAndLinks(note, noteMeta) {
async function saveAttributes(note, noteMeta) {
if (!noteMeta) {
return;
}
@@ -169,13 +167,6 @@ async function importTar(importContext, fileBuffer, importRootNote) {
attributes.push(attr);
}
for (const link of noteMeta.links) {
link.noteId = note.noteId;
link.targetNoteId = getNewNoteId(link.targetNoteId);
links.push(link);
}
}
async function saveDirectory(filePath) {
@@ -200,7 +191,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
isProtected: importRootNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
}));
await saveAttributesAndLinks(note, noteMeta);
await saveAttributes(note, noteMeta);
if (!firstNote) {
firstNote = note;
@@ -246,9 +237,11 @@ async function importTar(importContext, fileBuffer, importRootNote) {
content = content.toString("UTF-8");
if (noteMeta) {
const internalLinks = (noteMeta.attributes || []).find(attr => attr.type === 'relation' && attr.name === 'internal-link');
// this will replace all internal links (<a> and <img>) inside the body
// links pointing outside the export will be broken and changed (ctx.getNewNoteId() will still assign new noteId)
for (const link of noteMeta.links || []) {
for (const link of internalLinks) {
// no need to escape the regexp find string since it's a noteId which doesn't contain any special characters
content = content.replace(new RegExp(link.targetNoteId, "g"), getNewNoteId(link.targetNoteId));
}
@@ -278,7 +271,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
isProtected: importRootNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
}));
await saveAttributesAndLinks(note, noteMeta);
await saveAttributes(note, noteMeta);
if (!noteMeta && (type === 'file' || type === 'image')) {
attributes.push({
@@ -379,15 +372,6 @@ async function importTar(importContext, fileBuffer, importRootNote) {
}
}
for (const link of links) {
if (link.targetNoteId in createdNoteIds) {
await new Link(link).save();
}
else {
log.info("Link not imported since target note doesn't exist: " + JSON.stringify(link));
}
}
resolve(firstNote);
});

View File

@@ -8,7 +8,6 @@ const eventService = require('./events');
const repository = require('./repository');
const cls = require('../services/cls');
const Note = require('../entities/note');
const Link = require('../entities/link');
const NoteRevision = require('../entities/note_revision');
const Branch = require('../entities/branch');
const Attribute = require('../entities/attribute');
@@ -215,8 +214,8 @@ function findImageLinks(content, foundLinks) {
while (match = re.exec(content)) {
foundLinks.push({
type: 'image',
targetNoteId: match[1]
type: 'image-link',
value: match[1]
});
}
@@ -225,14 +224,14 @@ function findImageLinks(content, foundLinks) {
return content.replace(/src="[^"]*\/api\/images\//g, 'src="api/images/');
}
function findHyperLinks(content, foundLinks) {
function findInternalLinks(content, foundLinks) {
const re = /href="[^"]*#root[a-zA-Z0-9\/]*\/([a-zA-Z0-9]+)\/?"/g;
let match;
while (match = re.exec(content)) {
foundLinks.push({
type: 'hyper',
targetNoteId: match[1]
name: 'internal-link',
value: match[1]
});
}
@@ -245,8 +244,8 @@ function findRelationMapLinks(content, foundLinks) {
for (const note of obj.notes) {
foundLinks.push({
type: 'relation-map',
targetNoteId: note.noteId
type: 'relation-map-link',
value: note.noteId
})
}
}
@@ -260,7 +259,7 @@ async function saveLinks(note, content) {
if (note.type === 'text') {
content = findImageLinks(content, foundLinks);
content = findHyperLinks(content, foundLinks);
content = findInternalLinks(content, foundLinks);
}
else if (note.type === 'relation-map') {
findRelationMapLinks(content, foundLinks);
@@ -273,14 +272,15 @@ async function saveLinks(note, content) {
for (const foundLink of foundLinks) {
const existingLink = existingLinks.find(existingLink =>
existingLink.targetNoteId === foundLink.targetNoteId
&& existingLink.type === foundLink.type);
existingLink.value === foundLink.value
&& existingLink.name === foundLink.name);
if (!existingLink) {
await new Link({
await new Attribute({
noteId: note.noteId,
targetNoteId: foundLink.targetNoteId,
type: foundLink.type
type: 'relation',
name: foundLink.name,
value: foundLink.targetNoteId,
}).save();
}
else if (existingLink.isDeleted) {
@@ -292,8 +292,8 @@ async function saveLinks(note, content) {
// marking links as deleted if they are not present on the page anymore
const unusedLinks = existingLinks.filter(existingLink => !foundLinks.some(foundLink =>
existingLink.targetNoteId === foundLink.targetNoteId
&& existingLink.type === foundLink.type));
existingLink.value === foundLink.value
&& existingLink.name === foundLink.name));
for (const unusedLink of unusedLinks) {
unusedLink.isDeleted = true;
@@ -415,11 +415,6 @@ async function deleteNote(branch) {
await relation.save();
}
for (const link of await note.getLinks()) {
link.isDeleted = true;
await link.save();
}
for (const link of await note.getTargetLinks()) {
link.isDeleted = true;
await link.save();

View File

@@ -249,8 +249,7 @@ const primaryKeys = {
"recent_notes": "noteId",
"api_tokens": "apiTokenId",
"options": "name",
"attributes": "attributeId",
"links": "linkId"
"attributes": "attributeId"
};
async function getEntityRow(entityName, entityId) {

View File

@@ -32,10 +32,6 @@ async function addRecentNoteSync(noteId, sourceId) {
await addEntitySync("recent_notes", noteId, sourceId);
}
async function addLinkSync(linkId, sourceId) {
await addEntitySync("links", linkId, sourceId);
}
async function addAttributeSync(attributeId, sourceId) {
await addEntitySync("attributes", attributeId, sourceId);
}
@@ -101,7 +97,6 @@ async function fillAllSyncRows() {
await fillSyncRows("recent_notes", "noteId");
await fillSyncRows("attributes", "attributeId");
await fillSyncRows("api_tokens", "apiTokenId");
await fillSyncRows("links", "linkId");
await fillSyncRows("options", "name", 'isSynced = 1');
}
@@ -115,7 +110,6 @@ module.exports = {
addRecentNoteSync,
addAttributeSync,
addApiTokenSync,
addLinkSync,
addEntitySync,
fillAllSyncRows
};

View File

@@ -28,9 +28,6 @@ async function updateEntity(sync, entity, sourceId) {
else if (entityName === 'recent_notes') {
await updateRecentNotes(entity, sourceId);
}
else if (entityName === 'links') {
await updateLink(entity, sourceId);
}
else if (entityName === 'attributes') {
await updateAttribute(entity, sourceId);
}
@@ -159,20 +156,6 @@ async function updateRecentNotes(entity, sourceId) {
}
}
async function updateLink(entity, sourceId) {
const origLink = await sql.getRow("SELECT * FROM links WHERE linkId = ?", [entity.linkId]);
if (!origLink || origLink.utcDateModified <= entity.utcDateModified) {
await sql.transactional(async () => {
await sql.replace("links", entity);
await syncTableService.addLinkSync(entity.linkId, sourceId);
});
log.info("Update/sync link " + entity.linkId);
}
}
async function updateAttribute(entity, sourceId) {
const origAttribute = await sql.getRow("SELECT * FROM attributes WHERE attributeId = ?", [entity.attributeId]);