Skip to content

Commit

Permalink
Merge 8cd9d1a into a9d0313
Browse files Browse the repository at this point in the history
  • Loading branch information
cw6515 committed Aug 1, 2018
2 parents a9d0313 + 8cd9d1a commit f8ade69
Show file tree
Hide file tree
Showing 4 changed files with 430 additions and 4 deletions.
8 changes: 4 additions & 4 deletions graphql_compiler/compiler/ir_sanity_checks.py
Expand Up @@ -117,11 +117,11 @@ def _sanity_check_block_pairwise_constraints(ir_blocks):
raise AssertionError(u'Expected MarkLocation after Backtrack with optional=True, '
u'but none was found: {}'.format(ir_blocks))

# Recurse blocks are immediately preceded by a MarkLocation block.
# Recurse blocks are immediately preceded by a MarkLocation or Backtrack block.
if isinstance(second_block, Recurse):
if not isinstance(first_block, MarkLocation):
raise AssertionError(u'Expected MarkLocation before Recurse, but none was found: '
u'{}'.format(ir_blocks))
if not (isinstance(first_block, MarkLocation) or isinstance(first_block, Backtrack)):
raise AssertionError(u'Expected MarkLocation or Backtrack before Recurse, but none '
u'was found: {}'.format(ir_blocks))


def _sanity_check_mark_location_preceding_optional_traverse(ir_blocks):
Expand Down
186 changes: 186 additions & 0 deletions graphql_compiler/tests/test_compiler.py
Expand Up @@ -1209,6 +1209,192 @@ def test_simple_recurse(self):

check_test_data(self, test_data, expected_match, expected_gremlin)

def test_traverse_then_recurse(self):
test_data = test_input_data.traverse_then_recurse()

expected_match = '''
SELECT
Animal__out_Animal_ParentOf___1.name AS `ancestor_name`,
Animal___1.name AS `animal_name`,
Animal__out_Animal_ImportantEvent___1.name AS `important_event`
FROM (
MATCH {{
class: Animal,
as: Animal___1
}}.out('Animal_ImportantEvent') {{
class: Event,
as: Animal__out_Animal_ImportantEvent___1
}} , {{
class: Animal,
as: Animal___1
}}.out('Animal_ParentOf') {{
while: ($depth < 2),
as: Animal__out_Animal_ParentOf___1
}}
RETURN $matches
)
'''

expected_gremlin = '''
g.V('@class', 'Animal')
.as('Animal___1')
.out('Animal_ImportantEvent')
.filter{it, m -> ['Event'].contains(it['@class'])}
.as('Animal__out_Animal_ImportantEvent___1')
.back('Animal___1')
.copySplit(
_(),
_().out('Animal_ParentOf'),
_().out('Animal_ParentOf').out('Animal_ParentOf')
)
.exhaustMerge
.as('Animal__out_Animal_ParentOf___1')
.back('Animal___1')
.transform{it, m -> new com.orientechnologies.orient.core.record.impl.ODocument([
ancestor_name: m.Animal__out_Animal_ParentOf___1.name,
animal_name: m.Animal___1.name,
important_event: m.Animal__out_Animal_ImportantEvent___1.name
])}
'''

check_test_data(self, test_data, expected_match, expected_gremlin)

def test_filter_then_traverse_and_recurse(self):
test_data = test_input_data.filter_then_traverse_and_recurse()

expected_match = '''
SELECT
Animal__out_Animal_ParentOf___1.name AS `ancestor_name`,
Animal___1.name AS `animal_name`,
Animal__out_Animal_ImportantEvent___1.name AS `important_event`
FROM (
MATCH {{
class: Animal,
where: (
(
(name = {animal_name_or_alias})
OR
(alias CONTAINS {animal_name_or_alias})
)
),
as: Animal___1
}}.out('Animal_ImportantEvent') {{
where: ((@this INSTANCEOF 'Event')),
as: Animal__out_Animal_ImportantEvent___1
}} , {{
class: Animal,
as: Animal___1
}}.out('Animal_ParentOf') {{
while: ($depth < 2),
as: Animal__out_Animal_ParentOf___1
}}
RETURN $matches
)
'''

expected_gremlin = '''
g.V('@class', 'Animal')
.filter{it, m -> (
(it.name == $animal_name_or_alias) || it.alias.contains($animal_name_or_alias)
)}
.as('Animal___1')
.out('Animal_ImportantEvent')
.filter{it, m -> ['Event'].contains(it['@class'])}
.as('Animal__out_Animal_ImportantEvent___1')
.back('Animal___1')
.copySplit(
_(),
_().out('Animal_ParentOf'),
_().out('Animal_ParentOf').out('Animal_ParentOf')
)
.exhaustMerge
.as('Animal__out_Animal_ParentOf___1')
.back('Animal___1')
.transform{it, m -> new com.orientechnologies.orient.core.record.impl.ODocument([
ancestor_name: m.Animal__out_Animal_ParentOf___1.name,
animal_name: m.Animal___1.name,
important_event: m.Animal__out_Animal_ImportantEvent___1.name
])}
'''

check_test_data(self, test_data, expected_match, expected_gremlin)

def test_two_consecutive_recurses(self):
test_data = test_input_data.two_consecutive_recurses()

expected_match = '''
SELECT
Animal__out_Animal_ParentOf___1.name AS `ancestor_name`,
Animal___1.name AS `animal_name`,
Animal__in_Animal_ParentOf___1.name AS `descendent_name`,
Animal__out_Animal_ImportantEvent___1.name AS `important_event`
FROM (
MATCH {{
class: Animal,
where: (
(
(name = {animal_name_or_alias})
OR
(alias CONTAINS {animal_name_or_alias})
)
),
as: Animal___1
}}.out('Animal_ImportantEvent') {{
where: ((@this INSTANCEOF 'Event')),
as: Animal__out_Animal_ImportantEvent___1
}} , {{
class: Animal,
as: Animal___1
}}.out('Animal_ParentOf') {{
while: ($depth < 2),
as: Animal__out_Animal_ParentOf___1
}} , {{
class: Animal,
as: Animal___1
}}.in('Animal_ParentOf') {{
while: ($depth < 2),
as: Animal__in_Animal_ParentOf___1
}}
RETURN $matches
)
'''

expected_gremlin = '''
g.V('@class', 'Animal')
.filter{it, m -> (
(it.name == $animal_name_or_alias) || it.alias.contains($animal_name_or_alias)
)}
.as('Animal___1')
.out('Animal_ImportantEvent')
.filter{it, m -> ['Event'].contains(it['@class'])}
.as('Animal__out_Animal_ImportantEvent___1')
.back('Animal___1')
.copySplit(
_(),
_().out('Animal_ParentOf'),
_().out('Animal_ParentOf').out('Animal_ParentOf')
)
.exhaustMerge
.as('Animal__out_Animal_ParentOf___1')
.back('Animal___1')
.copySplit(
_(),
_().in('Animal_ParentOf'),
_().in('Animal_ParentOf').in('Animal_ParentOf')
)
.exhaustMerge
.as('Animal__in_Animal_ParentOf___1')
.back('Animal___1')
.transform{it, m -> new com.orientechnologies.orient.core.record.impl.ODocument([
ancestor_name: m.Animal__out_Animal_ParentOf___1.name,
animal_name: m.Animal___1.name,
descendent_name: m.Animal__in_Animal_ParentOf___1.name,
important_event: m.Animal__out_Animal_ImportantEvent___1.name
])}
'''

check_test_data(self, test_data, expected_match, expected_gremlin)

def test_recurse_within_fragment(self):
test_data = test_input_data.recurse_within_fragment()

Expand Down
98 changes: 98 additions & 0 deletions graphql_compiler/tests/test_input_data.py
Expand Up @@ -756,6 +756,104 @@ def simple_recurse():
type_equivalence_hints=None)


def traverse_then_recurse():
graphql_input = '''{
Animal {
name @output(out_name: "animal_name")
out_Animal_ImportantEvent {
... on Event {
name @output(out_name: "important_event")
}
}
out_Animal_ParentOf @recurse(depth: 2) {
name @output(out_name: "ancestor_name")
}
}
}'''

expected_output_metadata = {
'animal_name': OutputMetadata(type=GraphQLString, optional=False),
'important_event': OutputMetadata(type=GraphQLString, optional=False),
'ancestor_name': OutputMetadata(type=GraphQLString, optional=False),
}

expected_input_metadata = {}

return CommonTestData(
graphql_input=graphql_input,
expected_output_metadata=expected_output_metadata,
expected_input_metadata=expected_input_metadata,
type_equivalence_hints=None)


def filter_then_traverse_and_recurse():
graphql_input = '''{
Animal @filter(op_name: "name_or_alias", value: ["$animal_name_or_alias"]) {
name @output(out_name: "animal_name")
out_Animal_ImportantEvent {
... on Event {
name @output(out_name: "important_event")
}
}
out_Animal_ParentOf @recurse(depth: 2) {
name @output(out_name: "ancestor_name")
}
}
}'''

expected_output_metadata = {
'animal_name': OutputMetadata(type=GraphQLString, optional=False),
'important_event': OutputMetadata(type=GraphQLString, optional=False),
'ancestor_name': OutputMetadata(type=GraphQLString, optional=False),
}

expected_input_metadata = {
'animal_name_or_alias': GraphQLString
}

return CommonTestData(
graphql_input=graphql_input,
expected_output_metadata=expected_output_metadata,
expected_input_metadata=expected_input_metadata,
type_equivalence_hints=None)


def two_consecutive_recurses():
graphql_input = '''{
Animal @filter(op_name: "name_or_alias", value: ["$animal_name_or_alias"]) {
name @output(out_name: "animal_name")
out_Animal_ImportantEvent {
... on Event {
name @output(out_name: "important_event")
}
}
out_Animal_ParentOf @recurse(depth: 2) {
name @output(out_name: "ancestor_name")
}
in_Animal_ParentOf @recurse(depth: 2) {
name @output(out_name: "descendent_name")
}
}
}'''

expected_output_metadata = {
'animal_name': OutputMetadata(type=GraphQLString, optional=False),
'important_event': OutputMetadata(type=GraphQLString, optional=False),
'ancestor_name': OutputMetadata(type=GraphQLString, optional=False),
'descendent_name': OutputMetadata(type=GraphQLString, optional=False)
}

expected_input_metadata = {
'animal_name_or_alias': GraphQLString
}

return CommonTestData(
graphql_input=graphql_input,
expected_output_metadata=expected_output_metadata,
expected_input_metadata=expected_input_metadata,
type_equivalence_hints=None)


def recurse_within_fragment():
graphql_input = '''{
Food {
Expand Down

0 comments on commit f8ade69

Please sign in to comment.