Skip to content
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

Add FieldPath support #142

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/firestore-document-snapshot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

var _ = require('./lodash');
var FieldPath = require('./firestore-field-path');

function MockFirestoreDocumentSnapshot (id, ref, data) {
this.id = id;
Expand All @@ -12,10 +13,17 @@ function MockFirestoreDocumentSnapshot (id, ref, data) {
this.exists = this._snapshotdata !== null;
}

MockFirestoreDocumentSnapshot.prototype.get = function (path) {
if (!path || !this.exists) return undefined;
MockFirestoreDocumentSnapshot.prototype.get = function (field) {
if (!field || !this.exists) return undefined;

var parts = path.split('.');
var parts;
if (FieldPath.documentId().isEqual(field)) {
return this.id;
} else if (field instanceof FieldPath) {
parts = _.clone(field._path);
} else {
parts = field.split('.');
}
var part = parts.shift();
var data = this.data();

Expand Down
24 changes: 24 additions & 0 deletions src/firestore-field-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

var _ = require('./lodash');

function MockFirestoreFieldPath() {
this._path = [].slice.call(arguments);
}

MockFirestoreFieldPath.prototype.isEqual = function (other) {
if (other instanceof MockFirestoreFieldPath && _.isEqual(this._path, other._path)) {
return true;
}
return false;
};

MockFirestoreFieldPath.prototype._toString = function () {
return this._path.join('.');
};

MockFirestoreFieldPath.documentId = function () {
return new MockFirestoreFieldPath('_DOCUMENT_ID');
};

module.exports = MockFirestoreFieldPath;
19 changes: 16 additions & 3 deletions src/firestore-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var assert = require('assert');
var Stream = require('stream');
var Promise = require('rsvp').Promise;
var autoId = require('firebase-auto-ids');
var FieldPath = require('./firestore-field-path');
var QuerySnapshot = require('./firestore-query-snapshot');
var Queue = require('./queue').Queue;
var utils = require('./utils');
Expand Down Expand Up @@ -88,8 +89,8 @@ MockFirestoreQuery.prototype.get = function () {
});
});

queryable = _.orderBy(queryable, _.map(self.orderedProperties, function(p) { return 'data.' + p; }), self.orderedDirections);

var orderBy = _.map(self.orderedProperties, getPropertyPath);
queryable = _.orderBy(queryable, orderBy, self.orderedDirections);
queryable.forEach(function(q) {
if (self.limited <= 0 || limit < self.limited) {
results[q.key] = _.cloneDeep(q.data);
Expand Down Expand Up @@ -124,6 +125,7 @@ MockFirestoreQuery.prototype.stream = function () {

MockFirestoreQuery.prototype.where = function (property, operator, value) {
var query;
var path = getPropertyPath(property);

// check if unsupported operator
if (operator !== '==') {
Expand All @@ -133,9 +135,10 @@ MockFirestoreQuery.prototype.where = function (property, operator, value) {
if (_.size(this.data) !== 0) {
var results = {};
_.forEach(this.data, function(data, key) {
var queryable = { data: data, key: key };
switch (operator) {
case '==':
if (_.isEqual(_.get(data, property), value)) {
if (_.isEqual(_.get(queryable, path), value)) {
results[key] = _.cloneDeep(data);
}
break;
Expand Down Expand Up @@ -189,4 +192,14 @@ function extractName(path) {
return ((path || '').match(/\/([^.$\[\]#\/]+)$/) || [null, null])[1];
}

function getPropertyPath(p) {
if (FieldPath.documentId().isEqual(p)) {
return 'key';
} else if (p instanceof FieldPath) {
return 'data.' + p._path.join('.');
} else {
return 'data.' + p;
}
}

module.exports = MockFirestoreQuery;
2 changes: 2 additions & 0 deletions src/firestore.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var assert = require('assert');
var Promise = require('rsvp').Promise;
var CollectionReference = require('./firestore-collection');
var DocumentReference = require('./firestore-document');
var FieldPath = require('./firestore-field-path');
var FieldValue = require('./firestore-field-value');
var Queue = require('./queue').Queue;
var utils = require('./utils');
Expand All @@ -26,6 +27,7 @@ function MockFirestore(path, data, parent, name) {
this.data = _.cloneDeep(data) || null;
}

MockFirestore.FieldPath = FieldPath;
MockFirestore.FieldValue = FieldValue;

MockFirestore.prototype.flush = function (delay) {
Expand Down
2 changes: 2 additions & 0 deletions src/sdk.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var MockAuthentication = require('./auth');
var MockFirebase = require('./firebase');
var MockFirestore = require('./firestore');
var MockFieldPath = require('./firestore-field-path');
var MockFieldValue = require('./firestore-field-value');
var MockMessaging = require('./messaging');
var MockStorage = require('./storage');
Expand Down Expand Up @@ -76,6 +77,7 @@ function MockFirebaseSdk(createDatabase, createAuth, createFirestore, createStor
function MockFirebaseFirestore() {
return createFirestore ? createFirestore() : new MockFirestore();
}
MockFirebaseFirestore.FieldPath = MockFieldPath;
MockFirebaseFirestore.FieldValue = MockFieldValue;

function MockFirebaseStorage() {
Expand Down
52 changes: 50 additions & 2 deletions test/unit/firestore-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ describe('MockFirestoreCollection', function () {
var results5 = collection.where('name_type', '==', 'number').get();
var results6 = collection.where('name_type', '==', 'abc').get();
var results7 = collection.where('value', '==', 3).get();
var results8 = collection.where(Firestore.FieldPath.documentId(), '==', '3').get();
var results9 = collection.where(new Firestore.FieldPath('name'), '==', 3).get();
db.flush();

return Promise.all([
Expand All @@ -224,7 +226,9 @@ describe('MockFirestoreCollection', function () {
expect(results4).to.eventually.have.property('size').to.equal(3),
expect(results5).to.eventually.have.property('size').to.equal(3),
expect(results6).to.eventually.have.property('size').to.equal(0),
expect(results7).to.eventually.have.property('size').to.equal(0)
expect(results7).to.eventually.have.property('size').to.equal(0),
expect(results8).to.eventually.have.property('size').to.equal(1),
expect(results9).to.eventually.have.property('size').to.equal(1)
]);
});

Expand Down Expand Up @@ -259,11 +263,13 @@ describe('MockFirestoreCollection', function () {
it('allow using complex path', function() {
var results1 = collection.where('complex.name', '==', 'a').get();
var results2 = collection.where('complex.name', '==', 1).get();
var results3 = collection.where(new Firestore.FieldPath('complex', 'name'), '==', 1).get();
db.flush();

return Promise.all([
expect(results1).to.eventually.have.property('size').to.equal(1),
expect(results2).to.eventually.have.property('size').to.equal(1)
expect(results2).to.eventually.have.property('size').to.equal(1),
expect(results3).to.eventually.have.property('size').to.equal(1)
]);
});
});
Expand Down Expand Up @@ -332,6 +338,48 @@ describe('MockFirestoreCollection', function () {
done();
}).catch(done);
});

it('returns documents ordered by name using FieldPath', function(done) {
var results1 = collection.orderBy(new Firestore.FieldPath('name')).get();
var results2 = collection.orderBy(new Firestore.FieldPath('name'), 'desc').get();
db.flush();

Promise.all([results1, results2]).then(function(snaps) {
var names = [];
snaps[0].forEach(function(doc) {
names.push(doc.data().name);
});
expect(names).to.deep.equal([1, 2, 3, 'a', 'b', 'c']);

names = [];
snaps[1].forEach(function(doc) {
names.push(doc.data().name);
});
expect(names).to.deep.equal([1, 2, 3, 'c', 'b', 'a']);
done();
}).catch(done);
});

it('returns documents ordered by id', function(done) {
var results1 = collection.orderBy(Firestore.FieldPath.documentId()).get();
var results2 = collection.orderBy(Firestore.FieldPath.documentId(), 'desc').get();
db.flush();

Promise.all([results1, results2]).then(function(snaps) {
var names = [];
snaps[0].forEach(function(doc) {
names.push(doc.data().name);
});
expect(names).to.deep.equal([1, 2, 3, 'a', 'b', 'c']);

names = [];
snaps[1].forEach(function(doc) {
names.push(doc.data().name);
});
expect(names).to.deep.equal([1, 2, 3, 'c', 'b', 'a']);
done();
}).catch(done);
});
});

describe('#limit', function () {
Expand Down
18 changes: 18 additions & 0 deletions test/unit/firestore-document-snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ describe('DocumentSnapshot', function () {
};
expect(new Snapshot('docid', ref, data).get('hello')).to.equal(123);
});
it('returns data if field path exists', function () {
var data = {
hello: 123
};
expect(new Snapshot('docid', ref, data).get(new Firestore.FieldPath('hello'))).to.equal(123);
});
it('returns data with complex path', function () {
var data = {
hello: {
Expand All @@ -97,6 +103,18 @@ describe('DocumentSnapshot', function () {
};
expect(new Snapshot('docid', ref, data).get('hello.world')).to.equal(123);
});
it('returns data with complex field path', function () {
var data = {
hello: {
world: 123
}
};
expect(new Snapshot('docid', ref, data).get(new Firestore.FieldPath('hello', 'world'))).to.equal(123);
});
it('returns document id', function () {
var data = {};
expect(new Snapshot('docid', ref, data).get(Firestore.FieldPath.documentId())).to.equal('docid');
});
});

describe('#ref', function () {
Expand Down
42 changes: 42 additions & 0 deletions test/unit/firestore-field-path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';

var chai = require('chai');
var sinon = require('sinon');
var Promise = require('rsvp').Promise;

chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));

var expect = chai.expect;
var _ = require('../../src/lodash');
var FieldPath = require('../../src/firestore-field-path');

describe('FieldPath', function () {
describe('constructor', function () {
it('should have path to "name"', function () {
expect(new FieldPath('name')).to.have.property('_path').to.deep.equal(['name']);
});
});
describe('#documentId', function () {
it('should be a function', function () {
expect(FieldPath.documentId).to.be.a('function');
});
it('should return FieldPath', function () {
expect(FieldPath.documentId()).to.be.instanceof(FieldPath);
});
it('should have path to "documentId"', function () {
expect(FieldPath.documentId()).to.have.property('_path').to.deep.equal(['_DOCUMENT_ID']);
});
});

describe('#isEqual', function () {
it('should be a function', function () {
expect(FieldPath.documentId().isEqual).to.be.a('function');
});
it('should work with FieldPath.delete()', function () {
expect(FieldPath.documentId().isEqual(undefined)).to.equal(false);
expect(FieldPath.documentId().isEqual(null)).to.equal(false);
expect(FieldPath.documentId().isEqual(FieldPath.documentId())).to.equal(true);
});
});
});
4 changes: 4 additions & 0 deletions test/unit/sdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ describe('MockFirebaseSdk', function () {
it('FieldValue.serverTimestamp', function () {
expect(firebase.firestore.FieldValue.serverTimestamp).to.be.a('function');
});

it('FieldPath.documentId', function () {
expect(firebase.firestore.FieldPath.documentId).to.be.a('function');
});
});

describe('#auth', function() {
Expand Down