github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/common/tuple.go (about)

     1  package common
     2  
     3  import (
     4  	"runtime"
     5  
     6  	"github.com/authzed/spicedb/pkg/datastore"
     7  	"github.com/authzed/spicedb/pkg/datastore/options"
     8  	core "github.com/authzed/spicedb/pkg/proto/core/v1"
     9  )
    10  
    11  // NewSliceRelationshipIterator creates a datastore.TupleIterator instance from a materialized slice of tuples.
    12  func NewSliceRelationshipIterator(tuples []*core.RelationTuple, order options.SortOrder) datastore.RelationshipIterator {
    13  	iter := &sliceRelationshipIterator{tuples: tuples, order: order}
    14  	runtime.SetFinalizer(iter, MustIteratorBeClosed)
    15  	return iter
    16  }
    17  
    18  type sliceRelationshipIterator struct {
    19  	tuples []*core.RelationTuple
    20  	order  options.SortOrder
    21  	last   *core.RelationTuple
    22  	closed bool
    23  	err    error
    24  }
    25  
    26  // Next implements TupleIterator
    27  func (sti *sliceRelationshipIterator) Next() *core.RelationTuple {
    28  	if sti.closed {
    29  		sti.err = datastore.ErrClosedIterator
    30  		return nil
    31  	}
    32  
    33  	if len(sti.tuples) > 0 {
    34  		first := sti.tuples[0]
    35  		sti.tuples = sti.tuples[1:]
    36  		sti.last = first
    37  		return first
    38  	}
    39  
    40  	return nil
    41  }
    42  
    43  func (sti *sliceRelationshipIterator) Cursor() (options.Cursor, error) {
    44  	switch {
    45  	case sti.closed:
    46  		return nil, datastore.ErrClosedIterator
    47  	case sti.order == options.Unsorted:
    48  		return nil, datastore.ErrCursorsWithoutSorting
    49  	case sti.last == nil:
    50  		return nil, datastore.ErrCursorEmpty
    51  	default:
    52  		return sti.last, nil
    53  	}
    54  }
    55  
    56  // Err implements TupleIterator
    57  func (sti *sliceRelationshipIterator) Err() error {
    58  	return sti.err
    59  }
    60  
    61  // Close implements TupleIterator
    62  func (sti *sliceRelationshipIterator) Close() {
    63  	if sti.closed {
    64  		return
    65  	}
    66  
    67  	sti.tuples = nil
    68  	sti.closed = true
    69  }
    70  
    71  // MustIteratorBeClosed is a function which can be used as a finalizer to make sure that
    72  // tuples are getting closed before they are garbage collected.
    73  func MustIteratorBeClosed(iter *sliceRelationshipIterator) {
    74  	if !iter.closed {
    75  		panic("Tuple iterator garbage collected before Close() was called")
    76  	}
    77  }