11var util = require ( 'util' ) ,
22 _ = require ( 'lodash' ) ,
3+ async = require ( 'async' ) ,
34 ConcurrencyError = require ( '../concurrencyError' ) ,
45 gcFirestore = require ( '@google-cloud/firestore' ) ,
56 Repository = require ( '../base' ) ,
@@ -37,6 +38,59 @@ function firestoreQueryParser(collectionRef, queryParams) {
3738 return _ . reduce ( params , function ( acc , q ) {
3839 return acc . where . apply ( acc , q ) ;
3940 } , 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 ;
4094}
4195
4296_ . extend ( Firestore . prototype , {
@@ -82,6 +136,7 @@ _.extend(Firestore.prototype, {
82136
83137 documentRef . get ( ) . then ( function ( documentSnapshot ) {
84138 var vm = new ViewModel ( documentSnapshot . data ( ) || { id } , self ) ;
139+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
85140 if ( documentSnapshot . exists ) {
86141 vm . actionOnCommit = 'update' ;
87142 } else {
@@ -92,17 +147,18 @@ _.extend(Firestore.prototype, {
92147 } ,
93148
94149 find : function ( queryParams , queryOptions , callback ) {
95- // NOTE: queryOptions is ignored
96-
97150 this . checkConnection ( ) ;
98151
99152 var self = this ;
100153 var collectionRef = this . db . collection ( this . collection ) ;
101154
102155 var query = firestoreQueryParser ( collectionRef , queryParams ) ;
156+ query = applyQueryOptions ( query , queryOptions ) ;
157+
103158 query . get ( ) . then ( function ( querySnapshot ) {
104159 var vms = _ . map ( querySnapshot . docs , function ( documentSnapshot ) {
105160 var vm = new ViewModel ( documentSnapshot . data ( ) , self ) ;
161+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
106162 vm . actionOnCommit = 'update' ;
107163 return vm ;
108164 } ) ;
@@ -118,12 +174,15 @@ _.extend(Firestore.prototype, {
118174 var collectionRef = this . db . collection ( this . collection ) ;
119175
120176 var query = firestoreQueryParser ( collectionRef , queryParams ) ;
177+ _ . unset ( queryOptions , 'limit' ) ;
178+ query = applyQueryOptions ( query , queryOptions ) ;
121179 query . limit ( 1 ) . get ( ) . then ( function ( querySnapshot ) {
122180 if ( querySnapshot . size == 0 ) {
123181 callback ( null , null ) ;
124182 }
125183 querySnapshot . forEach ( function ( documentSnapshot ) {
126184 var vm = new ViewModel ( documentSnapshot . data ( ) , self ) ;
185+ vm = enrichVMWithTimestamps ( vm , documentSnapshot ) ;
127186 vm . actionOnCommit = 'update' ;
128187 callback ( null , vm ) ;
129188 } ) ;
@@ -135,12 +194,17 @@ _.extend(Firestore.prototype, {
135194
136195 if ( ! vm . actionOnCommit ) return callback ( new Error ( 'actionOnCommit is not defined!' ) ) ;
137196
197+ var self = this ;
198+
138199 switch ( vm . actionOnCommit ) {
139200 case 'delete' :
140201 var documentPath = this . collection + '/' + vm . id ;
141202 var documentRef = this . db . doc ( documentPath ) ;
142- documentRef . delete ( ) . then ( function ( ) {
203+ var precondition = getPrecondition ( vm ) ;
204+ documentRef . delete ( precondition ) . then ( function ( ) {
143205 callback ( null ) ;
206+ } ) . catch ( function ( err ) {
207+ return callback ( new ConcurrencyError ( ) ) ;
144208 } ) ;
145209 break ;
146210 case 'create' :
@@ -161,12 +225,23 @@ _.extend(Firestore.prototype, {
161225 var documentRef = this . db . doc ( documentPath ) ;
162226 documentRef . get ( ) . then ( function ( documentSnapshot ) {
163227 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+ } ) ;
165244 }
166- documentRef . update ( vm . attributes ) . then ( function ( ) {
167- vm . actionOnCommit = 'update' ;
168- callback ( null , vm ) ;
169- } ) ;
170245 } ) ;
171246 break ;
172247 default :
@@ -196,27 +271,14 @@ _.extend(Firestore.prototype, {
196271 return ;
197272 }
198273
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 ) ;
211275 } ,
212276
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- */
218277 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 ) ;
220282 } ,
221283
222284} ) ;
0 commit comments