diff --git a/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql-parsed.ron b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql-parsed.ron new file mode 100644 index 00000000..d330ce3f --- /dev/null +++ b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql-parsed.ron @@ -0,0 +1,124 @@ +Ok(TestParsedGraphQLQuery( + schema_name: "numbers", + query: Query( + root_connection: FieldConnection( + position: Pos( + line: 3, + column: 5, + ), + name: "Two", + ), + root_field: FieldNode( + position: Pos( + line: 3, + column: 5, + ), + name: "Two", + connections: [ + (FieldConnection( + position: Pos( + line: 4, + column: 9, + ), + name: "value", + ), FieldNode( + position: Pos( + line: 4, + column: 9, + ), + name: "value", + tag: [ + TagDirective( + name: Some("two"), + ), + ], + )), + (FieldConnection( + position: Pos( + line: 5, + column: 9, + ), + name: "multiple", + arguments: { + "max": Int64(3), + }, + ), FieldNode( + position: Pos( + line: 5, + column: 9, + ), + name: "multiple", + connections: [ + (FieldConnection( + position: Pos( + line: 6, + column: 13, + ), + name: "value", + ), FieldNode( + position: Pos( + line: 6, + column: 13, + ), + name: "value", + filter: [ + FilterDirective( + operation: Equals((), VariableRef("six")), + ), + ], + output: [ + OutputDirective(), + ], + )), + (FieldConnection( + position: Pos( + line: 7, + column: 13, + ), + name: "primeFactor", + fold: Some(FoldGroup( + fold: FoldDirective(), + transform: Some(TransformGroup( + transform: TransformDirective( + kind: Count, + ), + filter: [ + FilterDirective( + operation: GreaterThanOrEqual((), VariableRef("zero")), + ), + FilterDirective( + operation: LessThan((), TagRef("two")), + ), + ], + )), + )), + ), FieldNode( + position: Pos( + line: 7, + column: 13, + ), + name: "primeFactor", + transform_group: Some(TransformGroup( + transform: TransformDirective( + kind: Count, + ), + filter: [ + FilterDirective( + operation: GreaterThanOrEqual((), VariableRef("zero")), + ), + FilterDirective( + operation: LessThan((), TagRef("two")), + ), + ], + )), + )), + ], + )), + ], + ), + ), + arguments: { + "six": Uint64(6), + "zero": Uint64(0), + }, +)) diff --git a/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql.ron b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql.ron new file mode 100644 index 00000000..3b062aef --- /dev/null +++ b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.graphql.ron @@ -0,0 +1,26 @@ +TestGraphQLQuery ( + // This test ensures that we do not ignore filters that should + // disable an optimization in which we only compute part of a + // fold. + // + // This test should result in no results. However, if we partially + // compute the fold ignoring the `>=` filter, we will get a result + // of `{ "value": 6 }`. + schema_name: "numbers", + query: r#" +{ + Two { + value @tag(name: "two") + multiple(max: 3) { + value @filter(op: "=", value: ["$six"]) @output + primeFactor @fold @transform(op: "count") + @filter(op: ">=", value: ["$zero"]) + @filter(op: "<", value: ["%two"]) + } + } +}"#, + arguments: { + "zero": Uint64(0), + "six": Uint64(6), + }, +) diff --git a/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.ir.ron b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.ir.ron new file mode 100644 index 00000000..9bbf8635 --- /dev/null +++ b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.ir.ron @@ -0,0 +1,84 @@ +Ok(TestIRQuery( + schema_name: "numbers", + ir_query: IRQuery( + root_name: "Two", + root_component: IRQueryComponent( + root: Vid(1), + vertices: { + Vid(1): IRVertex( + vid: Vid(1), + type_name: "Prime", + ), + Vid(2): IRVertex( + vid: Vid(2), + type_name: "Composite", + filters: [ + Equals(LocalField( + field_name: "value", + field_type: "Int", + ), Variable(VariableRef( + variable_name: "six", + variable_type: "Int", + ))), + ], + ), + }, + edges: { + Eid(1): IREdge( + eid: Eid(1), + from_vid: Vid(1), + to_vid: Vid(2), + edge_name: "multiple", + parameters: EdgeParameters( + contents: { + "max": Int64(3), + }, + ), + ), + }, + folds: { + Eid(2): IRFold( + eid: Eid(2), + from_vid: Vid(2), + to_vid: Vid(3), + edge_name: "primeFactor", + component: IRQueryComponent( + root: Vid(3), + vertices: { + Vid(3): IRVertex( + vid: Vid(3), + type_name: "Prime", + ), + }, + ), + post_filters: [ + GreaterThanOrEqual(Count, Variable(VariableRef( + variable_name: "zero", + variable_type: "Int!", + ))), + LessThan(Count, Tag(ContextField(ContextField( + vertex_id: Vid(1), + field_name: "value", + field_type: "Int", + )))), + ], + ), + }, + outputs: { + "value": ContextField( + vertex_id: Vid(2), + field_name: "value", + field_type: "Int", + ), + }, + ), + variables: { + "six": "Int", + "zero": "Int!", + }, + ), + arguments: { + "six": Uint64(6), + "zero": Uint64(0), + }, +)) diff --git a/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.output.ron b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.output.ron new file mode 100644 index 00000000..5eacd738 --- /dev/null +++ b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.output.ron @@ -0,0 +1,11 @@ +TestInterpreterOutputData( + schema_name: "numbers", + outputs: { + "value": Output( + name: "value", + value_type: "Int", + vid: Vid(2), + ), + }, + results: [], +) diff --git a/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.trace.ron b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.trace.ron new file mode 100644 index 00000000..967f7124 --- /dev/null +++ b/trustfall_core/test_data/tests/valid_queries/fold_count_filter_on_a_tag.trace.ron @@ -0,0 +1,445 @@ +TestInterpreterOutputTrace( + schema_name: "numbers", + trace: Trace( + ops: { + Opid(1): TraceOp( + opid: Opid(1), + parent_opid: None, + content: Call(ResolveStartingVertices(Vid(1))), + ), + Opid(2): TraceOp( + opid: Opid(2), + parent_opid: None, + content: Call(ResolveNeighbors(Vid(1), "Prime", Eid(1))), + ), + Opid(3): TraceOp( + opid: Opid(3), + parent_opid: None, + content: Call(ResolveProperty(Vid(2), "Composite", "value")), + ), + Opid(4): TraceOp( + opid: Opid(4), + parent_opid: None, + content: Call(ResolveNeighbors(Vid(2), "Composite", Eid(2))), + ), + Opid(5): TraceOp( + opid: Opid(5), + parent_opid: None, + content: Call(ResolveProperty(Vid(1), "Prime", "value")), + ), + Opid(6): TraceOp( + opid: Opid(6), + parent_opid: None, + content: Call(ResolveProperty(Vid(2), "Composite", "value")), + ), + Opid(7): TraceOp( + opid: Opid(7), + parent_opid: Some(Opid(6)), + content: AdvanceInputIterator, + ), + Opid(8): TraceOp( + opid: Opid(8), + parent_opid: Some(Opid(5)), + content: AdvanceInputIterator, + ), + Opid(9): TraceOp( + opid: Opid(9), + parent_opid: Some(Opid(4)), + content: AdvanceInputIterator, + ), + Opid(10): TraceOp( + opid: Opid(10), + parent_opid: Some(Opid(3)), + content: AdvanceInputIterator, + ), + Opid(11): TraceOp( + opid: Opid(11), + parent_opid: Some(Opid(2)), + content: AdvanceInputIterator, + ), + Opid(12): TraceOp( + opid: Opid(12), + parent_opid: Some(Opid(1)), + content: YieldFrom(ResolveStartingVertices(Prime(PrimeNumber(2)))), + ), + Opid(13): TraceOp( + opid: Opid(13), + parent_opid: Some(Opid(2)), + content: YieldInto(SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + )), + ), + Opid(14): TraceOp( + opid: Opid(14), + parent_opid: Some(Opid(2)), + content: YieldFrom(ResolveNeighborsOuter(SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + ))), + ), + Opid(15): TraceOp( + opid: Opid(15), + parent_opid: Some(Opid(14)), + content: YieldFrom(ResolveNeighborsInner(0, Composite(CompositeNumber(4, [ + 2, + ])))), + ), + Opid(16): TraceOp( + opid: Opid(16), + parent_opid: Some(Opid(3)), + content: YieldInto(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(4, [ + 2, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + )), + ), + Opid(17): TraceOp( + opid: Opid(17), + parent_opid: Some(Opid(3)), + content: YieldFrom(ResolveProperty(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(4, [ + 2, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + ), Int64(4))), + ), + Opid(18): TraceOp( + opid: Opid(18), + parent_opid: Some(Opid(3)), + content: AdvanceInputIterator, + ), + Opid(19): TraceOp( + opid: Opid(19), + parent_opid: Some(Opid(14)), + content: YieldFrom(ResolveNeighborsInner(1, Composite(CompositeNumber(6, [ + 2, + 3, + ])))), + ), + Opid(20): TraceOp( + opid: Opid(20), + parent_opid: Some(Opid(3)), + content: YieldInto(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + )), + ), + Opid(21): TraceOp( + opid: Opid(21), + parent_opid: Some(Opid(3)), + content: YieldFrom(ResolveProperty(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + }, + ), Int64(6))), + ), + Opid(22): TraceOp( + opid: Opid(22), + parent_opid: Some(Opid(4)), + content: YieldInto(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + Vid(2): Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + }, + )), + ), + Opid(23): TraceOp( + opid: Opid(23), + parent_opid: Some(Opid(4)), + content: YieldFrom(ResolveNeighborsOuter(SerializableContext( + active_vertex: Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + Vid(2): Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + }, + ))), + ), + Opid(24): TraceOp( + opid: Opid(24), + parent_opid: Some(Opid(23)), + content: YieldFrom(ResolveNeighborsInner(0, Prime(PrimeNumber(2)))), + ), + Opid(25): TraceOp( + opid: Opid(25), + parent_opid: Some(Opid(23)), + content: YieldFrom(ResolveNeighborsInner(1, Prime(PrimeNumber(3)))), + ), + Opid(26): TraceOp( + opid: Opid(26), + parent_opid: Some(Opid(23)), + content: OutputIteratorExhausted, + ), + Opid(27): TraceOp( + opid: Opid(27), + parent_opid: Some(Opid(5)), + content: YieldInto(SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + Vid(2): Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + }, + values: [ + Uint64(2), + ], + suspended_vertices: [ + Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + ], + folded_contexts: { + Eid(2): Some([ + SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(3): Some(Prime(PrimeNumber(2))), + }, + ), + SerializableContext( + active_vertex: Some(Prime(PrimeNumber(3))), + vertices: { + Vid(3): Some(Prime(PrimeNumber(3))), + }, + ), + ]), + }, + )), + ), + Opid(28): TraceOp( + opid: Opid(28), + parent_opid: Some(Opid(5)), + content: YieldFrom(ResolveProperty(SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(1): Some(Prime(PrimeNumber(2))), + Vid(2): Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + }, + values: [ + Uint64(2), + ], + suspended_vertices: [ + Some(Composite(CompositeNumber(6, [ + 2, + 3, + ]))), + ], + folded_contexts: { + Eid(2): Some([ + SerializableContext( + active_vertex: Some(Prime(PrimeNumber(2))), + vertices: { + Vid(3): Some(Prime(PrimeNumber(2))), + }, + ), + SerializableContext( + active_vertex: Some(Prime(PrimeNumber(3))), + vertices: { + Vid(3): Some(Prime(PrimeNumber(3))), + }, + ), + ]), + }, + ), Int64(2))), + ), + Opid(29): TraceOp( + opid: Opid(29), + parent_opid: Some(Opid(5)), + content: AdvanceInputIterator, + ), + Opid(30): TraceOp( + opid: Opid(30), + parent_opid: Some(Opid(4)), + content: AdvanceInputIterator, + ), + Opid(31): TraceOp( + opid: Opid(31), + parent_opid: Some(Opid(3)), + content: AdvanceInputIterator, + ), + Opid(32): TraceOp( + opid: Opid(32), + parent_opid: Some(Opid(14)), + content: OutputIteratorExhausted, + ), + Opid(33): TraceOp( + opid: Opid(33), + parent_opid: Some(Opid(2)), + content: AdvanceInputIterator, + ), + Opid(34): TraceOp( + opid: Opid(34), + parent_opid: Some(Opid(1)), + content: OutputIteratorExhausted, + ), + Opid(35): TraceOp( + opid: Opid(35), + parent_opid: Some(Opid(2)), + content: InputIteratorExhausted, + ), + Opid(36): TraceOp( + opid: Opid(36), + parent_opid: Some(Opid(2)), + content: OutputIteratorExhausted, + ), + Opid(37): TraceOp( + opid: Opid(37), + parent_opid: Some(Opid(3)), + content: InputIteratorExhausted, + ), + Opid(38): TraceOp( + opid: Opid(38), + parent_opid: Some(Opid(3)), + content: OutputIteratorExhausted, + ), + Opid(39): TraceOp( + opid: Opid(39), + parent_opid: Some(Opid(4)), + content: InputIteratorExhausted, + ), + Opid(40): TraceOp( + opid: Opid(40), + parent_opid: Some(Opid(4)), + content: OutputIteratorExhausted, + ), + Opid(41): TraceOp( + opid: Opid(41), + parent_opid: Some(Opid(5)), + content: InputIteratorExhausted, + ), + Opid(42): TraceOp( + opid: Opid(42), + parent_opid: Some(Opid(5)), + content: OutputIteratorExhausted, + ), + Opid(43): TraceOp( + opid: Opid(43), + parent_opid: Some(Opid(6)), + content: InputIteratorExhausted, + ), + Opid(44): TraceOp( + opid: Opid(44), + parent_opid: Some(Opid(6)), + content: OutputIteratorExhausted, + ), + }, + ir_query: IRQuery( + root_name: "Two", + root_component: IRQueryComponent( + root: Vid(1), + vertices: { + Vid(1): IRVertex( + vid: Vid(1), + type_name: "Prime", + ), + Vid(2): IRVertex( + vid: Vid(2), + type_name: "Composite", + filters: [ + Equals(LocalField( + field_name: "value", + field_type: "Int", + ), Variable(VariableRef( + variable_name: "six", + variable_type: "Int", + ))), + ], + ), + }, + edges: { + Eid(1): IREdge( + eid: Eid(1), + from_vid: Vid(1), + to_vid: Vid(2), + edge_name: "multiple", + parameters: EdgeParameters( + contents: { + "max": Int64(3), + }, + ), + ), + }, + folds: { + Eid(2): IRFold( + eid: Eid(2), + from_vid: Vid(2), + to_vid: Vid(3), + edge_name: "primeFactor", + component: IRQueryComponent( + root: Vid(3), + vertices: { + Vid(3): IRVertex( + vid: Vid(3), + type_name: "Prime", + ), + }, + ), + post_filters: [ + GreaterThanOrEqual(Count, Variable(VariableRef( + variable_name: "zero", + variable_type: "Int!", + ))), + LessThan(Count, Tag(ContextField(ContextField( + vertex_id: Vid(1), + field_name: "value", + field_type: "Int", + )))), + ], + ), + }, + outputs: { + "value": ContextField( + vertex_id: Vid(2), + field_name: "value", + field_type: "Int", + ), + }, + ), + variables: { + "six": "Int", + "zero": "Int!", + }, + ), + arguments: { + "six": Uint64(6), + "zero": Uint64(0), + }, + ), +)