Skip to content

Commit 0e86668

Browse files
committed
Support for firestore
1 parent 2afe227 commit 0e86668

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed

README.md

+39
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,44 @@ Additionaly for elasticsearch6 the number of shards, number of replicas, the ref
294294
});
295295
```
296296
297+
## Firestore
298+
299+
### Setup
300+
301+
#### Library installation
302+
303+
`yarn add @google-cloud/firestore` or `npm install --save @google-cloud/firestore`
304+
305+
#### Options
306+
307+
Use the `firestore` type to support Google's Firestore database, and store your KeyFile in a location accessible by your application.
308+
309+
```javascript
310+
const options = {
311+
repository: {
312+
type: 'firestore',
313+
projectId: 'YOUR_PROJECT_ID',
314+
keyFilename: '/path/to/keyfile.json',
315+
},
316+
};
317+
```
318+
319+
### Find Queries
320+
321+
Find queries in Firestore are not compatible with MongoDb syntax. The query parameter passed to `find` or `findOne` should be an array with the separate query fields as individual elements, as they will be `apply`'d and passed to the `where` function on the `Query` object.
322+
323+
``` javascript
324+
aRepo.find(['aProp', '==', 'aValue'], (err, vm) => {
325+
if (err) {
326+
console.log('Repo find error', err);
327+
return;
328+
}
329+
console.log('Found', vm);
330+
});
331+
```
332+
333+
The queryOptions parameter is also ignored.
334+
297335
298336
# [Release notes](https://github.com/adrai/node-viewmodel/blob/master/releasenotes.md)
299337
@@ -310,6 +348,7 @@ Currently these databases are supported:
310348
8. elasticsearch ([elasticsearch] (https://github.com/elastic/elasticsearch-js))
311349
9. elasticsearch6 ([elasticsearch] (https://github.com/elastic/elasticsearch-js)) - for Elasticsearch 5.x and 6.x
312350
10. dynamodb ([aws-sdk] (https://github.com/aws/aws-sdk-js))
351+
11. firestore ([@google-cloud/firestore] (https://github.com/googleapis/nodejs-firestore))
313352
314353
## own db implementation
315354
You can use your own db implementation by extending this...

lib/databases/firestore.js

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
var util = require('util'),
2+
_ = require('lodash'),
3+
ConcurrencyError = require('../concurrencyError'),
4+
gcFirestore = require('@google-cloud/firestore'),
5+
Repository = require('../base'),
6+
uuid = require('uuid').v4,
7+
ViewModel = Repository.ViewModel;
8+
9+
var collections = [];
10+
11+
function Firestore(options) {
12+
Repository.call(this);
13+
this.options = options || {};
14+
}
15+
16+
util.inherits(Firestore, Repository);
17+
18+
function implementError (callback) {
19+
var err = new Error('Storage method add is not implemented');
20+
if (callback) callback(err);
21+
throw err;
22+
}
23+
24+
_.extend(Firestore.prototype, {
25+
26+
connect: function (callback) {
27+
var self = this;
28+
var options = this.options;
29+
self.db = new gcFirestore(options);
30+
if (callback) callback(null, self);
31+
},
32+
33+
disconnect: function (callback) {
34+
var self = this;
35+
delete self.db;
36+
if (callback) callback(null, self);
37+
},
38+
39+
getNewId: function (callback) {
40+
this.checkConnection();
41+
42+
var id = uuid().toString();
43+
if (callback) callback(null, id);
44+
},
45+
46+
get: function (id, callback) {
47+
this.checkConnection();
48+
49+
if(_.isFunction(id)) {
50+
callback = id;
51+
id = null;
52+
}
53+
54+
if (!id) {
55+
id = uuid().toString();
56+
}
57+
58+
var self = this;
59+
60+
var documentPath = this.collection + '/' + id;
61+
var documentRef = this.db.doc(documentPath);
62+
63+
documentRef.get().then(function (documentSnapshot) {
64+
var vm = new ViewModel(documentSnapshot.data() || { id }, self);
65+
if (documentSnapshot.exists) {
66+
vm.actionOnCommit = 'update';
67+
} else {
68+
vm.actionOnCommit = 'create';
69+
}
70+
callback(null, vm);
71+
});
72+
},
73+
74+
find: function (queryParams, queryOptions, callback) {
75+
this.checkConnection();
76+
77+
// NOTE: Query should be an array, e.g., ['foo', '==', 'bar']
78+
// queryOptions is ignored
79+
var self = this;
80+
81+
var collectionRef = this.db.collection(this.collection);
82+
var query = collectionRef.where.apply(collectionRef, queryParams);
83+
query.get().then(function (querySnapshot) {
84+
var vms = _.map(querySnapshot.docs, function(documentSnapshot) {
85+
var vm = new ViewModel(documentSnapshot.data(), self);
86+
vm.actionOnCommit = 'update';
87+
return vm;
88+
});
89+
callback(null, vms);
90+
});
91+
},
92+
93+
findOne: function (query, queryOptions, callback) {
94+
this.checkConnection();
95+
96+
// NOTE: Query should be an array, e.g., ['foo', '==', 'bar']
97+
var self = this;
98+
var collectionRef = this.db.collection(this.collection);
99+
var query = collectionRef.where.apply(collectionRef, query);
100+
query.limit(1).get().then(function (querySnapshot) {
101+
if (querySnapshot.size == 0) {
102+
callback(null, null);
103+
}
104+
querySnapshot.forEach(function (documentSnapshot) {
105+
var vm = new ViewModel(documentSnapshot.data(), self);
106+
vm.actionOnCommit = 'update';
107+
callback(null, vm);
108+
});
109+
});
110+
},
111+
112+
commit: function (vm, callback) {
113+
this.checkConnection();
114+
115+
if (!vm.actionOnCommit) return callback(new Error('actionOnCommit is not defined!'));
116+
117+
switch(vm.actionOnCommit) {
118+
case 'delete':
119+
var documentPath = this.collection + '/' + vm.id;
120+
var documentRef = this.db.doc(documentPath);
121+
documentRef.delete().then(function () {
122+
callback(null);
123+
});
124+
break;
125+
case 'create':
126+
var documentPath = this.collection + '/' + vm.id;
127+
var documentRef = this.db.doc(documentPath);
128+
documentRef.get().then(function (documentSnapshot) {
129+
if (documentSnapshot.exists) {
130+
return callback(new ConcurrencyError());
131+
}
132+
documentRef.set(vm.attributes).then(function () {
133+
vm.actionOnCommit = 'update';
134+
callback(null, vm);
135+
});
136+
});
137+
break;
138+
case 'update':
139+
var documentPath = this.collection + '/' + vm.id;
140+
var documentRef = this.db.doc(documentPath);
141+
documentRef.get().then(function (documentSnapshot) {
142+
if (!documentSnapshot.exists) {
143+
return callback(new ConcurrencyError());
144+
}
145+
documentRef.update(vm.attributes).then(function () {
146+
vm.actionOnCommit = 'update';
147+
callback(null, vm);
148+
});
149+
});
150+
break;
151+
default:
152+
return callback(new Error('Unknown actionOnCommit: ' + vm.actionOnCommit));
153+
};
154+
},
155+
156+
checkConnection: function (callback) {
157+
if (this.collection) {
158+
return;
159+
}
160+
161+
if (collections.indexOf(this.collectionName) < 0) {
162+
collections.push(this.collectionName)
163+
}
164+
165+
this.collection = this.collectionName;
166+
if (callback) callback(null);
167+
},
168+
169+
clear: function (callback) {
170+
this.checkConnection();
171+
172+
var self = this;
173+
if (!this.collection) {
174+
if (callback) callback(null);
175+
return;
176+
}
177+
178+
var collectionRef = this.db.collection(this.collection);
179+
var query = collectionRef.get().then(function (querySnapshot) {
180+
var writeBatch = self.db.batch();
181+
querySnapshot.forEach(function (documentSnapshot) {
182+
var documentPath = self.collection + '/' + documentSnapshot.id;
183+
var documentRef = self.db.doc(documentPath);
184+
writeBatch.delete(documentRef);
185+
});
186+
writeBatch.commit().then(function () {
187+
if (callback) callback(null);
188+
});
189+
});
190+
},
191+
192+
/**
193+
* NEVER USE THIS FUNCTION!!! ONLY FOR TESTS!
194+
* clears the complete store...
195+
* @param {Function} callback the function that will be called when this action has finished [optional]
196+
*/
197+
clearAll: function (callback) {
198+
implementError(callback);
199+
},
200+
201+
});
202+
203+
module.exports = Firestore;

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"uuid": "3.1.0"
2222
},
2323
"devDependencies": {
24+
"@google-cloud/firestore": "^0.14.1",
2425
"aws-sdk": ">=2.123.0",
2526
"azure-storage": ">=0.3.0",
2627
"cradle": ">=0.6.7",

0 commit comments

Comments
 (0)