From c1e487b76794b11981f33344e5fc37a6c23561b1 Mon Sep 17 00:00:00 2001 From: Shahzad Lone Date: Wed, 10 May 2023 12:45:35 -0400 Subject: [PATCH] PR: Add new non-join test and a test with multi sources in one count request, and convert all the tests to the new explain setup. --- .../explain/default/with_count_join_test.go | 353 ++++++++++++++++++ .../explain/default/with_count_test.go | 108 +++--- 2 files changed, 398 insertions(+), 63 deletions(-) create mode 100644 tests/integration/explain/default/with_count_join_test.go diff --git a/tests/integration/explain/default/with_count_join_test.go b/tests/integration/explain/default/with_count_join_test.go new file mode 100644 index 0000000000..e0bc02287f --- /dev/null +++ b/tests/integration/explain/default/with_count_join_test.go @@ -0,0 +1,353 @@ +// Copyright 2023 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_explain_default + +import ( + "testing" + + explainUtils "github.com/sourcenetwork/defradb/tests/integration/explain" +) + +var countTypeIndexJoinPattern = dataMap{ + "explain": dataMap{ + "selectTopNode": dataMap{ + "countNode": dataMap{ + "selectNode": dataMap{ + "typeIndexJoin": normalTypeJoinPattern, + }, + }, + }, + }, +} + +func TestDefaultExplainRequestWithCountOnOneToManyJoinedField(t *testing.T) { + test := explainUtils.ExplainRequestTestCase{ + + Description: "Explain (default) request with count on a one-to-many joined field.", + + Request: `query @explain { + Author { + name + numberOfBooks: _count(books: {}) + } + }`, + + Docs: map[int][]string{ + //articles + 0: { + `{ + "name": "After Guantánamo, Another Injustice", + "author_id": "bae-41598f0c-19bc-5da6-813b-e80f14a10df3" + }`, + `{ + "name": "To my dear readers", + "author_id": "bae-b769708d-f552-5c3d-a402-ccfd7ac7fb04" + }`, + `{ + "name": "Twinklestar's Favourite Xmas Cookie", + "author_id": "bae-b769708d-f552-5c3d-a402-ccfd7ac7fb04" + }`, + }, + //books + 1: { + `{ + "name": "Painted House", + "author_id": "bae-41598f0c-19bc-5da6-813b-e80f14a10df3" + }`, + `{ + "name": "A Time for Mercy", + "author_id": "bae-41598f0c-19bc-5da6-813b-e80f14a10df3" + }`, + `{ + "name": "Theif Lord", + "author_id": "bae-b769708d-f552-5c3d-a402-ccfd7ac7fb04" + }`, + }, + //authors + 2: { + // bae-41598f0c-19bc-5da6-813b-e80f14a10df3 + `{ + "name": "John Grisham", + "age": 65, + "verified": true + }`, + // bae-b769708d-f552-5c3d-a402-ccfd7ac7fb04 + `{ + "name": "Cornelia Funke", + "age": 62, + "verified": false + }`, + }, + }, + + ExpectedPatterns: []dataMap{countTypeIndexJoinPattern}, + + ExpectedTargets: []explainUtils.PlanNodeTargetCase{ + { + TargetNodeName: "countNode", + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "sources": []dataMap{ + { + "filter": nil, + "fieldName": "books", + }, + }, + }, + }, + { + TargetNodeName: "typeIndexJoin", + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "joinType": "typeJoinMany", + "rootName": "author", + "subTypeName": "books", + }, + }, + { + TargetNodeName: "scanNode", // inside of root + OccurancesToSkip: 0, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "filter": nil, + "collectionID": "3", + "collectionName": "Author", + "spans": []dataMap{ + { + "start": "/3", + "end": "/4", + }, + }, + }, + }, + { + TargetNodeName: "scanNode", // inside of subType (related type) + OccurancesToSkip: 1, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "filter": nil, + "collectionID": "2", + "collectionName": "Book", + "spans": []dataMap{ + { + "start": "/2", + "end": "/3", + }, + }, + }, + }, + }, + } + + runExplainTest(t, test) +} + +func TestDefaultExplainRequestWithCountOnOneToManyJoinedFieldWithManySources(t *testing.T) { + test := explainUtils.ExplainRequestTestCase{ + + Description: "Explain (default) request with count on a one-to-many joined field with many sources.", + + Request: `query @explain { + Author { + name + numberOfBooks: _count( + books: {} + articles: {} + ) + } + }`, + + Docs: map[int][]string{ + // articles + 0: { + `{ + "name": "After Guantánamo, Another Injustice", + "author_id": "bae-25fafcc7-f251-58c1-9495-ead73e676fb8", + "pages": 2 + }`, + `{ + "name": "To my dear readers", + "author_id": "bae-3dddb519-3612-5e43-86e5-49d6295d4f84", + "pages": 11 + }`, + `{ + "name": "Twinklestar's Favourite Xmas Cookie", + "author_id": "bae-3dddb519-3612-5e43-86e5-49d6295d4f84", + "pages": 31 + }`, + }, + + // books + 1: { + `{ + "name": "Painted House", + "author_id": "bae-25fafcc7-f251-58c1-9495-ead73e676fb8", + "pages": 22 + }`, + `{ + "name": "A Time for Mercy", + "author_id": "bae-25fafcc7-f251-58c1-9495-ead73e676fb8", + "pages": 101 + }`, + `{ + "name": "Theif Lord", + "author_id": "bae-3dddb519-3612-5e43-86e5-49d6295d4f84", + "pages": 321 + }`, + }, + + // authors + 2: { + // _key: "bae-25fafcc7-f251-58c1-9495-ead73e676fb8" + `{ + "name": "John Grisham", + "age": 65, + "verified": true, + "contact_id": "bae-1fe427b8-ab8d-56c3-9df2-826a6ce86fed" + }`, + // _key: "bae-3dddb519-3612-5e43-86e5-49d6295d4f84" + `{ + "name": "Cornelia Funke", + "age": 62, + "verified": false, + "contact_id": "bae-c0960a29-b704-5c37-9c2e-59e1249e4559" + }`, + }, + }, + + ExpectedPatterns: []dataMap{ + { + "explain": dataMap{ + "selectTopNode": dataMap{ + "countNode": dataMap{ + "selectNode": dataMap{ + "parallelNode": []dataMap{ + { + "typeIndexJoin": normalTypeJoinPattern, + }, + { + "typeIndexJoin": normalTypeJoinPattern, + }, + }, + }, + }, + }, + }, + }, + }, + + ExpectedTargets: []explainUtils.PlanNodeTargetCase{ + { + TargetNodeName: "countNode", + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "sources": []dataMap{ + { + "filter": nil, + "fieldName": "books", + }, + + { + "filter": nil, + "fieldName": "articles", + }, + }, + }, + }, + { + TargetNodeName: "typeIndexJoin", + OccurancesToSkip: 0, + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "joinType": "typeJoinMany", + "rootName": "author", + "subTypeName": "books", + }, + }, + { + TargetNodeName: "scanNode", // inside of 1st root type + OccurancesToSkip: 0, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "collectionID": "3", + "collectionName": "Author", + "filter": nil, + "spans": []dataMap{ + { + "start": "/3", + "end": "/4", + }, + }, + }, + }, + { + TargetNodeName: "scanNode", // inside of 1st subType (related type) + OccurancesToSkip: 1, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "collectionID": "2", + "collectionName": "Book", + "filter": nil, + "spans": []dataMap{ + { + "start": "/2", + "end": "/3", + }, + }, + }, + }, + { + TargetNodeName: "typeIndexJoin", + OccurancesToSkip: 1, + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "joinType": "typeJoinMany", + "rootName": "author", + "subTypeName": "articles", + }, + }, + { + TargetNodeName: "scanNode", // inside of 2nd root type (AKA: subType's root) + OccurancesToSkip: 2, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "collectionID": "3", + "collectionName": "Author", + "filter": nil, + "spans": []dataMap{ + { + "start": "/3", + "end": "/4", + }, + }, + }, + }, + { + TargetNodeName: "scanNode", // inside of 2nd subType (AKA: subType's subtype) + OccurancesToSkip: 3, + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "collectionID": "1", + "collectionName": "Article", + "filter": nil, + "spans": []dataMap{ + { + "start": "/1", + "end": "/2", + }, + }, + }, + }, + }, + } + + runExplainTest(t, test) +} diff --git a/tests/integration/explain/default/with_count_test.go b/tests/integration/explain/default/with_count_test.go index 715bc9c87b..9bc6568f3c 100644 --- a/tests/integration/explain/default/with_count_test.go +++ b/tests/integration/explain/default/with_count_test.go @@ -1,4 +1,4 @@ -// Copyright 2022 Democratized Data Foundation +// Copyright 2023 Democratized Data Foundation // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt. @@ -13,18 +13,30 @@ package test_explain_default import ( "testing" - testUtils "github.com/sourcenetwork/defradb/tests/integration" + explainUtils "github.com/sourcenetwork/defradb/tests/integration/explain" ) -func TestExplainQueryOneToManyWithACount(t *testing.T) { - test := testUtils.RequestTestCase{ +var countPattern = dataMap{ + "explain": dataMap{ + "selectTopNode": dataMap{ + "countNode": dataMap{ + "selectNode": dataMap{ + "scanNode": dataMap{}, + }, + }, + }, + }, +} + +func TestDefaultExplainRequestWithCountOnInlineArrayField(t *testing.T) { + test := explainUtils.ExplainRequestTestCase{ - Description: "Explain one one-to-many relation query with count.", + Description: "Explain (default) request with count on an inline array field.", Request: `query @explain { - Author { + Book { name - numberOfBooks: _count(books: {}) + _count(chapterPages: {}) } }`, @@ -76,62 +88,32 @@ func TestExplainQueryOneToManyWithACount(t *testing.T) { }, }, - // ----> selectTopNode (explainable but no-attributes) - // ----> countNode (explainable) - // ----> selectNode (explainable) - // ----> typeIndexJoin (explainable) - // ----> typeJoinMany (non-explainable) - // ----> scanNode (explainable) - Results: []dataMap{ + ExpectedPatterns: []dataMap{countPattern}, + + ExpectedTargets: []explainUtils.PlanNodeTargetCase{ + { + TargetNodeName: "countNode", + IncludeChildNodes: false, + ExpectedAttributes: dataMap{ + "sources": []dataMap{ + { + "filter": nil, + "fieldName": "chapterPages", + }, + }, + }, + }, { - "explain": dataMap{ - "selectTopNode": dataMap{ - "countNode": dataMap{ - "sources": []dataMap{ - { - "filter": nil, - "fieldName": "books", - }, - }, - "selectNode": dataMap{ - "filter": nil, - "typeIndexJoin": dataMap{ - "joinType": "typeJoinMany", - "rootName": "author", - "root": dataMap{ - "scanNode": dataMap{ - "filter": nil, - "collectionID": "3", - "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, - }, - }, - }, - "subTypeName": "books", - "subType": dataMap{ - "selectTopNode": dataMap{ - "selectNode": dataMap{ - "filter": nil, - "scanNode": dataMap{ - "filter": nil, - "collectionID": "2", - "collectionName": "Book", - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, - }, - }, - }, - }, - }, - }, - }, + TargetNodeName: "scanNode", + IncludeChildNodes: true, // should be leaf of it's branch, so will have no child nodes. + ExpectedAttributes: dataMap{ + "filter": nil, + "collectionID": "2", + "collectionName": "Book", + "spans": []dataMap{ + { + "start": "/2", + "end": "/3", }, }, }, @@ -139,5 +121,5 @@ func TestExplainQueryOneToManyWithACount(t *testing.T) { }, } - executeTestCase(t, test) + runExplainTest(t, test) }