From 2102211c2ebebe72558e3529be5e23b5a1b40157 Mon Sep 17 00:00:00 2001 From: Joren l'Ami Date: Fri, 21 Oct 2016 16:59:31 +0200 Subject: [PATCH 01/11] options.dontsave for hasmany --- bower.json | 2 +- dist/pouchdb.relational-pouch.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 786839c..1173025 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "relational-pouch", - "version": "1.4.2", + "version": "1.4.4", "description": "PouchDB, relational-style", "homepage": "https://github.com/nolanlawson/relational-pouch", "authors": [ diff --git a/dist/pouchdb.relational-pouch.js b/dist/pouchdb.relational-pouch.js index 429ca66..ff99297 100644 --- a/dist/pouchdb.relational-pouch.js +++ b/dist/pouchdb.relational-pouch.js @@ -210,6 +210,11 @@ exports.setSchema = function (schema) { obj[field] = obj[field].id; } } else { // hasMany + var relatedType = relationDef[relationType]; + if (relatedType.options && relatedType.options.dontsave) { + delete obj[field]; + return; + } if (obj[field]) { var dependents = obj[field].map(function (dependent) { if (dependent && typeof dependent.id !== 'undefined') { @@ -342,6 +347,12 @@ exports.setSchema = function (schema) { if (typeof relatedType !== 'string') { var relationOptions = relatedType.options; if (relationOptions && relationOptions.async) { + if (relationOptions.dontsave) { + delete obj[field]; + var links = obj.links || {}; + links[field] = field; + obj.links = links; + } return; } relatedType = relatedType.type; From 0bfa7117d54485c34bafb13aab360502a8dfb424 Mon Sep 17 00:00:00 2001 From: Joren l'Ami Date: Thu, 27 Oct 2016 16:17:21 +0200 Subject: [PATCH 02/11] findHasMany for synchronous lookups --- dist/pouchdb.relational-pouch.js | 50 +++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/dist/pouchdb.relational-pouch.js b/dist/pouchdb.relational-pouch.js index ff99297..01c0c50 100644 --- a/dist/pouchdb.relational-pouch.js +++ b/dist/pouchdb.relational-pouch.js @@ -344,15 +344,13 @@ exports.setSchema = function (schema) { var relationDef = typeInfo.relations[field]; var relationType = Object.keys(relationDef)[0]; var relatedType = relationDef[relationType]; + var relationOptions = {}; if (typeof relatedType !== 'string') { - var relationOptions = relatedType.options; - if (relationOptions && relationOptions.async) { - if (relationOptions.dontsave) { - delete obj[field]; - var links = obj.links || {}; - links[field] = field; - obj.links = links; - } + relationOptions = relatedType.options || {}; + if (relationOptions.dontsave) { + delete obj[field]; + } + if (relationOptions.async) { return; } relatedType = relatedType.type; @@ -377,10 +375,20 @@ exports.setSchema = function (schema) { })); } } else { // hasMany - var relatedIds = extend(true, [], obj[field]); - if (typeof relatedIds !== 'undefined' && relatedIds.length) { - subTasks.push(Promise.resolve().then(function () { - + var relatedIdsPromise; + if (relationOptions.dontsave) { + relatedIdsPromise = db.rel.findHasMany(relatedType, relationOptions.inverse, obj._id, {include_docs: false}).then( + function(data) { + return data.docs.map(function(doc) { + return doc._id; + }); + }); + } else { + relatedIdsPromise = Promise.resolve(extend(true, [], obj[field])); + } + + subTasks.push(relatedIdsPromise.then(function (relatedIds) { + if (typeof relatedIds !== 'undefined' && relatedIds.length) { // filter out all ids that are already in the foundObjects for (var i = relatedIds.length - 1; i >= 0; i--) { var relatedId = relatedIds[i]; @@ -401,8 +409,8 @@ exports.setSchema = function (schema) { relatedIds: relatedIds }; } - })); - } + }; + })); } }); return Promise.all(subTasks); @@ -487,6 +495,19 @@ exports.setSchema = function (schema) { return _find(getTypeInfo(type).singular, idOrIds, new collections.Map()); }); } + + function findHasMany(type, belongsToKey, belongsToId) { + var selector = { + '_id': { + '$gt': makeDocID({type: type}), + '$lt': makeDocID({type: type, id: {}}), + }, + }; + selector['data.' + belongsToKey] = belongsToId; + + //only use opts for return ids or whole doc? returning normal documents is not really good + return db.find({ selector: selector }); + } function del(type, obj) { return Promise.resolve().then(function () { @@ -528,6 +549,7 @@ exports.setSchema = function (schema) { db.rel = { save: save, find: find, + findHasMany: findHasMany, del: del, getAttachment: getAttachment, putAttachment: putAttachment, From 59da4e20209153a99b6cfb95e0a2ab8971143ed7 Mon Sep 17 00:00:00 2001 From: Joren l'Ami Date: Tue, 1 Nov 2016 13:07:36 +0100 Subject: [PATCH 03/11] lib changes instead of only dist --- dist/pouchdb.relational-pouch.js | 448 ++++++++++++++------------- dist/pouchdb.relational-pouch.min.js | 2 +- lib/index.js | 51 ++- 3 files changed, 277 insertions(+), 224 deletions(-) diff --git a/dist/pouchdb.relational-pouch.js b/dist/pouchdb.relational-pouch.js index 01c0c50..3b97ca8 100644 --- a/dist/pouchdb.relational-pouch.js +++ b/dist/pouchdb.relational-pouch.js @@ -500,15 +500,15 @@ exports.setSchema = function (schema) { var selector = { '_id': { '$gt': makeDocID({type: type}), - '$lt': makeDocID({type: type, id: {}}), - }, + '$lt': makeDocID({type: type, id: {}}) + } }; selector['data.' + belongsToKey] = belongsToId; //only use opts for return ids or whole doc? returning normal documents is not really good return db.find({ selector: selector }); } - + function del(type, obj) { return Promise.resolve().then(function () { return _del(type, obj); @@ -660,7 +660,7 @@ exports.Promise = Promise; exports.extend = require('pouchdb-extend'); }).call(this,require('_process')) -},{"_process":10,"inherits":6,"pouchdb-extend":7,"pouchdb-promise":8}],4:[function(require,module,exports){ +},{"_process":5,"inherits":6,"pouchdb-extend":7,"pouchdb-promise":8}],4:[function(require,module,exports){ "use strict"; // BEGIN Math.uuid.js @@ -747,78 +747,187 @@ module.exports = uuid; },{}],5:[function(require,module,exports){ -(function (global){ -'use strict'; -var Mutation = global.MutationObserver || global.WebKitMutationObserver; +// shim for using process in browser +var process = module.exports = {}; -var scheduleDrain; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. -{ - if (Mutation) { - var called = 0; - var observer = new Mutation(nextTick); - var element = global.document.createTextNode(''); - observer.observe(element, { - characterData: true - }); - scheduleDrain = function () { - element.data = (called = ++called % 2); - }; - } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') { - var channel = new global.MessageChannel(); - channel.port1.onmessage = nextTick; - scheduleDrain = function () { - channel.port2.postMessage(0); - }; - } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) { - scheduleDrain = function () { +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } - // Create a