github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/schema.go (about) 1 package avro 2 3 import ( 4 "bytes" 5 "crypto/md5" 6 "crypto/sha256" 7 "errors" 8 "fmt" 9 "sort" 10 "strconv" 11 "strings" 12 "sync" 13 "sync/atomic" 14 15 "github.com/hamba/avro/v2/pkg/crc64" 16 jsoniter "github.com/json-iterator/go" 17 ) 18 19 var nullDefault = struct{}{} 20 21 var ( 22 schemaReserved = []string{ 23 "doc", "fields", "items", "name", "namespace", "size", "symbols", 24 "values", "type", "aliases", "logicalType", "precision", "scale", 25 } 26 fieldReserved = []string{"default", "doc", "name", "order", "type", "aliases"} 27 ) 28 29 // Type is a schema type. 30 type Type string 31 32 // Schema type constants. 33 const ( 34 Record Type = "record" 35 Error Type = "error" 36 Ref Type = "<ref>" 37 Enum Type = "enum" 38 Array Type = "array" 39 Map Type = "map" 40 Union Type = "union" 41 Fixed Type = "fixed" 42 String Type = "string" 43 Bytes Type = "bytes" 44 Int Type = "int" 45 Long Type = "long" 46 Float Type = "float" 47 Double Type = "double" 48 Boolean Type = "boolean" 49 Null Type = "null" 50 ) 51 52 // Order is a field order. 53 type Order string 54 55 // Field orders. 56 const ( 57 Asc Order = "ascending" 58 Desc Order = "descending" 59 Ignore Order = "ignore" 60 ) 61 62 // LogicalType is a schema logical type. 63 type LogicalType string 64 65 // Schema logical type constants. 66 const ( 67 Decimal LogicalType = "decimal" 68 UUID LogicalType = "uuid" 69 Date LogicalType = "date" 70 TimeMillis LogicalType = "time-millis" 71 TimeMicros LogicalType = "time-micros" 72 TimestampMillis LogicalType = "timestamp-millis" 73 TimestampMicros LogicalType = "timestamp-micros" 74 LocalTimestampMillis LogicalType = "local-timestamp-millis" 75 LocalTimestampMicros LogicalType = "local-timestamp-micros" 76 Duration LogicalType = "duration" 77 ) 78 79 // Action is a field action used during decoding process. 80 type Action string 81 82 // Action type constants. 83 const ( 84 FieldIgnore Action = "ignore" 85 FieldSetDefault Action = "set_default" 86 ) 87 88 // FingerprintType is a fingerprinting algorithm. 89 type FingerprintType string 90 91 // Fingerprint type constants. 92 const ( 93 CRC64Avro FingerprintType = "CRC64-AVRO" 94 MD5 FingerprintType = "MD5" 95 SHA256 FingerprintType = "SHA256" 96 ) 97 98 // SchemaCache is a cache of schemas. 99 type SchemaCache struct { 100 cache sync.Map // map[string]Schema 101 } 102 103 // Add adds a schema to the cache with the given name. 104 func (c *SchemaCache) Add(name string, schema Schema) { 105 c.cache.Store(name, schema) 106 } 107 108 // Get returns the Schema if it exists. 109 func (c *SchemaCache) Get(name string) Schema { 110 if v, ok := c.cache.Load(name); ok { 111 return v.(Schema) 112 } 113 114 return nil 115 } 116 117 // Schemas is a slice of Schemas. 118 type Schemas []Schema 119 120 // Get gets a schema and position by type or name if it is a named schema. 121 func (s Schemas) Get(name string) (Schema, int) { 122 for i, schema := range s { 123 if schemaTypeName(schema) == name { 124 return schema, i 125 } 126 } 127 128 return nil, -1 129 } 130 131 // Schema represents an Avro schema. 132 type Schema interface { 133 // Type returns the type of the schema. 134 Type() Type 135 136 // String returns the canonical form of the schema. 137 String() string 138 139 // Fingerprint returns the SHA256 fingerprint of the schema. 140 Fingerprint() [32]byte 141 142 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 143 FingerprintUsing(FingerprintType) ([]byte, error) 144 145 // CacheFingerprint returns the unique identity of the schema. 146 // This returns a unique identity for schemas resolved from a writer schema, otherwise it returns 147 // the schemas Fingerprint. 148 CacheFingerprint() [32]byte 149 } 150 151 // LogicalSchema represents an Avro schema with a logical type. 152 type LogicalSchema interface { 153 // Type returns the type of the logical schema. 154 Type() LogicalType 155 156 // String returns the canonical form of the logical schema. 157 String() string 158 } 159 160 // PropertySchema represents a schema with properties. 161 type PropertySchema interface { 162 // Prop gets a property from the schema. 163 Prop(string) any 164 } 165 166 // NamedSchema represents a schema with a name. 167 type NamedSchema interface { 168 Schema 169 PropertySchema 170 171 // Name returns the name of the schema. 172 Name() string 173 174 // Namespace returns the namespace of a schema. 175 Namespace() string 176 177 // FullName returns the full qualified name of a schema. 178 FullName() string 179 180 // Aliases returns the full qualified aliases of a schema. 181 Aliases() []string 182 } 183 184 // LogicalTypeSchema represents a schema that can contain a logical type. 185 type LogicalTypeSchema interface { 186 // Logical returns the logical schema or nil. 187 Logical() LogicalSchema 188 } 189 190 type name struct { 191 name string 192 namespace string 193 full string 194 aliases []string 195 } 196 197 func newName(n, ns string, aliases []string) (name, error) { 198 if idx := strings.LastIndexByte(n, '.'); idx > -1 { 199 ns = n[:idx] 200 n = n[idx+1:] 201 } 202 203 full := n 204 if ns != "" { 205 full = ns + "." + n 206 } 207 208 for _, part := range strings.Split(full, ".") { 209 if err := validateName(part); err != nil { 210 return name{}, fmt.Errorf("avro: invalid name part %q in name %q: %w", full, part, err) 211 } 212 } 213 214 a := make([]string, 0, len(aliases)) 215 for _, alias := range aliases { 216 if !strings.Contains(alias, ".") { 217 if err := validateName(alias); err != nil { 218 return name{}, fmt.Errorf("avro: invalid name %q: %w", alias, err) 219 } 220 if ns == "" { 221 a = append(a, alias) 222 continue 223 } 224 a = append(a, ns+"."+alias) 225 continue 226 } 227 228 for _, part := range strings.Split(alias, ".") { 229 if err := validateName(part); err != nil { 230 return name{}, fmt.Errorf("avro: invalid name part %q in name %q: %w", full, part, err) 231 } 232 } 233 a = append(a, alias) 234 } 235 236 return name{ 237 name: n, 238 namespace: ns, 239 full: full, 240 aliases: a, 241 }, nil 242 } 243 244 // Name returns the name of a schema. 245 func (n name) Name() string { 246 return n.name 247 } 248 249 // Namespace returns the namespace of a schema. 250 func (n name) Namespace() string { 251 return n.namespace 252 } 253 254 // FullName returns the fully qualified name of a schema. 255 func (n name) FullName() string { 256 return n.full 257 } 258 259 // Aliases returns the fully qualified aliases of a schema. 260 func (n name) Aliases() []string { 261 return n.aliases 262 } 263 264 type fingerprinter struct { 265 fingerprint atomic.Value // [32]byte 266 cache sync.Map // map[FingerprintType][]byte 267 } 268 269 // Fingerprint returns the SHA256 fingerprint of the schema. 270 func (f *fingerprinter) Fingerprint(stringer fmt.Stringer) [32]byte { 271 if v := f.fingerprint.Load(); v != nil { 272 return v.([32]byte) 273 } 274 275 fingerprint := sha256.Sum256([]byte(stringer.String())) 276 f.fingerprint.Store(fingerprint) 277 return fingerprint 278 } 279 280 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 281 func (f *fingerprinter) FingerprintUsing(typ FingerprintType, stringer fmt.Stringer) ([]byte, error) { 282 if v, ok := f.cache.Load(typ); ok { 283 return v.([]byte), nil 284 } 285 286 data := []byte(stringer.String()) 287 288 var fingerprint []byte 289 switch typ { 290 case CRC64Avro: 291 h := crc64.Sum(data) 292 fingerprint = h[:] 293 case MD5: 294 h := md5.Sum(data) 295 fingerprint = h[:] 296 case SHA256: 297 h := sha256.Sum256(data) 298 fingerprint = h[:] 299 default: 300 return nil, fmt.Errorf("avro: unknown fingerprint algorithm %s", typ) 301 } 302 303 f.cache.Store(typ, fingerprint) 304 return fingerprint, nil 305 } 306 307 type cacheFingerprinter struct { 308 writerFingerprint *[32]byte 309 310 cache atomic.Value // [32]byte 311 } 312 313 // CacheFingerprint returns the SHA256 identity of the schema. 314 func (i *cacheFingerprinter) CacheFingerprint(schema Schema, fn func() []byte) [32]byte { 315 if v := i.cache.Load(); v != nil { 316 return v.([32]byte) 317 } 318 319 if i.writerFingerprint == nil { 320 fp := schema.Fingerprint() 321 i.cache.Store(fp) 322 return fp 323 } 324 325 fp := schema.Fingerprint() 326 d := append([]byte{}, fp[:]...) 327 d = append(d, (*i.writerFingerprint)[:]...) 328 if fn != nil { 329 d = append(d, fn()...) 330 } 331 ident := sha256.Sum256(d) 332 i.cache.Store(ident) 333 return ident 334 } 335 336 type properties struct { 337 props map[string]any 338 } 339 340 func newProperties(props map[string]any, res []string) properties { 341 p := properties{props: map[string]any{}} 342 for k, v := range props { 343 if isReserved(res, k) { 344 continue 345 } 346 p.props[k] = v 347 } 348 return p 349 } 350 351 func isReserved(res []string, k string) bool { 352 for _, r := range res { 353 if k == r { 354 return true 355 } 356 } 357 return false 358 } 359 360 // Prop gets a property from the schema. 361 func (p properties) Prop(name string) any { 362 if p.props == nil { 363 return nil 364 } 365 366 return p.props[name] 367 } 368 369 func (p properties) marshalPropertiesToJSON(buf *bytes.Buffer) error { 370 sortedPropertyKeys := make([]string, 0, len(p.props)) 371 for k := range p.props { 372 sortedPropertyKeys = append(sortedPropertyKeys, k) 373 } 374 sort.Strings(sortedPropertyKeys) 375 for _, k := range sortedPropertyKeys { 376 vv, err := jsoniter.Marshal(p.props[k]) 377 if err != nil { 378 return err 379 } 380 buf.WriteString(`,"` + k + `":`) 381 buf.Write(vv) 382 } 383 return nil 384 } 385 386 type schemaConfig struct { 387 aliases []string 388 doc string 389 def any 390 order Order 391 props map[string]any 392 wfp *[32]byte 393 } 394 395 // SchemaOption is a function that sets a schema option. 396 type SchemaOption func(*schemaConfig) 397 398 // WithAliases sets the aliases on a schema. 399 func WithAliases(aliases []string) SchemaOption { 400 return func(opts *schemaConfig) { 401 opts.aliases = aliases 402 } 403 } 404 405 // WithDoc sets the doc on a schema. 406 func WithDoc(doc string) SchemaOption { 407 return func(opts *schemaConfig) { 408 opts.doc = doc 409 } 410 } 411 412 // WithDefault sets the default on a schema. 413 func WithDefault(def any) SchemaOption { 414 return func(opts *schemaConfig) { 415 opts.def = def 416 } 417 } 418 419 // WithOrder sets the order on a schema. 420 func WithOrder(order Order) SchemaOption { 421 return func(opts *schemaConfig) { 422 opts.order = order 423 } 424 } 425 426 // WithProps sets the properties on a schema. 427 func WithProps(props map[string]any) SchemaOption { 428 return func(opts *schemaConfig) { 429 opts.props = props 430 } 431 } 432 433 func withWriterFingerprint(fp [32]byte) SchemaOption { 434 return func(opts *schemaConfig) { 435 opts.wfp = &fp 436 } 437 } 438 439 func withWriterFingerprintIfResolved(fp [32]byte, resolved bool) SchemaOption { 440 return func(opts *schemaConfig) { 441 if resolved { 442 opts.wfp = &fp 443 } 444 } 445 } 446 447 // PrimitiveSchema is an Avro primitive type schema. 448 type PrimitiveSchema struct { 449 properties 450 fingerprinter 451 cacheFingerprinter 452 453 typ Type 454 logical LogicalSchema 455 456 // encodedType is the type of the encoded value, if it is different from the typ. 457 // It's only used in the context of write-read schema resolution. 458 encodedType Type 459 } 460 461 // NewPrimitiveSchema creates a new PrimitiveSchema. 462 func NewPrimitiveSchema(t Type, l LogicalSchema, opts ...SchemaOption) *PrimitiveSchema { 463 var cfg schemaConfig 464 for _, opt := range opts { 465 opt(&cfg) 466 } 467 468 return &PrimitiveSchema{ 469 properties: newProperties(cfg.props, schemaReserved), 470 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 471 typ: t, 472 logical: l, 473 } 474 } 475 476 // Type returns the type of the schema. 477 func (s *PrimitiveSchema) Type() Type { 478 return s.typ 479 } 480 481 // Logical returns the logical schema or nil. 482 func (s *PrimitiveSchema) Logical() LogicalSchema { 483 return s.logical 484 } 485 486 // String returns the canonical form of the schema. 487 func (s *PrimitiveSchema) String() string { 488 if s.logical == nil { 489 return `"` + string(s.typ) + `"` 490 } 491 492 return `{"type":"` + string(s.typ) + `",` + s.logical.String() + `}` 493 } 494 495 // MarshalJSON marshals the schema to json. 496 func (s *PrimitiveSchema) MarshalJSON() ([]byte, error) { 497 if s.logical == nil && len(s.props) == 0 { 498 return jsoniter.Marshal(s.typ) 499 } 500 501 buf := new(bytes.Buffer) 502 buf.WriteString(`{"type":"` + string(s.typ) + `"`) 503 if s.logical != nil { 504 buf.WriteString(`,"logicalType":"` + string(s.logical.Type()) + `"`) 505 if d, ok := s.logical.(*DecimalLogicalSchema); ok { 506 buf.WriteString(`,"precision":` + strconv.Itoa(d.prec)) 507 if d.scale > 0 { 508 buf.WriteString(`,"scale":` + strconv.Itoa(d.scale)) 509 } 510 } 511 } 512 if err := s.marshalPropertiesToJSON(buf); err != nil { 513 return nil, err 514 } 515 buf.WriteString("}") 516 return buf.Bytes(), nil 517 } 518 519 // Fingerprint returns the SHA256 fingerprint of the schema. 520 func (s *PrimitiveSchema) Fingerprint() [32]byte { 521 return s.fingerprinter.Fingerprint(s) 522 } 523 524 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 525 func (s *PrimitiveSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 526 return s.fingerprinter.FingerprintUsing(typ, s) 527 } 528 529 // CacheFingerprint returns unique identity of the schema. 530 func (s *PrimitiveSchema) CacheFingerprint() [32]byte { 531 return s.cacheFingerprinter.CacheFingerprint(s, nil) 532 } 533 534 // RecordSchema is an Avro record type schema. 535 type RecordSchema struct { 536 name 537 properties 538 fingerprinter 539 cacheFingerprinter 540 isError bool 541 fields []*Field 542 doc string 543 } 544 545 // NewRecordSchema creates a new record schema instance. 546 func NewRecordSchema(name, namespace string, fields []*Field, opts ...SchemaOption) (*RecordSchema, error) { 547 var cfg schemaConfig 548 for _, opt := range opts { 549 opt(&cfg) 550 } 551 552 n, err := newName(name, namespace, cfg.aliases) 553 if err != nil { 554 return nil, err 555 } 556 557 return &RecordSchema{ 558 name: n, 559 properties: newProperties(cfg.props, schemaReserved), 560 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 561 fields: fields, 562 doc: cfg.doc, 563 }, nil 564 } 565 566 // NewErrorRecordSchema creates a new error record schema instance. 567 func NewErrorRecordSchema(name, namespace string, fields []*Field, opts ...SchemaOption) (*RecordSchema, error) { 568 rec, err := NewRecordSchema(name, namespace, fields, opts...) 569 if err != nil { 570 return nil, err 571 } 572 573 rec.isError = true 574 575 return rec, nil 576 } 577 578 // Type returns the type of the schema. 579 func (s *RecordSchema) Type() Type { 580 return Record 581 } 582 583 // Doc returns the documentation of a record. 584 func (s *RecordSchema) Doc() string { 585 return s.doc 586 } 587 588 // IsError determines is this is an error record. 589 func (s *RecordSchema) IsError() bool { 590 return s.isError 591 } 592 593 // Fields returns the fields of a record. 594 func (s *RecordSchema) Fields() []*Field { 595 return s.fields 596 } 597 598 // String returns the canonical form of the schema. 599 func (s *RecordSchema) String() string { 600 typ := "record" 601 if s.isError { 602 typ = "error" 603 } 604 605 fields := "" 606 for _, f := range s.fields { 607 fields += f.String() + "," 608 } 609 if len(fields) > 0 { 610 fields = fields[:len(fields)-1] 611 } 612 613 return `{"name":"` + s.FullName() + `","type":"` + typ + `","fields":[` + fields + `]}` 614 } 615 616 // MarshalJSON marshals the schema to json. 617 func (s *RecordSchema) MarshalJSON() ([]byte, error) { 618 buf := new(bytes.Buffer) 619 buf.WriteString(`{"name":"` + s.full + `"`) 620 if len(s.aliases) > 0 { 621 aliasesJSON, err := jsoniter.Marshal(s.aliases) 622 if err != nil { 623 return nil, err 624 } 625 buf.WriteString(`,"aliases":`) 626 buf.Write(aliasesJSON) 627 } 628 if s.doc != "" { 629 buf.WriteString(`,"doc":"` + s.doc + `"`) 630 } 631 if s.isError { 632 buf.WriteString(`,"type":"error"`) 633 } else { 634 buf.WriteString(`,"type":"record"`) 635 } 636 fieldsJSON, err := jsoniter.Marshal(s.fields) 637 if err != nil { 638 return nil, err 639 } 640 buf.WriteString(`,"fields":`) 641 buf.Write(fieldsJSON) 642 if err := s.marshalPropertiesToJSON(buf); err != nil { 643 return nil, err 644 } 645 buf.WriteString("}") 646 return buf.Bytes(), nil 647 } 648 649 // Fingerprint returns the SHA256 fingerprint of the schema. 650 func (s *RecordSchema) Fingerprint() [32]byte { 651 return s.fingerprinter.Fingerprint(s) 652 } 653 654 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 655 func (s *RecordSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 656 return s.fingerprinter.FingerprintUsing(typ, s) 657 } 658 659 // CacheFingerprint returns unique identity of the schema. 660 func (s *RecordSchema) CacheFingerprint() [32]byte { 661 return s.cacheFingerprinter.CacheFingerprint(s, func() []byte { 662 var defs []any 663 for _, field := range s.fields { 664 if !field.HasDefault() { 665 continue 666 } 667 defs = append(defs, field.Default()) 668 } 669 b, _ := jsoniter.Marshal(defs) 670 return b 671 }) 672 } 673 674 // Field is an Avro record type field. 675 type Field struct { 676 properties 677 678 name string 679 aliases []string 680 doc string 681 typ Schema 682 hasDef bool 683 def any 684 order Order 685 686 // action mainly used when decoding data that lack the field for schema evolution purposes. 687 action Action 688 // encodedDef mainly used when decoding data that lack the field for schema evolution purposes. 689 // Its value remains empty unless the field's encodeDefault function is called. 690 encodedDef atomic.Value 691 } 692 693 type noDef struct{} 694 695 // NoDefault is used when no default exists for a field. 696 var NoDefault = noDef{} 697 698 // NewField creates a new field instance. 699 func NewField(name string, typ Schema, opts ...SchemaOption) (*Field, error) { 700 cfg := schemaConfig{def: NoDefault} 701 for _, opt := range opts { 702 opt(&cfg) 703 } 704 705 if err := validateName(name); err != nil { 706 return nil, err 707 } 708 for _, a := range cfg.aliases { 709 if err := validateName(a); err != nil { 710 return nil, err 711 } 712 } 713 714 switch cfg.order { 715 case "": 716 cfg.order = Asc 717 case Asc, Desc, Ignore: 718 default: 719 return nil, fmt.Errorf("avro: field %q order %q is invalid", name, cfg.order) 720 } 721 722 f := &Field{ 723 properties: newProperties(cfg.props, fieldReserved), 724 name: name, 725 aliases: cfg.aliases, 726 doc: cfg.doc, 727 typ: typ, 728 order: cfg.order, 729 } 730 731 if cfg.def != NoDefault { 732 def, err := validateDefault(name, typ, cfg.def) 733 if err != nil { 734 return nil, err 735 } 736 f.def = def 737 f.hasDef = true 738 } 739 740 return f, nil 741 } 742 743 // Name returns the name of a field. 744 func (f *Field) Name() string { 745 return f.name 746 } 747 748 // Aliases return the field aliases. 749 func (f *Field) Aliases() []string { 750 return f.aliases 751 } 752 753 // Type returns the schema of a field. 754 func (f *Field) Type() Schema { 755 return f.typ 756 } 757 758 // HasDefault determines if the field has a default value. 759 func (f *Field) HasDefault() bool { 760 return f.hasDef 761 } 762 763 // Default returns the default of a field or nil. 764 // 765 // The only time a nil default is valid is for a Null Type. 766 func (f *Field) Default() any { 767 if f.def == nullDefault { 768 return nil 769 } 770 771 return f.def 772 } 773 774 func (f *Field) encodeDefault(encode func(any) ([]byte, error)) ([]byte, error) { 775 if v := f.encodedDef.Load(); v != nil { 776 return v.([]byte), nil 777 } 778 if !f.hasDef { 779 return nil, fmt.Errorf("avro: '%s' field must have a non-empty default value", f.name) 780 } 781 if encode == nil { 782 return nil, fmt.Errorf("avro: failed to encode '%s' default value", f.name) 783 } 784 b, err := encode(f.Default()) 785 if err != nil { 786 return nil, err 787 } 788 f.encodedDef.Store(b) 789 790 return b, nil 791 } 792 793 // Doc returns the documentation of a field. 794 func (f *Field) Doc() string { 795 return f.doc 796 } 797 798 // Order returns the field order. 799 func (f *Field) Order() Order { 800 return f.order 801 } 802 803 // String returns the canonical form of a field. 804 func (f *Field) String() string { 805 return `{"name":"` + f.name + `","type":` + f.typ.String() + `}` 806 } 807 808 // MarshalJSON marshals the schema to json. 809 func (f *Field) MarshalJSON() ([]byte, error) { 810 buf := new(bytes.Buffer) 811 buf.WriteString(`{"name":"` + f.name + `"`) 812 if len(f.aliases) > 0 { 813 aliasesJSON, err := jsoniter.Marshal(f.aliases) 814 if err != nil { 815 return nil, err 816 } 817 buf.WriteString(`,"aliases":`) 818 buf.Write(aliasesJSON) 819 } 820 if f.doc != "" { 821 buf.WriteString(`,"doc":"` + f.doc + `"`) 822 } 823 typeJSON, err := jsoniter.Marshal(f.typ) 824 if err != nil { 825 return nil, err 826 } 827 buf.WriteString(`,"type":`) 828 buf.Write(typeJSON) 829 if f.hasDef { 830 defaultValueJSON, err := jsoniter.Marshal(f.Default()) 831 if err != nil { 832 return nil, err 833 } 834 buf.WriteString(`,"default":`) 835 buf.Write(defaultValueJSON) 836 } 837 if f.order != "" && f.order != Asc { 838 buf.WriteString(`,"order":"` + string(f.order) + `"`) 839 } 840 if err := f.marshalPropertiesToJSON(buf); err != nil { 841 return nil, err 842 } 843 buf.WriteString("}") 844 return buf.Bytes(), nil 845 } 846 847 // EnumSchema is an Avro enum type schema. 848 type EnumSchema struct { 849 name 850 properties 851 fingerprinter 852 cacheFingerprinter 853 854 symbols []string 855 def string 856 doc string 857 858 // encodedSymbols is the symbols of the encoded value. 859 // It's only used in the context of write-read schema resolution. 860 encodedSymbols []string 861 } 862 863 // NewEnumSchema creates a new enum schema instance. 864 func NewEnumSchema(name, namespace string, symbols []string, opts ...SchemaOption) (*EnumSchema, error) { 865 var cfg schemaConfig 866 for _, opt := range opts { 867 opt(&cfg) 868 } 869 870 n, err := newName(name, namespace, cfg.aliases) 871 if err != nil { 872 return nil, err 873 } 874 875 if len(symbols) == 0 { 876 return nil, errors.New("avro: enum must have a non-empty array of symbols") 877 } 878 for _, sym := range symbols { 879 if err = validateName(sym); err != nil { 880 return nil, fmt.Errorf("avro: invalid symbol %q", sym) 881 } 882 } 883 884 var def string 885 if d, ok := cfg.def.(string); ok && d != "" { 886 if !hasSymbol(symbols, d) { 887 return nil, fmt.Errorf("avro: symbol default %q must be a symbol", d) 888 } 889 def = d 890 } 891 892 return &EnumSchema{ 893 name: n, 894 properties: newProperties(cfg.props, schemaReserved), 895 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 896 symbols: symbols, 897 def: def, 898 doc: cfg.doc, 899 }, nil 900 } 901 902 func hasSymbol(symbols []string, sym string) bool { 903 for _, s := range symbols { 904 if s == sym { 905 return true 906 } 907 } 908 return false 909 } 910 911 // Type returns the type of the schema. 912 func (s *EnumSchema) Type() Type { 913 return Enum 914 } 915 916 // Doc returns the schema doc. 917 func (s *EnumSchema) Doc() string { 918 return s.doc 919 } 920 921 // Symbols returns the symbols of an enum. 922 func (s *EnumSchema) Symbols() []string { 923 return s.symbols 924 } 925 926 // Symbol returns the symbol for the given index. 927 // It might return the default value in the context of write-read schema resolution. 928 func (s *EnumSchema) Symbol(i int) (string, bool) { 929 resolv := len(s.encodedSymbols) > 0 930 symbols := s.symbols 931 if resolv { 932 // A different set of symbols is encoded. 933 symbols = s.encodedSymbols 934 } 935 936 if i < 0 || i >= len(symbols) { 937 return "", false 938 } 939 940 symbol := symbols[i] 941 if resolv && !hasSymbol(s.symbols, symbol) { 942 if !s.HasDefault() { 943 return "", false 944 } 945 return s.Default(), true 946 } 947 return symbol, true 948 } 949 950 // Default returns the default of an enum or an empty string. 951 func (s *EnumSchema) Default() string { 952 return s.def 953 } 954 955 // HasDefault determines if the schema has a default value. 956 func (s *EnumSchema) HasDefault() bool { 957 return s.def != "" 958 } 959 960 // String returns the canonical form of the schema. 961 func (s *EnumSchema) String() string { 962 symbols := "" 963 for _, sym := range s.symbols { 964 symbols += `"` + sym + `",` 965 } 966 if len(symbols) > 0 { 967 symbols = symbols[:len(symbols)-1] 968 } 969 970 return `{"name":"` + s.FullName() + `","type":"enum","symbols":[` + symbols + `]}` 971 } 972 973 // MarshalJSON marshals the schema to json. 974 func (s *EnumSchema) MarshalJSON() ([]byte, error) { 975 buf := new(bytes.Buffer) 976 buf.WriteString(`{"name":"` + s.full + `"`) 977 if len(s.aliases) > 0 { 978 aliasesJSON, err := jsoniter.Marshal(s.aliases) 979 if err != nil { 980 return nil, err 981 } 982 buf.WriteString(`,"aliases":`) 983 buf.Write(aliasesJSON) 984 } 985 if s.doc != "" { 986 buf.WriteString(`,"doc":"` + s.doc + `"`) 987 } 988 buf.WriteString(`,"type":"enum"`) 989 symbolsJSON, err := jsoniter.Marshal(s.symbols) 990 if err != nil { 991 return nil, err 992 } 993 buf.WriteString(`,"symbols":`) 994 buf.Write(symbolsJSON) 995 if s.def != "" { 996 buf.WriteString(`,"default":"` + s.def + `"`) 997 } 998 if err := s.marshalPropertiesToJSON(buf); err != nil { 999 return nil, err 1000 } 1001 buf.WriteString("}") 1002 return buf.Bytes(), nil 1003 } 1004 1005 // Fingerprint returns the SHA256 fingerprint of the schema. 1006 func (s *EnumSchema) Fingerprint() [32]byte { 1007 return s.fingerprinter.Fingerprint(s) 1008 } 1009 1010 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1011 func (s *EnumSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1012 return s.fingerprinter.FingerprintUsing(typ, s) 1013 } 1014 1015 // CacheFingerprint returns unique identity of the schema. 1016 func (s *EnumSchema) CacheFingerprint() [32]byte { 1017 return s.cacheFingerprinter.CacheFingerprint(s, func() []byte { 1018 if !s.HasDefault() { 1019 return []byte{} 1020 } 1021 return []byte(s.Default()) 1022 }) 1023 } 1024 1025 // ArraySchema is an Avro array type schema. 1026 type ArraySchema struct { 1027 properties 1028 fingerprinter 1029 cacheFingerprinter 1030 1031 items Schema 1032 } 1033 1034 // NewArraySchema creates an array schema instance. 1035 func NewArraySchema(items Schema, opts ...SchemaOption) *ArraySchema { 1036 var cfg schemaConfig 1037 for _, opt := range opts { 1038 opt(&cfg) 1039 } 1040 1041 return &ArraySchema{ 1042 properties: newProperties(cfg.props, schemaReserved), 1043 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 1044 items: items, 1045 } 1046 } 1047 1048 // Type returns the type of the schema. 1049 func (s *ArraySchema) Type() Type { 1050 return Array 1051 } 1052 1053 // Items returns the items schema of an array. 1054 func (s *ArraySchema) Items() Schema { 1055 return s.items 1056 } 1057 1058 // String returns the canonical form of the schema. 1059 func (s *ArraySchema) String() string { 1060 return `{"type":"array","items":` + s.items.String() + `}` 1061 } 1062 1063 // MarshalJSON marshals the schema to json. 1064 func (s *ArraySchema) MarshalJSON() ([]byte, error) { 1065 buf := new(bytes.Buffer) 1066 buf.WriteString(`{"type":"array"`) 1067 itemsJSON, err := jsoniter.Marshal(s.items) 1068 if err != nil { 1069 return nil, err 1070 } 1071 buf.WriteString(`,"items":`) 1072 buf.Write(itemsJSON) 1073 if err = s.marshalPropertiesToJSON(buf); err != nil { 1074 return nil, err 1075 } 1076 buf.WriteString("}") 1077 return buf.Bytes(), nil 1078 } 1079 1080 // Fingerprint returns the SHA256 fingerprint of the schema. 1081 func (s *ArraySchema) Fingerprint() [32]byte { 1082 return s.fingerprinter.Fingerprint(s) 1083 } 1084 1085 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1086 func (s *ArraySchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1087 return s.fingerprinter.FingerprintUsing(typ, s) 1088 } 1089 1090 // CacheFingerprint returns unique identity of the schema. 1091 func (s *ArraySchema) CacheFingerprint() [32]byte { 1092 return s.cacheFingerprinter.CacheFingerprint(s, nil) 1093 } 1094 1095 // MapSchema is an Avro map type schema. 1096 type MapSchema struct { 1097 properties 1098 fingerprinter 1099 cacheFingerprinter 1100 1101 values Schema 1102 } 1103 1104 // NewMapSchema creates a map schema instance. 1105 func NewMapSchema(values Schema, opts ...SchemaOption) *MapSchema { 1106 var cfg schemaConfig 1107 for _, opt := range opts { 1108 opt(&cfg) 1109 } 1110 1111 return &MapSchema{ 1112 properties: newProperties(cfg.props, schemaReserved), 1113 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 1114 values: values, 1115 } 1116 } 1117 1118 // Type returns the type of the schema. 1119 func (s *MapSchema) Type() Type { 1120 return Map 1121 } 1122 1123 // Values returns the values schema of a map. 1124 func (s *MapSchema) Values() Schema { 1125 return s.values 1126 } 1127 1128 // String returns the canonical form of the schema. 1129 func (s *MapSchema) String() string { 1130 return `{"type":"map","values":` + s.values.String() + `}` 1131 } 1132 1133 // MarshalJSON marshals the schema to json. 1134 func (s *MapSchema) MarshalJSON() ([]byte, error) { 1135 buf := new(bytes.Buffer) 1136 buf.WriteString(`{"type":"map"`) 1137 valuesJSON, err := jsoniter.Marshal(s.values) 1138 if err != nil { 1139 return nil, err 1140 } 1141 buf.WriteString(`,"values":`) 1142 buf.Write(valuesJSON) 1143 if err := s.marshalPropertiesToJSON(buf); err != nil { 1144 return nil, err 1145 } 1146 buf.WriteString("}") 1147 return buf.Bytes(), nil 1148 } 1149 1150 // Fingerprint returns the SHA256 fingerprint of the schema. 1151 func (s *MapSchema) Fingerprint() [32]byte { 1152 return s.fingerprinter.Fingerprint(s) 1153 } 1154 1155 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1156 func (s *MapSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1157 return s.fingerprinter.FingerprintUsing(typ, s) 1158 } 1159 1160 // CacheFingerprint returns unique identity of the schema. 1161 func (s *MapSchema) CacheFingerprint() [32]byte { 1162 return s.cacheFingerprinter.CacheFingerprint(s, nil) 1163 } 1164 1165 // UnionSchema is an Avro union type schema. 1166 type UnionSchema struct { 1167 fingerprinter 1168 cacheFingerprinter 1169 1170 types Schemas 1171 } 1172 1173 // NewUnionSchema creates a union schema instance. 1174 func NewUnionSchema(types []Schema, opts ...SchemaOption) (*UnionSchema, error) { 1175 var cfg schemaConfig 1176 for _, opt := range opts { 1177 opt(&cfg) 1178 } 1179 1180 seen := map[string]bool{} 1181 for _, schema := range types { 1182 if schema.Type() == Union { 1183 return nil, errors.New("avro: union type cannot be a union") 1184 } 1185 1186 strType := schemaTypeName(schema) 1187 1188 if seen[strType] { 1189 return nil, errors.New("avro: union type must be unique") 1190 } 1191 seen[strType] = true 1192 } 1193 1194 return &UnionSchema{ 1195 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 1196 types: types, 1197 }, nil 1198 } 1199 1200 // Type returns the type of the schema. 1201 func (s *UnionSchema) Type() Type { 1202 return Union 1203 } 1204 1205 // Types returns the types of a union. 1206 func (s *UnionSchema) Types() Schemas { 1207 return s.types 1208 } 1209 1210 // Nullable returns the Schema if the union is nullable, otherwise nil. 1211 func (s *UnionSchema) Nullable() bool { 1212 if len(s.types) != 2 || s.types[0].Type() != Null && s.types[1].Type() != Null { 1213 return false 1214 } 1215 1216 return true 1217 } 1218 1219 // Indices returns the index of the null and type schemas for a 1220 // nullable schema. For non-nullable schemas 0 is returned for 1221 // both. 1222 func (s *UnionSchema) Indices() (null, typ int) { 1223 if !s.Nullable() { 1224 return 0, 0 1225 } 1226 if s.types[0].Type() == Null { 1227 return 0, 1 1228 } 1229 return 1, 0 1230 } 1231 1232 // String returns the canonical form of the schema. 1233 func (s *UnionSchema) String() string { 1234 types := "" 1235 for _, typ := range s.types { 1236 types += typ.String() + "," 1237 } 1238 if len(types) > 0 { 1239 types = types[:len(types)-1] 1240 } 1241 1242 return `[` + types + `]` 1243 } 1244 1245 // MarshalJSON marshals the schema to json. 1246 func (s *UnionSchema) MarshalJSON() ([]byte, error) { 1247 return jsoniter.Marshal(s.types) 1248 } 1249 1250 // Fingerprint returns the SHA256 fingerprint of the schema. 1251 func (s *UnionSchema) Fingerprint() [32]byte { 1252 return s.fingerprinter.Fingerprint(s) 1253 } 1254 1255 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1256 func (s *UnionSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1257 return s.fingerprinter.FingerprintUsing(typ, s) 1258 } 1259 1260 // CacheFingerprint returns unique identity of the schema. 1261 func (s *UnionSchema) CacheFingerprint() [32]byte { 1262 return s.cacheFingerprinter.CacheFingerprint(s, nil) 1263 } 1264 1265 // FixedSchema is an Avro fixed type schema. 1266 type FixedSchema struct { 1267 name 1268 properties 1269 fingerprinter 1270 cacheFingerprinter 1271 1272 size int 1273 logical LogicalSchema 1274 } 1275 1276 // NewFixedSchema creates a new fixed schema instance. 1277 func NewFixedSchema( 1278 name, namespace string, 1279 size int, 1280 logical LogicalSchema, 1281 opts ...SchemaOption, 1282 ) (*FixedSchema, error) { 1283 var cfg schemaConfig 1284 for _, opt := range opts { 1285 opt(&cfg) 1286 } 1287 1288 n, err := newName(name, namespace, cfg.aliases) 1289 if err != nil { 1290 return nil, err 1291 } 1292 1293 return &FixedSchema{ 1294 name: n, 1295 properties: newProperties(cfg.props, schemaReserved), 1296 cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp}, 1297 size: size, 1298 logical: logical, 1299 }, nil 1300 } 1301 1302 // Type returns the type of the schema. 1303 func (s *FixedSchema) Type() Type { 1304 return Fixed 1305 } 1306 1307 // Size returns the number of bytes of the fixed schema. 1308 func (s *FixedSchema) Size() int { 1309 return s.size 1310 } 1311 1312 // Logical returns the logical schema or nil. 1313 func (s *FixedSchema) Logical() LogicalSchema { 1314 return s.logical 1315 } 1316 1317 // String returns the canonical form of the schema. 1318 func (s *FixedSchema) String() string { 1319 size := strconv.Itoa(s.size) 1320 1321 var logical string 1322 if s.logical != nil { 1323 logical = "," + s.logical.String() 1324 } 1325 1326 return `{"name":"` + s.FullName() + `","type":"fixed","size":` + size + logical + `}` 1327 } 1328 1329 // MarshalJSON marshals the schema to json. 1330 func (s *FixedSchema) MarshalJSON() ([]byte, error) { 1331 buf := new(bytes.Buffer) 1332 buf.WriteString(`{"name":"` + s.full + `"`) 1333 if len(s.aliases) > 0 { 1334 aliasesJSON, err := jsoniter.Marshal(s.aliases) 1335 if err != nil { 1336 return nil, err 1337 } 1338 buf.WriteString(`,"aliases":`) 1339 buf.Write(aliasesJSON) 1340 } 1341 buf.WriteString(`,"type":"fixed"`) 1342 buf.WriteString(`,"size":` + strconv.Itoa(s.size)) 1343 if s.logical != nil { 1344 buf.WriteString(`,"logicalType":"` + string(s.logical.Type()) + `"`) 1345 if d, ok := s.logical.(*DecimalLogicalSchema); ok { 1346 buf.WriteString(`,"precision":` + strconv.Itoa(d.prec)) 1347 if d.scale > 0 { 1348 buf.WriteString(`,"scale":` + strconv.Itoa(d.scale)) 1349 } 1350 } 1351 } 1352 if err := s.marshalPropertiesToJSON(buf); err != nil { 1353 return nil, err 1354 } 1355 buf.WriteString("}") 1356 return buf.Bytes(), nil 1357 } 1358 1359 // Fingerprint returns the SHA256 fingerprint of the schema. 1360 func (s *FixedSchema) Fingerprint() [32]byte { 1361 return s.fingerprinter.Fingerprint(s) 1362 } 1363 1364 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1365 func (s *FixedSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1366 return s.fingerprinter.FingerprintUsing(typ, s) 1367 } 1368 1369 // CacheFingerprint returns unique identity of the schema. 1370 func (s *FixedSchema) CacheFingerprint() [32]byte { 1371 return s.cacheFingerprinter.CacheFingerprint(s, nil) 1372 } 1373 1374 // NullSchema is an Avro null type schema. 1375 type NullSchema struct { 1376 fingerprinter 1377 } 1378 1379 // Type returns the type of the schema. 1380 func (s *NullSchema) Type() Type { 1381 return Null 1382 } 1383 1384 // String returns the canonical form of the schema. 1385 func (s *NullSchema) String() string { 1386 return `"null"` 1387 } 1388 1389 // MarshalJSON marshals the schema to json. 1390 func (s *NullSchema) MarshalJSON() ([]byte, error) { 1391 return []byte(`"null"`), nil 1392 } 1393 1394 // Fingerprint returns the SHA256 fingerprint of the schema. 1395 func (s *NullSchema) Fingerprint() [32]byte { 1396 return s.fingerprinter.Fingerprint(s) 1397 } 1398 1399 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1400 func (s *NullSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1401 return s.fingerprinter.FingerprintUsing(typ, s) 1402 } 1403 1404 // CacheFingerprint returns unique identity of the schema. 1405 func (s *NullSchema) CacheFingerprint() [32]byte { 1406 return s.Fingerprint() 1407 } 1408 1409 // RefSchema is a reference to a named Avro schema. 1410 type RefSchema struct { 1411 actual NamedSchema 1412 } 1413 1414 // NewRefSchema creates a ref schema instance. 1415 func NewRefSchema(schema NamedSchema) *RefSchema { 1416 return &RefSchema{ 1417 actual: schema, 1418 } 1419 } 1420 1421 // Type returns the type of the schema. 1422 func (s *RefSchema) Type() Type { 1423 return Ref 1424 } 1425 1426 // Schema returns the schema being referenced. 1427 func (s *RefSchema) Schema() NamedSchema { 1428 return s.actual 1429 } 1430 1431 // String returns the canonical form of the schema. 1432 func (s *RefSchema) String() string { 1433 return `"` + s.actual.FullName() + `"` 1434 } 1435 1436 // MarshalJSON marshals the schema to json. 1437 func (s *RefSchema) MarshalJSON() ([]byte, error) { 1438 return []byte(`"` + s.actual.FullName() + `"`), nil 1439 } 1440 1441 // Fingerprint returns the SHA256 fingerprint of the schema. 1442 func (s *RefSchema) Fingerprint() [32]byte { 1443 return s.actual.Fingerprint() 1444 } 1445 1446 // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error. 1447 func (s *RefSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) { 1448 return s.actual.FingerprintUsing(typ) 1449 } 1450 1451 // CacheFingerprint returns unique identity of the schema. 1452 func (s *RefSchema) CacheFingerprint() [32]byte { 1453 return s.actual.CacheFingerprint() 1454 } 1455 1456 // PrimitiveLogicalSchema is a logical type with no properties. 1457 type PrimitiveLogicalSchema struct { 1458 typ LogicalType 1459 } 1460 1461 // NewPrimitiveLogicalSchema creates a new primitive logical schema instance. 1462 func NewPrimitiveLogicalSchema(typ LogicalType) *PrimitiveLogicalSchema { 1463 return &PrimitiveLogicalSchema{ 1464 typ: typ, 1465 } 1466 } 1467 1468 // Type returns the type of the logical schema. 1469 func (s *PrimitiveLogicalSchema) Type() LogicalType { 1470 return s.typ 1471 } 1472 1473 // String returns the canonical form of the logical schema. 1474 func (s *PrimitiveLogicalSchema) String() string { 1475 return `"logicalType":"` + string(s.typ) + `"` 1476 } 1477 1478 // DecimalLogicalSchema is a decimal logical type. 1479 type DecimalLogicalSchema struct { 1480 prec int 1481 scale int 1482 } 1483 1484 // NewDecimalLogicalSchema creates a new decimal logical schema instance. 1485 func NewDecimalLogicalSchema(prec, scale int) *DecimalLogicalSchema { 1486 return &DecimalLogicalSchema{ 1487 prec: prec, 1488 scale: scale, 1489 } 1490 } 1491 1492 // Type returns the type of the logical schema. 1493 func (s *DecimalLogicalSchema) Type() LogicalType { 1494 return Decimal 1495 } 1496 1497 // Precision returns the precision of the decimal logical schema. 1498 func (s *DecimalLogicalSchema) Precision() int { 1499 return s.prec 1500 } 1501 1502 // Scale returns the scale of the decimal logical schema. 1503 func (s *DecimalLogicalSchema) Scale() int { 1504 return s.scale 1505 } 1506 1507 // String returns the canonical form of the logical schema. 1508 func (s *DecimalLogicalSchema) String() string { 1509 var scale string 1510 if s.scale > 0 { 1511 scale = `,"scale":` + strconv.Itoa(s.scale) 1512 } 1513 precision := strconv.Itoa(s.prec) 1514 1515 return `"logicalType":"` + string(Decimal) + `","precision":` + precision + scale 1516 } 1517 1518 func invalidNameFirstChar(r rune) bool { 1519 return (r < 'A' || r > 'Z') && (r < 'a' || r > 'z') && r != '_' 1520 } 1521 1522 func invalidNameOtherChar(r rune) bool { 1523 return invalidNameFirstChar(r) && (r < '0' || r > '9') 1524 } 1525 1526 func validateName(name string) error { 1527 if name == "" { 1528 return errors.New("name must be a non-empty") 1529 } 1530 1531 if strings.IndexFunc(name[:1], invalidNameFirstChar) > -1 { 1532 return fmt.Errorf("invalid name %s", name) 1533 } 1534 if strings.IndexFunc(name[1:], invalidNameOtherChar) > -1 { 1535 return fmt.Errorf("invalid name %s", name) 1536 } 1537 1538 return nil 1539 } 1540 1541 func validateDefault(name string, schema Schema, def any) (any, error) { 1542 def, ok := isValidDefault(schema, def) 1543 if !ok { 1544 return nil, fmt.Errorf("avro: invalid default for field %s. %+v not a %s", name, def, schema.Type()) 1545 } 1546 return def, nil 1547 } 1548 1549 func isValidDefault(schema Schema, def any) (any, bool) { 1550 switch schema.Type() { 1551 case Ref: 1552 ref := schema.(*RefSchema) 1553 return isValidDefault(ref.Schema(), def) 1554 case Null: 1555 return nullDefault, def == nil 1556 case Enum: 1557 v, ok := def.(string) 1558 if !ok || len(v) == 0 { 1559 return def, false 1560 } 1561 1562 var found bool 1563 for _, sym := range schema.(*EnumSchema).symbols { 1564 if def == sym { 1565 found = true 1566 break 1567 } 1568 } 1569 return def, found 1570 case String: 1571 if _, ok := def.(string); ok { 1572 return def, true 1573 } 1574 case Bytes, Fixed: 1575 // Spec: Default values for bytes and fixed fields are JSON strings, 1576 // where Unicode code points 0-255 are mapped to unsigned 8-bit byte values 0-255. 1577 if d, ok := def.(string); ok { 1578 if b, ok := isValidDefaultBytes(d); ok { 1579 if schema.Type() == Fixed { 1580 return byteSliceToArray(b, schema.(*FixedSchema).Size()), true 1581 } 1582 return b, true 1583 } 1584 } 1585 case Boolean: 1586 if _, ok := def.(bool); ok { 1587 return def, true 1588 } 1589 case Int: 1590 if i, ok := def.(int8); ok { 1591 return int(i), true 1592 } 1593 if i, ok := def.(int16); ok { 1594 return int(i), true 1595 } 1596 if i, ok := def.(int32); ok { 1597 return int(i), true 1598 } 1599 if _, ok := def.(int); ok { 1600 return def, true 1601 } 1602 if f, ok := def.(float64); ok { 1603 return int(f), true 1604 } 1605 case Long: 1606 if _, ok := def.(int64); ok { 1607 return def, true 1608 } 1609 if f, ok := def.(float64); ok { 1610 return int64(f), true 1611 } 1612 case Float: 1613 if _, ok := def.(float32); ok { 1614 return def, true 1615 } 1616 if f, ok := def.(float64); ok { 1617 return float32(f), true 1618 } 1619 case Double: 1620 if _, ok := def.(float64); ok { 1621 return def, true 1622 } 1623 case Array: 1624 arr, ok := def.([]any) 1625 if !ok { 1626 return nil, false 1627 } 1628 1629 as := schema.(*ArraySchema) 1630 for i, v := range arr { 1631 v, ok := isValidDefault(as.Items(), v) 1632 if !ok { 1633 return nil, false 1634 } 1635 arr[i] = v 1636 } 1637 return arr, true 1638 case Map: 1639 m, ok := def.(map[string]any) 1640 if !ok { 1641 return nil, false 1642 } 1643 1644 ms := schema.(*MapSchema) 1645 for k, v := range m { 1646 v, ok := isValidDefault(ms.Values(), v) 1647 if !ok { 1648 return nil, false 1649 } 1650 1651 m[k] = v 1652 } 1653 return m, true 1654 case Union: 1655 unionSchema := schema.(*UnionSchema) 1656 return isValidDefault(unionSchema.Types()[0], def) 1657 case Record: 1658 m, ok := def.(map[string]any) 1659 if !ok { 1660 return nil, false 1661 } 1662 1663 for _, field := range schema.(*RecordSchema).Fields() { 1664 fieldDef := field.Default() 1665 if newDef, ok := m[field.Name()]; ok { 1666 fieldDef = newDef 1667 } 1668 1669 v, ok := isValidDefault(field.Type(), fieldDef) 1670 if !ok { 1671 return nil, false 1672 } 1673 1674 m[field.Name()] = v 1675 } 1676 return m, true 1677 } 1678 return nil, false 1679 } 1680 1681 func schemaTypeName(schema Schema) string { 1682 if schema.Type() == Ref { 1683 schema = schema.(*RefSchema).Schema() 1684 } 1685 1686 if n, ok := schema.(NamedSchema); ok { 1687 return n.FullName() 1688 } 1689 1690 sname := string(schema.Type()) 1691 if lt := getLogicalType(schema); lt != "" { 1692 sname += "." + string(lt) 1693 } 1694 return sname 1695 } 1696 1697 func isValidDefaultBytes(def string) ([]byte, bool) { 1698 runes := []rune(def) 1699 l := len(runes) 1700 b := make([]byte, l) 1701 for i := 0; i < l; i++ { 1702 if runes[i] < 0 || runes[i] > 255 { 1703 return nil, false 1704 } 1705 b[i] = byte(runes[i]) 1706 } 1707 return b, true 1708 }