Skip to content

Commit cab0da9

Browse files
Fix _x_count and optional filter creating duplicate GlobalOperationsStart (kensho-technologies#253)
* Fix bug * Fix merge conflict * Fix lint * Fix indentation
1 parent f6079c6 commit cab0da9

File tree

4 files changed

+121
-2
lines changed

4 files changed

+121
-2
lines changed

graphql_compiler/compiler/ir_lowering_match/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright 2018-present Kensho Technologies, LLC.
22
import six
33

4-
from ..blocks import Filter, GlobalOperationsStart
4+
from ..blocks import Filter
55
from ..ir_lowering_common import (extract_optional_location_root_info,
66
extract_simple_optional_location_info,
77
lower_context_field_existence, merge_consecutive_filter_clauses,
@@ -82,7 +82,8 @@ def lower_ir(ir_blocks, query_metadata_table, type_equivalence_hints=None):
8282
if len(simple_optional_root_info) > 0:
8383
where_filter_predicate = construct_where_filter_predicate(
8484
query_metadata_table, simple_optional_root_info)
85-
ir_blocks.insert(-1, GlobalOperationsStart())
85+
# The GlobalOperationsStart block should already exist at this point. It is inserted
86+
# in the compiler_frontend, and this function asserts that at the beginning.
8687
ir_blocks.insert(-1, Filter(where_filter_predicate))
8788

8889
# These lowering / optimization passes work on IR blocks.

graphql_compiler/tests/test_compiler.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,45 @@ def test_filter_in_optional_block(self):
660660

661661
check_test_data(self, test_data, expected_match, expected_gremlin, expected_sql)
662662

663+
def test_filter_in_optional_and_count(self):
664+
test_data = test_input_data.filter_in_optional_and_count()
665+
666+
expected_match = '''
667+
SELECT
668+
Species___1.name AS `species_name`
669+
FROM (
670+
MATCH {{
671+
class: Species,
672+
as: Species___1
673+
}}.in('Animal_OfSpecies') {{
674+
where: ((name = {animal_name})),
675+
optional: true,
676+
as: Species__in_Animal_OfSpecies___1
677+
}}
678+
RETURN $matches
679+
)
680+
LET $Species___1___in_Species_Eats = Species___1.in("Species_Eats").asList()
681+
WHERE (
682+
(
683+
$Species___1___in_Species_Eats.size() >= {predators}
684+
) AND (
685+
(
686+
(
687+
Species___1.in_Animal_OfSpecies IS null
688+
) OR (
689+
Species___1.in_Animal_OfSpecies.size() = 0
690+
)
691+
) OR (
692+
Species__in_Animal_OfSpecies___1 IS NOT null
693+
)
694+
)
695+
)
696+
'''
697+
expected_gremlin = NotImplementedError
698+
expected_sql = NotImplementedError
699+
700+
check_test_data(self, test_data, expected_match, expected_gremlin, expected_sql)
701+
663702
def test_between_filter_on_simple_scalar(self):
664703
# The "between" filter emits different output depending on what the compared types are.
665704
# This test checks for correct code generation when the type is a simple scalar (a String).

graphql_compiler/tests/test_input_data.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,34 @@ def filter_in_optional_block():
314314
type_equivalence_hints=None)
315315

316316

317+
def filter_in_optional_and_count():
318+
graphql_input = '''{
319+
Species {
320+
name @output(out_name: "species_name")
321+
322+
in_Animal_OfSpecies @optional {
323+
name @filter(op_name: "=", value: ["$animal_name"])
324+
}
325+
326+
in_Species_Eats @fold {
327+
_x_count @filter(op_name: ">=", value: ["$predators"])
328+
}
329+
}
330+
}'''
331+
expected_output_metadata = {
332+
'species_name': OutputMetadata(type=GraphQLString, optional=False),
333+
}
334+
expected_input_metadata = {
335+
'animal_name': GraphQLString,
336+
'predators': GraphQLInt,
337+
}
338+
return CommonTestData(
339+
graphql_input=graphql_input,
340+
expected_output_metadata=expected_output_metadata,
341+
expected_input_metadata=expected_input_metadata,
342+
type_equivalence_hints=None)
343+
344+
317345
def between_filter_on_simple_scalar():
318346
# The "between" filter emits different output depending on what the compared types are.
319347
# This test checks for correct code generation when the type is a simple scalar (a String).

graphql_compiler/tests/test_ir_generation.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,57 @@ def test_filter_in_optional_block(self):
702702

703703
check_test_data(self, test_data, expected_blocks, expected_location_types)
704704

705+
def test_filter_in_optional_and_count(self):
706+
test_data = test_input_data.filter_in_optional_and_count()
707+
708+
base_location = helpers.Location(('Species',))
709+
animal_location = base_location.navigate_to_subpath('in_Animal_OfSpecies')
710+
base_revisit_1 = base_location.revisit()
711+
fold_location = base_revisit_1.navigate_to_fold('in_Species_Eats')
712+
713+
expected_blocks = [
714+
blocks.QueryRoot({'Species'}),
715+
blocks.MarkLocation(base_location),
716+
blocks.Traverse('in', 'Animal_OfSpecies', optional=True),
717+
blocks.Filter(
718+
expressions.BinaryComposition(
719+
u'=',
720+
expressions.LocalField('name'),
721+
expressions.Variable('$animal_name', GraphQLString)
722+
)
723+
),
724+
blocks.MarkLocation(animal_location),
725+
blocks.EndOptional(),
726+
blocks.Backtrack(base_location, optional=True),
727+
blocks.MarkLocation(base_revisit_1),
728+
blocks.Fold(fold_location),
729+
blocks.MarkLocation(fold_location),
730+
blocks.Unfold(),
731+
blocks.GlobalOperationsStart(),
732+
blocks.Filter(expressions.BinaryComposition(
733+
u'>=',
734+
expressions.FoldedContextField(
735+
fold_location.navigate_to_field(COUNT_META_FIELD_NAME),
736+
GraphQLInt
737+
),
738+
expressions.Variable('$predators', GraphQLInt),
739+
)),
740+
blocks.ConstructResult({
741+
'species_name': expressions.OutputContextField(
742+
base_location.navigate_to_field('name'), GraphQLString
743+
),
744+
}),
745+
746+
]
747+
expected_location_types = {
748+
base_location: 'Species',
749+
animal_location: 'Animal',
750+
base_revisit_1: 'Species',
751+
fold_location: 'Species',
752+
}
753+
754+
check_test_data(self, test_data, expected_blocks, expected_location_types)
755+
705756
def test_between_filter_on_simple_scalar(self):
706757
test_data = test_input_data.between_filter_on_simple_scalar()
707758

0 commit comments

Comments
 (0)