Skip to content

Repository files navigation

English | 简体中文

NullED

Null Value Encode/Decode

nulled is a Go library that provides nullable types for bool, float64, int64, string, and time.Time. It is built as a wrapper around the popular gopkg.in/guregu/null.v4 library, extending it with additional functionality and convenience methods.

This library is particularly useful for handling nullable values from databases, JSON/YAML APIs, or any other source where a value can be either present or null.

Features

  • Provides nullable Bool, Float, Int, String, and Time types.
  • Seamlessly handles JSON encoding and decoding (json.Marshaler, json.Unmarshaler).
  • Implements sql.Scanner and driver.Valuer for easy database integration.
  • Supports text encoding and decoding (encoding.TextUnmarshaler).
  • Supports Gob encoding and decoding (gob.GobEncoder, gob.GobDecoder).
  • Helper functions to create nullable types from values and pointers.
  • Methods to safely retrieve values or a zero-value if null (ValueOrZero).
  • EncodeValues method for encoding values into net/url.Values.
  • NullValue method to get the underlying gopkg.in/guregu/null.v4 type.

Installation

To install the nulled package, use go get:

go get github.com/hiscaler/nulled

Usage

Here are some examples of how to use the different nullable types provided by this library.

String

package main
import (
"encoding/json""fmt""github.com/hiscaler/nulled"
)
funcmain() {
// Valid strings1:=nulled.StringFrom("Hello, World!")
fmt.Printf("s1: Value=%q, Valid=%t\n", s1.ValueOrZero(), s1.Valid)
// Null string (from empty string)s2:=nulled.StringFrom("")
fmt.Printf("s2: Value=%q, Valid=%t\n", s2.ValueOrZero(), s2.Valid)
// JSON MarshallingjsonData, _:=json.Marshal(struct {
S1 nulled.StringS2 nulled.String
}{S1: s1, S2: s2})
fmt.Println("JSON:", string(jsonData)) // JSON: {"S1":"Hello, World!","S2":null}
}

Int

package main
import (
"encoding/json""fmt""github.com/hiscaler/nulled"
)
funcmain() {
// Valid inti1:=nulled.IntFrom(123)
fmt.Printf("i1: Value=%d, Valid=%t\n", i1.ValueOrZero(), i1.Valid)
// Null int (from pointer)varp*int64i2:=nulled.IntFromPtr(p)
fmt.Printf("i2: Value=%d, Valid=%t\n", i2.ValueOrZero(), i2.Valid)
// JSON MarshallingjsonData, _:=json.Marshal(struct {
I1 nulled.IntI2 nulled.Int
}{I1: i1, I2: i2})
fmt.Println("JSON:", string(jsonData)) // JSON: {"I1":123,"I2":null}
}

Float

package main
import (
"encoding/json""fmt""github.com/hiscaler/nulled"
)
funcmain() {
// Valid floatf1:=nulled.FloatFrom(123.45)
fmt.Printf("f1: Value=%f, Valid=%t\n", f1.ValueOrZero(), f1.Valid)
// Null floatf2:=nulled.NewFloat(0, false)
fmt.Printf("f2: Value=%f, Valid=%t\n", f2.ValueOrZero(), f2.Valid)
// JSON MarshallingjsonData, _:=json.Marshal(struct {
F1 nulled.FloatF2 nulled.Float
}{F1: f1, F2: f2})
fmt.Println("JSON:", string(jsonData)) // JSON: {"F1":123.45,"F2":null}
}

Bool

package main
import (
"encoding/json""fmt""github.com/hiscaler/nulled"
)
funcmain() {
// Valid boolb1:=nulled.BoolFrom(true)
fmt.Printf("b1: Value=%t, Valid=%t\n", b1.ValueOrZero(), b1.Valid)
// Null boolb2:=nulled.NewBool(false, false)
fmt.Printf("b2: Value=%t, Valid=%t\n", b2.ValueOrZero(), b2.Valid)
// JSON MarshallingjsonData, _:=json.Marshal(struct {
B1 nulled.BoolB2 nulled.Bool
}{B1: b1, B2: b2})
fmt.Println("JSON:", string(jsonData)) // JSON: {"B1":true,"B2":null}
}

Time

package main
import (
"encoding/json""fmt""github.com/hiscaler/nulled""time"
)
funcmain() {
// Valid timet1:=nulled.TimeFrom(time.Now())
fmt.Printf("t1: Value=%s, Valid=%t\n", t1.ValueOrZero(), t1.Valid)
// Null timevarp*time.Timet2:=nulled.TimeFromPtr(p)
fmt.Printf("t2: Value=%s, Valid=%t\n", t2.ValueOrZero(), t2.Valid)
// JSON MarshallingjsonData, _:=json.Marshal(struct {
T1 nulled.TimeT2 nulled.Time
}{T1: t1, T2: t2})
fmt.Println("JSON:", string(jsonData))
}

Database Integration

All nulled types implement the database/sql.Scanner and database/sql/driver.Valuer interfaces, making them compatible with database/sql out of the box.

Scanning a Null Value

When you scan a NULL value from a database, the nulled type will be marked as invalid (Valid: false).

varname nulled.Stringerr:=db.QueryRow("SELECT name FROM users WHERE id = 1").Scan(&name)
// If the 'name' column is NULL, name.Valid will be false.

Storing a Null Value

To store a NULL value in the database, you can use a nulled type that is not valid.

invalidName:=nulled.NewString("", false)
_, err:=db.Exec("UPDATE users SET name = ? WHERE id = 1", invalidName)
// This will set the 'name' column to NULL.

gopkg.in/guregu/null.v4 Compatibility

To maintain compatibility with the underlying gopkg.in/guregu/null.v4 library, each nulled type has a NullValue() method that returns the corresponding null.v4 type.

import"gopkg.in/guregu/null.v4"// Get the underlying null.v4 typenulledString:=nulled.StringFrom("hello")
nullV4String:=nulledString.NullValue() // This is a null.String// You can use it with functions that expect a null.v4 typefuncprocessNullV4(s null.String) {
// ...
}
processNullV4(nullV4String)

Integration with go-querystring/query

The nulled types can be seamlessly integrated with github.com/google/go-querystring/query to encode structs into URL query parameters. This is facilitated by the EncodeValues method implemented on each nulled type, which correctly handles valid and null values.

First, ensure you have go-querystring installed:

go get github.com/google/go-querystring/query

Here's an example:

package main
import (
"fmt""net/url""time""github.com/google/go-querystring/query""github.com/hiscaler/nulled"
)
typeMyQueryParamsstruct {
Name nulled.String`url:"name"`Age nulled.Int`url:"age"`Active nulled.Bool`url:"active"`Amount nulled.Float`url:"amount"`Created nulled.Time`url:"created"`Search nulled.String`url:"search,omitempty"`// omitempty will skip if null or empty
}
funcmain() {
params:=MyQueryParams{
Name: nulled.StringFrom("John Doe"),
Age: nulled.IntFrom(30),
Active: nulled.BoolFrom(true),
Amount: nulled.FloatFrom(123.45),
Created: nulled.TimeFrom(time.Date(2023, 1, 15, 10, 30, 0, 0, time.UTC)),
Search: nulled.StringFrom("Go Lang"),
}
v, _:=query.Values(params)
fmt.Println("Query with all valid values:", v.Encode())
// Output: Query with all valid values: active=true&age=30&amount=123.45&created=2023-01-15+10%3A30%3A00&name=John+Doe&search=Go+LangnullParams:=MyQueryParams{
Name: nulled.NewString("", false), // Null stringAge: nulled.NewInt(0, false), // Null intActive: nulled.NewBool(false, false), // Null boolAmount: nulled.NewFloat(0, false), // Null floatCreated: nulled.NewTime(time.Time{}, false), // Null timeSearch: nulled.NewString("", false), // Null string with omitempty
}
nv, _:=query.Values(nullParams)
fmt.Println("Query with null values:", nv.Encode())
// Output: Query with null values:
}

Contributing

Contributions are welcome! Please feel free to submit a pull request or open an issue.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Null value encode/decode

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages