Merge lp:~uonedb-qt/u1db-qt/nativeQmlExperiment into lp:u1db-qt

Proposed by Christian Dywan on 2015-01-08
Status: Work in progress
Proposed branch: lp:~uonedb-qt/u1db-qt/nativeQmlExperiment
Merge into: lp:u1db-qt
Diff against target: 657 lines (+556/-8)
11 files modified
.bzrignore (+1/-0)
examples/shop/shop.qml (+160/-0)
modules/U1db/CMakeLists.txt (+4/-1)
modules/U1db/Database.qml (+50/-0)
modules/U1db/Document.qml (+37/-0)
modules/U1db/Query.qml (+108/-0)
modules/U1db/ThreadedModel.qml (+68/-0)
modules/U1db/plugin.cpp (+20/-7)
modules/U1db/plugin.h (+2/-0)
modules/U1db/plugin.qrc (+9/-0)
modules/U1db/worker.js (+97/-0)
To merge this branch: bzr merge lp:~uonedb-qt/u1db-qt/nativeQmlExperiment
Reviewer Review Type Date Requested Status
U1DB Qt developers 2015-01-08 Pending
Review via email: mp+245867@code.launchpad.net

Description of the change

Inspired by http://doc.qt.io/qt-5/qml-qtqml-models-listmodel.html#using-threaded-list-models-with-workerscript and motivated by the complexity of C++-based model implementation and performance implications of doing it wrongly.
For the Python API see https://pythonhosted.org/u1db/high-level-api.html

To post a comment you must log in.
123. By Christian Dywan on 2015-01-09

Implement index keys and use them for categories

Also, Index is now gone from the API.

124. By Christian Dywan on 2015-01-21

Properly load new U1db 1.1 types from resources

Unmerged revisions

124. By Christian Dywan on 2015-01-21

Properly load new U1db 1.1 types from resources

123. By Christian Dywan on 2015-01-09

Implement index keys and use them for categories

Also, Index is now gone from the API.

122. By Christian Dywan on 2015-01-08

vörc in brokreß

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2013-03-28 07:57:31 +0000
3+++ .bzrignore 2015-01-21 16:04:15 +0000
4@@ -21,3 +21,4 @@
5 documentation/u1db-qt.qhcp
6 documentation/u1db-qt.qhp
7 aDatabase*
8+_build
9
10=== added directory 'examples/shop'
11=== added file 'examples/shop/shop.qml'
12--- examples/shop/shop.qml 1970-01-01 00:00:00 +0000
13+++ examples/shop/shop.qml 2015-01-21 16:04:15 +0000
14@@ -0,0 +1,160 @@
15+/*
16+ * Copyright (C) 2015 Canonical, Ltd.
17+ *
18+ * Authors:
19+ * Christian Dywan <christian.dywan@canonical.com>
20+ *
21+ * This program is free software; you can redistribute it and/or modify
22+ * it under the terms of the GNU Lesser General Public License as published by
23+ * the Free Software Foundation; version 3.
24+ *
25+ * This program is distributed in the hope that it will be useful,
26+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28+ * GNU Lesser General Public License for more details.
29+ *
30+ * You should have received a copy of the GNU Lesser General Public License
31+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32+ */
33+
34+import QtQuick 2.0
35+import Ubuntu.Components 1.1
36+import Ubuntu.Components.ListItems 1.0 as ListItem
37+import U1db 1.1 as U1db
38+
39+MainView {
40+ width: units.gu(60)
41+ height: units.gu(80)
42+ useDeprecatedToolbar: false
43+
44+ U1db.Database {
45+ id: db
46+
47+ U1db.Document {
48+ docId: "mrFluffy"
49+ contents: { 'nom': "Mr.Fluffy", 'cat': "Cat", 'act': true }
50+ }
51+
52+ U1db.Document {
53+ docId: "sponge"
54+ contents: { 'nom': "Sponge", 'cat': "Kitchen", 'act': true }
55+ }
56+ U1db.Document {
57+ docId: "towel"
58+ contents: { 'nom': "Towel", 'cat': "Kitchen", 'act': true }
59+ }
60+
61+ Component.onCompleted: {
62+ for (var i = 0; i < 9; i++)
63+ db.putDoc( {nom: 'Felis Catus %1'.arg(i), cat: 'Cat'}, 'cat%1'.arg(i) )
64+ for (var i = 0; i < 9; i++)
65+ db.putDoc( {nom: 'Cloth %1'.arg(i), cat: 'Kitchen'}, 'kitchen%1'.arg(i) )
66+ // For the sake of testing modified and deleted documents
67+ db.putDoc( {nom: 'Axe', cat: 'Garage'}, 'axe' )
68+ db.putDoc( {}, 'axe' )
69+ db.putDoc( {}, 'docThatNeverWas' )
70+ db.putDoc( {nom: 'Torch', cat: 'Garage', act: true }, 'hammer' )
71+ db.putDoc( {nom: 'Hammer', cat: 'Tools', act: true }, 'hammer' )
72+ }
73+
74+ U1db.Query {
75+ id: active
76+ query: { 'act': true }
77+ }
78+
79+ U1db.Query {
80+ id: categorized
81+ query: { 'cat': nomPage.cat }
82+ }
83+ }
84+
85+ PageStack {
86+ id: stack
87+ Component.onCompleted: push(listPage)
88+
89+ Page {
90+ id: nomPage
91+ visible: active // Work-around PageStack limitation
92+ property string cat
93+ UbuntuListView {
94+ anchors.fill: parent
95+ model: categorized
96+ delegate: ListItem.Standard {
97+ text: nom
98+ control: CheckBox {
99+ checked: act
100+ }
101+ }
102+ }
103+ }
104+
105+ Page {
106+ id: catPage
107+ title: "Pick your poison"
108+ visible: active // Work-around PageStack limitation
109+ UbuntuListView {
110+ anchors.fill: parent
111+ model: categorized.keys
112+ delegate: ListItem.Standard {
113+ progression: true
114+ text: modelData
115+ onClicked: stack.push(nomPage, { title: modelData, cat: modelData })
116+ }
117+ }
118+ }
119+
120+ Page {
121+ id: listPage
122+ title: "Selected items"
123+ visible: active // Work-around PageStack limitation
124+ property string state: ""
125+ head.contents: state == 'search' ? searchField : null
126+
127+ property Item searchField: TextField {
128+ width: parent ? parent.width : 0
129+ }
130+ head.backAction: Action {
131+ iconName: 'back'
132+ onTriggered: listPage.state = ''
133+ visible: listPage.state != ''
134+ }
135+ head.actions: [
136+ Action {
137+ iconName: 'search'
138+ onTriggered: listPage.state = 'search'
139+ visible: listPage.state != 'search'
140+ },
141+ Action {
142+ iconName: 'list-add'
143+ onTriggered: stack.push(catPage)
144+ }
145+ ]
146+
147+ UbuntuListView {
148+ model: SortFilterModel {
149+ model: active
150+ sort.property: 'cat'
151+ // Work-around for sort.property not correctly re-sorting
152+ onCountChanged: sort.property = 'cat'
153+ filter.property: "nom"
154+ filter.pattern: listPage.state == 'search' ? RegExp(listPage.searchField.text, "i") : RegExp()
155+ }
156+
157+ anchors.fill: parent
158+ delegate: ListItem.Subtitled {
159+ text: nom
160+ width: parent.width
161+ height: units.gu(4)
162+ }
163+
164+ section.property: "cat"
165+ section.criteria: ViewSection.FullString
166+ section.delegate: ListItem.Header {
167+ text: section
168+ width: parent.width
169+ height: units.gu(4)
170+ }
171+ }
172+ }
173+ }
174+}
175
176=== modified file 'modules/U1db/CMakeLists.txt'
177--- modules/U1db/CMakeLists.txt 2013-08-08 10:11:39 +0000
178+++ modules/U1db/CMakeLists.txt 2015-01-21 16:04:15 +0000
179@@ -7,8 +7,11 @@
180 exec_program(${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML" OUTPUT_VARIABLE QT_IMPORTS_DIR)
181 file(TO_CMAKE_PATH "${QT_IMPORTS_DIR}" QT_IMPORTS_DIR)
182
183+qt5_add_resources(U1DBPlugin_RCS plugin.qrc)
184+
185 set(U1DBPlugin_SRCS
186 plugin.cpp
187+ ${U1DBPlugin_RCS}
188 )
189
190 include_directories(
191@@ -50,7 +53,7 @@
192 add_custom_command(
193 TARGET U1DBPlugin
194 POST_BUILD
195- COMMAND "qmlplugindump" "U1db" "1.0" "${CMAKE_BINARY_DIR}/modules" ">" "plugins.qmltypes"
196+ COMMAND "qmlplugindump" "U1db" "1.1" "${CMAKE_BINARY_DIR}/modules" ">" "plugins.qmltypes"
197 WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
198 )
199
200
201=== added file 'modules/U1db/Database.qml'
202--- modules/U1db/Database.qml 1970-01-01 00:00:00 +0000
203+++ modules/U1db/Database.qml 2015-01-21 16:04:15 +0000
204@@ -0,0 +1,50 @@
205+/*
206+ * Copyright (C) 2015 Canonical, Ltd.
207+ *
208+ * Authors:
209+ * Christian Dywan <christian.dywan@canonical.com>
210+ *
211+ * This program is free software; you can redistribute it and/or modify
212+ * it under the terms of the GNU Lesser General Public License as published by
213+ * the Free Software Foundation; version 3.
214+ *
215+ * This program is distributed in the hope that it will be useful,
216+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
217+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
218+ * GNU Lesser General Public License for more details.
219+ *
220+ * You should have received a copy of the GNU Lesser General Public License
221+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
222+ */
223+
224+import QtQuick 2.0
225+
226+ThreadedModel {
227+ id: db
228+ objectName: "U1DbDatabase"
229+ default property alias __children: db.__documents
230+ property list<QtObject> __documents
231+ Component.onCompleted: {
232+ for (var i in __documents) {
233+ var doc = __documents[i]
234+ if (!doc.__database)
235+ doc.__database = db
236+ }
237+ }
238+
239+ onItemAdded: docLoaded(item.docId, item)
240+ onItemModified: docChanged(item.docId, item)
241+ signal docLoaded(string docId, var content)
242+ signal docChanged(string docId, var content)
243+
244+ function putDoc(contents, docId) {
245+ var doc = contents
246+ if (docId)
247+ doc.docId = docId
248+ __worker.schedule('putDoc', { contents: doc })
249+ }
250+
251+ function deleteDoc(docId) {
252+ __worker.schedule('putDoc', { contents: { docId: docId } })
253+ }
254+}
255
256=== added file 'modules/U1db/Document.qml'
257--- modules/U1db/Document.qml 1970-01-01 00:00:00 +0000
258+++ modules/U1db/Document.qml 2015-01-21 16:04:15 +0000
259@@ -0,0 +1,37 @@
260+/*
261+ * Copyright (C) 2015 Canonical, Ltd.
262+ *
263+ * Authors:
264+ * Christian Dywan <christian.dywan@canonical.com>
265+ *
266+ * This program is free software; you can redistribute it and/or modify
267+ * it under the terms of the GNU Lesser General Public License as published by
268+ * the Free Software Foundation; version 3.
269+ *
270+ * This program is distributed in the hope that it will be useful,
271+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
272+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
273+ * GNU Lesser General Public License for more details.
274+ *
275+ * You should have received a copy of the GNU Lesser General Public License
276+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
277+ */
278+
279+import QtQuick 2.0
280+
281+Item {
282+ objectName: "U1DbDatabase"
283+ property string docId
284+ property var contents
285+
286+ property var __database: parent
287+ on__DatabaseChanged: __applyDefaults()
288+ onDocIdChanged: __applyDefaults()
289+ onContentsChanged: __applyDefaults()
290+ function __applyDefaults() {
291+ if (__database && docId && contents) {
292+ // console.debug("Updating %1".arg(docId))
293+ __database.putDoc(contents, docId)
294+ }
295+ }
296+}
297
298=== added file 'modules/U1db/Query.qml'
299--- modules/U1db/Query.qml 1970-01-01 00:00:00 +0000
300+++ modules/U1db/Query.qml 2015-01-21 16:04:15 +0000
301@@ -0,0 +1,108 @@
302+/*
303+ * Copyright (C) 2015 Canonical, Ltd.
304+ *
305+ * Authors:
306+ * Christian Dywan <christian.dywan@canonical.com>
307+ *
308+ * This program is free software; you can redistribute it and/or modify
309+ * it under the terms of the GNU Lesser General Public License as published by
310+ * the Free Software Foundation; version 3.
311+ *
312+ * This program is distributed in the hope that it will be useful,
313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
314+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
315+ * GNU Lesser General Public License for more details.
316+ *
317+ * You should have received a copy of the GNU Lesser General Public License
318+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
319+ */
320+
321+import QtQuick 2.0
322+
323+ThreadedModel {
324+ objectName: "U1DbQuery"
325+ property var query
326+
327+ property var __database: parent
328+ on__DatabaseChanged: __invalidateQuery()
329+
330+ property var keys
331+ property var __fields
332+ onQueryChanged: __invalidateQuery()
333+ function __invalidateQuery() {
334+ // console.debug('invalidateQuery %1'.arg(JSON.stringify(query)))
335+ __invalidate()
336+ }
337+
338+ function __invalidate() {
339+ if (!__database || !query)
340+ return
341+
342+ keys = []
343+ var expression = Object.keys(query)
344+ __fields = []
345+ for (var i in expression)
346+ __fields.push(expression[i])
347+ // console.debug("Fields %1".arg(JSON.stringify(__fields)))
348+
349+ clear()
350+ // console.debug("Resetting model: %1 in database".arg(__database.count))
351+ for (var i = 0; i < __database.count; i++) {
352+ var doc = __database.get(i)
353+ __mayCache(doc)
354+ }
355+ }
356+
357+ function __matches(doc) {
358+ var match = true
359+ var newKeys = false
360+ var __keys = keys
361+ for (var i in __fields) {
362+ var field = __fields[i]
363+ if (query[field] != '*' && doc[field] != query[field]) {
364+ // console.debug('Skipping %1'.arg(JSON.stringify(doc)))
365+ match = false
366+ }
367+ if (__keys.indexOf(doc[field]) == -1 && doc[field] !== undefined) {
368+ __keys.push(doc[field])
369+ newKeys = true
370+ }
371+ }
372+ if (newKeys) {
373+ // console.debug('Keys: %1'.arg(JSON.stringify(__keys)))
374+ keys = __keys
375+ }
376+ return match
377+ }
378+
379+ function __updateDoc(doc, docId) {
380+ if (__matches(doc))
381+ set(doc);
382+ else
383+ remove(doc);
384+ }
385+
386+ function __mayCache(doc, docId) {
387+ if (!__matches(doc))
388+ return false
389+
390+ // New hash to avoid passing a QtObject
391+ var __doc = {}
392+ for (var i in doc) {
393+ if (i == 'objectName')
394+ continue
395+ __doc[i] = doc[i]
396+ }
397+ if (docId)
398+ __doc.docId = docId
399+ // console.debug('Caching %1'.arg(JSON.stringify(__doc)))
400+ __worker.schedule('cache', { contents: __doc });
401+ return true
402+ }
403+
404+ property var __databaseConnections: Connections {
405+ target: __database
406+ onDocLoaded: __mayCache(content, docId)
407+ onDocChanged: __updateDoc(content, docId)
408+ }
409+}
410
411=== added file 'modules/U1db/ThreadedModel.qml'
412--- modules/U1db/ThreadedModel.qml 1970-01-01 00:00:00 +0000
413+++ modules/U1db/ThreadedModel.qml 2015-01-21 16:04:15 +0000
414@@ -0,0 +1,68 @@
415+/*
416+ * Copyright (C) 2015 Canonical, Ltd.
417+ *
418+ * Authors:
419+ * Christian Dywan <christian.dywan@canonical.com>
420+ *
421+ * This program is free software; you can redistribute it and/or modify
422+ * it under the terms of the GNU Lesser General Public License as published by
423+ * the Free Software Foundation; version 3.
424+ *
425+ * This program is distributed in the hope that it will be useful,
426+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
427+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
428+ * GNU Lesser General Public License for more details.
429+ *
430+ * You should have received a copy of the GNU Lesser General Public License
431+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
432+ */
433+
434+import QtQuick 2.0
435+
436+ListModel {
437+ id: model
438+ objectName: "ThreadedModel"
439+
440+ signal itemAdded(var item)
441+ signal itemModified(var item)
442+
443+ function set(item) {
444+ __worker.schedule('set', { contents: item })
445+ }
446+
447+ function remove(item) {
448+ __worker.schedule('remove', { contents: item })
449+ }
450+
451+ function clear() {
452+ __worker.schedule('clear', {})
453+ }
454+
455+ property var __worker: WorkerScript {
456+ source: "worker.js"
457+ function schedule(task, message) {
458+ if (!task) {
459+ console.warn("Can't schedule %1 without task".arg(message))
460+ return
461+ }
462+
463+ if (!message) {
464+ console.warn("Can't schedule %1 without a message".arg(task))
465+ return
466+ }
467+
468+ message.task = task
469+ message.model = model
470+ message.objectName = model.objectName
471+ sendMessage(message)
472+ }
473+ onMessage: {
474+ if (messageObject.reply == 'itemAdded')
475+ itemAdded(messageObject.item)
476+ else if (messageObject.reply == 'itemModified')
477+ itemModified(messageObject.item)
478+ else
479+ console.warn("Unexpected reply %1".arg(messageObject))
480+ }
481+ }
482+}
483
484=== modified file 'modules/U1db/plugin.cpp'
485--- modules/U1db/plugin.cpp 2013-05-02 19:52:10 +0000
486+++ modules/U1db/plugin.cpp 2015-01-21 16:04:15 +0000
487@@ -25,14 +25,27 @@
488 #include "plugin.h"
489 #include <qqml.h>
490
491-QT_USE_NAMESPACE_U1DB
492-
493 void U1DBPlugin::registerTypes(const char *uri)
494 {
495- qmlRegisterType<Database>(uri, 1, 0, "Database");
496- qmlRegisterType<Document>(uri, 1, 0, "Document");
497- qmlRegisterType<Index>(uri, 1, 0, "Index");
498- qmlRegisterType<Query>(uri, 1, 0, "Query");
499- qmlRegisterType<Synchronizer>(uri, 1, 0, "Synchronizer");
500+ Q_INIT_RESOURCE(plugin);
501+
502+ qmlRegisterType<QT_PREPEND_NAMESPACE_U1DB(Database)>(uri, 1, 0, "Database");
503+ qmlRegisterType<QT_PREPEND_NAMESPACE_U1DB(Document)>(uri, 1, 0, "Document");
504+ qmlRegisterType<QT_PREPEND_NAMESPACE_U1DB(Index)>(uri, 1, 0, "Index");
505+ qmlRegisterType<QT_PREPEND_NAMESPACE_U1DB(Query)>(uri, 1, 0, "Query");
506+ qmlRegisterType<QT_PREPEND_NAMESPACE_U1DB(Synchronizer)>(uri, 1, 0, "Synchronizer");
507+
508+ if (qmlRegisterType(QUrl("qrc:/Database.qml"), uri, 1, 1, "Database")) {
509+ qmlRegisterType(QUrl("qrc:/Document.qml"), uri, 1, 1, "Document");
510+ qmlRegisterType(QUrl("qrc:/Query.qml"), uri, 1, 1, "Query");
511+ } else {
512+ qCritical() << QString("Type registration failed for 1.1!");
513+ }
514+}
515+
516+void U1DBPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
517+{
518+ QQmlExtensionPlugin::initializeEngine(engine, uri);
519+ engine->addImportPath(QStringLiteral("qrc:/"));
520 }
521
522
523=== modified file 'modules/U1db/plugin.h'
524--- modules/U1db/plugin.h 2013-02-25 12:49:54 +0000
525+++ modules/U1db/plugin.h 2015-01-21 16:04:15 +0000
526@@ -20,6 +20,7 @@
527 #ifndef U1DB_PLUGIN_H
528 #define U1DB_PLUGIN_H
529
530+#include <QtQml/QQmlEngine>
531 #include <QQmlExtensionPlugin>
532
533 class U1DBPlugin : public QQmlExtensionPlugin
534@@ -28,6 +29,7 @@
535 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
536 public:
537 void registerTypes(const char *uri);
538+ void initializeEngine(QQmlEngine *engine, const char *uri);
539 };
540
541
542
543=== added file 'modules/U1db/plugin.qrc'
544--- modules/U1db/plugin.qrc 1970-01-01 00:00:00 +0000
545+++ modules/U1db/plugin.qrc 2015-01-21 16:04:15 +0000
546@@ -0,0 +1,9 @@
547+<!DOCTYPE RCC><RCC version="1.0">
548+<qresource prefix="/">
549+ <file>Database.qml</file>
550+ <file>Document.qml</file>
551+ <file>Query.qml</file>
552+ <file>ThreadedModel.qml</file>
553+ <file>worker.js</file>
554+</qresource>
555+</RCC>
556
557=== added file 'modules/U1db/worker.js'
558--- modules/U1db/worker.js 1970-01-01 00:00:00 +0000
559+++ modules/U1db/worker.js 2015-01-21 16:04:15 +0000
560@@ -0,0 +1,97 @@
561+function append(message) {
562+ // console.debug("append(%1) ← %2".arg(message.objectName).arg(JSON.stringify(message.contents)))
563+
564+ message.model.append(message.contents)
565+ message.model.sync()
566+ WorkerScript.sendMessage({ reply: 'itemAdded', item: message.contents })
567+}
568+
569+function uuid() {
570+ // RFC4122 http://www.ietf.org/rfc/rfc4122.txt
571+ var d = Date.now()
572+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
573+ var r = (d + Math.random()*16)%16 | 0
574+ d = Math.floor(d/16)
575+ return (c=='x' ? r : (r&0x3|0x8)).toString(16)
576+ })
577+};
578+
579+function lookupIndex(model, doc) {
580+ for (var i = 0; i < model.count; i++) {
581+ var contents = model.get(i)
582+ if (contents.docId == doc.docId)
583+ return i
584+ }
585+ return -1
586+}
587+
588+function set(model, doc, index) {
589+ var index = index == -1 ? lookupIndex(model, doc) : index
590+ if (index == -1) {
591+ console.log('Can\'t set non-existing %1'.arg(doc.docId))
592+ return
593+ }
594+ // console.debug('Set %1 (%2)'.arg(index).arg(doc.docId))
595+ model.set(index, doc)
596+ model.sync()
597+}
598+
599+function remove(model, doc) {
600+ var index = lookupIndex(model, doc)
601+ if (index == -1) {
602+ // console.debug('Can\'t remove non-existing %1'.arg(doc.docId))
603+ return
604+ }
605+ // console.debug('Remove %1 (%2)'.arg(index).arg(doc.docId))
606+ model.remove(index)
607+ model.sync()
608+}
609+
610+WorkerScript.onMessage = function(message) {
611+ if (message.task == 'clear') {
612+ message.model.clear()
613+ } else if (message.task == 'set') {
614+ set(message.model, message.contents, -1)
615+ } else if (message.task == 'remove') {
616+ remove(message.model, message.contents)
617+ } else if (message.task == "putDoc") {
618+ if (!message.contents) {
619+ console.error("Message %1 with no contents".arg(JSON.stringify(message)))
620+ return
621+ }
622+
623+ // Empty contents means delete
624+ if (message.contents.docId && message.contents == { docId: message.contents.docId }) {
625+ // TODO: Delete on disk
626+ remove(message.model, message.contents)
627+ return
628+ }
629+
630+ var index = message.contents.docId ? lookupIndex(message.model, message.contents) : -1
631+ if (index > -1) {
632+ set(message.model, message.contents, index)
633+ WorkerScript.sendMessage({ reply: 'itemModified', item: message.contents, index: index })
634+ // TODO: Save to disk
635+ return
636+ }
637+
638+ if (!message.contents.docId)
639+ message.contents.docId = uuid()
640+ else if (!message.contents.docId.match(/^[a-zA-Z0-9.%_-]+$/)) {
641+ console.error("Can't putDoc %1 with invalid docId %2".arg(JSON.stringify(message)).arg(docId))
642+ return
643+ }
644+
645+ append(message)
646+ // TODO: Save to disk
647+ } else if (message.task == "cache") {
648+ if (!message.contents) {
649+ console.warn("Message %1 with no contents".arg(JSON.stringify(message)))
650+ return
651+ }
652+
653+ append(message)
654+ } else {
655+ console.warn("Unexpected message %1".arg(message))
656+ }
657+}

Subscribers

People subscribed via source and target branches

to all changes: