Repository: hamba/avro
Pull request #293 (2023-08-21 15:53:27)

fix: cache schema globally
This fixes an issue where generated schema encoders do not cache the schema globally.


Patch:
diff --git a/gen/gen.go b/gen/gen.go
index d942eba..7deb952 100644
--- a/gen/gen.go
+++ b/gen/gen.go
@@ -61,25 +61,22 @@ import (
 )
 {{ end }}
 
+
+
 {{- range .Typedefs }}
 // {{ .Name }} is a generated struct.
 type {{ .Name }} struct {
 	{{- range .Fields }}
 		{{ .Name }} {{ .Type }} {{ .Tag }}
 	{{- end }}
-{{- if $encoders }}
-
-    schema avro.Schema
-{{- end }}
 }
 
 {{- if $encoders }}
+var schema{{ .Name }} = avro.MustParse(` + "`{{ .Schema }}`" + `)
+
 // Schema returns the schema for {{ .Name }}.
 func (o *{{ .Name }}) Schema() avro.Schema {
-  if o.schema == nil {
-    o.schema = avro.MustParse(` + "`{{ .Schema }}`" + `)
-  }
-  return o.schema
+  return schema{{ .Name }}
 }
 
 // Unmarshal decodes b into the receiver.


Test patch:
diff --git a/cmd/avrogen/testdata/golden_encoders.go b/cmd/avrogen/testdata/golden_encoders.go
index c9b90de..d071865 100644
--- a/cmd/avrogen/testdata/golden_encoders.go
+++ b/cmd/avrogen/testdata/golden_encoders.go
@@ -9,16 +9,13 @@ import (
 // Test is a generated struct.
 type Test struct {
 	SomeString string `avro:"someString"`
-
-	schema avro.Schema
 }
 
+var schemaTest = avro.MustParse(`{"name":"a.b.test","type":"record","fields":[{"name":"someString","type":"string"}]}`)
+
 // Schema returns the schema for Test.
 func (o *Test) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.test","type":"record","fields":[{"name":"someString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaTest
 }
 
 // Unmarshal decodes b into the receiver.
diff --git a/gen/testdata/golden_encoders.go b/gen/testdata/golden_encoders.go
index 09e03f2..859bbc4 100644
--- a/gen/testdata/golden_encoders.go
+++ b/gen/testdata/golden_encoders.go
@@ -13,16 +13,13 @@ import (
 type InnerRecord struct {
 	InnerJustBytes                   []byte    `avro:"innerJustBytes"`
 	InnerPrimitiveNullableArrayUnion *[]string `avro:"innerPrimitiveNullableArrayUnion"`
-
-	schema avro.Schema
 }
 
+var schemaInnerRecord = avro.MustParse(`{"name":"a.c.InnerRecord","type":"record","fields":[{"name":"innerJustBytes","type":"bytes"},{"name":"innerPrimitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]}]}`)
+
 // Schema returns the schema for InnerRecord.
 func (o *InnerRecord) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.c.InnerRecord","type":"record","fields":[{"name":"innerJustBytes","type":"bytes"},{"name":"innerPrimitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]}]}`)
-	}
-	return o.schema
+	return schemaInnerRecord
 }
 
 // Unmarshal decodes b into the receiver.
@@ -38,16 +35,13 @@ func (o *InnerRecord) Marshal() ([]byte, error) {
 // RecordInMap is a generated struct.
 type RecordInMap struct {
 	Name string `avro:"name"`
-
-	schema avro.Schema
 }
 
+var schemaRecordInMap = avro.MustParse(`{"name":"a.b.RecordInMap","type":"record","fields":[{"name":"name","type":"string"}]}`)
+
 // Schema returns the schema for RecordInMap.
 func (o *RecordInMap) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.RecordInMap","type":"record","fields":[{"name":"name","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecordInMap
 }
 
 // Unmarshal decodes b into the receiver.
@@ -63,16 +57,13 @@ func (o *RecordInMap) Marshal() ([]byte, error) {
 // RecordInArray is a generated struct.
 type RecordInArray struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecordInArray = avro.MustParse(`{"name":"a.b.recordInArray","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for RecordInArray.
 func (o *RecordInArray) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.recordInArray","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecordInArray
 }
 
 // Unmarshal decodes b into the receiver.
@@ -88,16 +79,13 @@ func (o *RecordInArray) Marshal() ([]byte, error) {
 // RecordInNullableUnion is a generated struct.
 type RecordInNullableUnion struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecordInNullableUnion = avro.MustParse(`{"name":"a.b.recordInNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for RecordInNullableUnion.
 func (o *RecordInNullableUnion) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.recordInNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecordInNullableUnion
 }
 
 // Unmarshal decodes b into the receiver.
@@ -113,16 +101,13 @@ func (o *RecordInNullableUnion) Marshal() ([]byte, error) {
 // Record1InNonNullableUnion is a generated struct.
 type Record1InNonNullableUnion struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecord1InNonNullableUnion = avro.MustParse(`{"name":"a.b.record1InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for Record1InNonNullableUnion.
 func (o *Record1InNonNullableUnion) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.record1InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecord1InNonNullableUnion
 }
 
 // Unmarshal decodes b into the receiver.
@@ -138,16 +123,13 @@ func (o *Record1InNonNullableUnion) Marshal() ([]byte, error) {
 // Record2InNonNullableUnion is a generated struct.
 type Record2InNonNullableUnion struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecord2InNonNullableUnion = avro.MustParse(`{"name":"a.b.record2InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for Record2InNonNullableUnion.
 func (o *Record2InNonNullableUnion) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.record2InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecord2InNonNullableUnion
 }
 
 // Unmarshal decodes b into the receiver.
@@ -163,16 +145,13 @@ func (o *Record2InNonNullableUnion) Marshal() ([]byte, error) {
 // Record1InNullableUnion is a generated struct.
 type Record1InNullableUnion struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecord1InNullableUnion = avro.MustParse(`{"name":"a.b.record1InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for Record1InNullableUnion.
 func (o *Record1InNullableUnion) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.record1InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecord1InNullableUnion
 }
 
 // Unmarshal decodes b into the receiver.
@@ -188,16 +167,13 @@ func (o *Record1InNullableUnion) Marshal() ([]byte, error) {
 // Record2InNullableUnion is a generated struct.
 type Record2InNullableUnion struct {
 	AString string `avro:"aString"`
-
-	schema avro.Schema
 }
 
+var schemaRecord2InNullableUnion = avro.MustParse(`{"name":"a.b.record2InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
+
 // Schema returns the schema for Record2InNullableUnion.
 func (o *Record2InNullableUnion) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.record2InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}`)
-	}
-	return o.schema
+	return schemaRecord2InNullableUnion
 }
 
 // Unmarshal decodes b into the receiver.
@@ -238,16 +214,13 @@ type Test struct {
 	NonNullableRecordUnion          any                    `avro:"nonNullableRecordUnion"`
 	NullableRecordUnionWith3Options any                    `avro:"nullableRecordUnionWith3Options"`
 	Ref                             Record2InNullableUnion `avro:"ref"`
-
-	schema avro.Schema
 }
 
+var schemaTest = avro.MustParse(`{"name":"a.b.test","type":"record","fields":[{"name":"aString","type":"string"},{"name":"aBoolean","type":"boolean"},{"name":"anInt","type":"int"},{"name":"aFloat","type":"float"},{"name":"aDouble","type":"double"},{"name":"aLong","type":"long"},{"name":"justBytes","type":"bytes"},{"name":"primitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]},{"name":"innerRecord","type":{"name":"a.c.InnerRecord","type":"record","fields":[{"name":"innerJustBytes","type":"bytes"},{"name":"innerPrimitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]}]}},{"name":"anEnum","type":{"name":"a.b.Cards","type":"enum","symbols":["SPADES","HEARTS","DIAMONDS","CLUBS"]}},{"name":"aFixed","type":{"name":"a.b.fixedField","type":"fixed","size":7}},{"name":"aLogicalFixed","type":{"name":"a.b.logicalDuration","type":"fixed","size":12,"logicalType":"duration"}},{"name":"anotherLogicalFixed","type":{"name":"a.b.logicalDuration","type":"fixed","size":12,"logicalType":"duration"}},{"name":"mapOfStrings","type":{"type":"map","values":"string"}},{"name":"mapOfRecords","type":{"type":"map","values":{"name":"a.b.RecordInMap","type":"record","fields":[{"name":"name","type":"string"}]}}},{"name":"aDate","type":{"type":"int","logicalType":"date"}},{"name":"aDuration","type":{"type":"int","logicalType":"time-millis"}},{"name":"aLongTimeMicros","type":{"type":"long","logicalType":"time-micros"}},{"name":"aLongTimestampMillis","type":{"type":"long","logicalType":"timestamp-millis"}},{"name":"aLongTimestampMicro","type":{"type":"long","logicalType":"timestamp-micros"}},{"name":"aBytesDecimal","type":{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}},{"name":"aRecordArray","type":{"type":"array","items":{"name":"a.b.recordInArray","type":"record","fields":[{"name":"aString","type":"string"}]}}},{"name":"nullableRecordUnion","type":["null",{"name":"a.b.recordInNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"nonNullableRecordUnion","type":[{"name":"a.b.record1InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]},{"name":"a.b.record2InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"nullableRecordUnionWith3Options","type":["null",{"name":"a.b.record1InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]},{"name":"a.b.record2InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"ref","type":"a.b.record2InNullableUnion"}]}`)
+
 // Schema returns the schema for Test.
 func (o *Test) Schema() avro.Schema {
-	if o.schema == nil {
-		o.schema = avro.MustParse(`{"name":"a.b.test","type":"record","fields":[{"name":"aString","type":"string"},{"name":"aBoolean","type":"boolean"},{"name":"anInt","type":"int"},{"name":"aFloat","type":"float"},{"name":"aDouble","type":"double"},{"name":"aLong","type":"long"},{"name":"justBytes","type":"bytes"},{"name":"primitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]},{"name":"innerRecord","type":{"name":"a.c.InnerRecord","type":"record","fields":[{"name":"innerJustBytes","type":"bytes"},{"name":"innerPrimitiveNullableArrayUnion","type":["null",{"type":"array","items":"string"}]}]}},{"name":"anEnum","type":{"name":"a.b.Cards","type":"enum","symbols":["SPADES","HEARTS","DIAMONDS","CLUBS"]}},{"name":"aFixed","type":{"name":"a.b.fixedField","type":"fixed","size":7}},{"name":"aLogicalFixed","type":{"name":"a.b.logicalDuration","type":"fixed","size":12,"logicalType":"duration"}},{"name":"anotherLogicalFixed","type":{"name":"a.b.logicalDuration","type":"fixed","size":12,"logicalType":"duration"}},{"name":"mapOfStrings","type":{"type":"map","values":"string"}},{"name":"mapOfRecords","type":{"type":"map","values":{"name":"a.b.RecordInMap","type":"record","fields":[{"name":"name","type":"string"}]}}},{"name":"aDate","type":{"type":"int","logicalType":"date"}},{"name":"aDuration","type":{"type":"int","logicalType":"time-millis"}},{"name":"aLongTimeMicros","type":{"type":"long","logicalType":"time-micros"}},{"name":"aLongTimestampMillis","type":{"type":"long","logicalType":"timestamp-millis"}},{"name":"aLongTimestampMicro","type":{"type":"long","logicalType":"timestamp-micros"}},{"name":"aBytesDecimal","type":{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}},{"name":"aRecordArray","type":{"type":"array","items":{"name":"a.b.recordInArray","type":"record","fields":[{"name":"aString","type":"string"}]}}},{"name":"nullableRecordUnion","type":["null",{"name":"a.b.recordInNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"nonNullableRecordUnion","type":[{"name":"a.b.record1InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]},{"name":"a.b.record2InNonNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"nullableRecordUnionWith3Options","type":["null",{"name":"a.b.record1InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]},{"name":"a.b.record2InNullableUnion","type":"record","fields":[{"name":"aString","type":"string"}]}]},{"name":"ref","type":"a.b.record2InNullableUnion"}]}`)
-	}
-	return o.schema
+	return schemaTest
 }
 
 // Unmarshal decodes b into the receiver.