diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-22 17:35:49 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-22 17:35:49 -0600 |
| commit | 20ef0d92694465ac86b550df139e8366a0a2b4fa (patch) | |
| tree | 3f14589e1ce6eb9306a3af31c3a1f9e1af5ed637 /vendor/github.com/authzed/zed/pkg/backupformat/schema.go | |
| parent | 44e0d272c040cdc53a98b9f1dc58ae7da67752e6 (diff) | |
feat: connect to spicedb
Diffstat (limited to 'vendor/github.com/authzed/zed/pkg/backupformat/schema.go')
| -rw-r--r-- | vendor/github.com/authzed/zed/pkg/backupformat/schema.go | 101 |
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) +} |
