mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-27 10:32:58 +02:00
Better handling of db errors
This commit is contained in:
parent
a53ca42a92
commit
62c56044b0
@ -1,6 +1,5 @@
|
|||||||
import { time } from 'lib/time-utils.js';
|
import { time } from 'lib/time-utils.js';
|
||||||
import { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient } from 'test-utils.js';
|
import { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient } from 'test-utils.js';
|
||||||
import { createFoldersAndNotes } from 'test-data.js';
|
|
||||||
import { Folder } from 'lib/models/folder.js';
|
import { Folder } from 'lib/models/folder.js';
|
||||||
import { Note } from 'lib/models/note.js';
|
import { Note } from 'lib/models/note.js';
|
||||||
import { Setting } from 'lib/models/setting.js';
|
import { Setting } from 'lib/models/setting.js';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { time } from 'lib/time-utils.js';
|
import { time } from 'lib/time-utils.js';
|
||||||
import { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient } from 'test-utils.js';
|
import { setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient } from 'test-utils.js';
|
||||||
import { createFoldersAndNotes } from 'test-data.js';
|
|
||||||
import { Folder } from 'lib/models/folder.js';
|
import { Folder } from 'lib/models/folder.js';
|
||||||
import { Note } from 'lib/models/note.js';
|
import { Note } from 'lib/models/note.js';
|
||||||
import { Tag } from 'lib/models/tag.js';
|
import { Tag } from 'lib/models/tag.js';
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
import { Note } from 'lib/models/note.js';
|
|
||||||
import { Folder } from 'lib/models/folder.js';
|
|
||||||
import { promiseChain } from 'lib/promise-utils.js';
|
|
||||||
|
|
||||||
function createNotes(id = 1, parentId) {
|
|
||||||
let notes = [];
|
|
||||||
if (id === 1) {
|
|
||||||
notes.push({ parent_id: parentId, title: 'note one', body: 'content of note one' });
|
|
||||||
notes.push({ parent_id: parentId, title: 'note two', body: 'content of note two' });
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid ID: ' + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = [];
|
|
||||||
let chain = [];
|
|
||||||
for (let i = 0; i < notes.length; i++) {
|
|
||||||
chain.push(() => {
|
|
||||||
return Note.save(notes[i]).then((note) => {
|
|
||||||
output.push(note);
|
|
||||||
return output;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return promiseChain(chain, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFolders(id = 1) {
|
|
||||||
let folders = [];
|
|
||||||
if (id === 1) {
|
|
||||||
folders.push({ title: 'myfolder1' });
|
|
||||||
folders.push({ title: 'myfolder2' });
|
|
||||||
folders.push({ title: 'myfolder3' });
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid ID: ' + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = [];
|
|
||||||
let chain = [];
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
|
||||||
chain.push(() => {
|
|
||||||
return Folder.save(folders[i]).then((folder) => {
|
|
||||||
output.push(folder);
|
|
||||||
return output;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return promiseChain(chain, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFoldersAndNotes(id = 1) {
|
|
||||||
return createFolders(id).then((folders) => {
|
|
||||||
return createNotes(id, folders[0].id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export { createNotes, createFolders, createFoldersAndNotes };
|
|
125
lib/database.js
125
lib/database.js
@ -121,11 +121,11 @@ class Database {
|
|||||||
// Converts the SQLite error to a regular JS error
|
// Converts the SQLite error to a regular JS error
|
||||||
// so that it prints a stacktrace when passed to
|
// so that it prints a stacktrace when passed to
|
||||||
// console.error()
|
// console.error()
|
||||||
sqliteErrorToJsError(error, sql, params = null) {
|
sqliteErrorToJsError(error, sql = null, params = null) {
|
||||||
let msg = sql;
|
let msg = [error.toString()];
|
||||||
if (params) msg += ': ' + JSON.stringify(params);
|
if (sql) msg.push(sql);
|
||||||
msg += ': ' + error.toString();
|
if (params) msg.push(params);
|
||||||
let output = new Error(msg);
|
let output = new Error(msg.join(': '));
|
||||||
if (error.code) output.code = error.code;
|
if (error.code) output.code = error.code;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -146,14 +146,10 @@ class Database {
|
|||||||
return this.driver_;
|
return this.driver_;
|
||||||
}
|
}
|
||||||
|
|
||||||
open(options) {
|
async open(options) {
|
||||||
return this.driver().open(options).then((db) => {
|
await this.driver().open(options);
|
||||||
this.logger().info('Database was open successfully');
|
this.logger().info('Database was open successfully');
|
||||||
return this.initialize();
|
return this.initialize();
|
||||||
}).catch((error) => {
|
|
||||||
this.logger().error('Cannot open database:');
|
|
||||||
this.logger().error(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
escapeField(field) {
|
escapeField(field) {
|
||||||
@ -416,71 +412,58 @@ class Database {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultFolderData() {
|
async initialize() {
|
||||||
let now = time.unixMs();
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: uuid.create(),
|
|
||||||
title: _('Notebook'),
|
|
||||||
created_time: now,
|
|
||||||
updated_time: now,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultFolderQuery() {
|
|
||||||
return Database.insertQuery('folders', this.defaultFolderData());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
initialize() {
|
|
||||||
this.logger().info('Checking for database schema update...');
|
this.logger().info('Checking for database schema update...');
|
||||||
|
|
||||||
return this.selectOne('SELECT * FROM version LIMIT 1').then((row) => {
|
for (let initLoopCount = 1; initLoopCount <= 2; initLoopCount++) {
|
||||||
this.logger().info('Current database version', row);
|
try {
|
||||||
// TODO: version update logic
|
let row = await this.selectOne('SELECT * FROM version LIMIT 1');
|
||||||
|
this.logger().info('Current database version', row);
|
||||||
|
|
||||||
|
// TODO: version update logic
|
||||||
|
// TODO: only do this if db has been updated:
|
||||||
|
// return this.refreshTableFields();
|
||||||
|
} catch (error) {
|
||||||
|
if (error && error.code != 0 && error.code != 'SQLITE_ERROR') throw this.sqliteErrorToJsError(error);
|
||||||
|
|
||||||
|
// Assume that error was:
|
||||||
|
// { message: 'no such table: version (code 1): , while compiling: SELECT * FROM version', code: 0 }
|
||||||
|
// which means the database is empty and the tables need to be created.
|
||||||
|
// If it's any other error there's nothing we can do anyway.
|
||||||
|
|
||||||
|
this.logger().info('Database is new - creating the schema...');
|
||||||
|
|
||||||
|
let queries = this.wrapQueries(this.sqlStringToLines(structureSql));
|
||||||
|
queries.push(this.wrapQuery('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + uuid.create() + '", "' + Database.enumId('settings', 'string') + '")'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.transactionExecBatch(queries);
|
||||||
|
this.logger().info('Database schema created successfully');
|
||||||
|
await this.refreshTableFields();
|
||||||
|
} catch (error) {
|
||||||
|
throw this.sqliteErrorToJsError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that the database has been created, go through the normal initialisation process
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: only do this if db has been updated:
|
|
||||||
// return this.refreshTableFields();
|
|
||||||
}).then(() => {
|
|
||||||
this.tableFields_ = {};
|
this.tableFields_ = {};
|
||||||
|
|
||||||
return this.selectAll('SELECT * FROM table_fields').then((rows) => {
|
let rows = await this.selectAll('SELECT * FROM table_fields');
|
||||||
for (let i = 0; i < rows.length; i++) {
|
|
||||||
let row = rows[i];
|
for (let i = 0; i < rows.length; i++) {
|
||||||
if (!this.tableFields_[row.table_name]) this.tableFields_[row.table_name] = [];
|
let row = rows[i];
|
||||||
this.tableFields_[row.table_name].push({
|
if (!this.tableFields_[row.table_name]) this.tableFields_[row.table_name] = [];
|
||||||
name: row.field_name,
|
this.tableFields_[row.table_name].push({
|
||||||
type: row.field_type,
|
name: row.field_name,
|
||||||
default: Database.formatValue(row.field_type, row.field_default),
|
type: row.field_type,
|
||||||
});
|
default: Database.formatValue(row.field_type, row.field_default),
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error && error.code != 0 && error.code != 'SQLITE_ERROR') {
|
|
||||||
this.logger().error(error);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume that error was:
|
|
||||||
// { message: 'no such table: version (code 1): , while compiling: SELECT * FROM version', code: 0 }
|
|
||||||
// which means the database is empty and the tables need to be created.
|
|
||||||
// If it's any other error there's nothing we can do anyway.
|
|
||||||
|
|
||||||
this.logger().info('Database is new - creating the schema...');
|
break;
|
||||||
|
}
|
||||||
let queries = this.wrapQueries(this.sqlStringToLines(structureSql));
|
|
||||||
queries.push(this.wrapQuery('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + uuid.create() + '", "' + Database.enumId('settings', 'string') + '")'));
|
|
||||||
//queries.push(Database.defaultFolderQuery());
|
|
||||||
|
|
||||||
return this.transactionExecBatch(queries).then(() => {
|
|
||||||
this.logger().info('Database schema created successfully');
|
|
||||||
// Calling initialize() now that the db has been created will make it go through
|
|
||||||
// the normal db update process (applying any additional patch).
|
|
||||||
return this.refreshTableFields();
|
|
||||||
}).then(() => {
|
|
||||||
return this.initialize();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,6 @@ class Folder extends BaseItem {
|
|||||||
return this.modelSelectOne('SELECT * FROM folders ORDER BY created_time DESC LIMIT 1');
|
return this.modelSelectOne('SELECT * FROM folders ORDER BY created_time DESC LIMIT 1');
|
||||||
}
|
}
|
||||||
|
|
||||||
static createDefaultFolder() {
|
|
||||||
let folder = Database.defaultFolderData();
|
|
||||||
return Folder.save(folder, { isNew: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
static async save(o, options = null) {
|
static async save(o, options = null) {
|
||||||
if (options && options.duplicateCheck === true && o.title) {
|
if (options && options.duplicateCheck === true && o.title) {
|
||||||
let existingFolder = await Folder.loadByTitle(o.title);
|
let existingFolder = await Folder.loadByTitle(o.title);
|
||||||
|
Loading…
Reference in New Issue
Block a user