Helps you convert every SQL nullable data types into Golang's supported types. So you don't have to create your own scanner and valuer only for.. let's say... BIGINT UNSIGNED NULL
Nullable handles all SQL<->Go data type conversion burden just for you :)
- 100% GORM support
- Can be marshalled into JSON
- Can be unmarshal from JSON
- Convenient Set/Get operation
- Support MySQL, MariaDB, SQLite, and PostgreSQL
- Zero configuration, just use it as normal data type.
- Heavily tested! So you don't have to worry of many bugs :D
- bool
- byte
- string
- time.Time (capable of handling
DATETIME
,TIME
,DATE
, andTIMESTAMP
) - []byte
- float32
- float64
- int
- int8
- int16
- int32
- int64
- uint
- uint8
- uint16
- uint32
- uint64
WARNING: PostgreSQL won't support any form of unsigned integers. However, you still able to use any uint variants with a drawback: they will be stored in form of raw binary instead of normal integer. Thus, PostgreSQL-side uint comparation is impossible, you have to compare them in your Go application. MySQL, MariaDB, and SQLite won't affected by this issue, don't worry.
Very easy! first of all, let's install like normal Go packages
go get github.com/Thor-x86/nullable
Remember, all you need to have is a basic variable and a nullable variable created with nullable.New...(&yourBasicVar)
. Example:
import (
"fmt"
"gorm.io/gorm"
"github.com/Thor-x86/nullable"
)
func main() {
// Create new
myBasicString := "Hello blяoW!"
myNullableString := nullable.NewString(&myBasicString)
// Create new but already nil
myAlreadyNullString := nullable.NewString(nil)
// Get and print to command console
fmt.Println(myNullableString.Get()) // Output: Hello blяoW!
fmt.Println(myAlreadyNullString.Get()) // Output: nil
}
You'll use .Set(&anotherBasicVar)
to change existing variable. Example:
import (
"fmt"
"gorm.io/gorm"
"github.com/Thor-x86/nullable"
)
func main() {
// Create new
myBasicString := "Hello blяoW!"
myNullableString := nullable.NewString(&myBasicString)
fmt.Println(myNullableString.Get()) // Output: Hello blяoW!
// Change existing variable
anotherString := "Hello World!"
myNullableString.Set(&anotherString)
fmt.Println(myNullableString.Get()) // Output: Hello World!
// Change with nil
myNullableString.Set(nil)
fmt.Println(myNullableString.Get()) // Output: nil
}
Also another example for uint64:
import (
"fmt"
"gorm.io/gorm"
"github.com/Thor-x86/nullable"
)
func main() {
// Create new
var theNumber uint64 = 70
nullableNumber := nullable.NewUint64(&theNumber)
fmt.Println(nullableNumber.Get()) // Output: 70
// Change to another number
var anotherNumber uint64 = 3306
nullableNumber.Set(&anotherNumber)
fmt.Println(nullableNumber.Get()) // Output: 3306
// Change to nil
nullableNumber.Set(nil)
fmt.Println(nullableNumber.Get()) // Output: nil
}
If you thinking it's not really convenient to create a basic variable first, then you can use .Scan(...)
instead of .Set(&yourBasicVar)
. Example:
import (
"fmt"
"gorm.io/gorm"
"github.com/Thor-x86/nullable"
)
func main() {
// Create new
nullableString := nullable.NewString(nil)
// Directly write string
nullableString.Scan("Hello blяoW!")
fmt.Println(nullableString.Get()) // Output: Hello blяoW!
// Change existing string
nullableString.Scan("Hello World!")
fmt.Println(nullableString.Get()) // Output: Hello World!
// Scan also works with nil
nullableString.Scan(nil)
fmt.Println(nullableString.Get()) // Output: nil
}
WARNING: Mostly .Scan(...)
won't cause compile-time error when you did something wrong, please be careful.
Feel free to clone, fork, pull request, and open a new issue on this repository. However, you must test your work before asking for pull request. Here's how to execute the test:
- For Windows users, install WSL first. MacOS and Linux users can skip to the next step.
- Open your bash terminal. Then install Docker and Docker Compose.
- Make sure your bash terminal is currently pointing nullable project directory.
- Run this to start the databases:
docker-compose up
- Wait for a minute, just to make sure all databases are ready.
- Run this to start the testing process:
./test_all.sh
- If everything OK, you're good to pull request. Otherwise, check what's the root of problem.
Q: If everything set with pointer, will it causes memory leak or something?
A: No, it won't store the pointer but the real value itself. Much like sql.NullString
but every nil checking already done at nullable package.
Q: Why Scan is unsafe?
A: The Scan
method actually meant to be implemented for Golang's SQL package to read query response from SQL server. However, you're allowed to use that as you like within risk of runtime error if you did something wrong.
Q: Will you add Microsoft SQL (MsSQL) Server support?
A: MsSQL throws me a lot of error while developing this project. I don't have much that time to tame MsSQL. Anyway, feel free to pull request. I already added the test configuration at test_all.sh
, main_test.go
, and .github/workflows/tests.yml
. Just uncomment them and run the test as usual.
Q: How about key-value server support like Redis, Cassandra, and Memcached? A: First of all, another ORM need to be implemented like redis-orm. The challenge is we need to make sure it won't conflict with GORM. Pull request always welcome :)
Q: Is this support NoSQL like MongoDB? A: If it JSON-marshallable, then the answer is yes. Nullable can be unmarshalled from JSON.
Q: I found security issue, can I open issue for this? A: Please don't. You risking another users' security. Email me instead at [email protected]
Q: This FAQ section didn't answer my problem. A: Feel free to find issue regarding the problem. If you found nothing, you are allowed to open a new issue.