diff --git a/internal/datastore/common/sql.go b/internal/datastore/common/sql.go index 85fd497b3d..531afa82a9 100644 --- a/internal/datastore/common/sql.go +++ b/internal/datastore/common/sql.go @@ -148,6 +148,7 @@ type nameAndValue struct { } func (sqf SchemaQueryFilterer) After(cursor *core.RelationTuple, order options.SortOrder) SchemaQueryFilterer { + // NOTE: The ordering of these columns can affect query performance, be aware when changing. columnsAndValues := map[options.SortOrder][]nameAndValue{ options.ByResource: { { @@ -156,15 +157,15 @@ func (sqf SchemaQueryFilterer) After(cursor *core.RelationTuple, order options.S { sqf.schema.colObjectID, cursor.ResourceAndRelation.ObjectId, }, - { - sqf.schema.colRelation, cursor.ResourceAndRelation.Relation, - }, { sqf.schema.colUsersetNamespace, cursor.Subject.Namespace, }, { sqf.schema.colUsersetObjectID, cursor.Subject.ObjectId, }, + { + sqf.schema.colRelation, cursor.ResourceAndRelation.Relation, + }, { sqf.schema.colUsersetRelation, cursor.Subject.Relation, }, @@ -176,9 +177,6 @@ func (sqf SchemaQueryFilterer) After(cursor *core.RelationTuple, order options.S { sqf.schema.colUsersetObjectID, cursor.Subject.ObjectId, }, - { - sqf.schema.colUsersetRelation, cursor.Subject.Relation, - }, { sqf.schema.colNamespace, cursor.ResourceAndRelation.Namespace, }, @@ -188,6 +186,9 @@ func (sqf SchemaQueryFilterer) After(cursor *core.RelationTuple, order options.S { sqf.schema.colRelation, cursor.ResourceAndRelation.Relation, }, + { + sqf.schema.colUsersetRelation, cursor.Subject.Relation, + }, }, }[order] diff --git a/internal/datastore/common/sql_test.go b/internal/datastore/common/sql_test.go index 8c74615b08..29163e8644 100644 --- a/internal/datastore/common/sql_test.go +++ b/internal/datastore/common/sql_test.go @@ -473,8 +473,8 @@ func TestSchemaQueryFilterer(t *testing.T) { }, ).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE ns = ? AND (object_id,relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?,?)", - []any{"someresourcetype", "foo", "viewer", "user", "bar", "..."}, + "SELECT * WHERE ns = ? AND (object_id,subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"someresourcetype", "foo", "user", "bar", "viewer", "..."}, map[string]int{ "ns": 1, }, @@ -504,8 +504,8 @@ func TestSchemaQueryFilterer(t *testing.T) { }, ).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE ns = ? AND object_id IN (?) AND (relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?)", - []any{"someresourcetype", "one", "viewer", "user", "bar", "..."}, + "SELECT * WHERE ns = ? AND object_id IN (?) AND (subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?)", + []any{"someresourcetype", "one", "user", "bar", "viewer", "..."}, map[string]int{ "ns": 1, "object_id": 1, @@ -520,8 +520,8 @@ func TestSchemaQueryFilterer(t *testing.T) { }, ).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE object_id IN (?) AND (ns,relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?,?)", - []any{"one", "someresourcetype", "viewer", "user", "bar", "..."}, + "SELECT * WHERE object_id IN (?) AND (ns,subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"one", "someresourcetype", "user", "bar", "viewer", "..."}, map[string]int{ "object_id": 1, }, @@ -536,8 +536,8 @@ func TestSchemaQueryFilterer(t *testing.T) { }, ).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE ns = ? AND object_id IN (?, ?) AND (object_id,relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?,?)", - []any{"someresourcetype", "one", "two", "foo", "viewer", "user", "bar", "..."}, + "SELECT * WHERE ns = ? AND object_id IN (?, ?) AND (object_id,subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"someresourcetype", "one", "two", "foo", "user", "bar", "viewer", "..."}, map[string]int{ "ns": 1, "object_id": 2, @@ -567,8 +567,8 @@ func TestSchemaQueryFilterer(t *testing.T) { OptionalSubjectType: "somesubjectype", }).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE ((subject_ns = ?)) AND (ns,object_id,relation,subject_object_id,subject_relation) > (?,?,?,?,?)", - []any{"somesubjectype", "someresourcetype", "foo", "viewer", "bar", "..."}, + "SELECT * WHERE ((subject_ns = ?)) AND (ns,object_id,subject_object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"somesubjectype", "someresourcetype", "foo", "bar", "viewer", "..."}, map[string]int{ "subject_ns": 1, }, @@ -584,8 +584,8 @@ func TestSchemaQueryFilterer(t *testing.T) { OptionalSubjectType: "anothersubjectype", }).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE ((subject_ns = ?)) AND ((subject_ns = ?)) AND (ns,object_id,relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?,?,?)", - []any{"somesubjectype", "anothersubjectype", "someresourcetype", "foo", "viewer", "user", "bar", "..."}, + "SELECT * WHERE ((subject_ns = ?)) AND ((subject_ns = ?)) AND (ns,object_id,subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?,?,?)", + []any{"somesubjectype", "anothersubjectype", "someresourcetype", "foo", "user", "bar", "viewer", "..."}, map[string]int{ "subject_ns": 2, }, @@ -595,8 +595,8 @@ func TestSchemaQueryFilterer(t *testing.T) { func(filterer SchemaQueryFilterer) SchemaQueryFilterer { return filterer.MustFilterWithResourceIDPrefix("someprefix").After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.ByResource) }, - "SELECT * WHERE object_id LIKE ? AND (ns,object_id,relation,subject_ns,subject_object_id,subject_relation) > (?,?,?,?,?,?)", - []any{"someprefix%", "someresourcetype", "foo", "viewer", "user", "bar", "..."}, + "SELECT * WHERE object_id LIKE ? AND (ns,object_id,subject_ns,subject_object_id,relation,subject_relation) > (?,?,?,?,?,?)", + []any{"someprefix%", "someresourcetype", "foo", "user", "bar", "viewer", "..."}, map[string]int{}, }, { @@ -621,8 +621,8 @@ func TestSchemaQueryFilterer(t *testing.T) { OptionalSubjectType: "somesubjectype", }).After(tuple.MustParse("someresourcetype:foo#viewer@user:bar"), options.BySubject) }, - "SELECT * WHERE ((subject_ns = ?)) AND (subject_object_id,subject_relation,ns,object_id,relation) > (?,?,?,?,?)", - []any{"somesubjectype", "bar", "...", "someresourcetype", "foo", "viewer"}, + "SELECT * WHERE ((subject_ns = ?)) AND (subject_object_id,ns,object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"somesubjectype", "bar", "someresourcetype", "foo", "viewer", "..."}, map[string]int{ "subject_ns": 1, }, @@ -635,8 +635,8 @@ func TestSchemaQueryFilterer(t *testing.T) { OptionalSubjectIds: []string{"foo"}, }).After(tuple.MustParse("someresourcetype:someresource#viewer@user:bar"), options.BySubject) }, - "SELECT * WHERE ((subject_ns = ? AND subject_object_id IN (?))) AND (subject_relation,ns,object_id,relation) > (?,?,?,?)", - []any{"somesubjectype", "foo", "...", "someresourcetype", "someresource", "viewer"}, + "SELECT * WHERE ((subject_ns = ? AND subject_object_id IN (?))) AND (ns,object_id,relation,subject_relation) > (?,?,?,?)", + []any{"somesubjectype", "foo", "someresourcetype", "someresource", "viewer", "..."}, map[string]int{"subject_ns": 1, "subject_object_id": 1}, }, { @@ -647,8 +647,8 @@ func TestSchemaQueryFilterer(t *testing.T) { OptionalSubjectIds: []string{"foo", "bar"}, }).After(tuple.MustParse("someresourcetype:someresource#viewer@user:next"), options.BySubject) }, - "SELECT * WHERE ((subject_ns = ? AND subject_object_id IN (?, ?))) AND (subject_object_id,subject_relation,ns,object_id,relation) > (?,?,?,?,?)", - []any{"somesubjectype", "foo", "bar", "next", "...", "someresourcetype", "someresource", "viewer"}, + "SELECT * WHERE ((subject_ns = ? AND subject_object_id IN (?, ?))) AND (subject_object_id,ns,object_id,relation,subject_relation) > (?,?,?,?,?)", + []any{"somesubjectype", "foo", "bar", "next", "someresourcetype", "someresource", "viewer", "..."}, map[string]int{"subject_ns": 1, "subject_object_id": 2}, }, } diff --git a/internal/graph/lookupresources.go b/internal/graph/lookupresources.go index dfe4aac7da..4d651d7057 100644 --- a/internal/graph/lookupresources.go +++ b/internal/graph/lookupresources.go @@ -85,7 +85,7 @@ func (cl *CursoredLookupResources) LookupResources( reachableResourcesCursor = newCursor // If no additional reachable results were found or the request was unlimited, then we can stop. - if reachableCount == 0 || req.OptionalLimit == 0 { + if reachableCount == 0 { return nil } }