@@ -18,9 +18,9 @@ use std::str::FromStr;
18
18
19
19
use graph:: data:: { schema:: FulltextAlgorithm , store:: scalar} ;
20
20
use graph:: prelude:: {
21
- format_err, serde_json, Attribute , BlockNumber , Entity , EntityCollection , EntityFilter ,
22
- EntityKey , EntityLink , EntityOrder , EntityRange , EntityWindow , ParentLink , QueryExecutionError ,
23
- StoreError , Value ,
21
+ format_err, serde_json, Attribute , BlockNumber , ChildMultiplicity , Entity , EntityCollection ,
22
+ EntityFilter , EntityKey , EntityLink , EntityOrder , EntityRange , EntityWindow , ParentLink ,
23
+ QueryExecutionError , StoreError , Value ,
24
24
} ;
25
25
26
26
use crate :: block_range:: {
@@ -1361,16 +1361,16 @@ impl ParentIds {
1361
1361
/// corresponding table and column
1362
1362
#[ derive( Debug , Clone ) ]
1363
1363
enum TableLink < ' a > {
1364
- Direct ( & ' a Column ) ,
1364
+ Direct ( & ' a Column , ChildMultiplicity ) ,
1365
1365
Parent ( ParentIds ) ,
1366
1366
}
1367
1367
1368
1368
impl < ' a > TableLink < ' a > {
1369
1369
fn new ( child_table : & ' a Table , link : EntityLink ) -> Result < Self , QueryExecutionError > {
1370
1370
match link {
1371
- EntityLink :: Direct ( attribute, _ ) => {
1371
+ EntityLink :: Direct ( attribute, multiplicity ) => {
1372
1372
let column = child_table. column_for_field ( attribute. name ( ) ) ?;
1373
- Ok ( TableLink :: Direct ( column) )
1373
+ Ok ( TableLink :: Direct ( column, multiplicity ) )
1374
1374
}
1375
1375
EntityLink :: Parent ( parent_link) => Ok ( TableLink :: Parent ( ParentIds :: new ( parent_link) ) ) ,
1376
1376
}
@@ -1487,7 +1487,7 @@ impl<'a> FilterWindow<'a> {
1487
1487
// limit {first} offset {skip}) c
1488
1488
// order by c.{sort_key}
1489
1489
1490
- out. push_sql ( "\n from unnest(" ) ;
1490
+ out. push_sql ( "\n /* children_type_a */ from unnest(" ) ;
1491
1491
column. bind_ids ( & self . ids , out) ?;
1492
1492
out. push_sql ( ") as p(id) cross join lateral (select * from " ) ;
1493
1493
out. push_sql ( self . table . qualified_name . as_str ( ) ) ;
@@ -1503,6 +1503,37 @@ impl<'a> FilterWindow<'a> {
1503
1503
Ok ( ( ) )
1504
1504
}
1505
1505
1506
+ fn child_type_a (
1507
+ & self ,
1508
+ column : & Column ,
1509
+ limit : ParentLimit < ' _ > ,
1510
+ block : BlockNumber ,
1511
+ out : & mut AstPass < Pg > ,
1512
+ ) -> QueryResult < ( ) > {
1513
+ assert ! ( column. is_list( ) ) ;
1514
+
1515
+ // Generate
1516
+ // from unnest({parent_ids}) as p(id),
1517
+ // children c
1518
+ // where c.{parent_field} @> array[p.id]
1519
+ // and .. other conditions on c ..
1520
+ // limit {parent_ids.len} + 1
1521
+
1522
+ out. push_sql ( "\n /* child_type_a */ from unnest(" ) ;
1523
+ column. bind_ids ( & self . ids , out) ?;
1524
+ out. push_sql ( ") as p(id), " ) ;
1525
+ out. push_sql ( self . table . qualified_name . as_str ( ) ) ;
1526
+ out. push_sql ( " c where " ) ;
1527
+ BlockRangeContainsClause :: new ( "c." , block) . walk_ast ( out. reborrow ( ) ) ?;
1528
+ limit. filter ( out) ;
1529
+ out. push_sql ( " and c." ) ;
1530
+ out. push_identifier ( column. name . as_str ( ) ) ?;
1531
+ out. push_sql ( " @> array[p.id]" ) ;
1532
+ self . and_filter ( out. reborrow ( ) ) ?;
1533
+ limit. single_limit ( self . ids . len ( ) , out) ;
1534
+ Ok ( ( ) )
1535
+ }
1536
+
1506
1537
fn children_type_b (
1507
1538
& self ,
1508
1539
column : & Column ,
@@ -1523,7 +1554,7 @@ impl<'a> FilterWindow<'a> {
1523
1554
// limit {first} offset {skip}) c
1524
1555
// order by c.{sort_key}
1525
1556
1526
- out. push_sql ( "\n from unnest(" ) ;
1557
+ out. push_sql ( "\n /* children_type_b */ from unnest(" ) ;
1527
1558
column. bind_ids ( & self . ids , out) ?;
1528
1559
out. push_sql ( ") as p(id) cross join lateral (select * from " ) ;
1529
1560
out. push_sql ( self . table . qualified_name . as_str ( ) ) ;
@@ -1538,6 +1569,35 @@ impl<'a> FilterWindow<'a> {
1538
1569
Ok ( ( ) )
1539
1570
}
1540
1571
1572
+ fn child_type_b (
1573
+ & self ,
1574
+ column : & Column ,
1575
+ limit : ParentLimit < ' _ > ,
1576
+ block : BlockNumber ,
1577
+ out : & mut AstPass < Pg > ,
1578
+ ) -> QueryResult < ( ) > {
1579
+ assert ! ( !column. is_list( ) ) ;
1580
+
1581
+ // Generate
1582
+ // from unnest({parent_ids}) as p(id), children c
1583
+ // where c.{parent_field} = p.id
1584
+ // and .. other conditions on c ..
1585
+ // limit {parent_ids.len} + 1
1586
+
1587
+ out. push_sql ( "\n /* child_type_b */ from unnest(" ) ;
1588
+ column. bind_ids ( & self . ids , out) ?;
1589
+ out. push_sql ( ") as p(id), " ) ;
1590
+ out. push_sql ( self . table . qualified_name . as_str ( ) ) ;
1591
+ out. push_sql ( " c where " ) ;
1592
+ BlockRangeContainsClause :: new ( "c." , block) . walk_ast ( out. reborrow ( ) ) ?;
1593
+ limit. filter ( out) ;
1594
+ out. push_sql ( " and p.id = c." ) ;
1595
+ out. push_identifier ( column. name . as_str ( ) ) ?;
1596
+ self . and_filter ( out. reborrow ( ) ) ?;
1597
+ limit. single_limit ( self . ids . len ( ) , out) ;
1598
+ Ok ( ( ) )
1599
+ }
1600
+
1541
1601
fn children_type_c (
1542
1602
& self ,
1543
1603
child_ids : & Vec < Vec < Option < SafeString > > > ,
@@ -1557,7 +1617,7 @@ impl<'a> FilterWindow<'a> {
1557
1617
// limit {first} offset {skip}) c
1558
1618
// order by c.{sort_key}
1559
1619
1560
- out. push_sql ( "\n from " ) ;
1620
+ out. push_sql ( "\n /* children_type_c */ from " ) ;
1561
1621
out. push_sql ( "rows from (unnest(" ) ;
1562
1622
out. push_bind_param :: < Array < Text > , _ > ( & self . ids ) ?;
1563
1623
out. push_sql ( "), reduce_dim(" ) ;
@@ -1588,7 +1648,7 @@ impl<'a> FilterWindow<'a> {
1588
1648
// where c.id = p.child_id
1589
1649
// and .. other conditions on c ..
1590
1650
1591
- out. push_sql ( "\n from rows from (unnest(" ) ;
1651
+ out. push_sql ( "\n /* child_type_d */ from rows from (unnest(" ) ;
1592
1652
out. push_bind_param :: < Array < Text > , _ > ( & self . ids ) ?;
1593
1653
out. push_sql ( "), unnest(" ) ;
1594
1654
self . table . primary_key ( ) . bind_ids ( & child_ids, out) ?;
@@ -1611,11 +1671,18 @@ impl<'a> FilterWindow<'a> {
1611
1671
mut out : AstPass < Pg > ,
1612
1672
) -> QueryResult < ( ) > {
1613
1673
match & self . link {
1614
- TableLink :: Direct ( column) => {
1674
+ TableLink :: Direct ( column, multiplicity) => {
1675
+ use ChildMultiplicity :: * ;
1615
1676
if column. is_list ( ) {
1616
- self . children_type_a ( column, limit, block, & mut out)
1677
+ match multiplicity {
1678
+ Many => self . children_type_a ( column, limit, block, & mut out) ,
1679
+ Single => self . child_type_a ( column, limit, block, & mut out) ,
1680
+ }
1617
1681
} else {
1618
- self . children_type_b ( column, limit, block, & mut out)
1682
+ match multiplicity {
1683
+ Many => self . children_type_b ( column, limit, block, & mut out) ,
1684
+ Single => self . child_type_b ( column, limit, block, & mut out) ,
1685
+ }
1619
1686
}
1620
1687
}
1621
1688
TableLink :: Parent ( ParentIds :: List ( child_ids) ) => {
0 commit comments