|
80 | 80 | import java.util.stream.StreamSupport; |
81 | 81 | import org.hypertrace.core.documentstore.commons.DocStoreConstants; |
82 | 82 | import org.hypertrace.core.documentstore.expression.impl.AggregateExpression; |
| 83 | +import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression; |
83 | 84 | import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; |
84 | 85 | import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; |
85 | 86 | import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; |
86 | 87 | import org.hypertrace.core.documentstore.expression.impl.KeyExpression; |
87 | 88 | import org.hypertrace.core.documentstore.expression.impl.LogicalExpression; |
88 | 89 | import org.hypertrace.core.documentstore.expression.impl.RelationalExpression; |
| 90 | +import org.hypertrace.core.documentstore.expression.impl.SubQueryJoinExpression; |
89 | 91 | import org.hypertrace.core.documentstore.expression.impl.UnnestExpression; |
| 92 | +import org.hypertrace.core.documentstore.expression.operators.AggregationOperator; |
90 | 93 | import org.hypertrace.core.documentstore.expression.operators.FunctionOperator; |
91 | 94 | import org.hypertrace.core.documentstore.expression.operators.RelationalOperator; |
92 | 95 | import org.hypertrace.core.documentstore.expression.type.FilterTypeExpression; |
@@ -3478,6 +3481,182 @@ public void testToLowerCaseMongoFunctionOperator(String dataStoreName) throws Ex |
3478 | 3481 | dataStoreName, resultDocs, "query/case_insensitive_exact_match_response.json", 2); |
3479 | 3482 | } |
3480 | 3483 |
|
| 3484 | + @ParameterizedTest |
| 3485 | + @ArgumentsSource(MongoProvider.class) |
| 3486 | + void testSelfJoinWithSubQuery(String dataStoreName) throws IOException { |
| 3487 | + Collection collection = getCollection(dataStoreName); |
| 3488 | + |
| 3489 | + /* |
| 3490 | + This is the query we want to execute: |
| 3491 | + SELECT item, quantity, date |
| 3492 | + FROM <implicit_collection> |
| 3493 | + JOIN ( |
| 3494 | + SELECT item, MAX(date) AS latest_date |
| 3495 | + FROM <implicit_collection> |
| 3496 | + GROUP BY item |
| 3497 | + ) latest |
| 3498 | + ON item = latest.item |
| 3499 | + AND date = latest.latest_date |
| 3500 | + ORDER BY `item` ASC; |
| 3501 | + */ |
| 3502 | + |
| 3503 | + /* |
| 3504 | + The right subquery: |
| 3505 | + SELECT item, MAX(date) AS latest_date |
| 3506 | + FROM <implicit_collection> |
| 3507 | + GROUP BY item |
| 3508 | + */ |
| 3509 | + Query subQuery = |
| 3510 | + Query.builder() |
| 3511 | + .addSelection(SelectionSpec.of(IdentifierExpression.of("item"))) |
| 3512 | + .addSelection( |
| 3513 | + SelectionSpec.of( |
| 3514 | + AggregateExpression.of( |
| 3515 | + AggregationOperator.MAX, IdentifierExpression.of("date")), |
| 3516 | + "latest_date")) |
| 3517 | + .addAggregation(IdentifierExpression.of("item")) |
| 3518 | + .build(); |
| 3519 | + |
| 3520 | + /* |
| 3521 | + The FROM expression representing a join with the right subquery: |
| 3522 | + FROM <implicit_collection> |
| 3523 | + JOIN ( |
| 3524 | + SELECT item, MAX(date) AS latest_date |
| 3525 | + FROM <implicit_collection> |
| 3526 | + GROUP BY item |
| 3527 | + ) latest |
| 3528 | + ON item = latest.item |
| 3529 | + AND date = latest.latest_date; |
| 3530 | + */ |
| 3531 | + SubQueryJoinExpression subQueryJoinExpression = |
| 3532 | + SubQueryJoinExpression.builder() |
| 3533 | + .subQuery(subQuery) |
| 3534 | + .subQueryAlias("latest") |
| 3535 | + .joinCondition( |
| 3536 | + LogicalExpression.and( |
| 3537 | + RelationalExpression.of( |
| 3538 | + IdentifierExpression.of("item"), |
| 3539 | + RelationalOperator.EQ, |
| 3540 | + AliasedIdentifierExpression.builder() |
| 3541 | + .name("item") |
| 3542 | + .contextAlias("latest") |
| 3543 | + .build()), |
| 3544 | + RelationalExpression.of( |
| 3545 | + IdentifierExpression.of("date"), |
| 3546 | + RelationalOperator.EQ, |
| 3547 | + AliasedIdentifierExpression.builder() |
| 3548 | + .name("latest_date") |
| 3549 | + .contextAlias("latest") |
| 3550 | + .build()))) |
| 3551 | + .build(); |
| 3552 | + |
| 3553 | + /* |
| 3554 | + Now build the top-level Query: |
| 3555 | + SELECT item, quantity, date FROM <subQueryJoinExpression> ORDER BY `item` ASC; |
| 3556 | + */ |
| 3557 | + Query mainQuery = |
| 3558 | + Query.builder() |
| 3559 | + .addSelection(IdentifierExpression.of("item")) |
| 3560 | + .addSelection(IdentifierExpression.of("quantity")) |
| 3561 | + .addSelection(IdentifierExpression.of("date")) |
| 3562 | + .addFromClause(subQueryJoinExpression) |
| 3563 | + .addSort(IdentifierExpression.of("item"), ASC) |
| 3564 | + .build(); |
| 3565 | + |
| 3566 | + Iterator<Document> iterator = collection.aggregate(mainQuery); |
| 3567 | + assertDocsAndSizeEqual( |
| 3568 | + dataStoreName, iterator, "query/self_join_with_sub_query_response.json", 4); |
| 3569 | + } |
| 3570 | + |
| 3571 | + @ParameterizedTest |
| 3572 | + @ArgumentsSource(MongoProvider.class) |
| 3573 | + void testSelfJoinWithSubQueryWithNestedFields(String dataStoreName) throws IOException { |
| 3574 | + createCollectionData( |
| 3575 | + "query/items_data_with_nested_fields.json", "items_data_with_nested_fields"); |
| 3576 | + Collection collection = getCollection(dataStoreName, "items_data_with_nested_fields"); |
| 3577 | + |
| 3578 | + /* |
| 3579 | + This is the query we want to execute: |
| 3580 | + SELECT itemDetails.item, itemDetails.quantity, itemDetails.date |
| 3581 | + FROM <implicit_collection> |
| 3582 | + JOIN ( |
| 3583 | + SELECT itemDetails.item, MAX(itemDetails.date) AS latest_date |
| 3584 | + FROM <implicit_collection> |
| 3585 | + GROUP BY itemDetails.item |
| 3586 | + ) latest |
| 3587 | + ON itemDetails.item = latest.itemDetails.item |
| 3588 | + AND itemDetails.date = latest.latest_date |
| 3589 | + ORDER BY `itemDetails.item` ASC; |
| 3590 | + */ |
| 3591 | + |
| 3592 | + /* |
| 3593 | + The right subquery: |
| 3594 | + SELECT itemDetails.item, MAX(itemDetails.date) AS latest_date |
| 3595 | + FROM <implicit_collection> |
| 3596 | + GROUP BY itemDetails.item |
| 3597 | + */ |
| 3598 | + Query subQuery = |
| 3599 | + Query.builder() |
| 3600 | + .addSelection(SelectionSpec.of(IdentifierExpression.of("itemDetails.item"))) |
| 3601 | + .addSelection( |
| 3602 | + SelectionSpec.of( |
| 3603 | + AggregateExpression.of( |
| 3604 | + AggregationOperator.MAX, IdentifierExpression.of("itemDetails.date")), |
| 3605 | + "latest_date")) |
| 3606 | + .addAggregation(IdentifierExpression.of("itemDetails.item")) |
| 3607 | + .build(); |
| 3608 | + |
| 3609 | + /* |
| 3610 | + The FROM expression representing a join with the right subquery: |
| 3611 | + FROM <implicit_collection> |
| 3612 | + JOIN ( |
| 3613 | + SELECT itemDetails.item, MAX(itemDetails.date) AS latest_date |
| 3614 | + FROM <implicit_collection> |
| 3615 | + GROUP BY itemDetails.item |
| 3616 | + ) latest |
| 3617 | + ON itemDetails.item = latest.itemDetails.item |
| 3618 | + AND itemDetails.date = latest.latest_date; |
| 3619 | + */ |
| 3620 | + SubQueryJoinExpression subQueryJoinExpression = |
| 3621 | + SubQueryJoinExpression.builder() |
| 3622 | + .subQuery(subQuery) |
| 3623 | + .subQueryAlias("latest") |
| 3624 | + .joinCondition( |
| 3625 | + LogicalExpression.and( |
| 3626 | + RelationalExpression.of( |
| 3627 | + IdentifierExpression.of("itemDetails.item"), |
| 3628 | + RelationalOperator.EQ, |
| 3629 | + AliasedIdentifierExpression.builder() |
| 3630 | + .name("itemDetails.item") |
| 3631 | + .contextAlias("latest") |
| 3632 | + .build()), |
| 3633 | + RelationalExpression.of( |
| 3634 | + IdentifierExpression.of("itemDetails.date"), |
| 3635 | + RelationalOperator.EQ, |
| 3636 | + AliasedIdentifierExpression.builder() |
| 3637 | + .name("latest_date") |
| 3638 | + .contextAlias("latest") |
| 3639 | + .build()))) |
| 3640 | + .build(); |
| 3641 | + |
| 3642 | + /* |
| 3643 | + Now build the top-level Query: |
| 3644 | + SELECT itemDetails.item, itemDetails.quantity, itemDetails.date FROM <subQueryJoinExpression> ORDER BY `itemDetails.item` ASC; |
| 3645 | + */ |
| 3646 | + Query mainQuery = |
| 3647 | + Query.builder() |
| 3648 | + .addSelection(IdentifierExpression.of("itemDetails.item")) |
| 3649 | + .addSelection(IdentifierExpression.of("itemDetails.quantity")) |
| 3650 | + .addSelection(IdentifierExpression.of("itemDetails.date")) |
| 3651 | + .addFromClause(subQueryJoinExpression) |
| 3652 | + .addSort(IdentifierExpression.of("itemDetails.item"), ASC) |
| 3653 | + .build(); |
| 3654 | + |
| 3655 | + Iterator<Document> iterator = collection.aggregate(mainQuery); |
| 3656 | + assertDocsAndSizeEqual( |
| 3657 | + dataStoreName, iterator, "query/sub_query_join_response_with_nested_fields.json", 3); |
| 3658 | + } |
| 3659 | + |
3481 | 3660 | private static Collection getCollection(final String dataStoreName) { |
3482 | 3661 | return getCollection(dataStoreName, COLLECTION_NAME); |
3483 | 3662 | } |
|
0 commit comments