1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Handle settings

This commit is contained in:
Laurent Cozic 2017-05-12 20:17:23 +00:00
parent a0472274a6
commit 1c9f358f96
6 changed files with 215 additions and 41 deletions

View File

@ -1,5 +1,6 @@
import { Log } from 'src/log.js';
import { Database } from 'src/database.js';
import { Registry } from 'src/registry.js';
import createUuid from 'uuid/v4';
class BaseModel {
@ -29,12 +30,8 @@ class BaseModel {
return this.db().exec(query.sql, query.params).then(() => { return o; });
}
static setDb(database) {
this.db_ = database;
}
static db() {
return this.db_;
return Registry.db();
}
}

View File

@ -1,5 +1,6 @@
import SQLite from 'react-native-sqlite-storage';
import { Log } from 'src/log.js';
import createUuid from 'uuid/v4';
const structureSql = `
CREATE TABLE folders (
@ -84,6 +85,7 @@ class Database {
constructor() {
this.debugMode_ = false;
this.initialized_ = false;
}
setDebugEnabled(v) {
@ -95,14 +97,26 @@ class Database {
return this.debugMode_;
}
initialized() {
return this.initialized_;
}
open() {
this.db_ = SQLite.openDatabase({ name: '/storage/emulated/0/Download/joplin.sqlite' }, (db) => {
this.db_ = SQLite.openDatabase({ name: '/storage/emulated/0/Download/joplin-4.sqlite' }, (db) => {
Log.info('Database was open successfully');
}, (error) => {
Log.error('Cannot open database: ', error);
});
this.updateSchema();
return this.updateSchema();
}
static enumToId(type, s) {
if (type == 'settings') {
if (s == 'int') return 1;
if (s == 'string') return 2;
}
throw new Error('Unknown enum type or value: ' + type + ', ' + s);
}
sqlStringToLines(sql) {
@ -202,28 +216,41 @@ class Database {
};
}
transaction(readyCallack, errorCallback, successCallback) {
return this.db_.transaction(readyCallack, errorCallback, successCallback);
}
updateSchema() {
Log.info('Checking for database schema update...');
this.selectOne('SELECT * FROM version LIMIT 1').then((row) => {
Log.info('Current database version', row);
// TODO: version update logic
}).catch((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.
return new Promise((resolve, reject) => {
this.selectOne('SELECT * FROM version LIMIT 1').then((row) => {
Log.info('Current database version', row);
resolve();
// TODO: version update logic
}).catch((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.
Log.info('Database is new - creating the schema...');
Log.info('Database is new - creating the schema...');
let statements = this.sqlStringToLines(structureSql)
this.db_.transaction((tx) => {
for (let i = 0; i < statements.length; i++) {
tx.executeSql(statements[i]);
}
}, (error) => {
Log.error('Could not create database schema:', error);
}, () => {
Log.info('Database schema created successfully');
let statements = this.sqlStringToLines(structureSql)
//this.db_.transaction((tx) => {
this.transaction((tx) => {
try {
for (let i = 0; i < statements.length; i++) {
tx.executeSql(statements[i]);
}
tx.executeSql('INSERT INTO settings (`key`, `value`, `type`) VALUES ("clientId", "' + createUuid() + '", "' + Database.enumToId('settings', 'string') + '")');
} catch (error) {
reject(error);
}
}, (error) => {
reject(error);
}, () => {
resolve('Database schema created successfully');
});
});
});
}

View File

@ -1,20 +1,14 @@
import { AppRegistry } from 'react-native';
import { Database } from 'src/database.js'
import { Log } from 'src/log.js'
import { Root } from 'src/root.js';
import { BaseModel } from 'src/base-model.js';
import { Registry } from 'src/registry.js';
import { Database } from 'src/database.js';
function main() {
let debugMode = true;
let clientId = 'A7D301DA7D301DA7D301DA7D301DA7D3';
Registry.setDebugMode(true);
AppRegistry.registerComponent('AwesomeProject', () => Root);
let db = new Database();
db.setDebugEnabled(debugMode);
db.open();
BaseModel.setDb(db);
// Note: The final part of the initialization process is in
// AppComponent.componentDidMount(), when the application is ready.
}
export { main }

View File

@ -0,0 +1,82 @@
import { BaseModel } from 'src/base-model.js';
import { Log } from 'src/log.js';
import { Database } from 'src/database.js';
class Setting extends BaseModel {
static tableName() {
return 'settings';
}
static defaultSetting(key) {
if (!this.defaults_) {
this.defaults_ = {
'clientId': { value: '', type: 'string' },
'sessionId': { value: '', type: 'string' },
'lastUpdateTime': { value: '', type: 'int' },
}
}
if (!(key in this.defaults_)) throw new Error('Unknown key: ' + key);
let output = Object.assign({}, this.defaults_[key]);
output.key = key;
return output;
}
static load() {
this.cache_ = [];
return this.db().selectAll('SELECT * FROM settings').then((r) => {
for (let i = 0; i < r.rows.length; i++) {
this.cache_.push(r.rows.item(i));
}
});
}
static setValue(key, value) {
this.scheduleUpdate();
for (let i = 0; i < this.cache_.length; i++) {
if (this.cache_[i].key == key) {
this.cache_[i].value = value;
return;
}
}
let s = this.defaultSetting(key);
s.value = value;
this.cache_.push(s);
}
static value(key) {
for (let i = 0; i < this.cache_.length; i++) {
if (this.cache_[i].key == key) {
return this.cache_[i].value;
}
}
let s = this.defaultSetting(key);
return s.value;
}
static scheduleUpdate() {
if (this.updateTimeoutId) clearTimeout(this.updateTimeoutId);
this.updateTimeoutId = setTimeout(() => {
Log.info('Saving settings...');
this.updateTimeoutId = null;
BaseModel.db().transaction((tx) => {
tx.executeSql('DELETE FROM settings');
for (let i = 0; i < this.cache_.length; i++) {
let q = Database.insertQuery(this.tableName(), this.cache_[i]);
tx.executeSql(q.sql, q.params);
}
}, (error) => {
Log.warn('Could not update settings:', error);
}, () => {
Log.info('Settings have been saved.');
});
}, 500);
}
}
export { Setting };

View File

@ -0,0 +1,45 @@
// Stores global dynamic objects that are not state but that are required
// throughout the application. Dependency injection would be a better solution
// but more complex and YAGNI at this point. However classes that make use of the
// registry should be designed in such a way that they can be converted to use
// dependency injection later on (eg. `BaseModel.db()`, `Synchroniser.api()`)
import { Database } from 'src/database.js'
class Registry {
static setDebugMode(v) {
this.debugMode_ = v;
}
static debugMode() {
if (this.debugMode_ === undefined) return false;
return this.debugMode_;
}
static setApi(v) {
this.api_ = v;
}
static setDb(v) {
this.db_ = v;
}
static db() {
if (!this.db_) throw new Error('Accessing database before it has been initialised');
// if (!this.db_) {
// this.db_ = new Database();
// this.db_.setDebugEnabled(this.debugMode());
// this.db_.open();
// }
return this.db_;
}
static api() {
if (!this.api_) throw new Error('Accessing web API before it has been initialised');
return this.api_;
}
}
export { Registry };

View File

@ -8,7 +8,10 @@ import { StackNavigator } from 'react-navigation';
import { addNavigationHelpers } from 'react-navigation';
import { Log } from 'src/log.js'
import { Note } from 'src/models/note.js'
import { Database } from 'src/database.js'
import { Registry } from 'src/registry.js'
import { ItemList } from 'src/components/item-list.js'
import { Setting } from 'src/models/setting.js'
let defaultState = {
defaultText: 'bla',
@ -93,12 +96,24 @@ class NotesScreenComponent extends React.Component {
});
}
loginButton_press = () => {
}
syncButton_press = () => {
Log.info('SYNC');
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={{flex: 1}}>
<ItemList style={{flex: 1}}/>
<Button title="Create note" onPress={this.createNoteButton_press} />
<View style={{flexDirection: 'row'}}>
<Button title="Create note" onPress={this.createNoteButton_press} />
<Button title="Login" onPress={this.loginButton_press} />
<Button title="Sync" onPress={this.syncButton_press} />
</View>
</View>
);
}
@ -180,13 +195,27 @@ const AppNavigator = StackNavigator({
class AppComponent extends React.Component {
componentDidMount() {
Note.previews().then((notes) => {
this.props.dispatch({
type: 'NOTES_UPDATE_ALL',
notes: notes,
let db = new Database();
db.setDebugEnabled(Registry.debugMode());
db.open().then(() => {
Log.info('Database is ready.');
Registry.setDb(db);
}).then(() => {
Log.info('Loading settings...');
return Setting.load();
}).then(() => {
Log.info('Loading notes...');
Note.previews().then((notes) => {
this.props.dispatch({
type: 'NOTES_UPDATE_ALL',
notes: notes,
});
}).catch((error) => {
Log.warn('Cannot load notes', error);
});
}).catch((error) => {
Log.warn('Cannot load notes', error);
Log.error('Cannot initialize database:', error);
});
}