summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/zed/pkg/backupformat/schema.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/authzed/zed/pkg/backupformat/schema.go')
-rw-r--r--vendor/github.com/authzed/zed/pkg/backupformat/schema.go101
1 files changed, 101 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/zed/pkg/backupformat/schema.go b/vendor/github.com/authzed/zed/pkg/backupformat/schema.go
new file mode 100644
index 0000000..64a8ab6
--- /dev/null
+++ b/vendor/github.com/authzed/zed/pkg/backupformat/schema.go
@@ -0,0 +1,101 @@
+package backupformat
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+
+ "github.com/hamba/avro/v2"
+)
+
+func init() {
+ avro.DefaultConfig.Register(spiceDBBackupNamespace+"."+schemaV1SchemaName, SchemaV1{})
+ avro.DefaultConfig.Register(spiceDBBackupNamespace+"."+relationshipV1SchemaName, RelationshipV1{})
+}
+
+type RelationshipV1 struct {
+ ObjectType string `avro:"object_type"`
+ ObjectID string `avro:"object_id"`
+ Relation string `avro:"relation"`
+ SubjectObjectType string `avro:"subject_object_type"`
+ SubjectObjectID string `avro:"subject_object_id"`
+ SubjectRelation string `avro:"subject_relation"`
+ CaveatName string `avro:"caveat_name"`
+ CaveatContext []byte `avro:"caveat_context"`
+}
+
+type SchemaV1 struct {
+ SchemaText string `avro:"schema_text"`
+}
+
+const (
+ spiceDBBackupNamespace = "com.authzed.spicedb.backup"
+
+ relationshipV1SchemaName = "relationship_v1"
+ schemaV1SchemaName = "schema_v1"
+
+ metadataKeyZT = "com.authzed.spicedb.zedtoken.v1"
+)
+
+func avroSchemaV1() (string, error) {
+ relationshipSchema, err := recordSchemaFromAvroStruct(
+ relationshipV1SchemaName,
+ spiceDBBackupNamespace,
+ RelationshipV1{},
+ )
+ if err != nil {
+ return "", fmt.Errorf("unable to create schema: %w", err)
+ }
+
+ schemaSchema, err := recordSchemaFromAvroStruct(
+ schemaV1SchemaName,
+ spiceDBBackupNamespace,
+ SchemaV1{},
+ )
+ if err != nil {
+ return "", fmt.Errorf("unable to create avro SpiceDB schema schema: %w", err)
+ }
+
+ unionSchema, err := avro.NewUnionSchema([]avro.Schema{relationshipSchema, schemaSchema})
+ if err != nil {
+ return "", fmt.Errorf("unable to create avro union schema: %w", err)
+ }
+
+ serialized, err := unionSchema.MarshalJSON()
+ return string(serialized), err
+}
+
+func recordSchemaFromAvroStruct(name, namespace string, avroStruct any) (*avro.RecordSchema, error) {
+ v := reflect.TypeOf(avroStruct)
+ schemaFields := make([]*avro.Field, 0, v.NumField())
+ for i := 0; i < v.NumField(); i++ {
+ f := v.Field(i)
+ fieldName := f.Tag.Get("avro")
+ if fieldName == "" {
+ return nil, fmt.Errorf("field `%s` missing avro struct tag", f.Name)
+ }
+ fieldGoType := f.Type
+
+ var fieldType avro.Type
+ switch fieldGoType.Kind() {
+ case reflect.String:
+ fieldType = avro.String
+ case reflect.Slice:
+ if fieldGoType.Elem().Kind() != reflect.Uint8 {
+ return nil, errors.New("unable to build schema for slice, only byte slices are supported")
+ }
+ fieldType = avro.Bytes
+ default:
+ return nil, fmt.Errorf("unsupported struct kind: %s", fieldGoType)
+ }
+
+ schemaField, err := avro.NewField(fieldName, avro.NewPrimitiveSchema(fieldType, nil))
+ if err != nil {
+ return nil, fmt.Errorf("unable to create avro schema field: %w", err)
+ }
+
+ schemaFields = append(schemaFields, schemaField)
+ }
+
+ return avro.NewRecordSchema(name, namespace, schemaFields)
+}