@@ -137,3 +137,93 @@ func ExampleReader_NetworksWithin() {
137
137
// 1.0.64.0/18: Cable/DSL
138
138
// 1.0.128.0/17: Cable/DSL
139
139
}
140
+
141
+ // CustomCity represents a simplified city record with custom unmarshaling.
142
+ // This demonstrates the Unmarshaler interface for high-performance decoding.
143
+ type CustomCity struct {
144
+ Names map [string ]string
145
+ GeoNameID uint
146
+ }
147
+
148
+ // UnmarshalMaxMindDB implements the maxminddb.Unmarshaler interface.
149
+ // This provides significant performance improvements over reflection-based decoding
150
+ // by allowing custom, optimized decoding logic for performance-critical applications.
151
+ func (c * CustomCity ) UnmarshalMaxMindDB (d * maxminddb.Decoder ) error {
152
+ for key , err := range d .DecodeMap () {
153
+ if err != nil {
154
+ return err
155
+ }
156
+
157
+ switch string (key ) {
158
+ case "city" :
159
+ // Decode nested city structure
160
+ for cityKey , cityErr := range d .DecodeMap () {
161
+ if cityErr != nil {
162
+ return cityErr
163
+ }
164
+ switch string (cityKey ) {
165
+ case "names" :
166
+ // Decode nested map[string]string for localized names
167
+ names := make (map [string ]string )
168
+ for nameKey , nameErr := range d .DecodeMap () {
169
+ if nameErr != nil {
170
+ return nameErr
171
+ }
172
+ value , valueErr := d .DecodeString ()
173
+ if valueErr != nil {
174
+ return valueErr
175
+ }
176
+ names [string (nameKey )] = value
177
+ }
178
+ c .Names = names
179
+ case "geoname_id" :
180
+ geoID , err := d .DecodeUInt32 ()
181
+ if err != nil {
182
+ return err
183
+ }
184
+ c .GeoNameID = uint (geoID )
185
+ default :
186
+ if err := d .SkipValue (); err != nil {
187
+ return err
188
+ }
189
+ }
190
+ }
191
+ default :
192
+ // Skip unknown fields to ensure forward compatibility
193
+ if err := d .SkipValue (); err != nil {
194
+ return err
195
+ }
196
+ }
197
+ }
198
+ return nil
199
+ }
200
+
201
+ // This example demonstrates how to use the Unmarshaler interface for high-performance
202
+ // custom decoding. Types implementing Unmarshaler automatically use custom decoding
203
+ // logic instead of reflection, providing better performance for critical applications.
204
+ func ExampleUnmarshaler () {
205
+ db , err := maxminddb .Open ("test-data/test-data/GeoIP2-City-Test.mmdb" )
206
+ if err != nil {
207
+ log .Fatal (err )
208
+ }
209
+ defer db .Close () //nolint:errcheck // error doesn't matter
210
+
211
+ addr := netip .MustParseAddr ("81.2.69.142" )
212
+
213
+ // CustomCity implements Unmarshaler, so it will automatically use
214
+ // the custom UnmarshalMaxMindDB method instead of reflection
215
+ var city CustomCity
216
+ err = db .Lookup (addr ).Decode (& city )
217
+ if err != nil {
218
+ log .Panic (err )
219
+ }
220
+
221
+ fmt .Printf ("City ID: %d\n " , city .GeoNameID )
222
+ fmt .Printf ("English name: %s\n " , city .Names ["en" ])
223
+ fmt .Printf ("German name: %s\n " , city .Names ["de" ])
224
+
225
+ // Output:
226
+ // City ID: 2643743
227
+ // English name: London
228
+ // German name: London
229
+ }
0 commit comments