@@ -581,6 +581,7 @@ async fn insert_test_entities(
581
581
vec![
582
582
entity! { is => id: "m3" , name: "Tom" , mainBand: "b2" , bands: vec![ "b1" , "b2" ] , favoriteCount: 5 , birthDate: timestamp. clone( ) , vid: 2i64 } ,
583
583
entity! { is => id: "m4" , name: "Valerie" , bands: Vec :: <String >:: new( ) , favoriteCount: 20 , birthDate: timestamp. clone( ) , vid: 3i64 } ,
584
+ entity! { is => id: "m5" , name: "Paul" , mainBand: "b2" , bands: vec![ "b2" ] , favoriteCount: 2 , birthDate: timestamp. clone( ) , vid: 4i64 } ,
584
585
] ,
585
586
) ] ;
586
587
let entities1 = insert_ops ( & manifest. schema , entities1) ;
@@ -771,7 +772,8 @@ fn can_query_one_to_one_relationship() {
771
772
object! { name: "John" , mainBand: object! { name: "The Musicians" } , favoriteCount: "10" , birthDate: "1710837304040956" } ,
772
773
object! { name: "Lisa" , mainBand: object! { name: "The Musicians" } , favoriteCount: "100" , birthDate: "1710837304040956" } ,
773
774
object! { name: "Tom" , mainBand: object! { name: "The Amateurs" } , favoriteCount: "5" , birthDate: "1710837304040956" } ,
774
- object! { name: "Valerie" , mainBand: r:: Value :: Null , favoriteCount: "20" , birthDate: "1710837304040956" }
775
+ object! { name: "Valerie" , mainBand: r:: Value :: Null , favoriteCount: "20" , birthDate: "1710837304040956" } ,
776
+ object! { name: "Paul" , mainBand: object! { name: "The Amateurs" } , favoriteCount: "2" , birthDate: "1710837304040956" }
775
777
] ,
776
778
songStats: vec![
777
779
object! {
@@ -815,7 +817,8 @@ fn can_filter_by_timestamp() {
815
817
object! { name: "John" } ,
816
818
object! { name: "Lisa" } ,
817
819
object! { name: "Tom" } ,
818
- object! { name: "Valerie" }
820
+ object! { name: "Valerie" } ,
821
+ object! { name: "Paul" } ,
819
822
] ,
820
823
} ;
821
824
let data = extract_data ! ( result) . unwrap ( ) ;
@@ -868,6 +871,9 @@ fn can_query_one_to_many_relationships_in_both_directions() {
868
871
object! {
869
872
name: "Valerie" , writtenSongs: Vec :: <String >:: new( )
870
873
} ,
874
+ object! {
875
+ name: "Paul" , writtenSongs: Vec :: <String >:: new( )
876
+ } ,
871
877
]
872
878
} ;
873
879
@@ -906,15 +912,16 @@ fn can_query_many_to_many_relationship() {
906
912
907
913
let the_amateurs = object ! {
908
914
name: "The Amateurs" ,
909
- members: members( vec![ "John" , "Tom" ] )
915
+ members: members( vec![ "John" , "Tom" , "Paul" ] )
910
916
} ;
911
917
912
918
let exp = object ! {
913
919
musicians: vec![
914
920
object! { name: "John" , bands: vec![ the_musicians. clone( ) , the_amateurs. clone( ) ] } ,
915
921
object! { name: "Lisa" , bands: vec![ the_musicians. clone( ) ] } ,
916
- object! { name: "Tom" , bands: vec![ the_musicians, the_amateurs ] } ,
917
- object! { name: "Valerie" , bands: Vec :: <String >:: new( ) }
922
+ object! { name: "Tom" , bands: vec![ the_musicians, the_amateurs. clone( ) ] } ,
923
+ object! { name: "Valerie" , bands: Vec :: <String >:: new( ) } ,
924
+ object! { name: "Paul" , bands: vec![ the_amateurs ] }
918
925
]
919
926
} ;
920
927
@@ -996,10 +1003,12 @@ fn can_query_with_sorting_by_child_entity() {
996
1003
object! { name: "Valerie" , mainBand: r:: Value :: Null } ,
997
1004
object! { name: "Lisa" , mainBand: object! { name: "The Musicians" } } ,
998
1005
object! { name: "John" , mainBand: object! { name: "The Musicians" } } ,
1006
+ object! { name: "Paul" , mainBand: object! { name: "The Amateurs" } } ,
999
1007
object! { name: "Tom" , mainBand: object! { name: "The Amateurs" } } ,
1000
1008
] ,
1001
1009
asc: vec![
1002
1010
object! { name: "Tom" , mainBand: object! { name: "The Amateurs" } } ,
1011
+ object! { name: "Paul" , mainBand: object! { name: "The Amateurs" } } ,
1003
1012
object! { name: "John" , mainBand: object! { name: "The Musicians" } } ,
1004
1013
object! { name: "Lisa" , mainBand: object! { name: "The Musicians" } } ,
1005
1014
object! { name: "Valerie" , mainBand: r:: Value :: Null } ,
@@ -1307,7 +1316,8 @@ fn can_query_with_child_filter_on_list_type_field() {
1307
1316
let exp = object ! {
1308
1317
musicians: vec![
1309
1318
object! { name: "John" , bands: vec![ the_musicians. clone( ) , the_amateurs. clone( ) ] } ,
1310
- object! { name: "Tom" , bands: vec![ the_musicians, the_amateurs ] } ,
1319
+ object! { name: "Tom" , bands: vec![ the_musicians, the_amateurs. clone( ) ] } ,
1320
+ object! { name: "Paul" , bands: vec![ the_amateurs ] } ,
1311
1321
]
1312
1322
} ;
1313
1323
@@ -1352,7 +1362,8 @@ fn can_query_with_child_filter_on_named_type_field() {
1352
1362
run_query ( QUERY , |result, _| {
1353
1363
let exp = object ! {
1354
1364
musicians: vec![
1355
- object! { name: "Tom" , mainBand: object! { id: "b2" } }
1365
+ object! { name: "Tom" , mainBand: object! { id: "b2" } } ,
1366
+ object! { name: "Paul" , mainBand: object! { id: "b2" } }
1356
1367
]
1357
1368
} ;
1358
1369
@@ -1703,7 +1714,7 @@ fn skip_directive_works_with_query_variables() {
1703
1714
1704
1715
run_query ( ( QUERY , object ! { skip: true } ) , |result, _| {
1705
1716
// Assert that only names are returned
1706
- let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" ]
1717
+ let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" , "Paul" ]
1707
1718
. into_iter ( )
1708
1719
. map ( |name| object ! { name: name } )
1709
1720
. collect ( ) ;
@@ -1719,7 +1730,8 @@ fn skip_directive_works_with_query_variables() {
1719
1730
object! { id: "m1" , name: "John" } ,
1720
1731
object! { id: "m2" , name: "Lisa" } ,
1721
1732
object! { id: "m3" , name: "Tom" } ,
1722
- object! { id: "m4" , name: "Valerie" }
1733
+ object! { id: "m4" , name: "Valerie" } ,
1734
+ object! { id: "m5" , name: "Paul" }
1723
1735
]
1724
1736
} ;
1725
1737
let data = extract_data ! ( result) . unwrap ( ) ;
@@ -1745,7 +1757,8 @@ fn include_directive_works_with_query_variables() {
1745
1757
object! { id: "m1" , name: "John" } ,
1746
1758
object! { id: "m2" , name: "Lisa" } ,
1747
1759
object! { id: "m3" , name: "Tom" } ,
1748
- object! { id: "m4" , name: "Valerie" }
1760
+ object! { id: "m4" , name: "Valerie" } ,
1761
+ object! { id: "m5" , name: "Paul" }
1749
1762
]
1750
1763
} ;
1751
1764
let data = extract_data ! ( result) . unwrap ( ) ;
@@ -1754,7 +1767,7 @@ fn include_directive_works_with_query_variables() {
1754
1767
1755
1768
run_query ( ( QUERY , object ! { include: false } ) , |result, _| {
1756
1769
// Assert that only names are returned
1757
- let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" ]
1770
+ let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" , "Paul" ]
1758
1771
. into_iter ( )
1759
1772
. map ( |name| object ! { name: name } )
1760
1773
. collect ( ) ;
@@ -1894,7 +1907,7 @@ fn skip_is_nullable() {
1894
1907
" ;
1895
1908
1896
1909
run_query ( QUERY , |result, _| {
1897
- let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" ]
1910
+ let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" , "Paul" ]
1898
1911
. into_iter ( )
1899
1912
. map ( |name| object ! { name: name } )
1900
1913
. collect ( ) ;
@@ -1915,7 +1928,7 @@ fn first_is_nullable() {
1915
1928
" ;
1916
1929
1917
1930
run_query ( QUERY , |result, _| {
1918
- let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" ]
1931
+ let musicians: Vec < _ > = [ "John" , "Lisa" , "Tom" , "Valerie" , "Paul" ]
1919
1932
. into_iter ( )
1920
1933
. map ( |name| object ! { name: name } )
1921
1934
. collect ( ) ;
@@ -1992,7 +2005,8 @@ fn can_filter_by_relationship_fields() {
1992
2005
1993
2006
let exp = object ! {
1994
2007
musicians: vec![
1995
- object! { id: "m3" , name: "Tom" , mainBand: object! { id: "b2" } }
2008
+ object! { id: "m3" , name: "Tom" , mainBand: object! { id: "b2" } } ,
2009
+ object! { id: "m5" , name: "Paul" , mainBand: object! { id: "b2" } }
1996
2010
] ,
1997
2011
bands: vec![
1998
2012
object! {
@@ -2074,6 +2088,10 @@ fn can_use_nested_filter() {
2074
2088
object! {
2075
2089
name: "Valerie" ,
2076
2090
bands: Vec :: <r:: Value >:: new( ) ,
2091
+ } ,
2092
+ object! {
2093
+ name: "Paul" ,
2094
+ bands: vec![ object! { id: "b2" } ]
2077
2095
}
2078
2096
]
2079
2097
} ;
@@ -2096,7 +2114,7 @@ fn ignores_invalid_field_arguments() {
2096
2114
// Without validations
2097
2115
Ok ( Some ( r:: Value :: Object ( obj) ) ) => match obj. get ( "musicians" ) . unwrap ( ) {
2098
2116
r:: Value :: List ( lst) => {
2099
- assert_eq ! ( 4 , lst. len( ) ) ;
2117
+ assert_eq ! ( 5 , lst. len( ) ) ;
2100
2118
}
2101
2119
_ => panic ! ( "expected a list of values" ) ,
2102
2120
} ,
@@ -2202,6 +2220,7 @@ fn missing_variable() {
2202
2220
object! { id: "m2" } ,
2203
2221
object! { id: "m3" } ,
2204
2222
object! { id: "m4" } ,
2223
+ object! { id: "m5" } ,
2205
2224
]
2206
2225
} ;
2207
2226
@@ -2232,6 +2251,7 @@ fn missing_variable() {
2232
2251
object! { id: "m2" } ,
2233
2252
object! { id: "m3" } ,
2234
2253
object! { id: "m4" } ,
2254
+ object! { id: "m5" } ,
2235
2255
]
2236
2256
} ;
2237
2257
@@ -2326,13 +2346,15 @@ fn query_at_block() {
2326
2346
up to block number 2 and data for block number 3 is therefore not yet available";
2327
2347
const BLOCK_HASH_NOT_FOUND : & str = "no block with that hash found" ;
2328
2348
2349
+ let all_musicians = vec ! [ "m1" , "m2" , "m3" , "m4" , "m5" ] ;
2350
+
2329
2351
musicians_at ( "number: 7000" , Err ( BLOCK_NOT_INDEXED ) , "n7000" ) ;
2330
2352
musicians_at ( "number: 0" , Ok ( vec ! [ "m1" , "m2" ] ) , "n0" ) ;
2331
- musicians_at ( "number: 1" , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "n1" ) ;
2353
+ musicians_at ( "number: 1" , Ok ( all_musicians . clone ( ) ) , "n1" ) ;
2332
2354
2333
2355
musicians_at ( & hash ( & BLOCKS [ 0 ] ) , Ok ( vec ! [ "m1" , "m2" ] ) , "h0" ) ;
2334
- musicians_at ( & hash ( & BLOCKS [ 1 ] ) , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "h1" ) ;
2335
- musicians_at ( & hash ( & BLOCKS [ 2 ] ) , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "h2" ) ;
2356
+ musicians_at ( & hash ( & BLOCKS [ 1 ] ) , Ok ( all_musicians . clone ( ) ) , "h1" ) ;
2357
+ musicians_at ( & hash ( & BLOCKS [ 2 ] ) , Ok ( all_musicians . clone ( ) ) , "h2" ) ;
2336
2358
musicians_at ( & hash ( & BLOCKS [ 3 ] ) , Err ( BLOCK_NOT_INDEXED2 ) , "h3" ) ;
2337
2359
musicians_at ( & hash ( & BLOCKS [ 4 ] ) , Err ( BLOCK_HASH_NOT_FOUND ) , "h4" ) ;
2338
2360
}
@@ -2371,17 +2393,19 @@ fn query_at_block_with_vars() {
2371
2393
up to block number 2 and data for block number 3 is therefore not yet available";
2372
2394
const BLOCK_HASH_NOT_FOUND : & str = "no block with that hash found" ;
2373
2395
2396
+ let all_musicians = vec ! [ "m1" , "m2" , "m3" , "m4" , "m5" ] ;
2397
+
2374
2398
musicians_at_nr ( 7000 , Err ( BLOCK_NOT_INDEXED ) , "n7000" ) ;
2375
2399
musicians_at_nr ( 0 , Ok ( vec ! [ "m1" , "m2" ] ) , "n0" ) ;
2376
- musicians_at_nr ( 1 , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "n1" ) ;
2400
+ musicians_at_nr ( 1 , Ok ( all_musicians . clone ( ) ) , "n1" ) ;
2377
2401
2378
2402
musicians_at_nr_gte ( 7000 , Err ( BLOCK_NOT_INDEXED ) , "ngte7000" ) ;
2379
- musicians_at_nr_gte ( 0 , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "ngte0" ) ;
2380
- musicians_at_nr_gte ( 1 , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "ngte1" ) ;
2403
+ musicians_at_nr_gte ( 0 , Ok ( all_musicians . clone ( ) ) , "ngte0" ) ;
2404
+ musicians_at_nr_gte ( 1 , Ok ( all_musicians . clone ( ) ) , "ngte1" ) ;
2381
2405
2382
2406
musicians_at_hash ( & BLOCKS [ 0 ] , Ok ( vec ! [ "m1" , "m2" ] ) , "h0" ) ;
2383
- musicians_at_hash ( & BLOCKS [ 1 ] , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "h1" ) ;
2384
- musicians_at_hash ( & BLOCKS [ 2 ] , Ok ( vec ! [ "m1" , "m2" , "m3" , "m4" ] ) , "h2" ) ;
2407
+ musicians_at_hash ( & BLOCKS [ 1 ] , Ok ( all_musicians . clone ( ) ) , "h1" ) ;
2408
+ musicians_at_hash ( & BLOCKS [ 2 ] , Ok ( all_musicians . clone ( ) ) , "h2" ) ;
2385
2409
musicians_at_hash ( & BLOCKS [ 3 ] , Err ( BLOCK_NOT_INDEXED2 ) , "h3" ) ;
2386
2410
musicians_at_hash ( & BLOCKS [ 4 ] , Err ( BLOCK_HASH_NOT_FOUND ) , "h4" ) ;
2387
2411
}
@@ -2822,6 +2846,7 @@ fn can_query_with_or_and_filter() {
2822
2846
musicians: vec![
2823
2847
object! { name: "John" , id: "m1" } ,
2824
2848
object! { name: "Tom" , id: "m3" } ,
2849
+ object! { name: "Paul" , id: "m5" } ,
2825
2850
] ,
2826
2851
} ;
2827
2852
let data = extract_data ! ( result) . unwrap ( ) ;
@@ -2847,6 +2872,7 @@ fn can_query_with_or_explicit_and_filter() {
2847
2872
musicians: vec![
2848
2873
object! { name: "John" , id: "m1" } ,
2849
2874
object! { name: "Tom" , id: "m3" } ,
2875
+ object! { name: "Paul" , id: "m5" } ,
2850
2876
] ,
2851
2877
} ;
2852
2878
let data = extract_data ! ( result) . unwrap ( ) ;
@@ -3049,3 +3075,79 @@ fn simple_aggregation() {
3049
3075
assert_eq ! ( data, exp) ;
3050
3076
} )
3051
3077
}
3078
+
3079
+ /// Check that if we have entities where a related entity is null, followed
3080
+ /// by one where it is not null that the children are joined correctly to
3081
+ /// their respective parent
3082
+ #[ test]
3083
+ fn children_are_joined_correctly ( ) {
3084
+ // Get just the `id` for the `mainBand` and `bands`
3085
+ const QUERY1 : & str = "
3086
+ query {
3087
+ musicians {
3088
+ id
3089
+ mainBand { id }
3090
+ bands { id }
3091
+ }
3092
+ }
3093
+ " ;
3094
+
3095
+ // Get the `id` and one more attribute for the `mainBand` and `bands`
3096
+ const QUERY2 : & str = "
3097
+ query {
3098
+ musicians {
3099
+ id
3100
+ mainBand { id name }
3101
+ bands { id name }
3102
+ }
3103
+ }
3104
+ " ;
3105
+
3106
+ run_query ( QUERY1 , |result, _| {
3107
+ fn b1 ( ) -> r:: Value {
3108
+ object ! { id: "b1" }
3109
+ }
3110
+ fn b2 ( ) -> r:: Value {
3111
+ object ! { id: "b2" }
3112
+ }
3113
+ let null = r:: Value :: Null ;
3114
+ let none = Vec :: < r:: Value > :: new ( ) ;
3115
+
3116
+ let exp = object ! {
3117
+ musicians: vec![
3118
+ object! { id: "m1" , mainBand: b1( ) , bands: vec![ b1( ) , b2( ) ] } ,
3119
+ object! { id: "m2" , mainBand: b1( ) , bands: vec![ b1( ) ] } ,
3120
+ object! { id: "m3" , mainBand: b2( ) , bands: vec![ b1( ) , b2( ) ] } ,
3121
+ object! { id: "m4" , mainBand: null, bands: none } ,
3122
+ object! { id: "m5" , mainBand: b2( ) , bands: vec![ b2( ) ] } ,
3123
+ ] ,
3124
+ } ;
3125
+
3126
+ let data = extract_data ! ( result) . unwrap ( ) ;
3127
+ assert_eq ! ( data, exp) ;
3128
+ } ) ;
3129
+
3130
+ run_query ( QUERY2 , |result, _| {
3131
+ fn b1 ( ) -> r:: Value {
3132
+ object ! { id: "b1" , name: "The Musicians" }
3133
+ }
3134
+ fn b2 ( ) -> r:: Value {
3135
+ object ! { id: "b2" , name: "The Amateurs" }
3136
+ }
3137
+ let null = r:: Value :: Null ;
3138
+ let none = Vec :: < r:: Value > :: new ( ) ;
3139
+
3140
+ let exp = object ! {
3141
+ musicians: vec![
3142
+ object! { id: "m1" , mainBand: b1( ) , bands: vec![ b1( ) , b2( ) ] } ,
3143
+ object! { id: "m2" , mainBand: b1( ) , bands: vec![ b1( ) ] } ,
3144
+ object! { id: "m3" , mainBand: b2( ) , bands: vec![ b1( ) , b2( ) ] } ,
3145
+ object! { id: "m4" , mainBand: null, bands: none } ,
3146
+ object! { id: "m5" , mainBand: b2( ) , bands: vec![ b2( ) ] } ,
3147
+ ] ,
3148
+ } ;
3149
+
3150
+ let data = extract_data ! ( result) . unwrap ( ) ;
3151
+ assert_eq ! ( data, exp) ;
3152
+ } ) ;
3153
+ }
0 commit comments