@@ -72,23 +72,23 @@ angular.module('mm.core')
7272 * @return {Promise } Promise to be resolved when the operation finishes.
7373 */
7474 function callDBFunction ( db , func ) {
75+ if ( typeof db == 'undefined' ) {
76+ return $q . reject ( ) ;
77+ }
78+
7579 var deferred = $q . defer ( ) ;
7680
7781 try {
78- if ( typeof ( db ) != 'undefined' ) {
79- db [ func ] . apply ( db , Array . prototype . slice . call ( arguments , 2 ) ) . then ( function ( result ) {
80- if ( typeof ( result ) == 'undefined' ) {
81- deferred . reject ( ) ;
82- } else {
83- deferred . resolve ( result ) ;
84- }
85- } ) ;
86- } else {
87- deferred . reject ( ) ;
88- }
82+ db [ func ] . apply ( db , Array . prototype . slice . call ( arguments , 2 ) ) . then ( function ( result ) {
83+ if ( typeof result == 'undefined' ) {
84+ deferred . reject ( ) ;
85+ } else {
86+ deferred . resolve ( result ) ;
87+ }
88+ } , deferred . reject ) ;
8989 } catch ( ex ) {
90- $log . error ( 'Error executing function ' + func + ' to DB ' + db . getName ( ) ) ;
91- $log . error ( ex . name + ': ' + ex . message ) ;
90+ $log . error ( 'Error executing function ' + func + ' to DB ' + db . getName ( ) ) ;
91+ $log . error ( ex . name + ': ' + ex . message ) ;
9292 deferred . reject ( ) ;
9393 }
9494
@@ -103,24 +103,32 @@ angular.module('mm.core')
103103 * @return {Promise }
104104 */
105105 function callCount ( db , store , where ) {
106- var deferred = $q . defer ( ) ,
107- query ;
106+ if ( typeof db == 'undefined' ) {
107+ return $q . reject ( ) ;
108+ }
109+
110+ var deferred = $q . defer ( ) ;
108111
109112 try {
110- if ( typeof ( db ) != 'undefined' ) {
111- query = db . from ( store ) ;
112- query = applyWhere ( query , where ) ;
113- query . count ( ) . then ( function ( count ) {
114- deferred . resolve ( count ) ;
115- } , function ( ) {
116- deferred . reject ( ) ;
113+ var query = db . from ( store ) ;
114+ query = applyWhere ( query , where ) ;
115+ query . count ( ) . then ( deferred . resolve , deferred . reject ) ;
116+ } catch ( ex ) {
117+ var promise ;
118+
119+ if ( where [ 1 ] == '=' ) {
120+ // Fallback, not using all options.
121+ promise = callWhereEqualFallBack ( db , store , where [ 0 ] , where [ 2 ] ) . then ( function ( list ) {
122+ deferred . resolve ( list . length ) ;
117123 } ) ;
118124 } else {
119- deferred . reject ( ) ;
125+ promise = $q . reject ( ) ;
120126 }
121- } catch ( ex ) {
122- $log . error ( 'Error querying db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
123- deferred . reject ( ) ;
127+
128+ promise . catch ( function ( ) {
129+ $log . error ( 'Error counting on db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
130+ deferred . reject ( ) ;
131+ } ) ;
124132 }
125133
126134 return deferred . promise ;
@@ -138,21 +146,28 @@ angular.module('mm.core')
138146 * @return {Promise } Promise to be resolved when the list is retrieved.
139147 */
140148 function callWhere ( db , store , field_name , op , value , op2 , value2 ) {
149+ if ( typeof db == 'undefined' ) {
150+ return $q . reject ( ) ;
151+ }
152+
141153 var deferred = $q . defer ( ) ;
142154
143155 try {
144- if ( typeof ( db ) != 'undefined' ) {
145- db . from ( store ) . where ( field_name , op , value , op2 , value2 ) . list ( ) . then ( function ( list ) {
146- deferred . resolve ( list ) ;
147- } , function ( ) {
148- deferred . reject ( ) ;
149- } ) ;
156+ db . from ( store ) . where ( field_name , op , value , op2 , value2 ) . list ( ) . then ( deferred . resolve , deferred . reject ) ;
157+ } catch ( ex ) {
158+ var promise ;
159+
160+ if ( op == '=' ) {
161+ // Fallback, not using all options.
162+ promise = callWhereEqualFallBack ( db , store , field_name , value ) . then ( deferred . resolve ) . catch ( deferred . reject ) ;
150163 } else {
151- deferred . reject ( ) ;
164+ promise = $q . reject ( ) ;
152165 }
153- } catch ( ex ) {
154- $log . error ( 'Error querying db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
155- deferred . reject ( ) ;
166+
167+ promise . catch ( function ( ) {
168+ $log . error ( 'Error getting where from db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
169+ deferred . reject ( ) ;
170+ } ) ;
156171 }
157172
158173 return deferred . promise ;
@@ -168,26 +183,97 @@ angular.module('mm.core')
168183 * @return {Promise } Promise to be resolved when the list is retrieved.
169184 */
170185 function callWhereEqual ( db , store , field_name , value ) {
186+ if ( typeof db == 'undefined' ) {
187+ return $q . reject ( ) ;
188+ }
189+
171190 var deferred = $q . defer ( ) ;
172191
173192 try {
174- if ( typeof ( db ) != 'undefined' ) {
175- db . from ( store ) . where ( field_name , '=' , value ) . list ( ) . then ( function ( list ) {
176- deferred . resolve ( list ) ;
177- } , function ( ) {
178- deferred . reject ( ) ;
179- } ) ;
180- } else {
193+ db . from ( store ) . where ( field_name , '=' , value ) . list ( ) . then ( deferred . resolve , deferred . reject ) ;
194+ } catch ( ex ) {
195+ callWhereEqualFallBack ( db , store , field_name , value ) . then ( deferred . resolve ) . catch ( function ( ) {
196+ $log . error ( 'Error getting where equal from db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
181197 deferred . reject ( ) ;
182- }
198+ } ) ;
199+ }
200+
201+ return deferred . promise ;
202+ }
203+
204+ // FallBack Method when where equal is not supported by the DB. See callWhereEqual for more info.
205+ // It will only be used if the field_name is a compound index and the database does not support where equals on IndexedDB.
206+ function callWhereEqualFallBack ( db , store , field_name , values ) {
207+ var fields = getCompoundIndex ( db , store , field_name ) ;
208+ if ( ! fields ) {
209+ return $q . reject ( ) ;
210+ }
211+
212+ if ( typeof fields == "string" ) {
213+ // This should not happen.
214+ fields = [ fields ] ;
215+ }
216+
217+ var deferred = $q . defer ( ) ;
218+
219+ try {
220+ db . from ( store ) . where ( fields [ 0 ] , '=' , values [ 0 ] ) . list ( ) . then ( function ( list ) {
221+ var results = filterWhereList ( list , fields , values , 1 ) ;
222+ deferred . resolve ( results ) ;
223+ } , deferred . reject ) ;
183224 } catch ( ex ) {
184- $log . error ( 'Error getting where equal from db ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
185225 deferred . reject ( ) ;
186226 }
187227
188228 return deferred . promise ;
189229 }
190230
231+ /**
232+ * Convenience function that returns the Compound Index for a given store and db.
233+ * @param {Object } db Database to get the schema.
234+ * @param {String } storeName The store where to find the index.
235+ * @param {String } index Index to get.
236+ * @return {Mixed } KeyPath of the index found or false.
237+ */
238+ function getCompoundIndex ( db , storeName , index ) {
239+ var stores = db . getSchema ( ) . stores ;
240+ for ( var x in stores ) {
241+ if ( stores [ x ] . name == storeName ) {
242+ var indexes = stores [ x ] . indexes ;
243+ for ( var y in indexes ) {
244+ if ( indexes [ y ] . name == index ) {
245+ return indexes [ y ] . keyPath ;
246+ }
247+ }
248+ return false ;
249+ }
250+ }
251+ return false ;
252+ }
253+
254+ /**
255+ * Convenience function to filter results by a list of fields and values. Recursive.
256+ *
257+ * @param {Array] list List of results to be filtered.
258+ * @param {Array } fields List of field names to filter.
259+ * @param {Array } values List of field values to filter, in the same order as fields.
260+ * @param {Number } indexNum What field - value have to be filtered.
261+ * @return {Array } Filtered list.
262+ */
263+ function filterWhereList ( list , fields , values , indexNum ) {
264+ if ( list . length == 0 || fields . length < indexNum || values . length < indexNum ) {
265+ return list ;
266+ }
267+
268+ var field = fields [ indexNum ] ,
269+ value = values [ indexNum ] ;
270+
271+ list = list . filter ( function ( item ) {
272+ return item [ field ] == value ;
273+ } ) ;
274+ return filterWhereList ( list , fields , values , indexNum + 1 ) ;
275+ }
276+
191277 /**
192278 * Performs an operation with every entry in a certain store.
193279 * @param {Object } db DB to use.
@@ -203,9 +289,7 @@ angular.module('mm.core')
203289 callback ( entries [ i ] ) ;
204290 }
205291 deferred . resolve ( ) ;
206- } , function ( ) {
207- deferred . reject ( ) ;
208- } ) ;
292+ } , deferred . reject ) ;
209293
210294 return deferred . promise ;
211295 }
@@ -222,22 +306,18 @@ angular.module('mm.core')
222306 * @return {Promise }
223307 */
224308 function doQuery ( db , store , where , order , reverse , limit ) {
309+ if ( typeof db == 'undefined' ) {
310+ return $q . reject ( ) ;
311+ }
312+
225313 var deferred = $q . defer ( ) ,
226314 query ;
227315
228316 try {
229- if ( typeof ( db ) != 'undefined' ) {
230- query = db . from ( store ) ;
231- query = applyWhere ( query , where ) ;
232- query = applyOrder ( query , order , reverse ) ;
233- query . list ( limit ) . then ( function ( list ) {
234- deferred . resolve ( list ) ;
235- } , function ( ) {
236- deferred . reject ( ) ;
237- } ) ;
238- } else {
239- deferred . reject ( ) ;
240- }
317+ query = db . from ( store ) ;
318+ query = applyWhere ( query , where ) ;
319+ query = applyOrder ( query , order , reverse ) ;
320+ query . list ( limit ) . then ( deferred . resolve , deferred . reject ) ;
241321 } catch ( ex ) {
242322 $log . error ( 'Error querying ' + store + ' on ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
243323 deferred . reject ( ) ;
@@ -256,23 +336,19 @@ angular.module('mm.core')
256336 * @return {Promise }
257337 */
258338 function doUpdate ( db , store , values , where ) {
339+ if ( typeof db == 'undefined' ) {
340+ return $q . reject ( ) ;
341+ }
342+
259343 var deferred = $q . defer ( ) ,
260344 query ;
261345
262346 try {
263- if ( typeof ( db ) != 'undefined' ) {
264- query = db . from ( store ) ;
265- query = applyWhere ( query , where ) ;
266- query . patch ( values ) . then ( function ( count ) {
267- deferred . resolve ( count ) ;
268- } , function ( ) {
269- deferred . reject ( ) ;
270- } ) ;
271- } else {
272- deferred . reject ( ) ;
273- }
347+ query = db . from ( store ) ;
348+ query = applyWhere ( query , where ) ;
349+ query . patch ( values ) . then ( deferred . resolve , deferred . reject ) ;
274350 } catch ( ex ) {
275- $log . error ( 'Error querying ' + store + ' on ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
351+ $log . error ( 'Error updating ' + store + ' on ' + db . getName ( ) + '. ' + ex . name + ': ' + ex . message ) ;
276352 deferred . reject ( ) ;
277353 }
278354
@@ -296,8 +372,8 @@ angular.module('mm.core')
296372 self . getDB = function ( name , schema , options , forceNew ) {
297373 if ( typeof dbInstances [ name ] === 'undefined' || forceNew ) {
298374
299- var isSafari = ! ionic . Platform . isIOS ( ) && ! ionic . Platform . isAndroid ( ) && navigator . userAgent . indexOf ( 'Safari' ) != - 1
300- && navigator . userAgent . indexOf ( 'Chrome' ) == - 1 && navigator . userAgent . indexOf ( 'Firefox' ) == - 1 ;
375+ var isSafari = ! ionic . Platform . isIOS ( ) && ! ionic . Platform . isAndroid ( ) && navigator . userAgent . indexOf ( 'Safari' ) != - 1 &&
376+ navigator . userAgent . indexOf ( 'Chrome' ) == - 1 && navigator . userAgent . indexOf ( 'Firefox' ) == - 1 ;
301377 if ( typeof IDBObjectStore == 'undefined' || typeof IDBObjectStore . prototype . count == 'undefined' || isSafari ) {
302378 // IndexedDB not implemented or not fully implemented (Galaxy S4 Mini). Use WebSQL.
303379 if ( typeof options . mechanisms == 'undefined' ) {
@@ -387,6 +463,7 @@ angular.module('mm.core')
387463 } ,
388464 /**
389465 * Query the database.
466+ * WARNING: Do not use it with compound indexes, on Android versions lower than 4.4 will fail.
390467 *
391468 * @param {String } store Name of the store.
392469 * @param {Array } [where] Array of where conditions, see applyWhere.
@@ -419,6 +496,7 @@ angular.module('mm.core')
419496 } ,
420497 /**
421498 * Update records matching.
499+ * WARNING: Do not use it with compound indexes, on Android versions lower than 4.4 will fail.
422500 *
423501 * @param {String } store Name of the store.
424502 * @param {Object } values The values to update.
@@ -430,6 +508,8 @@ angular.module('mm.core')
430508 } ,
431509 /**
432510 * Get the entries where a field match certain conditions.
511+ * WARNING: Do not use it with compound indexes, on Android versions lower than 4.4 will fail.
512+ * Try to use whereEqual instead.
433513 *
434514 * @param {String } store Name of the store.
435515 * @param {String } field_name Name of the field to match.
0 commit comments