summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
committermo khan <mo@mokhan.ca>2025-07-22 17:35:49 -0600
commit20ef0d92694465ac86b550df139e8366a0a2b4fa (patch)
tree3f14589e1ce6eb9306a3af31c3a1f9e1af5ed637 /vendor/github.com/authzed/spicedb/pkg/tuple/v1.go
parent44e0d272c040cdc53a98b9f1dc58ae7da67752e6 (diff)
feat: connect to spicedb
Diffstat (limited to 'vendor/github.com/authzed/spicedb/pkg/tuple/v1.go')
-rw-r--r--vendor/github.com/authzed/spicedb/pkg/tuple/v1.go340
1 files changed, 340 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go b/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go
new file mode 100644
index 0000000..5a3705f
--- /dev/null
+++ b/vendor/github.com/authzed/spicedb/pkg/tuple/v1.go
@@ -0,0 +1,340 @@
+package tuple
+
+import (
+ "fmt"
+ "time"
+
+ v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
+ "github.com/jzelinskie/stringz"
+ "google.golang.org/protobuf/types/known/timestamppb"
+
+ core "github.com/authzed/spicedb/pkg/proto/core/v1"
+ "github.com/authzed/spicedb/pkg/spiceerrors"
+)
+
+// ParseV1Rel parses a string representation of a relationship into a v1.Relationship object.
+func ParseV1Rel(relString string) (*v1.Relationship, error) {
+ parsed, err := Parse(relString)
+ if err != nil {
+ return nil, err
+ }
+
+ return ToV1Relationship(parsed), nil
+}
+
+// Same as above, but panics if it cannot be parsed. Should only be used in tests.
+func MustParseV1Rel(relString string) *v1.Relationship {
+ parsed, err := Parse(relString)
+ if err != nil {
+ panic(fmt.Sprintf("could not parse relationship string: %s %s", relString, err))
+ }
+
+ return ToV1Relationship(parsed)
+}
+
+// MustV1RelString converts a relationship into a string. Will panic if
+// the Relationship does not validate.
+func MustV1RelString(rel *v1.Relationship) string {
+ if err := rel.Validate(); err != nil {
+ panic(fmt.Sprintf("invalid relationship: %#v %s", rel, err))
+ }
+ return MustV1StringRelationship(rel)
+}
+
+// StringObjectRef marshals a *v1.ObjectReference into a string.
+//
+// This function assumes that the provided values have already been validated.
+func V1StringObjectRef(ref *v1.ObjectReference) string {
+ return JoinObjectRef(ref.ObjectType, ref.ObjectId)
+}
+
+// StringSubjectRef marshals a *v1.SubjectReference into a string.
+//
+// This function assumes that the provided values have already been validated.
+func V1StringSubjectRef(ref *v1.SubjectReference) string {
+ if ref.OptionalRelation == "" {
+ return V1StringObjectRef(ref.Object)
+ }
+ return JoinRelRef(V1StringObjectRef(ref.Object), ref.OptionalRelation)
+}
+
+// MustV1StringRelationship converts a v1.Relationship to a string.
+func MustV1StringRelationship(rel *v1.Relationship) string {
+ relString, err := V1StringRelationship(rel)
+ if err != nil {
+ panic(err)
+ }
+ return relString
+}
+
+// V1StringRelationship converts a v1.Relationship to a string.
+func V1StringRelationship(rel *v1.Relationship) (string, error) {
+ if rel == nil || rel.Resource == nil || rel.Subject == nil {
+ return "", nil
+ }
+
+ caveatString, err := V1StringCaveatRef(rel.OptionalCaveat)
+ if err != nil {
+ return "", err
+ }
+
+ expirationString, err := V1StringExpiration(rel.OptionalExpiresAt)
+ if err != nil {
+ return "", err
+ }
+
+ return V1StringRelationshipWithoutCaveatOrExpiration(rel) + caveatString + expirationString, nil
+}
+
+func V1StringExpiration(expiration *timestamppb.Timestamp) (string, error) {
+ if expiration == nil {
+ return "", nil
+ }
+
+ return "[expiration:" + expiration.AsTime().Format(expirationFormat) + "]", nil
+}
+
+// V1StringRelationshipWithoutCaveatOrExpiration converts a v1.Relationship to a string, excluding any caveat.
+func V1StringRelationshipWithoutCaveatOrExpiration(rel *v1.Relationship) string {
+ if rel == nil || rel.Resource == nil || rel.Subject == nil {
+ return ""
+ }
+
+ return V1StringObjectRef(rel.Resource) + "#" + rel.Relation + "@" + V1StringSubjectRef(rel.Subject)
+}
+
+// V1StringCaveatRef converts a v1.ContextualizedCaveat to a string.
+func V1StringCaveatRef(caveat *v1.ContextualizedCaveat) (string, error) {
+ if caveat == nil || caveat.CaveatName == "" {
+ return "", nil
+ }
+
+ contextString, err := StringCaveatContext(caveat.Context)
+ if err != nil {
+ return "", err
+ }
+
+ if len(contextString) > 0 {
+ contextString = ":" + contextString
+ }
+
+ return "[" + caveat.CaveatName + contextString + "]", nil
+}
+
+// UpdateToV1RelationshipUpdate converts a RelationshipUpdate into a
+// v1.RelationshipUpdate.
+func UpdateToV1RelationshipUpdate(update RelationshipUpdate) (*v1.RelationshipUpdate, error) {
+ var op v1.RelationshipUpdate_Operation
+ switch update.Operation {
+ case UpdateOperationCreate:
+ op = v1.RelationshipUpdate_OPERATION_CREATE
+ case UpdateOperationDelete:
+ op = v1.RelationshipUpdate_OPERATION_DELETE
+ case UpdateOperationTouch:
+ op = v1.RelationshipUpdate_OPERATION_TOUCH
+ default:
+ return nil, spiceerrors.MustBugf("unknown update operation: %v", update.Operation)
+ }
+
+ return &v1.RelationshipUpdate{
+ Operation: op,
+ Relationship: ToV1Relationship(update.Relationship),
+ }, nil
+}
+
+// MustUpdateToV1RelationshipUpdate converts a RelationshipUpdate into a
+// v1.RelationshipUpdate. Panics on error.
+func MustUpdateToV1RelationshipUpdate(update RelationshipUpdate) *v1.RelationshipUpdate {
+ v1rel, err := UpdateToV1RelationshipUpdate(update)
+ if err != nil {
+ panic(err)
+ }
+
+ return v1rel
+}
+
+// UpdateFromV1RelationshipUpdate converts a RelationshipUpdate into a
+// RelationTupleUpdate.
+func UpdateFromV1RelationshipUpdate(update *v1.RelationshipUpdate) (RelationshipUpdate, error) {
+ var op UpdateOperation
+ switch update.Operation {
+ case v1.RelationshipUpdate_OPERATION_CREATE:
+ op = UpdateOperationCreate
+ case v1.RelationshipUpdate_OPERATION_DELETE:
+ op = UpdateOperationDelete
+ case v1.RelationshipUpdate_OPERATION_TOUCH:
+ op = UpdateOperationTouch
+ default:
+ return RelationshipUpdate{}, spiceerrors.MustBugf("unknown update operation: %v", update.Operation)
+ }
+
+ return RelationshipUpdate{
+ Operation: op,
+ Relationship: FromV1Relationship(update.Relationship),
+ }, nil
+}
+
+// FromV1Relationship converts a v1.Relationship into a Relationship.
+func FromV1Relationship(rel *v1.Relationship) Relationship {
+ var caveat *core.ContextualizedCaveat
+ if rel.OptionalCaveat != nil {
+ caveat = &core.ContextualizedCaveat{
+ CaveatName: rel.OptionalCaveat.CaveatName,
+ Context: rel.OptionalCaveat.Context,
+ }
+ }
+
+ var expiration *time.Time
+ if rel.OptionalExpiresAt != nil {
+ t := rel.OptionalExpiresAt.AsTime()
+ expiration = &t
+ }
+
+ return Relationship{
+ RelationshipReference: RelationshipReference{
+ Resource: ObjectAndRelation{
+ ObjectID: rel.Resource.ObjectId,
+ ObjectType: rel.Resource.ObjectType,
+ Relation: rel.Relation,
+ },
+ Subject: ObjectAndRelation{
+ ObjectID: rel.Subject.Object.ObjectId,
+ ObjectType: rel.Subject.Object.ObjectType,
+ Relation: stringz.Default(rel.Subject.OptionalRelation, Ellipsis, ""),
+ },
+ },
+ OptionalCaveat: caveat,
+ OptionalExpiration: expiration,
+ }
+}
+
+// ToV1Relationship converts a Relationship into a v1.Relationship.
+func ToV1Relationship(rel Relationship) *v1.Relationship {
+ var caveat *v1.ContextualizedCaveat
+ if rel.OptionalCaveat != nil {
+ caveat = &v1.ContextualizedCaveat{
+ CaveatName: rel.OptionalCaveat.CaveatName,
+ Context: rel.OptionalCaveat.Context,
+ }
+ }
+
+ var expiration *timestamppb.Timestamp
+ if rel.OptionalExpiration != nil {
+ expiration = timestamppb.New(*rel.OptionalExpiration)
+ }
+
+ return &v1.Relationship{
+ Resource: &v1.ObjectReference{
+ ObjectType: rel.Resource.ObjectType,
+ ObjectId: rel.Resource.ObjectID,
+ },
+ Relation: rel.Resource.Relation,
+ Subject: &v1.SubjectReference{
+ Object: &v1.ObjectReference{
+ ObjectType: rel.Subject.ObjectType,
+ ObjectId: rel.Subject.ObjectID,
+ },
+ OptionalRelation: stringz.Default(rel.Subject.Relation, "", Ellipsis),
+ },
+ OptionalCaveat: caveat,
+ OptionalExpiresAt: expiration,
+ }
+}
+
+// CopyToV1Relationship copies a Relationship into a v1.Relationship.
+func CopyToV1Relationship(rel Relationship, v1rel *v1.Relationship) {
+ v1rel.Resource.ObjectType = rel.Resource.ObjectType
+ v1rel.Resource.ObjectId = rel.Resource.ObjectID
+ v1rel.Relation = rel.Resource.Relation
+ v1rel.Subject.Object.ObjectType = rel.Subject.ObjectType
+ v1rel.Subject.Object.ObjectId = rel.Subject.ObjectID
+ v1rel.Subject.OptionalRelation = stringz.Default(rel.Subject.Relation, "", Ellipsis)
+
+ if rel.OptionalCaveat != nil {
+ if v1rel.OptionalCaveat == nil {
+ v1rel.OptionalCaveat = &v1.ContextualizedCaveat{}
+ }
+
+ v1rel.OptionalCaveat.CaveatName = rel.OptionalCaveat.CaveatName
+ v1rel.OptionalCaveat.Context = rel.OptionalCaveat.Context
+ } else {
+ v1rel.OptionalCaveat = nil
+ }
+
+ if rel.OptionalExpiration != nil {
+ v1rel.OptionalExpiresAt = timestamppb.New(*rel.OptionalExpiration)
+ } else {
+ v1rel.OptionalExpiresAt = nil
+ }
+}
+
+// UpdatesToV1RelationshipUpdates converts a slice of RelationshipUpdate into a
+// slice of v1.RelationshipUpdate.
+func UpdatesToV1RelationshipUpdates(updates []RelationshipUpdate) ([]*v1.RelationshipUpdate, error) {
+ relationshipUpdates := make([]*v1.RelationshipUpdate, 0, len(updates))
+
+ for _, update := range updates {
+ converted, err := UpdateToV1RelationshipUpdate(update)
+ if err != nil {
+ return nil, err
+ }
+
+ relationshipUpdates = append(relationshipUpdates, converted)
+ }
+
+ return relationshipUpdates, nil
+}
+
+// UpdatesFromV1RelationshipUpdates converts a slice of v1.RelationshipUpdate into a
+// slice of RelationshipUpdate.
+func UpdatesFromV1RelationshipUpdates(updates []*v1.RelationshipUpdate) ([]RelationshipUpdate, error) {
+ relationshipUpdates := make([]RelationshipUpdate, 0, len(updates))
+
+ for _, update := range updates {
+ converted, err := UpdateFromV1RelationshipUpdate(update)
+ if err != nil {
+ return nil, err
+ }
+
+ relationshipUpdates = append(relationshipUpdates, converted)
+ }
+
+ return relationshipUpdates, nil
+}
+
+// ToV1Filter converts a RelationTuple into a RelationshipFilter.
+func ToV1Filter(rel Relationship) *v1.RelationshipFilter {
+ return &v1.RelationshipFilter{
+ ResourceType: rel.Resource.ObjectType,
+ OptionalResourceId: rel.Resource.ObjectID,
+ OptionalRelation: rel.Resource.Relation,
+ OptionalSubjectFilter: SubjectONRToSubjectFilter(rel.Subject),
+ }
+}
+
+// SubjectONRToSubjectFilter converts a userset to the equivalent exact SubjectFilter.
+func SubjectONRToSubjectFilter(subject ObjectAndRelation) *v1.SubjectFilter {
+ return &v1.SubjectFilter{
+ SubjectType: subject.ObjectType,
+ OptionalSubjectId: subject.ObjectID,
+ OptionalRelation: &v1.SubjectFilter_RelationFilter{
+ Relation: stringz.Default(subject.Relation, "", Ellipsis),
+ },
+ }
+}
+
+// RelToFilter converts a Relationship into a RelationshipFilter.
+func RelToFilter(rel *v1.Relationship) *v1.RelationshipFilter {
+ return &v1.RelationshipFilter{
+ ResourceType: rel.Resource.ObjectType,
+ OptionalResourceId: rel.Resource.ObjectId,
+ OptionalRelation: rel.Relation,
+ OptionalSubjectFilter: &v1.SubjectFilter{
+ SubjectType: rel.Subject.Object.ObjectType,
+ OptionalSubjectId: rel.Subject.Object.ObjectId,
+ OptionalRelation: &v1.SubjectFilter_RelationFilter{
+ Relation: rel.Subject.OptionalRelation,
+ },
+ },
+ }
+}