Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add modifier for nested type codec constructor #228

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion codec.go
Expand Up @@ -42,6 +42,8 @@ var (
MaxBlockSize = int64(math.MaxInt32)
)

type CodecModifier func(map[string]*Codec)

// Codec supports decoding binary and text Avro data to Go native data types,
// and conversely encoding Go native data types to binary or text Avro data. A
// Codec is created as a stateless structure that can be safely used in multiple
Expand Down Expand Up @@ -86,7 +88,7 @@ type Codec struct {
// if err != nil {
// fmt.Println(err)
// }
func NewCodec(schemaSpecification string) (*Codec, error) {
func NewCodec(schemaSpecification string, modifiers ...CodecModifier) (*Codec, error) {
var schema interface{}

if err := json.Unmarshal([]byte(schemaSpecification), &schema); err != nil {
Expand All @@ -96,6 +98,10 @@ func NewCodec(schemaSpecification string) (*Codec, error) {
// bootstrap a symbol table with primitive type codecs for the new codec
st := newSymbolTable()

for _, modifier := range modifiers {
modifier(st)
}

c, err := buildCodec(st, nullNamespace, schema)
if err != nil {
return nil, err
Expand Down
76 changes: 76 additions & 0 deletions record_test.go
Expand Up @@ -445,6 +445,82 @@ func TestRecordRecursiveRoundTrip(t *testing.T) {
}
}

func TestUnknownTypeCodecError(t *testing.T) {
_, err := NewCodec(`
{
"type": "record",
"name": "Parent",
"fields" : [
{"name": "child", "type": "Child"}
]
}
`)
ensureError(t, err, "Record \"Parent\" field 1 ought to be valid Avro named type: unknown type name: \"Child\"")
}

func TestCodecModifier(t *testing.T) {
childCodec, err := NewCodec(`
{
"type": "record",
"name": "Child",
"fields" : [
{"name": "age", "type": "int"}
]
}
`)
ensureError(t, err)

modifier := func(st map[string]*Codec) {
st["Child"] = childCodec
}

codec, err := NewCodec(`
{
"type": "record",
"name": "Parent",
"fields" : [
{"name": "child", "type": "Child"}
]
}
`, modifier)
ensureError(t, err)

child := map[string]interface{} {
"age": 7,
}
parent := map[string]interface{} {
"child": child,
}

// Convert native Go form to binary Avro data
buf, err := codec.BinaryFromNative(nil, parent)
ensureError(t, err)

// Convert binary Avro data back to native Go form
datum, _, err := codec.NativeFromBinary(buf)
ensureError(t, err)

actual, ok := datum.(map[string]interface{})
if !ok {
t.Fatalf("origin data contaminated")
}

child, ok = actual["child"].(map[string]interface{})
if !ok {
t.Fatalf("child type contaminated")
}

age, ok := child["age"].(int32)
if !ok {
t.Fatalf("child age field contaminated")
}

if age != 7 {
t.Fatalf("child age data contaminated")
}
}


func ExampleRecordRecursiveRoundTrip() {
codec, err := NewCodec(`
{
Expand Down