diff --git a/internal/db/fetcher/indexer_iterators.go b/internal/db/fetcher/indexer_iterators.go index 5d9da70c9f..e4e69c99c3 100644 --- a/internal/db/fetcher/indexer_iterators.go +++ b/internal/db/fetcher/indexer_iterators.go @@ -141,6 +141,9 @@ func (iter *indexPrefixIterator) Next() (indexIterResult, error) { } func (iter *indexPrefixIterator) Close() error { + if iter.resultIter == nil { + return nil + } return iter.resultIter.Close() } diff --git a/tests/integration/index/query_with_relation_filter_test.go b/tests/integration/index/query_with_relation_filter_test.go index e31685a0cf..deba6946e2 100644 --- a/tests/integration/index/query_with_relation_filter_test.go +++ b/tests/integration/index/query_with_relation_filter_test.go @@ -1018,36 +1018,36 @@ func TestQueryWithIndexOnManyToOne_MultipleViaOneToMany(t *testing.T) { testUtils.ExecuteTestCase(t, test) } -func TestQueryWithIndex_UniqueIndexOnChildWithEmptyParentCollection(t *testing.T) { +func TestQueryWithUniqueIndex_WithFilterOnChildIndexedField_ShouldFetch(t *testing.T) { test := testUtils.TestCase{ Actions: []any{ testUtils.SchemaUpdate{ Schema: ` - type Action { - key: String @index(unique: true) - playerActions: [PlayerAction] + type User { + name: String @index(unique: true) + devices: [Device] } - type PlayerAction { - deleted: Boolean - action: Action + type Device { + trusted: Boolean + owner: User } `, }, testUtils.CreateDoc{ CollectionID: 0, DocMap: map[string]any{ - "key": "ACTION_KEY", + "name": "John", }, }, testUtils.Request{ Request: `query { - PlayerAction(filter: {action: {key: {_eq: "ACTION_KEY"}}}) { - deleted + Device(filter: {owner: {name: {_eq: "John"}}}) { + trusted } }`, Results: map[string]any{ - "PlayerAction": []map[string]any{}, + "Device": []map[string]any{}, }, }, }, diff --git a/tests/integration/index/query_with_unique_index_on_relation_filter_test.go b/tests/integration/index/query_with_unique_index_on_relation_filter_test.go new file mode 100644 index 0000000000..05c4b05395 --- /dev/null +++ b/tests/integration/index/query_with_unique_index_on_relation_filter_test.go @@ -0,0 +1,72 @@ +// Copyright 2024 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 index + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryWithUniqueCompositeIndex_WithFilterOnIndexedRelation_ShouldFilter(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + devices: [Device] + } + + type Device { + manufacturer: String + owner: User @index(unique: true, includes: [{name: "manufacturer"}]) + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "John", + }, + }, + testUtils.CreateDoc{ + CollectionID: 1, + DocMap: map[string]any{ + "manufacturer": "Apple", + "owner_id": testUtils.NewDocIndex(0, 0), + }, + }, + testUtils.Request{ + Request: `query { + User { + name + devices(filter: {owner_id: {_eq: "bae-1ef746f8-821e-586f-99b2-4cb1fb9b782f"}}) { + manufacturer + } + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + { + "name": "John", + "devices": []map[string]any{ + {"manufacturer": "Apple"}, + }, + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +}