maxminddb-gen generates reflection-free decoder methods for types owned by
the package where generation runs. It is part of the
maxminddb-golang module and uses the same version as the decoder support API.
Generation is optional: a type with neither generated nor handwritten custom
unmarshaling methods continues to use the reflection decoder.
Pin maxminddb-golang and declare its generator as a module tool:
require github.com/oschwald/maxminddb-golang/v2 v2.5.0
tool github.com/oschwald/maxminddb-golang/v2/maxminddb-genAdd a directive to a non-generated file in the package that declares the target types:
//go:generate go tool maxminddb-gen $GOFILEThe command generates methods for every exported, named struct declared in each
input file. Unexported structs, aliases, and non-struct types are skipped.
Generated targets receive both UnmarshalMaxMindDBCursor and, throughout v2,
the deprecated UnmarshalMaxMindDB compatibility bridge. A handwritten
implementation of either callback causes that target to be skipped with a
diagnostic; new handwritten decoders should implement
mmdbdata.CursorUnmarshaler. Generation fails when no eligible exported
structs remain, avoiding a successful header-only output.
The default output name is derived from the source
filename: a directive in models.go writes models_maxminddb.go. Recognized
build suffixes remain at the end, so models_linux.go writes
models_maxminddb_linux.go. Source build constraints are reproduced in the
generated file. Generation loads the package using the current GOOS, GOARCH,
and build tags, so every constrained input must be selected by that environment.
Use -output to override the default. Multiple input files may be passed when
-output is set; their explicit and filename constraints are combined with
&& on the shared output.
The generator ignores prior maxminddb-gen files while analyzing the package,
so multiple per-file directives produce the same output regardless of their
execution order or which generated files already exist. When changing an output
path, remove the superseded generated file after verifying the new output;
keeping both files will define duplicate methods.
To exclude an exported struct that is not an MMDB model, name it in a source directive:
//maxminddb:ignore ServerConfig InternalRecordUnknown names are rejected so that stale or misspelled exclusions do not pass silently.
Then generate and verify the checked-in output:
go generate ./...
git diff --exit-code
go test ./...The command writes formatted output atomically. Its output contains no
timestamps or local paths, and rerunning it fully replaces stale declarations.
It refuses to overwrite a file that does not have its generated-file header.
go tool maxminddb-gen -version reports the version of the containing module, or
devel for an unversioned local build.
The initial generator supports:
- structs with exported, non-embedded fields and
maxminddbtags bool,string,[]byte,float32, andfloat64- signed and unsigned integer destinations up to 64 bits (excluding
uintptr), with overflow checks - named types whose underlying type is a supported scalar
- pointers recursively composed from any supported type
- slices of supported values
- maps with string or named-string keys and supported values
- nested package-owned structs
- nested types that implement
mmdbdata.CursorUnmarshaler; the deprecatedmmdbdata.Unmarshalerremains supported throughout v2, and cursor unmarshaling takes precedence when both are present
Named-string map keys may also implement either custom unmarshaling interface. Their callback receives the original MMDB key, and cursor unmarshaling takes precedence when both interfaces are implemented.
Non-embedded fields tagged maxminddb:"-" are ignored. Fields without a tag,
or with an explicit empty tag, use their Go field name, matching reflection
decoding.
The generator rejects embedded fields, including those tagged maxminddb:"-",
generic structs, recursive type graphs, interfaces, unsupported map keys,
arrays, complex numbers, channels, functions, unsafe pointers, struct types
owned by another package without a custom unmarshaler, and unsupported target
fields. Diagnostics include the source position and field name.
Generated slice decoding matches reflection reuse behavior: it reuses adequate
capacity, clears visible elements before decoding, and clears a hidden tail
that could otherwise retain references. Existing maps and pointers are reused
when possible, and absent struct fields remain unchanged. Reused maps are not
cleared, so keys absent from the newly decoded map retain their previous values.
The exception is an exact []byte decoded from the MMDB Bytes kind: generated
code may reuse and mutate an adequately sized destination backing array,
whereas reflection decoding allocates a replacement slice. If another value
must retain the old contents, copy its contents into a newly allocated slice
(for example, preserved := append([]byte(nil), value...)) or detach the decode
destination from the shared backing array (for example, assign the destination
nil) before decoding. Clearing or reslicing the destination does not detach
its backing array and does not protect aliases.
Generation must run in the package that owns the target type. The command does
not add methods to types from another package and does not replace handwritten
UnmarshalMaxMindDBCursor methods. It also leaves deprecated handwritten
UnmarshalMaxMindDB methods in place for v2 compatibility.