diff --git a/CliClient/run_test.sh b/CliClient/run_test.sh index 857d4092b..46e74cf34 100755 --- a/CliClient/run_test.sh +++ b/CliClient/run_test.sh @@ -5,5 +5,5 @@ rm -f "$CLIENT_DIR/tests-build/src" mkdir -p "$CLIENT_DIR/tests-build/data" ln -s "$CLIENT_DIR/build/src" "$CLIENT_DIR/tests-build" -# npm run build && NODE_PATH="$CLIENT_DIR/tests-build/" npm test tests-build/synchronizer.js -npm run build && NODE_PATH="$CLIENT_DIR/tests-build/" npm test tests-build/services/note-folder-service.js \ No newline at end of file +npm run build && NODE_PATH="$CLIENT_DIR/tests-build/" npm test tests-build/synchronizer.js +# npm run build && NODE_PATH="$CLIENT_DIR/tests-build/" npm test tests-build/services/note-folder-service.js \ No newline at end of file diff --git a/CliClient/tests/synchronizer.js b/CliClient/tests/synchronizer.js index a0bc8929a..1c218d521 100644 --- a/CliClient/tests/synchronizer.js +++ b/CliClient/tests/synchronizer.js @@ -155,4 +155,8 @@ describe('Synchronizer syncActions', function() { }); }); + it('should sync items', function(done) { + + }); + }); \ No newline at end of file diff --git a/ReactNativeClient/src/base-model.js b/ReactNativeClient/src/base-model.js index aed87df8e..9a0aeca8f 100644 --- a/ReactNativeClient/src/base-model.js +++ b/ReactNativeClient/src/base-model.js @@ -138,7 +138,7 @@ class BaseModel { query.id = itemId; - Log.info('Saving', JSON.stringify(o)); + // Log.info('Saving', JSON.stringify(o)); return query; } diff --git a/ReactNativeClient/src/database.js b/ReactNativeClient/src/database.js index cab8ee5d9..baccdd510 100644 --- a/ReactNativeClient/src/database.js +++ b/ReactNativeClient/src/database.js @@ -10,6 +10,7 @@ CREATE TABLE folders ( title TEXT NOT NULL DEFAULT "", created_time INT NOT NULL DEFAULT 0, updated_time INT NOT NULL DEFAULT 0, + sync_time INT NOT NULL DEFAULT 0, is_default BOOLEAN NOT NULL DEFAULT 0 ); @@ -20,6 +21,7 @@ CREATE TABLE notes ( body TEXT NOT NULL DEFAULT "", created_time INT NOT NULL DEFAULT 0, updated_time INT NOT NULL DEFAULT 0, + sync_time INT NOT NULL DEFAULT 0, latitude NUMERIC NOT NULL DEFAULT 0, longitude NUMERIC NOT NULL DEFAULT 0, altitude NUMERIC NOT NULL DEFAULT 0, @@ -88,6 +90,12 @@ CREATE TABLE table_fields ( field_default TEXT ); +CREATE TABLE item_sync_times ( + id INTEGER PRIMARY KEY, + item_id TEXT, + \`time\` INT +); + INSERT INTO version (version) VALUES (1); `; @@ -142,6 +150,9 @@ class Database { } transactionExecBatch(queries) { + queries.splice(0, 0, 'BEGIN TRANSACTION'); + queries.push('COMMIT'); // Note: ROLLBACK is currently not supported + let chain = []; for (let i = 0; i < queries.length; i++) { let query = this.wrapQuery(queries[i]); @@ -149,6 +160,7 @@ class Database { return this.exec(query.sql, query.params); }); } + return promiseChain(chain); } @@ -247,18 +259,7 @@ class Database { params: params, }; } - - transaction(readyCallack) { - throw new Error('transaction() DEPRECATED'); - // return new Promise((resolve, reject) => { - // this.db_.transaction( - // readyCallack, - // (error) => { reject(error); }, - // () => { resolve(); } - // ); - // }); - } - + wrapQueries(queries) { let output = []; for (let i = 0; i < queries.length; i++) { diff --git a/ReactNativeClient/src/models/item-sync-time.js b/ReactNativeClient/src/models/item-sync-time.js new file mode 100644 index 000000000..1183ae6a6 --- /dev/null +++ b/ReactNativeClient/src/models/item-sync-time.js @@ -0,0 +1,39 @@ +import { BaseModel } from 'src/base-model.js'; + +class ItemSyncTime extends BaseModel { + + static time(itemId) { + if (itemId in this.cache_) return Promise.resolve(this.cache_[itemId]); + + return this.db().selectOne('SELECT * FROM item_sync_times WHERE item_id = ?', [itemId]).then((row) => { + this.cache_[itemId] = row ? row.time : 0; + return this.cache_[itemId]; + }); + } + + static setTime(itemId, time) { + return this.db().selectOne('SELECT * FROM item_sync_times WHERE item_id = ?', [itemId]).then((row) => { + let p = null; + if (row) { + p = this.db().exec('UPDATE item_sync_times SET `time` = ? WHERE item_id = ?', [time, itemId]); + } else { + p = this.db().exec('INSERT INTO item_sync_times (item_id, `time`) VALUES (?, ?)', [itemId, time]); + } + + return p.then(() => { + this.cache_[itemId] = time; + }); + }); + } + + static deleteTime(itemId) { + return this.db().exec('DELETE FROM item_sync_times WHERE item_id = ?', [itemId]).then(() => { + delete this.cache_[itemId]; + }); + } + +} + +ItemSyncTime.cache_ = {}; + +export { ItemSyncTime }; \ No newline at end of file diff --git a/ReactNativeClient/src/models/note.js b/ReactNativeClient/src/models/note.js index 0f1191a9d..6385ddef0 100644 --- a/ReactNativeClient/src/models/note.js +++ b/ReactNativeClient/src/models/note.js @@ -122,7 +122,7 @@ class Note extends BaseModel { return super.save(o, options).then((result) => { // 'result' could be a partial one at this point (if, for example, only one property of it was saved) // so call this.preview() so that the right fields are populated. - return this.preview(result.id); + return this.load(result.id); }).then((note) => { this.dispatch({ type: 'NOTES_UPDATE_ONE', diff --git a/ReactNativeClient/src/promise-chain.js b/ReactNativeClient/src/promise-chain.js index 1c8212a8e..ded1c470a 100644 --- a/ReactNativeClient/src/promise-chain.js +++ b/ReactNativeClient/src/promise-chain.js @@ -1,5 +1,5 @@ -function promiseChain(chain) { - let output = new Promise((resolve, reject) => { resolve(); }); +function promiseChain(chain, defaultValue = null) { + let output = new Promise((resolve, reject) => { resolve(defaultValue); }); for (let i = 0; i < chain.length; i++) { let f = chain[i]; output = output.then(f); diff --git a/ReactNativeClient/src/services/note-folder-service.js b/ReactNativeClient/src/services/note-folder-service.js index 9a08cffd8..573e6c5ff 100644 --- a/ReactNativeClient/src/services/note-folder-service.js +++ b/ReactNativeClient/src/services/note-folder-service.js @@ -5,6 +5,7 @@ import { BaseModel } from 'src/base-model.js'; import { Note } from 'src/models/note.js'; import { Folder } from 'src/models/folder.js'; import { Log } from 'src/log.js'; +import { time } from 'src/time-utils.js'; import { Registry } from 'src/registry.js'; class NoteFolderService extends BaseService { @@ -72,6 +73,38 @@ class NoteFolderService extends BaseService { }); } + static itemsThatNeedSync(context = null, limit = 100) { + let now = time.unix(); + + if (!context) { + context = { + hasMoreNotes: true, + hasMoreFolders: true, + noteOffset: 0, + folderOffset: 0, + hasMore: true, + items: [], + }; + } + + if (context.hasMoreNotes) { + return BaseModel.db().selectAll('SELECT * FROM notes WHERE sync_time < ? LIMIT ' + limit + ' OFFSET ' + context.noteOffset, [now]).then((items) => { + context.items = items; + context.hasMoreNotes = items.length >= limit; + context.noteOffset += items.length; + return context; + }); + } else { + return BaseModel.db().selectAll('SELECT * FROM folders WHERE sync_time < ? LIMIT ' + limit + ' OFFSET ' + context.folderOffset, [now]).then((items) => { + context.items = items; + context.hasMoreFolders = items.length >= limit; + context.hasMore = context.hasMoreFolders; + context.folderOffset += items.length; + return context; + }); + } + } + } export { NoteFolderService }; \ No newline at end of file diff --git a/ReactNativeClient/src/synchronizer.js b/ReactNativeClient/src/synchronizer.js index a2ab69385..970e121e9 100644 --- a/ReactNativeClient/src/synchronizer.js +++ b/ReactNativeClient/src/synchronizer.js @@ -201,6 +201,12 @@ class Synchronizer { return output; } + processSyncActions(syncActions) { + for (let i = 0; i < syncActions.length; i++) { + + } + } + processState_uploadChanges() { let remoteFiles = []; let processedChangeIds = []; @@ -550,12 +556,16 @@ class Synchronizer { return; } + this.state_ = 'started'; + + + // if (!this.api().session()) { // Log.info("Sync: cannot start synchronizer because user is not logged in."); // return; // } - return this.processState('uploadChanges'); + //return this.processState('uploadChanges'); } }