-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
merge pouchdb-hoodie-api and pouchdb-hoodie-sync #153
Changes from all commits
e979725
ca27633
c28e2a4
085dcea
a392183
1d723d9
c788b21
f00e758
46c4468
9f1beb9
a27459d
4e0200b
f2ed3bc
a31c393
3473d43
33d2d7b
5a5be71
85aae31
9124eca
baf2205
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
var addOne = require('./helpers/add-one') | ||
var addMany = require('./helpers/add-many') | ||
|
||
module.exports = add | ||
|
||
/** | ||
* adds one or multiple objects to local database | ||
* | ||
* @param {String} prefix optional id prefix | ||
* @param {Object|Object[]} properties Properties of one or | ||
* multiple objects | ||
* @return {Promise} | ||
*/ | ||
function add (state, prefix, properties) { | ||
return Array.isArray(properties) | ||
? addMany(state, properties, prefix) | ||
: addOne(state, properties, prefix) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
module.exports = connect | ||
|
||
var Promise = require('lie') | ||
|
||
/** | ||
* connects local and remote database | ||
* | ||
* @return {Promise} | ||
*/ | ||
function connect (state) { | ||
return Promise.resolve(state.remote) | ||
|
||
.then(function (remote) { | ||
if (state.replication) { | ||
return | ||
} | ||
|
||
state.replication = state.db.sync(remote, { | ||
create_target: true, | ||
live: true, | ||
retry: true | ||
}) | ||
|
||
state.replication.on('error', function (error) { | ||
state.emitter.emit('error', error) | ||
}) | ||
|
||
state.replication.on('change', function (change) { | ||
for (var i = 0; i < change.change.docs.length; i++) { | ||
state.emitter.emit(change.direction, change.change.docs[i]) | ||
} | ||
}) | ||
|
||
state.emitter.emit('connect') | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module.exports = disconnect | ||
|
||
var Promise = require('lie') | ||
|
||
/** | ||
* disconnects local and remote database | ||
* | ||
* @return {Promise} | ||
*/ | ||
function disconnect (state) { | ||
if (state.replication) { | ||
state.replication.cancel() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Afaik There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch! This didn’t cause problems so far, so I don’t think it’s critical, but I created a follow up issues for it so we don’t forget to fix it: #155 |
||
delete state.replication | ||
state.emitter.emit('disconnect') | ||
} | ||
|
||
return Promise.resolve() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
var isntDesignDoc = require('./utils/isnt-design-doc') | ||
|
||
module.exports = findAll | ||
|
||
/** | ||
* finds all existing objects in local database. | ||
* | ||
* @param {String} prefix optional id prefix | ||
* @param {Function} [filter] Function returning `true` for any object | ||
* to be returned. | ||
* @return {Promise} | ||
*/ | ||
|
||
function findAll (state, prefix, filter) { | ||
var options = { | ||
include_docs: true | ||
} | ||
|
||
if (prefix) { | ||
options.startkey = prefix | ||
options.endkey = prefix + '\uffff' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it’s the highest Unicode character, so it makes sure it gives us all keys which start with the prefix string, see http://docs.couchdb.org/en/2.0.0/couchapp/views/collation.html#string-ranges (I don’t know why they use |
||
} | ||
|
||
return state.db.allDocs(options) | ||
|
||
.then(function (res) { | ||
var objects = res.rows | ||
.filter(isntDesignDoc) | ||
.map(function (row) { | ||
return row.doc | ||
}) | ||
|
||
return typeof filter === 'function' | ||
? objects.filter(filter) | ||
: objects | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
var findOrAddOne = require('./helpers/find-or-add-one') | ||
var findOrAddMany = require('./helpers/find-or-add-many') | ||
|
||
module.exports = findOrAdd | ||
|
||
/** | ||
* tries to find object in local database, otherwise creates new one | ||
* with passed properties. | ||
* | ||
* @param {String} prefix optional id prefix | ||
* @param {String|Object|Object[]} idOrObject id or object with `._id` property | ||
* @param {Object} [properties] Optional properties if id passed | ||
* as first option | ||
* @return {Promise} | ||
*/ | ||
function findOrAdd (state, prefix, idOrObjectOrArray, properties) { | ||
return Array.isArray(idOrObjectOrArray) | ||
? findOrAddMany(state, idOrObjectOrArray, prefix) | ||
: findOrAddOne(state, idOrObjectOrArray, properties, prefix) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
var findOne = require('./helpers/find-one') | ||
var findMany = require('./helpers/find-many') | ||
|
||
module.exports = find | ||
|
||
/** | ||
* finds existing object in local database | ||
* | ||
* @param {String} prefix optional id prefix | ||
* @param {String|Object|Object[]} objectsOrIds Id of object or object with | ||
* `._id` property | ||
* @return {Promise} | ||
*/ | ||
function find (state, prefix, objectsOrIds) { | ||
return Array.isArray(objectsOrIds) | ||
? findMany(state, objectsOrIds, prefix) | ||
: findOne(state, objectsOrIds, prefix) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
var clone = require('lodash/clone') | ||
var uuid = require('pouchdb-utils').uuid | ||
|
||
var addTimestamps = require('../utils/add-timestamps') | ||
|
||
module.exports = function addMany (state, docs, prefix) { | ||
docs = docs.map(function (doc) { | ||
doc = clone(doc) | ||
delete doc.hoodie | ||
return addTimestamps(doc) | ||
}) | ||
|
||
if (prefix) { | ||
docs.forEach(function (doc) { | ||
doc._id = prefix + (doc._id || uuid()) | ||
}) | ||
} | ||
|
||
return state.db.bulkDocs(docs) | ||
|
||
.then(function (responses) { | ||
return responses.map(function (response, i) { | ||
if (response instanceof Error) { | ||
if (response.status === 409) { | ||
var conflict = new Error('Object with id "' + docs[i]._id + '" already exists') | ||
conflict.name = 'Conflict' | ||
conflict.status = 409 | ||
return conflict | ||
} else { | ||
return response | ||
} | ||
} | ||
|
||
docs[i]._id = response.id | ||
docs[i]._rev = response.rev | ||
return docs[i] | ||
}) | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
var clone = require('lodash/clone') | ||
var PouchDBErrors = require('pouchdb-errors') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed, thanks 👍 |
||
var Promise = require('lie') | ||
var uuid = require('pouchdb-utils').uuid | ||
|
||
var addTimestamps = require('../utils/add-timestamps') | ||
|
||
module.exports = function addOne (state, doc, prefix) { | ||
if (typeof doc !== 'object') { | ||
return Promise.reject(PouchDBErrors.NOT_AN_OBJECT) | ||
} | ||
|
||
doc = clone(doc) | ||
|
||
if (!doc._id) { | ||
doc._id = uuid() | ||
} | ||
|
||
if (prefix) { | ||
doc._id = prefix + doc._id | ||
} | ||
|
||
delete doc.hoodie | ||
|
||
return state.db.put(addTimestamps(doc)) | ||
|
||
.then(function (response) { | ||
doc._id = response.id | ||
doc._rev = response.rev | ||
return doc | ||
}) | ||
|
||
.catch(function (error) { | ||
if (error.status === 409) { | ||
var conflict = new Error('Object with id "' + doc._id + '" already exists') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are constructing this Error object at different places. Might it be sensible to extract it to a helper function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we had the idea a while ago to have a central repository where we keep all our errors, in an effort to normalise them across all repositories and also client & server: gr2m/milestones#95 I think for now we can keep it as is, it’s just two instances of a missing and conflict error respectively |
||
conflict.name = 'Conflict' | ||
conflict.status = 409 | ||
throw conflict | ||
} else { | ||
throw error | ||
} | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
var toId = require('../utils/to-id') | ||
|
||
module.exports = function findMany (state, idsOrObjects, prefix) { | ||
var ids = idsOrObjects.map(toId) | ||
|
||
if (prefix) { | ||
ids = ids.map(function (id) { | ||
return id.substr(0, prefix.length) === prefix ? id : prefix + id | ||
}) | ||
} | ||
|
||
return state.db.allDocs({keys: ids, include_docs: true}) | ||
|
||
.then(function (response) { | ||
var foundMap = response.rows.reduce(function (map, row) { | ||
map[row.id] = row.doc | ||
return map | ||
}, {}) | ||
var docs = ids.map(function (id) { | ||
var doc = foundMap[id] | ||
if (doc) { | ||
return doc | ||
} | ||
|
||
var missing = new Error('Object with id "' + id + '" is missing') | ||
missing.name = 'Not found' | ||
missing.status = 404 | ||
return missing | ||
}) | ||
|
||
return docs | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
var toId = require('../utils/to-id') | ||
|
||
module.exports = function findOne (state, idOrObject, prefix) { | ||
var id = toId(idOrObject) | ||
|
||
if (prefix && id.substr(0, prefix.length) !== prefix) { | ||
id = prefix + id | ||
} | ||
|
||
return state.db.get(id) | ||
|
||
.catch(function (error) { | ||
if (error.status === 404) { | ||
var missing = new Error('Object with id "' + id + '" is missing') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding my comment about error construction. Might this also be sensible to extract as a helper function if we need it at different places? |
||
missing.name = 'Not found' | ||
missing.status = 404 | ||
throw missing | ||
} else { | ||
throw error | ||
} | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You named it
properties
but the param is namedobjects
. Should we choose the same term to prevent confusion?