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

Loading and saving note to SQLite

This commit is contained in:
Laurent Cozic 2017-05-11 20:14:01 +00:00
parent 017c4f7338
commit 3d46cf4b55
8 changed files with 151 additions and 47 deletions

View File

@ -9,7 +9,8 @@
"dependencies": {
"react": "16.0.0-alpha.6",
"react-native": "0.44.0",
"react-navigation": "^1.0.0-beta.9"
"react-navigation": "^1.0.0-beta.9",
"uuid": "^3.0.1"
},
"devDependencies": {
"babel-jest": "19.0.0",

View File

@ -1,5 +1,6 @@
import { Log } from 'src/log.js';
import { Database } from 'src/database.js';
import createUuid from 'uuid/v4';
class BaseModel {
@ -7,9 +8,16 @@ class BaseModel {
throw new Error('Must be overriden');
}
static save(object) {
let sql = Database.insertSql(this.tableName(), object);
Log.info(sql);
static save(o) {
let isNew = !o.id;
if (isNew) o.id = createUuid();
if (isNew) {
let q = Database.insertQuery(this.tableName(), o);
return this.db().insert(q.sql, q.params);
} else {
Log.error('NOT EIMPLEMETNED');
// TODO: update
}
}
static setDb(database) {

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { ListView, Text, TouchableHighlight } from 'react-native';
import { Log } from 'src/log.js';
import { _ } from 'src/locale.js';
class ItemListComponent extends Component {
@ -17,11 +18,12 @@ class ItemListComponent extends Component {
}
componentWillReceiveProps(newProps) {
// TODO: use this to update:
// https://stackoverflow.com/questions/38186114/react-native-redux-and-listview
this.setState({ dataSource: this.state.dataSource.cloneWithRows(newProps.notes) });
}
render() {
Log.info('RENDER');
let renderRow = (rowData) => {
let onPress = () => {
this.props.onItemClick(rowData.id)

View File

@ -82,14 +82,21 @@ INSERT INTO version (version) VALUES (1);
class Database {
constructor() {}
constructor() {
this.debugMode_ = false;
}
setDebugEnabled(v) {
SQLite.DEBUG(v);
this.debugMode_ = v;
}
debugMode() {
return this.debugMode_;
}
open() {
this.db_ = SQLite.openDatabase({ name: 'joplin.sqlite', location: 'Documents' }, (db) => {
this.db_ = SQLite.openDatabase({ name: '/storage/emulated/0/Download/joplin.sqlite' }, (db) => {
Log.info('Database was open successfully');
}, (error) => {
Log.error('Cannot open database: ', error);
@ -115,7 +122,14 @@ class Database {
return output;
}
logQuery(sql, params = null) {
if (!this.debugMode()) return;
Log.debug('DB: ' + sql, params);
}
selectOne(sql, params = null) {
this.logQuery(sql, params);
return new Promise((resolve, reject) => {
this.db_.executeSql(sql, params, (r) => {
resolve(r.rows.length ? r.rows.item(0) : null);
@ -125,24 +139,65 @@ class Database {
});
}
static insertSql(tableName, data) {
let output = '';
selectAll(sql, params = null) {
this.logQuery(sql, params);
return new Promise((resolve, reject) => {
this.db_.executeSql(sql, params, (r) => {
resolve(r);
}, (error) => {
reject(error);
});
});
}
insert(sql, params = null) {
this.logQuery(sql, params);
return new Promise((resolve, reject) => {
this.db_.executeSql(sql, params, (r) => {
resolve();
}, (error) => {
reject(error);
});
});
}
del(sql, params = null) {
this.logQuery(sql, params);
return new Promise((resolve, reject) => {
this.db_.executeSql(sql, params, (r) => {
resolve();
}, (error) => {
reject(error);
});
});
}
static insertQuery(tableName, data) {
let keySql= '';
let valueSql = '';
let params = [];
for (let key in data) {
if (data.hasOwnProperty(key)) continue;
if (!data.hasOwnProperty(key)) continue;
if (keySql != '') keySql += ', ';
if (valueSql != '') valueSql += ', ';
keySql += key;
keySql += '`' + key + '`';
valueSql += '?';
params.push(data[key]);
}
return 'INSERT INTO ' + tableName + ' (' + keySql + ') VALUES (' + valueSql + ')';
return {
sql: 'INSERT INTO `' + tableName + '` (' + keySql + ') VALUES (' + valueSql + ')',
params: params,
};
}
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:

View File

@ -2,6 +2,10 @@
class Log {
static debug(...o) {
console.debug(...o);
}
static info(...o) {
console.info(...o);
}

View File

@ -7,14 +7,14 @@ import { BaseModel } from 'src/base-model.js';
function main() {
let debugMode = true;
let clientId = 'A7D301DA7D301DA7D301DA7D301DA7D3';
AppRegistry.registerComponent('AwesomeProject', () => Root);
let db = new Database();
db.setDebugEnabled(debugMode);
db.open();
BaseModel.setDb(db);
AppRegistry.registerComponent('AwesomeProject', () => Root);
BaseModel.setDb(db);
}
export { main }

View File

@ -1,4 +1,5 @@
import { BaseModel } from 'src/base-model.js';
import { Log } from 'src/log.js';
class Note extends BaseModel {
@ -21,6 +22,16 @@ class Note extends BaseModel {
}
}
static previews() {
return this.db().selectAll('SELECT id, title, body, updated_time FROM notes').then((r) => {
let output = [];
for (let i = 0; i < r.rows.length; i++) {
output.push(r.rows.item(i));
}
return output;
});
}
}
export { Note };

View File

@ -24,8 +24,6 @@ let defaultState = {
const reducer = (state = defaultState, action) => {
Log.info('Reducer action', action);
Log.info('DB LA', Note.db());
let newState = state;
switch (action.type) {
@ -45,11 +43,16 @@ const reducer = (state = defaultState, action) => {
break;
case 'VIEW_NOTE':
case 'NOTES_LOADED':
newState = Object.assign({}, state);
newState.notes = action.notes;
break;
break;
case 'SAVE_NOTE':
break;
}
@ -102,7 +105,7 @@ class NoteScreenComponent extends React.Component {
this.setState({ note: this.props.note });
}
noteComponent_onChange = (propName, propValue) => {
noteComponent_change = (propName, propValue) => {
this.setState((prevState, props) => {
let note = Object.assign({}, prevState.note);
note[propName] = propValue;
@ -110,25 +113,39 @@ class NoteScreenComponent extends React.Component {
});
}
title_onChangeText = (text) => {
this.noteComponent_onChange('title', text);
title_changeText = (text) => {
this.noteComponent_change('title', text);
}
body_onChangeText = (text) => {
this.noteComponent_onChange('body', text);
body_changeText = (text) => {
this.noteComponent_change('body', text);
}
saveNoteButton_press = () => {
// TODO: if state changes are asynchronous, how to be sure that, when
// the button is presssed, this.state.note contains the actual note?
// - Save to database
// - Dispatch "noteSaved" when done
// -* Move i^p on state
Note.save(this.state.note).then(() => {
Log.info('NOTE INSERTED');
}).catch((error) => {
Log.warn('CANONT INSERT NOTE', error);
});
// this.props.dispatch({
// type: 'SAVE_NOTE',
// note: this.state.note,
// });
}
render() {
let onSaveButtonPress = () => {
return this.props.onSaveButtonPress(this.state.note);
}
return (
<View style={{flex: 1}}>
<TextInput value={this.state.note.title} onChangeText={this.title_onChangeText} />
<TextInput style={{flex: 1, textAlignVertical: 'top'}} multiline={true} value={this.state.note.body} onChangeText={this.body_onChangeText} />
<Button title="Save note" onPress={onSaveButtonPress} />
<TextInput value={this.state.note.title} onChangeText={this.title_changeText} />
<TextInput style={{flex: 1, textAlignVertical: 'top'}} multiline={true} value={this.state.note.body} onChangeText={this.body_changeText} />
<Button title="Save note" onPress={this.saveNoteButton_press} />
</View>
);
}
@ -139,13 +156,7 @@ const NoteScreen = connect(
(state) => {
return {
note: state.selectedNoteId ? Note.noteById(state.notes, state.selectedNoteId) : Note.newNote(),
onSaveButtonPress: (note) => {
Log.info(note);
}
};
},
(dispatch) => {
return {};
}
)(NoteScreenComponent)
@ -155,14 +166,26 @@ const AppNavigator = StackNavigator({
});
class AppComponent extends React.Component {
render() {
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
componentDidMount() {
Note.previews().then((notes) => {
this.props.dispatch({
type: 'NOTES_LOADED',
notes: notes,
});
}).catch((error) => {
Log.warn('Cannot load notes', error);
});
}
render() {
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
}
defaultState.nav = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Notes'));