becca conversion WIP

This commit is contained in:
zadam 2021-05-02 19:59:16 +02:00
parent 77eac8f764
commit 273d4e0052
23 changed files with 136 additions and 116 deletions

View file

@ -3,7 +3,7 @@ const Note = require('../entities/note');
const NoteRevision = require('../services/becca/entities/note_revision.js');
const Branch = require('../entities/branch');
const Attribute = require('../entities/attribute');
const RecentNote = require('../entities/recent_note');
const RecentNote = require('../services/becca/entities/recent_note.js');
const ApiToken = require('../entities/api_token');
const cls = require('../services/cls');

View file

@ -1,28 +0,0 @@
"use strict";
const Entity = require('./entity');
const dateUtils = require('../services/date_utils');
/**
* RecentNote represents recently visited note.
*
* @property {string} noteId
* @property {string} notePath
* @property {string} utcDateCreated
*
* @extends Entity
*/
class RecentNote extends Entity {
static get entityName() { return "recent_notes"; }
static get primaryKeyName() { return "noteId"; }
beforeSaving() {
if (!this.utcDateCreated) {
this.utcDateCreated = dateUtils.utcNowDateTime();
}
super.beforeSaving();
}
}
module.exports = RecentNote;

View file

@ -5,7 +5,7 @@ const log = require('../../services/log');
const attributeService = require('../../services/attributes');
const repository = require('../../services/repository');
const Attribute = require('../../entities/attribute');
const becca = require("../../services/becca/becca.js");
const becca = require("../../services/becca/becca");
function getEffectiveNoteAttributes(req) {
const note = becca.getNote(req.params.noteId);

View file

@ -6,6 +6,7 @@ const repository = require('../../services/repository');
const log = require('../../services/log');
const utils = require('../../services/utils');
const cls = require('../../services/cls');
const becca = require("../../services/becca/becca");
function getAutocomplete(req) {
const query = req.query.query.trim();
@ -41,7 +42,7 @@ function getRecentNotes(activeNoteId) {
params.push('%' + hoistedNoteId + '%');
}
const recentNotes = repository.getEntities(`
const recentNotes = becca.getRecentNotesFromQuery(`
SELECT
recent_notes.*
FROM

View file

@ -9,7 +9,7 @@ const fs = require('fs');
const { Readable } = require('stream');
const chokidar = require('chokidar');
const ws = require('../../services/ws');
const becca = require("../../services/becca/becca.js");
const becca = require("../../services/becca/becca");
function updateFile(req) {
const {noteId} = req.params;

View file

@ -7,10 +7,10 @@ const noteRevisionService = require('../../services/note_revisions');
const utils = require('../../services/utils');
const sql = require('../../services/sql');
const path = require('path');
const becca = require("../../services/becca/becca.js");
const becca = require("../../services/becca/becca");
function getNoteRevisions(req) {
return repository.getEntities(`
return becca.getNoteRevisionsFromQuery(`
SELECT note_revisions.*,
LENGTH(note_revision_contents.content) AS contentLength
FROM note_revisions
@ -107,7 +107,7 @@ function restoreNoteRevision(req) {
}
function getEditedNotesOnDate(req) {
const notes = repository.getEntities(`
const noteIds = sql.getColumn(`
SELECT notes.*
FROM notes
WHERE noteId IN (
@ -121,6 +121,8 @@ function getEditedNotesOnDate(req) {
ORDER BY isDeleted
LIMIT 50`, {date: req.params.date + '%'});
const notes = becca.getNotes(noteIds);
for (const note of notes) {
const notePath = note.isDeleted ? null : beccaService.getNotePath(note.noteId);

View file

@ -9,7 +9,7 @@ const log = require('../../services/log');
const TaskContext = require('../../services/task_context');
const fs = require('fs');
const noteRevisionService = require("../../services/note_revisions.js");
const becca = require("../../services/becca/becca.js");
const becca = require("../../services/becca/becca");
function getNote(req) {
const noteId = req.params.noteId;
@ -159,7 +159,8 @@ function getRelationMap(req) {
console.log("displayRelations", displayRelations);
const notes = repository.getEntities(`SELECT * FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
const foundNoteIds = sql.getColumn(`SELECT noteId FROM notes WHERE isDeleted = 0 AND noteId IN (${questionMarks})`, noteIds);
const notes = becca.getNotes(foundNoteIds);
for (const note of notes) {
resp.noteTitles[note.noteId] = note.title;

View file

@ -1,6 +1,6 @@
"use strict";
const RecentNote = require('../../entities/recent_note');
const RecentNote = require('../../services/becca/entities/recent_note.js');
const sql = require('../../services/sql');
const dateUtils = require('../../services/date_utils');

View file

@ -6,6 +6,7 @@ const log = require('../../services/log');
const scriptService = require('../../services/script');
const searchService = require('../../services/search/services/search');
const noteRevisionService = require("../../services/note_revisions.js");
const {formatAttrForSearch} = require("../../services/attribute_formatter.js");
async function searchFromNoteInt(note) {
let searchResultNoteIds;
@ -267,51 +268,6 @@ function getRelatedNotes(req) {
};
}
function formatAttrForSearch(attr, searchWithValue) {
let searchStr = '';
if (attr.type === 'label') {
searchStr += '#';
}
else if (attr.type === 'relation') {
searchStr += '~';
}
else {
throw new Error(`Unrecognized attribute type ${JSON.stringify(attr)}`);
}
searchStr += attr.name;
if (searchWithValue && attr.value) {
if (attr.type === 'relation') {
searchStr += ".noteId";
}
searchStr += '=';
searchStr += formatValue(attr.value);
}
return searchStr;
}
function formatValue(val) {
if (!/[^\w_-]/.test(val)) {
return val;
}
else if (!val.includes('"')) {
return '"' + val + '"';
}
else if (!val.includes("'")) {
return "'" + val + "'";
}
else if (!val.includes("`")) {
return "`" + val + "`";
}
else {
return '"' + val.replace(/"/g, '\\"') + '"';
}
}
module.exports = {
searchFromNote,
searchAndExecute,

View file

@ -1,7 +1,7 @@
"use strict";
const similarityService = require('../../services/becca/similarity.js');
const becca = require("../../services/becca/becca.js");
const becca = require("../../services/becca/becca");
async function getSimilarNotes(req) {
const noteId = req.params.noteId;

View file

@ -3,13 +3,17 @@ const log = require('../services/log');
const fileUploadService = require('./api/files.js');
const scriptService = require('../services/script');
const cls = require('../services/cls');
const sql = require("../services/sql");
const becca = require("../services/becca/becca");
async function handleRequest(req, res) {
// express puts content after first slash into 0 index element
const path = req.params.path + req.params[0];
const attrs = repository.getEntities("SELECT * FROM attributes WHERE isDeleted = 0 AND type = 'label' AND name IN ('customRequestHandler', 'customResourceProvider')");
const attributeIds = sql.getColumn("SELECT attributeId FROM attributes WHERE isDeleted = 0 AND type = 'label' AND name IN ('customRequestHandler', 'customResourceProvider')");
const attrs = attributeIds.map(attrId => becca.getAttribute(attrId));
for (const attr of attrs) {
if (!attr.value.trim()) {

View file

@ -0,0 +1,50 @@
"use strict"
function formatAttrForSearch(attr, searchWithValue) {
let searchStr = '';
if (attr.type === 'label') {
searchStr += '#';
}
else if (attr.type === 'relation') {
searchStr += '~';
}
else {
throw new Error(`Unrecognized attribute type ${JSON.stringify(attr)}`);
}
searchStr += attr.name;
if (searchWithValue && attr.value) {
if (attr.type === 'relation') {
searchStr += ".noteId";
}
searchStr += '=';
searchStr += formatValue(attr.value);
}
return searchStr;
}
function formatValue(val) {
if (!/[^\w_-]/.test(val)) {
return val;
}
else if (!val.includes('"')) {
return '"' + val + '"';
}
else if (!val.includes("'")) {
return "'" + val + "'";
}
else if (!val.includes("`")) {
return "`" + val + "`";
}
else {
return '"' + val.replace(/"/g, '\\"') + '"';
}
}
module.exports = {
formatAttrForSearch
}

View file

@ -1,9 +1,10 @@
"use strict";
const repository = require('./repository');
const searchService = require('./search/services/search');
const sql = require('./sql');
const becca = require('./becca/becca.js');
const Attribute = require('../entities/attribute');
const {formatAttrForSearch} = require("./attribute_formatter.js");
const ATTRIBUTE_TYPES = [ 'label', 'relation' ];
@ -59,16 +60,7 @@ const BUILTIN_ATTRIBUTES = [
];
function getNotesWithLabel(name, value) {
let valueCondition = "";
let params = [name];
if (value !== undefined) {
valueCondition = " AND attributes.value = ?";
params.push(value);
}
return repository.getEntities(`SELECT notes.* FROM notes JOIN attributes USING(noteId)
WHERE notes.isDeleted = 0 AND attributes.isDeleted = 0 AND attributes.name = ? ${valueCondition} ORDER BY position`, params);
return searchService.findNotes(formatAttrForSearch({type: 'label', name, value}, true));
}
function getNoteIdsWithLabels(names) {

View file

@ -14,7 +14,7 @@ const cloningService = require('./cloning');
const appInfo = require('./app_info');
const searchService = require('./search/services/search');
const SearchContext = require("./search/search_context.js");
const becca = require("./becca/becca.js");
const becca = require("./becca/becca");
/**
* This is the main backend API interface for scripts. It's published in the local "api" object.

View file

@ -2,6 +2,7 @@
const sql = require("../sql.js");
const NoteRevision = require("./entities/note_revision.js");
const RecentNote = require("./entities/recent_note.js");
class Becca {
constructor() {
@ -94,6 +95,18 @@ class Becca {
return this[camelCaseEntityName][entityId];
}
getRecentNotesFromQuery(query, params = []) {
const rows = sql.getRows(query, params);
return rows.map(row => new RecentNote(row));
}
getNoteRevisionsFromQuery(query, params = []) {
const rows = sql.getRows(query, params);
return rows.map(row => new NoteRevision(row));
}
}
const becca = new Becca();

View file

@ -0,0 +1,22 @@
"use strict";
const dateUtils = require('../../date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* RecentNote represents recently visited note.
*/
class RecentNote extends AbstractEntity {
static get entityName() { return "recent_notes"; }
static get primaryKeyName() { return "noteId"; }
constructor(row) {
super();
this.noteId = row.noteId;
this.notePath = row.notePath;
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
}
}
module.exports = RecentNote;

View file

@ -8,7 +8,7 @@ const repository = require('./repository');
const Branch = require('../entities/branch');
const TaskContext = require("./task_context.js");
const utils = require('./utils');
const becca = require("./becca/becca.js");
const becca = require("./becca/becca");
function cloneNoteToParent(noteId, parentBranchId, prefix) {
const parentBranch = becca.getBranch(parentBranchId);

View file

@ -13,7 +13,7 @@ const Branch = require('../entities/branch');
const dateUtils = require('./date_utils');
const attributeService = require('./attributes');
const noteRevisionService = require('./note_revisions');
const becca = require("./becca/becca.js");
const becca = require("./becca/becca");
class ConsistencyChecks {
constructor(autoFix) {
@ -244,13 +244,15 @@ class ConsistencyChecks {
HAVING COUNT(1) > 1`,
({noteId, parentNoteId}) => {
if (this.autoFix) {
const branches = repository.getEntities(
`SELECT *
const branchIds = sql.getColumn(
`SELECT branchId
FROM branches
WHERE noteId = ?
and parentNoteId = ?
and isDeleted = 0`, [noteId, parentNoteId]);
const branches = branchIds.map(branchId => becca.getBranch(branchId));
// it's not necessarily "original" branch, it's just the only one which will survive
const origBranch = branches[0];
@ -359,11 +361,13 @@ class ConsistencyChecks {
AND branches.isDeleted = 0`,
({parentNoteId}) => {
if (this.autoFix) {
const branches = repository.getEntities(`SELECT *
const branchIds = sql.getColumn(`SELECT branchId
FROM branches
WHERE isDeleted = 0
AND parentNoteId = ?`, [parentNoteId]);
const branches = branchIds.map(branchId => becca.getBranch(branchId));
for (const branch of branches) {
branch.parentNoteId = 'root';
branch.save();

View file

@ -2,7 +2,7 @@
const repository = require("../repository");
const utils = require('../utils');
const becca = require("../becca/becca.js");
const becca = require("../becca/becca");
function exportToOpml(taskContext, branch, version, res) {
if (!['1.0', '2.0'].includes(version)) {

View file

@ -6,11 +6,8 @@ const entityChangesService = require('./entity_changes.js');
const eventService = require('./events');
const repository = require('./repository');
const cls = require('../services/cls');
const Note = require('../entities/note');
const BeccaNote = require('../services/becca/entities/note.js');
const Branch = require('../entities/branch');
const BeccaBranch = require('../services/becca/entities/branch.js');
const Attribute = require('../entities/attribute');
const BeccaAttribute = require('../services/becca/entities/attribute.js');
const protectedSessionService = require('../services/protected_session');
const log = require('../services/log');
@ -617,14 +614,14 @@ function undeleteBranch(branch, deleteId, taskContext) {
note.isDeleted = false;
note.save();
const attrs = repository.getEntities(`
SELECT * FROM attributes
const attributeIds = sql.getColumn(`
SELECT attributeId FROM attributes
WHERE isDeleted = 1
AND deleteId = ?
AND (noteId = ?
OR (type = 'relation' AND value = ?))`, [deleteId, note.noteId, note.noteId]);
for (const attr of attrs) {
for (const attr of attributeIds) {
attr.isDeleted = false;
attr.save();
}
@ -646,14 +643,16 @@ function undeleteBranch(branch, deleteId, taskContext) {
* @return return deleted branches of an undeleted parent note
*/
function getUndeletedParentBranches(noteId, deleteId) {
return repository.getEntities(`
SELECT branches.*
const branchIds = sql.getColumn(`
SELECT branches.branchId
FROM branches
JOIN notes AS parentNote ON parentNote.noteId = branches.parentNoteId
WHERE branches.noteId = ?
AND branches.isDeleted = 1
AND branches.deleteId = ?
AND parentNote.isDeleted = 0`, [noteId, deleteId]);
return branchIds.map(branchId => becca.getBranch(branchId));
}
function scanForLinks(note) {

View file

@ -1,9 +1,10 @@
const scriptService = require('./script');
const repository = require('./repository');
const cls = require('./cls');
const sqlInit = require('./sql_init');
const config = require('./config');
const log = require('./log');
const sql = require("./sql");
const becca = require("./becca/becca");
function getRunAtHours(note) {
try {
@ -17,8 +18,9 @@ function getRunAtHours(note) {
}
function runNotesWithLabel(runAttrValue) {
const notes = repository.getEntities(`
SELECT notes.*
// TODO: should be refactored into becca search
const noteIds = sql.getColumn(`
SELECT notes.noteId
FROM notes
JOIN attributes ON attributes.noteId = notes.noteId
AND attributes.isDeleted = 0
@ -29,6 +31,8 @@ function runNotesWithLabel(runAttrValue) {
notes.type = 'code'
AND notes.isDeleted = 0`, [runAttrValue]);
const notes = becca.getNotes(noteIds);
const instanceName = config.General ? config.General.instanceName : null;
const currentHours = new Date().getHours();

View file

@ -2,7 +2,7 @@ const ScriptContext = require('./script_context');
const repository = require('./repository');
const cls = require('./cls');
const log = require('./log');
const becca = require("./becca/becca.js");
const becca = require("./becca/becca");
async function executeNote(note, apiParams) {
if (!note.isJavaScript() || note.getScriptEnv() !== 'backend' || !note.isContentAvailable) {

View file

@ -7,7 +7,7 @@ const syncOptions = require('./sync_options');
const request = require('./request');
const appInfo = require('./app_info');
const utils = require('./utils');
const becca = require("./becca/becca.js");
const becca = require("./becca/becca");
async function hasSyncServerSchemaAndSeed() {
const response = await requestToSyncServer('GET', '/api/setup/status');