query

package
v1.45.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2025 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

This package provides the structures, interfaces, and functions for a sort of Lego-set to build query trees. It should depend on as few other packages as possible, as in the longer future, these can be passed around a lot, and refactoring to reduce import loops is a pain.

The underlying philosophy of a query plan is that we build query trees out of iterators. Iterators are nodes in the tree and represent a logical set of valid relations that match or don't match.

Take the example schema:

definition foo {
  relation bar: foo
}

For example, the simplest set is that of `bar` -- all relationships written directly with `bar` as the Relation type, `foo:a#bar@foo:b#...`

But by combining different operations on these sets, we can invent arbitrary permissions, using standard set operations like And and Or, along with a few special ones that come from relational algebra, like Arrow (as a form of the Join operation).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Alias

type Alias struct {
	// contains filtered or unexported fields
}

Alias is an iterator that rewrites the Resource's Relation field of all relations streamed from the sub-iterator to a specified alias relation.

func NewAlias

func NewAlias(relation string, subIt Iterator) *Alias

NewAlias creates a new Alias iterator that rewrites relations from the sub-iterator to use the specified relation name.

func (*Alias) CheckImpl

func (a *Alias) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*Alias) Clone

func (a *Alias) Clone() Iterator

func (*Alias) Explain

func (a *Alias) Explain() Explain

func (*Alias) IterResourcesImpl

func (a *Alias) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*Alias) IterSubjectsImpl

func (a *Alias) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type Arrow

type Arrow struct {
	// contains filtered or unexported fields
}

Arrow is an iterator that represents the set of relations that follow from a walk in the graph.

Ex: `folder->owner` and `left->right`

func NewArrow

func NewArrow(left, right Iterator) *Arrow

func (*Arrow) CheckImpl

func (a *Arrow) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*Arrow) Clone

func (a *Arrow) Clone() Iterator

func (*Arrow) Explain

func (a *Arrow) Explain() Explain

func (*Arrow) IterResourcesImpl

func (a *Arrow) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*Arrow) IterSubjectsImpl

func (a *Arrow) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type Context

type Context struct {
	context.Context
	Executor  Executor
	Datastore datastore.ReadOnlyDatastore
	Revision  datastore.Revision
}

Context represents a single execution of a query. It is both a standard context.Context and all the query-time specific handles needed to evaluate a query, such as which datastore it is running against.

Context is the concrete type that contains the overall handles, and uses the executor as a strategy for continuing execution.

func (*Context) Check

func (ctx *Context) Check(it Iterator, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

Check tests if, for the underlying set of relationships (which may be a full expression or a basic lookup, depending on the iterator) any of the `resources` are connected to `subject`. Returns the sequence of matching relations, if they exist, at most `len(resources)`.

func (*Context) IterResources

func (ctx *Context) IterResources(it Iterator, subject ObjectAndRelation) (RelationSeq, error)

IterResources returns a sequence of all the relations in this set that match the given subject.

func (*Context) IterSubjects

func (ctx *Context) IterSubjects(it Iterator, resource Object) (RelationSeq, error)

IterSubjects returns a sequence of all the relations in this set that match the given resource.

type Exclusion

type Exclusion struct {
	// contains filtered or unexported fields
}

Exclusion represents the set of relations that are in the mainSet but not in the excluded set. This is equivalent to `permission foo = bar - baz`

func NewExclusion

func NewExclusion(mainSet, excluded Iterator) *Exclusion

func (*Exclusion) CheckImpl

func (e *Exclusion) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*Exclusion) Clone

func (e *Exclusion) Clone() Iterator

func (*Exclusion) Explain

func (e *Exclusion) Explain() Explain

func (*Exclusion) IterResourcesImpl

func (e *Exclusion) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*Exclusion) IterSubjectsImpl

func (e *Exclusion) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type Executor

type Executor interface {
	// Check tests if, for the underlying set of relationships (which may be a full expression or a basic lookup, depending on the iterator)
	// any of the `resources` are connected to `subject`.
	// Returns the sequence of matching relations, if they exist, at most `len(resources)`.
	Check(ctx *Context, it Iterator, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

	// IterSubjects returns a sequence of all the relations in this set that match the given resource.
	IterSubjects(ctx *Context, it Iterator, resource Object) (RelationSeq, error)

	// IterResources returns a sequence of all the relations in this set that match the given subject.
	IterResources(ctx *Context, it Iterator, subject ObjectAndRelation) (RelationSeq, error)
}

Executor as chooses how to proceed given an iterator -- perhaps in parallel, perhaps by RPC, etc -- and chooses how to process iteration from the subtree. The correctness logic for the results that are generated are up to each iterator, and each iterator may use statistics to choose the best, yet still correct, logical evaluation strategy. The Executor, meanwhile, makes that evaluation happen in the most convienent form, based on its implementation.

type Explain

type Explain struct {
	Info       string
	SubExplain []Explain
}

Explain describes the state of an iterator tree, in a human-readable fashion, with an Info line at each node.

TODO: This can be extended with other interesting stats about the tree.

func (Explain) IndentString

func (e Explain) IndentString(depth int) string

IndentString pretty-prints an Explain tree with a given indentation.

func (Explain) String

func (e Explain) String() string

type FaultyIterator

type FaultyIterator struct {
	// contains filtered or unexported fields
}

FaultyIterator is a test helper that simulates iterator errors

func NewFaultyIterator

func NewFaultyIterator(shouldFailOnCheck, shouldFailOnCollect bool) *FaultyIterator

NewFaultyIterator creates a new FaultyIterator for testing error conditions

func (*FaultyIterator) CheckImpl

func (f *FaultyIterator) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*FaultyIterator) Clone

func (f *FaultyIterator) Clone() Iterator

func (*FaultyIterator) Explain

func (f *FaultyIterator) Explain() Explain

func (*FaultyIterator) IterResourcesImpl

func (f *FaultyIterator) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*FaultyIterator) IterSubjectsImpl

func (f *FaultyIterator) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type FixedIterator

type FixedIterator struct {
	// contains filtered or unexported fields
}

For example: document->folder->ownerGroup->user -- and we'd like to find all documents (IterResources) that traverse a known folder->ownerGroup relationship

func NewConflictingPermissionsFixedIterator

func NewConflictingPermissionsFixedIterator() *FixedIterator

NewConflictingPermissionsFixedIterator creates a FixedIterator with potential permission conflicts for testing

func NewDocumentAccessFixedIterator

func NewDocumentAccessFixedIterator() *FixedIterator

NewDocumentAccessFixedIterator creates a FixedIterator with typical document access patterns

func NewEmptyFixedIterator

func NewEmptyFixedIterator() *FixedIterator

NewEmptyFixedIterator creates an empty FixedIterator for testing edge cases

func NewFixedIterator

func NewFixedIterator(rels ...Relation) *FixedIterator

func NewFolderHierarchyFixedIterator

func NewFolderHierarchyFixedIterator() *FixedIterator

NewFolderHierarchyFixedIterator creates a FixedIterator with folder hierarchy relations

func NewGroupMembershipFixedIterator

func NewGroupMembershipFixedIterator() *FixedIterator

NewGroupMembershipFixedIterator creates a FixedIterator with group membership and nested groups

func NewLargeFixedIterator

func NewLargeFixedIterator() *FixedIterator

NewLargeFixedIterator creates a FixedIterator with many relations for performance testing

func NewMultiRoleFixedIterator

func NewMultiRoleFixedIterator() *FixedIterator

NewMultiRoleFixedIterator creates a FixedIterator where users have multiple roles on the same resources

func NewSingleUserFixedIterator

func NewSingleUserFixedIterator(userID string) *FixedIterator

NewSingleUserFixedIterator creates a FixedIterator with relations for a single user across multiple resources

func (*FixedIterator) CheckImpl

func (f *FixedIterator) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*FixedIterator) Clone

func (f *FixedIterator) Clone() Iterator

func (*FixedIterator) Explain

func (f *FixedIterator) Explain() Explain

func (*FixedIterator) IterResourcesImpl

func (f *FixedIterator) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*FixedIterator) IterSubjectsImpl

func (f *FixedIterator) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type Intersection

type Intersection struct {
	// contains filtered or unexported fields
}

Intersection the set of relations that are in all of underlying subiterators. This is equivalent to `permission foo = bar & baz`

func NewIntersection

func NewIntersection() *Intersection

func (*Intersection) CheckImpl

func (i *Intersection) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*Intersection) Clone

func (i *Intersection) Clone() Iterator

func (*Intersection) Explain

func (i *Intersection) Explain() Explain

func (*Intersection) IterResourcesImpl

func (i *Intersection) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*Intersection) IterSubjectsImpl

func (i *Intersection) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type Iterator

type Iterator interface {
	Plan

	// Clone does a deep-copy to duplicate the iterator tree at this point.
	Clone() Iterator
}

Iterator is an interface for manipulating iterators to create more query plans.

A Plan is abstract and more limited, and easier to pass around.

An Iterator is what Iterators (even future datastore-specific ones) implement so that optimizations and reorderings and rebalancing can take place.

func BuildIteratorFromSchema

func BuildIteratorFromSchema(fullSchema *schema.Schema, definitionName string, relationName string) (Iterator, error)

BuildIteratorFromSchema takes a schema and walks the schema tree for a given definition namespace and a relationship or permission therein. From this, it generates an iterator tree, rooted on that relationship.

type LocalExecutor

type LocalExecutor struct{}

LocalExecutor is the simplest executor. It simply calls the iterator's implementation directly.

func (LocalExecutor) Check

func (l LocalExecutor) Check(ctx *Context, it Iterator, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

Check tests if, for the underlying set of relationships (which may be a full expression or a basic lookup, depending on the iterator) any of the `resources` are connected to `subject`. Returns the sequence of matching relations, if they exist, at most `len(resources)`.

func (LocalExecutor) IterResources

func (l LocalExecutor) IterResources(ctx *Context, it Iterator, subject ObjectAndRelation) (RelationSeq, error)

IterResources returns a sequence of all the relations in this set that match the given subject.

func (LocalExecutor) IterSubjects

func (l LocalExecutor) IterSubjects(ctx *Context, it Iterator, resource Object) (RelationSeq, error)

IterSubjects returns a sequence of all the relations in this set that match the given resource.

type Object

type Object struct {
	ObjectID   string
	ObjectType string
}

Object represents a single object, without specifying the relation.

func GetObject

func GetObject(oar ObjectAndRelation) Object

GetObject extracts the Object part from an ObjectAndRelation.

func NewObject

func NewObject(objectType, objectID string) Object

NewObject creates a new Object with the given object type and ID.

func NewObjects

func NewObjects(objectType string, objectIDs ...string) []Object

NewObjects creates a slice of Objects of the same type with the given object IDs.

func (Object) Equals

func (o Object) Equals(other Object) bool

func (Object) WithEllipses

func (o Object) WithEllipses() ObjectAndRelation

WithEllipses builds an ObjectAndRelation from an object with the default ellipses relation.

func (Object) WithRelation

func (o Object) WithRelation(relation string) ObjectAndRelation

WithRelation builds a full ObjectAndRelation out of the given Object.

type ObjectAndRelation

type ObjectAndRelation = tuple.ObjectAndRelation

func NewObjectAndRelation

func NewObjectAndRelation(objectID, objectType, relation string) ObjectAndRelation

NewObjectAndRelation creates a new ObjectAndRelation with the given object ID, type, and relation.

type Plan

type Plan interface {
	// CheckImpl tests if, for the underlying set of relationships (which may be a full expression or a basic lookup, depending on the iterator)
	// any of the `resourceIDs` are connected to `subjectID`.
	// Returns the sequence of matching relations, if they exist, at most `len(resourceIDs)`.
	CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

	// IterSubjectsImpl returns a sequence of all the relations in this set that match the given resourceID.
	IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

	// IterResourcesImpl returns a sequence of all the relations in this set that match the given subjectID.
	IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

	// Explain generates a human-readable tree that describes each iterator and its state.
	Explain() Explain
}

Plan is the external-facing notion of a query plan. These follow the general API for querying anything in the database as well as describing the plan.

type Relation

type Relation = tuple.Relationship

Relation is the basic unit of connection

func CollectAll

func CollectAll(seq RelationSeq) ([]Relation, error)

CollectAll is a helper function to build read a complete RelationSeq and turn it into a fully realized slice of Relations.

type RelationIterator

type RelationIterator struct {
	// contains filtered or unexported fields
}

RelationIterator is a common leaf iterator. It represents the set of all relationships of the given schema.BaseRelation, ie, relations that have a known resource and subject type and may contain caveats or expiration.

The RelationIterator, being the leaf, generates this set by calling the datastore.

func NewRelationIterator

func NewRelationIterator(base *schema.BaseRelation) *RelationIterator

func (*RelationIterator) CheckImpl

func (r *RelationIterator) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*RelationIterator) Clone

func (r *RelationIterator) Clone() Iterator

func (*RelationIterator) Explain

func (r *RelationIterator) Explain() Explain

func (*RelationIterator) IterResourcesImpl

func (r *RelationIterator) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*RelationIterator) IterSubjectsImpl

func (r *RelationIterator) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

type RelationSeq

type RelationSeq iter.Seq2[Relation, error]

RelationSeq is the intermediate iter closure that any of the planning calls return.

type Union

type Union struct {
	// contains filtered or unexported fields
}

Union the set of relations that are in any of underlying subiterators. This is equivalent to `permission foo = bar | baz`

func NewUnion

func NewUnion() *Union

func (*Union) CheckImpl

func (u *Union) CheckImpl(ctx *Context, resources []Object, subject ObjectAndRelation) (RelationSeq, error)

func (*Union) Clone

func (u *Union) Clone() Iterator

func (*Union) Explain

func (u *Union) Explain() Explain

func (*Union) IterResourcesImpl

func (u *Union) IterResourcesImpl(ctx *Context, subject ObjectAndRelation) (RelationSeq, error)

func (*Union) IterSubjectsImpl

func (u *Union) IterSubjectsImpl(ctx *Context, resource Object) (RelationSeq, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL