{"id":51415169,"url":"https://github.com/coregx/opt","last_synced_at":"2026-07-04T19:00:28.167Z","repository":{"id":369314344,"uuid":"1289318942","full_name":"coregx/opt","owner":"coregx","description":"Optional types for Go — generic-first SQL+JSON nullable types with three-state PATCH support","archived":false,"fork":false,"pushed_at":"2026-07-04T15:54:40.000Z","size":35,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T17:14:07.569Z","etag":null,"topics":["database","generics","go","golang","json","nullable","optional","patch-api","sql"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coregx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-04T15:42:51.000Z","updated_at":"2026-07-04T15:54:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/coregx/opt","commit_stats":null,"previous_names":["coregx/opt"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/coregx/opt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coregx%2Fopt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coregx%2Fopt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coregx%2Fopt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coregx%2Fopt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coregx","download_url":"https://codeload.github.com/coregx/opt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coregx%2Fopt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35132289,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","generics","go","golang","json","nullable","optional","patch-api","sql"],"created_at":"2026-07-04T19:00:18.333Z","updated_at":"2026-07-04T19:00:28.151Z","avatar_url":"https://github.com/coregx.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eopt\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eOptional types for Go — a Go-idiomatic Option\u0026lt;T\u0026gt;\u003c/strong\u003e\u003cbr\u003e\n  Full SQL + JSON integration. Three-state PATCH support. Zero dependencies beyond stdlib.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/coregx/opt/actions\"\u003e\u003cimg src=\"https://github.com/coregx/opt/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/coregx/opt\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/coregx/opt.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/coregx/opt\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/coregx/opt\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/coregx/opt/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/coregx/opt\"\u003e\u003cimg src=\"https://img.shields.io/badge/Go-1.24+-00ADD8\" alt=\"Go 1.24+\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Why opt?\n\nGo's `sql.Null[T]` handles SQL but [will never get JSON support](https://github.com/golang/go/issues/68375) (closed as infeasible). Pointers (`*string`) work but have overhead and awkward ergonomics. `opt` fills this gap permanently.\n\n```go\ntype User struct {\n    Name  opt.String `json:\"name\"`\n    Email opt.String `json:\"email,omitzero\"`\n    Age   opt.Int    `json:\"age\"`\n}\n// {\"name\":\"Alice\",\"age\":null}  — Email omitted (omitzero), Age is explicit null\n```\n\n## Features\n\n- **Generic foundation** — `Value[T]` works with any type via `sql.Null[T]`\n- **9 concrete types** — String, Int, Int32, Int16, Float, Bool, Byte, Time\n- **Three-state `Field[T]`** — distinguish absent / null / value for PATCH APIs\n- **Functional API** — `Map`, `FlatMap`, `Equal` for composable transformations\n- **Zero dependencies** — only Go stdlib (`database/sql`, `encoding/json`)\n- **SQL-ready** — `Scanner`/`Valuer` via `sql.Null[T]`, works with pgx, database/sql\n- **JSON-ready** — proper null marshaling, `omitzero` support (Go 1.24+)\n- **json/v2 compatible** — works with `encoding/json/v2` without changes\n- **`zero/` subpackage** — alternative semantics where zero value = null\n- **Benchmarked** — zero-allocation unmarshal, Bool marshal in \u003c1ns\n\n## Installation\n\n```bash\ngo get github.com/coregx/opt\n```\n\n**Requires Go 1.24+**\n\n## Quick Start\n\n```go\npackage main\n\nimport (\n    \"encoding/json\"\n    \"fmt\"\n\n    \"github.com/coregx/opt\"\n)\n\nfunc main() {\n    // Create optional values\n    name := opt.StringFrom(\"Alice\")\n    age := opt.NewInt(0, false) // null\n\n    // Safe access with fallbacks\n    fmt.Println(name.Or(\"unknown\")) // \"Alice\"\n    fmt.Println(age.Or(18))         // 18\n\n    // JSON marshaling — just works\n    type User struct {\n        Name opt.String `json:\"name\"`\n        Age  opt.Int    `json:\"age\"`\n    }\n    data, _ := json.Marshal(User{Name: name, Age: age})\n    fmt.Println(string(data)) // {\"name\":\"Alice\",\"age\":null}\n}\n```\n\n## API\n\n### Constructors\n\n```go\nopt.From(value)          // Always valid: opt.From(\"hello\"), opt.From(42)\nopt.New(value, valid)    // Explicit: opt.New(\"\", false) → null\nopt.FromPtr(ptr)         // From pointer: nil → null, \u0026v → valid\nopt.OrNull(value)        // Zero value → null: opt.OrNull(\"\") → null, opt.OrNull(42) → valid\n\n// Type-specific shortcuts\nopt.StringFrom(\"hello\")      opt.StringOrNull(\"\")     // \"\" → null\nopt.IntFrom(42)              opt.IntOrNull(0)         // 0 → null\nopt.FloatFrom(3.14)          opt.FloatOrNull(0.0)     // 0 → null\nopt.BoolFrom(true)           opt.BoolOrNull(false)    // false → null\nopt.TimeFrom(t)              opt.TimeOrNull(t)        // zero time → null\nopt.ByteFrom(0x42)           opt.ByteOrNull(0)        // 0 → null\n```\n\n`From` = value is always valid. `OrNull` = zero value means \"not set\" → null. Choose based on your semantics.\n\n### Value Access\n\n```go\nv.Or(fallback)           // Value or fallback\nv.OrZero()               // Value or zero value of T\nv.OrElse(func() T)       // Value or lazy-computed fallback\nv.Ptr()                  // *T or nil\nv.IsZero()               // true when null (for omitzero)\n```\n\n### Functional\n\n```go\nopt.Map(v, func(T) U) Value[U]              // Transform if valid\nopt.FlatMap(v, func(T) Value[U]) Value[U]    // Chain optional operations\nopt.Equal(a, b)                               // Nil-safe comparison\n```\n\n### Three-State Field (PATCH API)\n\n```go\ntype PatchUser struct {\n    Name  opt.Field[string] `json:\"name,omitzero\"`\n    Email opt.Field[string] `json:\"email,omitzero\"`\n}\n\n// {}                    → Name.IsAbsent()=true  — don't touch\n// {\"name\": null}        → Name.IsNull()=true    — set to NULL\n// {\"name\": \"Alice\"}     → Name.IsValue()=true   — set to \"Alice\"\n```\n\n### Zero Subpackage\n\n```go\nimport \"github.com/coregx/opt/zero\"\n\ns := zero.StringFrom(\"\")   // Invalid — empty string = null\ni := zero.IntFrom(0)       // Invalid — zero = null\ndata, _ := json.Marshal(i) // \"0\" (not \"null\")\n```\n\n| Behavior | `opt` | `opt/zero` |\n|----------|-------|-----------|\n| `From(\"\")` | Valid (empty string) | Invalid (empty = null) |\n| `From(0)` | Valid (zero int) | Invalid (zero = null) |\n| Marshal null | `null` | `\"\"` / `0` / `false` |\n\n## SQL Usage\n\n```go\n// Works with database/sql\nvar user struct {\n    Name opt.String\n    Age  opt.Int\n}\ndb.QueryRow(\"SELECT name, age FROM users WHERE id=$1\", id).Scan(\u0026user.Name, \u0026user.Age)\n\n// Also works with pgx, sqlx, and other drivers\n```\n\n## Comparison with Alternatives\n\n| Feature | opt | guregu/null | `*T` (pointer) | `sql.Null[T]` |\n|---------|-----|-----------|----------------|---------------|\n| Generic `Value[T]` | **Full** | Partial (MarshalText commented out) | N/A | No JSON |\n| Three-state (PATCH) | **`Field[T]`** | No | No | No |\n| Map / FlatMap | **Yes** | No | No | No |\n| OrElse (lazy) | **Yes** | No | No | No |\n| JSON marshal | **Yes** | Yes | Yes | Broken (`{\"V\":...,\"Valid\":...}`) |\n| SQL Scanner/Valuer | **Yes** | Yes | Yes | Yes |\n| omitzero | **Yes** | Yes | No | No |\n| Zero-is-null variant | **`zero/`** | `zero/` | No | No |\n| json/v2 compatible | **Yes** | Yes | Yes | No |\n| Legacy code | **None** | v1→v6 | N/A | N/A |\n\n## Benchmarks\n\n```\nBenchmarkBoolMarshalJSON     0.85 ns/op    0 allocs\nBenchmarkBoolUnmarshalJSON   2.1 ns/op     0 allocs\nBenchmarkIntMarshalJSON      48 ns/op      2 allocs\nBenchmarkIntUnmarshalJSON    193 ns/op     1 alloc\nBenchmarkStringUnmarshalJSON 137 ns/op     0 allocs\nBenchmarkStructMarshalJSON   876 ns/op     9 allocs\nBenchmarkStructUnmarshalJSON 1116 ns/op    2 allocs\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoregx%2Fopt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoregx%2Fopt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoregx%2Fopt/lists"}