@@ -212,3 +212,137 @@ fn parameters() {
212
212
assert_eq ! ( query. execute( ) . unwrap( ) . count( ) , 1 ) ;
213
213
} ) ;
214
214
}
215
+
216
+ #[ test]
217
+ fn array_contains ( ) {
218
+ use std:: path:: PathBuf ;
219
+ use std:: time:: Instant ;
220
+
221
+ const DB_NAME : & str = "test_db" ;
222
+
223
+ let base_loc = dirs:: data_local_dir ( )
224
+ . unwrap ( )
225
+ . to_str ( )
226
+ . unwrap ( )
227
+ . to_string ( ) ;
228
+ let dir = PathBuf :: from ( format ! ( "{base_loc}/billeo" ) ) ;
229
+
230
+ let cfg = DatabaseConfiguration {
231
+ directory : dir. as_path ( ) ,
232
+ encryption_key : None ,
233
+ } ;
234
+
235
+ if let Ok ( db) = Database :: open ( DB_NAME , Some ( cfg. clone ( ) ) ) {
236
+ db. delete ( ) . unwrap ( ) ;
237
+ }
238
+
239
+ let mut db = Database :: open ( DB_NAME , Some ( cfg) ) . expect ( "open db" ) ;
240
+ assert ! ( Database :: exists( DB_NAME , dir. as_path( ) ) ) ;
241
+
242
+ // Add documents
243
+
244
+ // - Add Model1
245
+
246
+ for i in 0 ..25000 {
247
+ let mut doc = Document :: new_with_id ( & format ! ( "id_model1_{i}" ) ) ;
248
+
249
+ let mut props = doc. mutable_properties ( ) ;
250
+ props. at ( "type" ) . put_string ( "Model1" ) ;
251
+ props. at ( "uselessField" ) . put_i64 ( i) ;
252
+
253
+ let mut model2_ids = MutableArray :: new ( ) ;
254
+ model2_ids
255
+ . append ( )
256
+ . put_string ( & format ! ( "id_model2_{}" , 4 * i) ) ;
257
+ model2_ids
258
+ . append ( )
259
+ . put_string ( & format ! ( "id_model2_{}" , 4 * i + 1 ) ) ;
260
+ model2_ids
261
+ . append ( )
262
+ . put_string ( & format ! ( "id_model2_{}" , 4 * i + 2 ) ) ;
263
+ model2_ids
264
+ . append ( )
265
+ . put_string ( & format ! ( "id_model2_{}" , 4 * i + 3 ) ) ;
266
+ props. at ( "model2Ids" ) . put_value ( & model2_ids) ;
267
+
268
+ db. save_document_with_concurency_control ( & mut doc, ConcurrencyControl :: FailOnConflict )
269
+ . expect ( "save" ) ;
270
+ }
271
+
272
+ // - Add Model2
273
+
274
+ for i in 0 ..100000 {
275
+ let mut doc = Document :: new_with_id ( & format ! ( "id_model2_{i}" ) ) ;
276
+
277
+ let mut props = doc. mutable_properties ( ) ;
278
+ props. at ( "type" ) . put_string ( "Model2" ) ;
279
+
280
+ db. save_document_with_concurency_control ( & mut doc, ConcurrencyControl :: FailOnConflict )
281
+ . expect ( "save" ) ;
282
+ }
283
+
284
+ // Run query
285
+
286
+ let query = Query :: new (
287
+ & db,
288
+ QueryLanguage :: N1QL ,
289
+ "SELECT _.* FROM _ \
290
+ WHERE _.type='Model1' \
291
+ AND ARRAY_CONTAINS(_.model2Ids, $model2Id)",
292
+ )
293
+ . expect ( "create query" ) ;
294
+
295
+ fn run_query ( use_case : & str , query : & Query ) {
296
+ println ! (
297
+ "Explain for use case [{}]: {}" ,
298
+ use_case,
299
+ query. explain( ) . unwrap( )
300
+ ) ;
301
+
302
+ let start = Instant :: now ( ) ;
303
+
304
+ for i in 0 ..100 {
305
+ let mut params = MutableDict :: new ( ) ;
306
+ params
307
+ . at ( "model2Id" )
308
+ . put_string ( & format ! ( "id_model2_{}" , i * 100 ) ) ;
309
+ query. set_parameters ( & params) ;
310
+
311
+ assert_eq ! ( query. execute( ) . unwrap( ) . count( ) , 1 ) ;
312
+ }
313
+
314
+ let stop = start. elapsed ( ) ;
315
+
316
+ println ! (
317
+ "Query average time for use case [{}]: {:?}" ,
318
+ use_case,
319
+ stop / 100
320
+ ) ;
321
+ }
322
+
323
+ // - No index
324
+
325
+ run_query ( "no index" , & query) ;
326
+
327
+ // - Good index
328
+
329
+ assert ! ( db
330
+ . create_index(
331
+ "good_index" ,
332
+ & ValueIndexConfiguration :: new( QueryLanguage :: JSON , r#"[[".type"], [".model2Ids"]]"# ) ,
333
+ )
334
+ . unwrap( ) ) ;
335
+
336
+ run_query ( "good_index" , & query) ;
337
+
338
+ // - Bad index
339
+
340
+ assert ! ( db
341
+ . create_index(
342
+ "bad_index" ,
343
+ & ValueIndexConfiguration :: new( QueryLanguage :: JSON , r#"[[".type"], [".uselessField"]]"# ) ,
344
+ )
345
+ . unwrap( ) ) ;
346
+
347
+ run_query ( "bad_index" , & query) ;
348
+ }
0 commit comments