guregu / null

reasonable handling of nullable values
BSD 2-Clause "Simplified" License
1.81k stars 238 forks source link

Not to use sql.Null*** for storing value? #62

Open ypresto opened 3 years ago

ypresto commented 3 years ago

Each struct of this library uses sql package (persistence or infrastructure layer), while it can be used for JSON marshaling (presentation layer). It seems to be against some software architecture patterns based on layered architecture or etc.

guregu commented 3 years ago

You can use JSON for persistence too. One of the original reasons I made this was to store the same data in SQL and MongoDB, which uses JSON. The types in this package also implement TextMarshaler which can be used for various storage packages. Whether not you use the same structs for persistence and presentation is up to you. I don't prescribe any particular development philosophy here. I embedded the sql.NullXYZ structs in the types here so it can be a drop-in replacement for them. This also means I don't have to re-implement their Scan methods, and we can benefit from any standard library improvements in new Go versions. It also serves to limit the scope of this library, instead of supporting every imaginable nullable type, we limit support to database/sql/driver.Value's types. Personally I think the zero packages types are the most useful part of the this package, because you can decode Go-friendly JSON data straight into nullable SQL types without having to manually convert them all yourself. For example, you could use it to store data from a JSON file in an SQL database. Because encoding/json's omitempty doesn't support non-pointer structs, this library is actually not great for presentation.

For greenfield development, I think it's best to eliminate nullable usage altogether and work with Go's zero values instead of against them. My original use-case was for interfacing with a legacy SQL database. You can also just use pointers.

I think eliminating the SQL dependency is completely fine if you want to focus on presentation, but until encoding/json is improved, pointers will likely be the better choice. Feel free to fork and experiment.

Also, when generics come with Go 2.0, I might experiment with generic nullable types and remove the embedded SQL stuff (or maybe make a new package). Until then, this project's API is unlikely to change.