1
1
var util = require ( 'util' ) ,
2
2
_ = require ( 'lodash' ) ,
3
+ async = require ( 'async' ) ,
3
4
ConcurrencyError = require ( '../concurrencyError' ) ,
4
5
gcFirestore = require ( '@google-cloud/firestore' ) ,
5
6
Repository = require ( '../base' ) ,
@@ -37,6 +38,59 @@ function firestoreQueryParser(collectionRef, queryParams) {
37
38
return _ . reduce ( params , function ( acc , q ) {
38
39
return acc . where . apply ( acc , q ) ;
39
40
} , collectionRef ) ;
41
+ } ;
42
+
43
+ function emptyCollection ( db , collection , callback ) {
44
+ var collectionRef = db . collection ( collection ) ;
45
+ var query = collectionRef . get ( ) . then ( function ( querySnapshot ) {
46
+ var writeBatch = db . batch ( ) ;
47
+ querySnapshot . forEach ( function ( documentSnapshot ) {
48
+ var documentPath = collection + '/' + documentSnapshot . id ;
49
+ var documentRef = db . doc ( documentPath ) ;
50
+ writeBatch . delete ( documentRef ) ;
51
+ } ) ;
52
+ writeBatch . commit ( ) . then ( function ( ) {
53
+ if ( callback ) callback ( null ) ;
54
+ } ) ;
55
+ } ) ;
56
+ } ;
57
+
58
+ function getPrecondition ( vm ) {
59
+ var precondition = { } ;
60
+ if ( ! _ . isUndefined ( vm . get ( '_updateTime' ) ) ) {
61
+ const time = vm . get ( '_updateTime' ) ;
62
+ if ( _ . isDate ( time ) ) {
63
+ precondition [ 'lastUpdateTime' ] = time . toISOString ( ) ;
64
+ } else if ( _ . isString ( time ) ) {
65
+ precondition [ 'lastUpdateTime' ] = time ;
66
+ }
67
+ }
68
+ return precondition ;
69
+ }
70
+
71
+ function enrichVMWithTimestamps ( vm , documentSnapshot ) {
72
+ _ . isUndefined ( documentSnapshot . readTime ) ? false : vm . set ( '_readTime' , documentSnapshot . readTime ) ;
73
+ _ . isUndefined ( documentSnapshot . createTime ) ? false : vm . set ( '_createTime' , documentSnapshot . createTime ) ;
74
+ _ . isUndefined ( documentSnapshot . updateTime ) ? false : vm . set ( '_updateTime' , documentSnapshot . updateTime ) ;
75
+ return vm ;
76
+ } ;
77
+
78
+ function applyQueryOptions ( query , options ) {
79
+ if ( ! _ . isUndefined ( options ) ) {
80
+ // Apply supported queryOptions
81
+ if ( _ . has ( options , 'limit' ) ) {
82
+ query = query . limit ( options . limit ) ;
83
+ }
84
+ if ( _ . has ( options , 'skip' ) ) {
85
+ query = query . offset ( options . skip ) ;
86
+ }
87
+ if ( _ . has ( options , 'sort' ) ) {
88
+ var sortKey = options . sort . keys [ 0 ] ;
89
+ var direction = options . sort . keys [ sortKey ] == 1 ? 'asc' : 'desc' ;
90
+ query = query . orderBy ( sortKey , direction ) ;
91
+ }
92
+ }
93
+ return query ;
40
94
}
41
95
42
96
_ . extend ( Firestore . prototype , {
@@ -82,6 +136,7 @@ _.extend(Firestore.prototype, {
82
136
83
137
documentRef . get ( ) . then ( function ( documentSnapshot ) {
84
138
var vm = new ViewModel ( documentSnapshot . data ( ) || { id } , self ) ;
139
+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
85
140
if ( documentSnapshot . exists ) {
86
141
vm . actionOnCommit = 'update' ;
87
142
} else {
@@ -92,17 +147,18 @@ _.extend(Firestore.prototype, {
92
147
} ,
93
148
94
149
find : function ( queryParams , queryOptions , callback ) {
95
- // NOTE: queryOptions is ignored
96
-
97
150
this . checkConnection ( ) ;
98
151
99
152
var self = this ;
100
153
var collectionRef = this . db . collection ( this . collection ) ;
101
154
102
155
var query = firestoreQueryParser ( collectionRef , queryParams ) ;
156
+ query = applyQueryOptions ( query , queryOptions ) ;
157
+
103
158
query . get ( ) . then ( function ( querySnapshot ) {
104
159
var vms = _ . map ( querySnapshot . docs , function ( documentSnapshot ) {
105
160
var vm = new ViewModel ( documentSnapshot . data ( ) , self ) ;
161
+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
106
162
vm . actionOnCommit = 'update' ;
107
163
return vm ;
108
164
} ) ;
@@ -118,12 +174,15 @@ _.extend(Firestore.prototype, {
118
174
var collectionRef = this . db . collection ( this . collection ) ;
119
175
120
176
var query = firestoreQueryParser ( collectionRef , queryParams ) ;
177
+ _ . unset ( queryOptions , 'limit' ) ;
178
+ query = applyQueryOptions ( query , queryOptions ) ;
121
179
query . limit ( 1 ) . get ( ) . then ( function ( querySnapshot ) {
122
180
if ( querySnapshot . size == 0 ) {
123
181
callback ( null , null ) ;
124
182
}
125
183
querySnapshot . forEach ( function ( documentSnapshot ) {
126
184
var vm = new ViewModel ( documentSnapshot . data ( ) , self ) ;
185
+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
127
186
vm . actionOnCommit = 'update' ;
128
187
callback ( null , vm ) ;
129
188
} ) ;
@@ -135,12 +194,17 @@ _.extend(Firestore.prototype, {
135
194
136
195
if ( ! vm . actionOnCommit ) return callback ( new Error ( 'actionOnCommit is not defined!' ) ) ;
137
196
197
+ var self = this ;
198
+
138
199
switch ( vm . actionOnCommit ) {
139
200
case 'delete' :
140
201
var documentPath = this . collection + '/' + vm . id ;
141
202
var documentRef = this . db . doc ( documentPath ) ;
142
- documentRef . delete ( ) . then ( function ( ) {
203
+ var precondition = getPrecondition ( vm ) ;
204
+ documentRef . delete ( precondition ) . then ( function ( ) {
143
205
callback ( null ) ;
206
+ } ) . catch ( function ( err ) {
207
+ return callback ( new ConcurrencyError ( ) ) ;
144
208
} ) ;
145
209
break ;
146
210
case 'create' :
@@ -161,12 +225,23 @@ _.extend(Firestore.prototype, {
161
225
var documentRef = this . db . doc ( documentPath ) ;
162
226
documentRef . get ( ) . then ( function ( documentSnapshot ) {
163
227
if ( ! documentSnapshot . exists ) {
164
- return callback ( new ConcurrencyError ( ) ) ;
228
+ documentRef . set ( vm . attributes ) . then ( function ( ) {
229
+ vm . actionOnCommit = 'update' ;
230
+ callback ( null , vm ) ;
231
+ } ) ;
232
+ } else {
233
+ if ( ! _ . isUndefined ( documentSnapshot . updateTime ) &&
234
+ _ . isUndefined ( vm . get ( '_updateTime' ) ) ) {
235
+ return callback ( new ConcurrencyError ( ) ) ;
236
+ }
237
+
238
+ var precondition = getPrecondition ( vm ) ;
239
+ documentRef . update ( vm . attributes , precondition ) . then ( function ( ) {
240
+ self . get ( vm . id , callback ) ;
241
+ } , function ( err ) {
242
+ return callback ( new ConcurrencyError ( ) ) ;
243
+ } ) ;
165
244
}
166
- documentRef . update ( vm . attributes ) . then ( function ( ) {
167
- vm . actionOnCommit = 'update' ;
168
- callback ( null , vm ) ;
169
- } ) ;
170
245
} ) ;
171
246
break ;
172
247
default :
@@ -196,27 +271,14 @@ _.extend(Firestore.prototype, {
196
271
return ;
197
272
}
198
273
199
- var collectionRef = this . db . collection ( this . collection ) ;
200
- var query = collectionRef . get ( ) . then ( function ( querySnapshot ) {
201
- var writeBatch = self . db . batch ( ) ;
202
- querySnapshot . forEach ( function ( documentSnapshot ) {
203
- var documentPath = self . collection + '/' + documentSnapshot . id ;
204
- var documentRef = self . db . doc ( documentPath ) ;
205
- writeBatch . delete ( documentRef ) ;
206
- } ) ;
207
- writeBatch . commit ( ) . then ( function ( ) {
208
- if ( callback ) callback ( null ) ;
209
- } ) ;
210
- } ) ;
274
+ emptyCollection ( this . db , this . collection , callback ) ;
211
275
} ,
212
276
213
- /**
214
- * NEVER USE THIS FUNCTION!!! ONLY FOR TESTS!
215
- * clears the complete store...
216
- * @param {Function } callback the function that will be called when this action has finished [optional]
217
- */
218
277
clearAll : function ( callback ) {
219
- implementError ( callback ) ;
278
+ var self = this ;
279
+ async . each ( collections , function ( col , callback ) {
280
+ emptyCollection ( self . db , col , callback ) ;
281
+ } , callback ) ;
220
282
} ,
221
283
222
284
} ) ;
0 commit comments