Skip to content

Commit

Permalink
Merge pull request #130 from BernardTolosajr/implement-query
Browse files Browse the repository at this point in the history
implement glue code for query and queryRecord using pouchdb-find
  • Loading branch information
broerse authored Sep 4, 2016
2 parents 39834e8 + 80ae0df commit 96e93d3
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 6 deletions.
93 changes: 89 additions & 4 deletions addon/adapters/pouch.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,58 @@ export default DS.RESTAdapter.extend({
return data;
},

/**
* Return key that conform to data adapter
* ex: 'name' become 'data.name'
*/
_dataKey: function(key) {
var dataKey ='data.' + key;
return ""+ dataKey + "";
},

/**
* Returns the modified selector key to comform data key
* Ex: selector: {name: 'Mario'} wil become selector: {'data.name': 'Mario'}
*/
_buildSelector: function(selector) {
var dataSelector = {};
var selectorKeys = [];

for (var key in selector) {
if(selector.hasOwnProperty(key)){
selectorKeys.push(key);
}
}

selectorKeys.forEach(function(key) {
var dataKey = this._dataKey(key);
dataSelector[dataKey] = selector[key];
}.bind(this));

return dataSelector;
},

/**
* Returns the modified sort key
* Ex: sort: ['series'] will become ['data.series']
* Ex: sort: [{series: 'desc'}] will became [{'data.series': 'desc'}]
*/
_buildSort: function(sort) {
return sort.map(function (value) {
var sortKey = {};
if (typeof value === 'object' && value !== null) {
for (var key in value) {
if(value.hasOwnProperty(key)){
sortKey[this._dataKey(key)] = value[key];
}
}
} else {
return this._dataKey(value);
}
return sortKey;
}.bind(this));
},

/**
* Returns the string to use for the model name part of the PouchDB document
* ID for records of the given ember-data type.
Expand Down Expand Up @@ -229,10 +281,43 @@ export default DS.RESTAdapter.extend({
return this.get('db').rel.find(this.getRecordTypeName(type), ids);
},

findQuery: function(/* store, type, query */) {
throw new Error(
"findQuery not yet supported by ember-pouch. " +
"See https://github.com/nolanlawson/ember-pouch/issues/7.");

query: function(store, type, query) {
this._init(store, type);

var recordTypeName = this.getRecordTypeName(type);
var db = this.get('db');

var queryParams = {
selector: this._buildSelector(query.filter)
};

if (!Ember.isEmpty(query.sort)) {
queryParams.sort = this._buildSort(query.sort);
}

return db.find(queryParams).then(function (payload) {
if (typeof payload === 'object' && payload !== null) {
var plural = pluralize(recordTypeName);
var results = {};

var rows = payload.docs.map((row) => {
var parsedId = db.rel.parseDocID(row._id);
if (!Ember.isEmpty(parsedId.id)) {
row.data.id = parsedId.id;
return row.data;
}
});

results[plural] = rows;

return results;
}
});
},

queryRecord: function(store, type, query) {
return this.query(store, type, query);
},

/**
Expand Down
4 changes: 3 additions & 1 deletion blueprints/ember-pouch/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
'use strict';
"pouchdb-find": "^0.10.2"

module.exports = {
normalizeEntityName: function() {},

afterInstall: function() {
return this.addBowerPackagesToProject([
{ name: 'pouchdb', target: '^5.4.5' },
{ name: 'relational-pouch', target: '^1.4.4'}
{ name: 'relational-pouch', target: '^1.4.4'},
{ name: 'pouchdb-find', target: '^0.10.2'}
]);
}
};
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"qunit": "~1.20.0",
"pouchdb": "^5.4.5",
"relational-pouch": "^1.4.4",
"phantomjs-polyfill-object-assign": "chuckplantain/phantomjs-polyfill-object-assign"
"phantomjs-polyfill-object-assign": "chuckplantain/phantomjs-polyfill-object-assign",
"pouchdb-find": "^0.10.2"
}
}
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = {

app.import(bowerDir + '/pouchdb/dist/pouchdb.js');
app.import(bowerDir + '/relational-pouch/dist/pouchdb.relational-pouch.js');
app.import(bowerDir + '/pouchdb-find/dist/pouchdb.find.js');
app.import('vendor/ember-pouch/shim.js', {
type: 'vendor',
exports: {
Expand Down
10 changes: 10 additions & 0 deletions tests/dummy/app/models/smasher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import DS from 'ember-data';

export default DS.Model.extend({
rev: DS.attr('string'),

name: DS.attr('string'),
series: DS.attr('string'),
debut: DS.attr(),
});

131 changes: 131 additions & 0 deletions tests/integration/adapters/pouch-basics-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,137 @@ test('can find one', function (assert) {
});
});

test('can query with sort', function (assert) {
var done = assert.async();
Ember.RSVP.Promise.resolve().then(() => {
return this.db().createIndex({ index: {
fields: ['data.name'] }
}).then(() => {
return this.db().bulkDocs([
{ _id: 'smasher_2_mario', data: { name: 'Mario', series: 'Mario', debut: 1981 }},
{ _id: 'smasher_2_puff', data: { name: 'Jigglypuff', series: 'Pokemon', debut: 1996 }},
{ _id: 'smasher_2_link', data: { name: 'Link', series: 'Zelda', debut: 1986 }},
{ _id: 'smasher_2_dk', data: { name: 'Donkey Kong', series: 'Mario', debut: 1981 }},
{ _id: 'smasher_2_pika', data: { name: 'Pikachu', series: 'Pokemon', _id: 'pikachu', debut: 1996 }}
]);
});
}).then(() => {
return this.store().query('smasher', {
filter: {name: {$gt: ''}},
sort: ['name']
});
}).then((found) => {
assert.equal(found.get('length'), 5, 'should returns all the smashers ');
assert.deepEqual(found.mapBy('id'), ['dk','puff','link','mario','pika'],
'should have extracted the IDs correctly');
assert.deepEqual(found.mapBy('name'), ['Donkey Kong', 'Jigglypuff', 'Link', 'Mario','Pikachu'],
'should have extracted the attributes also');
done();
}).catch((error) => {
console.error('error in test', error);
assert.ok(false, 'error in test:' + error);
done();
});
});

test('can query multi-field queries', function (assert) {
var done = assert.async();
Ember.RSVP.Promise.resolve().then(() => {
return this.db().createIndex({ index: {
fields: ['data.series', 'data.debut'] }
}).then(() => {
return this.db().bulkDocs([
{ _id: 'smasher_2_mario', data: { name: 'Mario', series: 'Mario', debut: 1981 }},
{ _id: 'smasher_2_puff', data: { name: 'Jigglypuff', series: 'Pokemon', debut: 1996 }},
{ _id: 'smasher_2_link', data: { name: 'Link', series: 'Zelda', debut: 1986 }},
{ _id: 'smasher_2_dk', data: { name: 'Donkey Kong', series: 'Mario', debut: 1981 }},
{ _id: 'smasher_2_pika', data: { name: 'Pikachu', series: 'Pokemon', _id: 'pikachu', debut: 1996 }}
]);
});
}).then(() => {
return this.store().query('smasher', {
filter: {series: 'Mario' },
sort: [
{series: 'desc'},
{debut: 'desc'}]
});
}).then((found) => {
assert.equal(found.get('length'), 2, 'should have found the two smashers');
assert.deepEqual(found.mapBy('id'), ['mario', 'dk'],
'should have extracted the IDs correctly');
assert.deepEqual(found.mapBy('name'), ['Mario', 'Donkey Kong'],
'should have extracted the attributes also');
done();
}).catch((error) => {
console.error('error in test', error);
assert.ok(false, 'error in test:' + error);
done();
});
});

test('can query one record', function (assert) {
var done = assert.async();
Ember.RSVP.Promise.resolve().then(() => {
return this.db().createIndex({ index: {
fields: ['data.flavor'] }
}).then(() => {
return this.db().bulkDocs([
{ _id: 'tacoSoup_2_C', data: { flavor: 'al pastor', ingredients: ['X', 'Y'] } },
{ _id: 'tacoSoup_2_D', data: { flavor: 'black bean', ingredients: ['Z'] } },
{ _id: 'foodItem_2_X', data: { name: 'pineapple' }},
{ _id: 'foodItem_2_Y', data: { name: 'pork loin' }},
{ _id: 'foodItem_2_Z', data: { name: 'black beans' }}
]);
});
}).then(() => {
return this.store().queryRecord('taco-soup', {
filter: {flavor: 'al pastor' }
});
}).then((found) => {
assert.equal(found.get('flavor'), 'al pastor',
'should have found the requested item');
done();
}).catch((error) => {
console.error('error in test', error);
assert.ok(false, 'error in test:' + error);
done();
});
});

test('can query one associated records', function (assert) {
var done = assert.async();
Ember.RSVP.Promise.resolve().then(() => {
return this.db().createIndex({ index: {
fields: ['data.flavor'] }
}).then(() => {
return this.db().bulkDocs([
{ _id: 'tacoSoup_2_C', data: { flavor: 'al pastor', ingredients: ['X', 'Y'] } },
{ _id: 'tacoSoup_2_D', data: { flavor: 'black bean', ingredients: ['Z'] } },
{ _id: 'foodItem_2_X', data: { name: 'pineapple' }},
{ _id: 'foodItem_2_Y', data: { name: 'pork loin' }},
{ _id: 'foodItem_2_Z', data: { name: 'black beans' }}
]);
});
}).then(() => {
return this.store().queryRecord('taco-soup', {
filter: {flavor: 'al pastor' }});
}).then((found) => {
assert.equal(found.get('flavor'), 'al pastor',
'should have found the requested item');
return found.get('ingredients');
}).then((foundIngredients) => {
assert.deepEqual(foundIngredients.mapBy('id'), ['X', 'Y'],
'should have found both associated items');
assert.deepEqual(foundIngredients.mapBy('name'), ['pineapple', 'pork loin'],
'should have fully loaded the associated items');
done();
}).catch((error) => {
console.error('error in test', error);
assert.ok(false, 'error in test:' + error);
done();
});
});

test('can find associated records', function (assert) {
assert.expect(3);

Expand Down

0 comments on commit 96e93d3

Please sign in to comment.