@@ -212,3 +212,137 @@ fn parameters() {
212212 assert_eq ! ( query. execute( ) . unwrap( ) . count( ) , 1 ) ;
213213 } ) ;
214214}
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