Open 0xjac opened 3 weeks ago
This is an interesting concept. I wonder if any other Go lib has implemented this, to compare the proposed annotations against. I also wonder if the number of annotations could be reduced to just go-type
and go-type-pkg
but putting the import, name and pointer into go-type
, eg. @go-type("github.com/hamba/avro/*Schema")
?
I'm not aware of other libs doing type annotation for Avro. However I did not come up with it. I just took from the example for Java in the Avro specs, and adapted it for Go.
Regarding reducing the number of annotations, you can in most cases but it has some caveats which requires those extra ones for edge cases.
According to the Go spec, an import path can be any character. Thus it is a bit complicated to separate the import path from the rest without coming up with a mini markup language. I find it easier to have different annotations.
However a compiler "may also exclude the characters !"#$%&'()*,:;<=>?[\]^`{|}
and the Unicode replacement character U+FFFD". I'm not sure if that's what go is actually doing, but in practice I have never seen a third part package which was not a URL and for most cases, we can have a simple logic to split the import path, package, type and pointer from a @go-type
annotation, similar to SQLC.
This would look like: an optional *
to indicate a pointer, the full import path which must end with the package name, a .
, and the type, which looks like:
@go-type("*math/big.Int")
@go-type("github.com/hamba/avro/Schema")
@go-type("*github.com/hamba/avro/Schema")
This should work in most cases. However if for any reason, the package name is not the suffix of the import path, if we need to use an import alias (for example if we use data types from two "avro" libs) or any other weird edge case which may come up; we need to be able to specify everything (import path, pkg name, type, alias, ptr) explicitly.
The schema proposed for @go-type
seems quiet good. Personally I also ways prefer starting in a simple place and dealing with edge cases as they arise and are concrete. I think it is clear that a second annotation like @go-type-pkg
will be needed, and it is not uncommon for the package and import path to vary.
Somewhat similar to #429 but more flexible and with keeping type annotations within the Avro schema, it would be great to generate a Go struct with custom types using annotations.
Specifically: add the ability to support specific annotations (
go-type
,go-key-type
) similar to Java's but for go. The Go types would be expected to implementencoding.TextMarshaler
/encoding.TextUnmarshaler
(taking advantage of #68 and #327).Example
Schema
Which results in the following schema
```avsc { "type" : "record", "name" : "MyRecord", "fields" : [ { "name" : "value", "type" : { "type" : "string", "go-type" : "math/big.Float" } }, { "name" : "balances", "type" : { "type" : "map", "values" : { "type" : "string", "go-type" : "math/big.Float" }, "go-key-type" : "go.custom.com/ident.ID4" } }, { "name" : "values", "type" : { "type" : "array", "items" : { "type" : "string", "go-type" : "math/big.Float" } } }, { "name" : "totals", "type" : { "type" : "array", "items" : "string", "go-type" : "github.com/google/btree.BTreeG[int]" } } ] } ```Gen cmd
Actual Output
Desired Output
Notes
Potential pain points are:
go-type
annotation.For complex cases, extra annotations should be considered... SQLC which also allows go type override handles this decently. Taking inspiration from their doc, this would define:
go-type-import
: Import path of the package.go-type-pkg
: Package name if it doesn't match the import path.go-type-name
: The actual Go type namego-type-ptr
: Whether to use a pointer or the type directly.go-key-type-import
,go-key-type-pkg
,go-key-type-name
,go-key-type-ptr
annotations.goimports
.@go-type("github.com/google/btree.BTreeG[int]") array<string> totals;
) is a bit more tricky as it is overwriting the array type. Marshaling to and from that type is not supported as it is not a string type supportingencoding.TextMarshaler
/encoding.TextUnmarshaler
. Overriding array (and map!) types be ignored (potentially with a warning/error) until marshaling can be handled for array, map or even arbitrary types.