{"id":48246465,"url":"https://github.com/tracewayapp/lit","last_synced_at":"2026-04-04T20:38:23.289Z","repository":{"id":330444806,"uuid":"1121434782","full_name":"tracewayapp/lit","owner":"tracewayapp","description":"A small library for mapping between queries and structs.","archived":false,"fork":false,"pushed_at":"2026-02-21T06:09:24.000Z","size":2492,"stargazers_count":5,"open_issues_count":2,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-21T09:28:27.726Z","etag":null,"topics":["database","golang","golang-orm","orm","orm-library"],"latest_commit_sha":null,"homepage":"https://lit.tracewayapp.com","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/tracewayapp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-23T01:55:13.000Z","updated_at":"2026-02-21T06:18:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tracewayapp/lit","commit_stats":null,"previous_names":["tracewayapp/go-lightning"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/tracewayapp/lit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tracewayapp%2Flit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tracewayapp%2Flit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tracewayapp%2Flit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tracewayapp%2Flit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tracewayapp","download_url":"https://codeload.github.com/tracewayapp/lit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tracewayapp%2Flit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31413282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T20:09:54.854Z","status":"ssl_error","status_checked_at":"2026-04-04T20:09:44.350Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","golang","golang-orm","orm","orm-library"],"created_at":"2026-04-04T20:38:20.678Z","updated_at":"2026-04-04T20:38:23.235Z","avatar_url":"https://github.com/tracewayapp.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://lit.tracewayapp.com\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"logo-white.png\" /\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"logo-black.png\" /\u003e\n      \u003cimg src=\"logo-black.png\" alt=\"lit logo\" width=\"150\" /\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# lit\n\n`lit` is a lightweight, high-performance database interaction library for Go. It is designed to be slim, fast, and easy to use, especially when working with projections and Data Transfer Objects (DTOs).\n\nThe project is currently used in a **production environment**.\n\n## Key Features\n\n- **Unified API**: The `lit` package provides a single API for PostgreSQL, MySQL, SQLite, and custom database drivers, with driver-specific optimizations handled internally.\n- **Lightweight Projections**: The biggest advantage of `lit` is its ability to load DTOs and projections with minimal effort. Regardless of your table structure, mapping a query result to a Go struct is straightforward and clean.\n- **MySQL, PostgreSQL, and SQLite Support**: Register your models with the appropriate driver and the library handles query generation and driver-specific optimizations.\n- **Generic CRUD Operations**: Automatic generation of `INSERT` and `UPDATE` queries for registered types.\n- **Works with DB and Tx**: All operations accept both `*sql.DB` and `*sql.Tx` via the `Executor` interface.\n- **Minimal Dependencies**: Keeps your project slim and focused.\n\n## Docs\n\nDocumentation is available at https://lit.tracewayapp.com\n\n## Usage Limitations\n\n- **ID Column Requirement**: For automatic `Insert` and `Update` operations, the library requires your tables to have an `id` column. It does not support tables without a primary `id` field for these specific automatic operations.\n\n## Installation\n\n```bash\ngo get github.com/tracewayapp/lit/v2\n```\n\n## Configuration \u0026 Usage\n\n### 1. Registration\n\nEvery model you intend to use with generic functions must be registered with a specific driver.\n\n```go\nimport \"github.com/tracewayapp/lit/v2\"\n\ntype User struct {\n    Id        int\n    FirstName string\n    LastName  string\n    Email     string\n}\n\nfunc init() {\n    // Register for PostgreSQL\n    lit.RegisterModel[User](lit.PostgreSQL)\n    // OR Register for MySQL\n    lit.RegisterModel[User](lit.MySQL)\n    // OR Register for SQLite\n    lit.RegisterModel[User](lit.SQLite)\n}\n```\n\n**Placeholder Syntax:** PostgreSQL uses `$1, $2, $3...` placeholders while MySQL uses `?` placeholders. The examples below use PostgreSQL syntax.\n\n### 2. Basic Usage\n\n```go\nimport (\n    \"github.com/tracewayapp/lit/v2\"\n    _ \"github.com/jackc/pgx/v5/stdlib\"\n)\n\nfunc example(db *sql.DB) {\n    // Insert - returns auto-generated ID\n    id, _ := lit.Insert(db, \u0026User{FirstName: \"Jane\", LastName: \"Smith\"})\n\n    // Select Single\n    user, _ := lit.SelectSingle[User](db, \"SELECT * FROM users WHERE id = $1\", id)\n\n    // Select Multiple\n    users, _ := lit.Select[User](db, \"SELECT * FROM users WHERE last_name = $1\", \"Smith\")\n\n    // Update\n    user.Email = \"jane@example.com\"\n    _ = lit.Update(db, user, \"id = $1\", user.Id)\n\n    // Delete\n    _ = lit.Delete(db, \"DELETE FROM users WHERE id = $1\", user.Id)\n}\n```\n\n### 3. Working with Transactions\n\nAll operations work with both `*sql.DB` and `*sql.Tx`:\n\n```go\nfunc exampleWithTx(db *sql.DB) error {\n    tx, err := db.Begin()\n    if err != nil {\n        return err\n    }\n    defer tx.Rollback()\n\n    // All operations accept tx\n    id, err := lit.Insert(tx, \u0026User{FirstName: \"John\"})\n    if err != nil {\n        return err\n    }\n\n    user, err := lit.SelectSingle[User](tx, \"SELECT * FROM users WHERE id = $1\", id)\n    if err != nil {\n        return err\n    }\n\n    return tx.Commit()\n}\n```\n\n### 4. UUID Support\n\nFor models with string ID fields, use UUID-specific insert functions:\n\n```go\ntype Product struct {\n    Id    string\n    Name  string\n    Price int\n}\n\nfunc init() {\n    lit.RegisterModel[Product](lit.PostgreSQL)\n}\n\nfunc example(db *sql.DB) {\n    // Auto-generate UUID\n    uuid, _ := lit.InsertUuid(db, \u0026Product{Name: \"Widget\", Price: 100})\n\n    // Use existing UUID\n    product := \u0026Product{Id: \"my-custom-uuid\", Name: \"Gadget\", Price: 200}\n    _ = lit.InsertExistingUuid(db, product)\n}\n```\n\n### 5. Named Parameters\n\nWrite portable queries with `:name` placeholders. lit automatically converts them to the correct driver syntax (`$1` for PostgreSQL, `?` for MySQL/SQLite):\n\n```go\n// Use lit.P as a shorthand for map[string]any\nusers, _ := lit.SelectNamed[User](db,\n    \"SELECT * FROM users WHERE last_name = :last_name AND email = :email\",\n    lit.P{\"last_name\": \"Doe\", \"email\": \"john@example.com\"})\n\n// Single result\nuser, _ := lit.SelectSingleNamed[User](db,\n    \"SELECT * FROM users WHERE id = :id\",\n    lit.P{\"id\": 1})\n\n// Update with named WHERE clause\nuser.Email = \"jane@example.com\"\n_ = lit.UpdateNamed(db, user,\n    \"id = :id\",\n    lit.P{\"id\": 1})\n\n// Delete (requires explicit driver since Delete is non-generic)\n_ = lit.DeleteNamed(lit.PostgreSQL, db,\n    \"DELETE FROM users WHERE id = :id\",\n    lit.P{\"id\": 1})\n```\n\nFor advanced use, you can parse named queries manually:\n\n```go\n// Using model's registered driver\nquery, args, err := lit.ParseNamedQueryForModel[User](\n    \"SELECT * FROM users WHERE id = :id\", lit.P{\"id\": 1})\n\n// Using explicit driver\nquery, args, err := lit.ParseNamedQuery(lit.PostgreSQL,\n    \"SELECT * FROM users WHERE id = :id\", lit.P{\"id\": 1})\n```\n\nThe parser handles PostgreSQL `::` type casts, string literals, and repeated parameters correctly.\n\n### 6. Helper Functions\n\n```go\n// JoinForIn - for integer IN clauses\nids := []int{1, 2, 3}\nquery := fmt.Sprintf(\"SELECT * FROM users WHERE id IN (%s)\", lit.JoinForIn(ids))\n\n// JoinStringForIn - generates driver-appropriate placeholders\n// PostgreSQL: $1,$2,$3 (with offset support)\n// MySQL: ?,?,?\nnames := []string{\"a\", \"b\", \"c\"}\nplaceholders := lit.JoinStringForIn[User](0, names)\n\n// Or specify driver explicitly\nplaceholders := lit.JoinStringForInWithDriver(lit.PostgreSQL, 0, 3) // \"$1,$2,$3\"\nplaceholders := lit.JoinStringForInWithDriver(lit.MySQL, 0, 3)      // \"?,?,?\"\n```\n\n### 7. Column Naming\n\nBy default, `lit` converts Go struct field names from CamelCase to snake_case for database column names:\n\n| Struct Field | Database Column |\n| ------------ | --------------- |\n| `Id`         | `id`            |\n| `FirstName`  | `first_name`    |\n| `LastName`   | `last_name`     |\n| `Email`      | `email`         |\n\n#### Custom Column Names with `lit` Tags\n\nYou can override the default naming by using the `lit` struct tag:\n\n```go\ntype User struct {\n    Id        int    `lit:\"id\"`\n    FirstName string `lit:\"first_name\"`\n    LastName  string `lit:\"surname\"`       // Maps to \"surname\" instead of \"last_name\"\n    Email     string `lit:\"email_address\"` // Maps to \"email_address\" instead of \"email\"\n}\n```\n\nThe `lit` tag is used for:\n\n- **INSERT queries**: Column names in the generated INSERT statement\n- **UPDATE queries**: Column names in the generated UPDATE statement\n- **SELECT queries**: Mapping database columns back to struct fields\n\n#### Mixing Tagged and Untagged Fields\n\nYou can use `lit` tags on only some fields. Fields without tags use the default snake_case conversion:\n\n```go\ntype User struct {\n    Id          int                       // Uses default: \"id\"\n    FirstName   string `lit:\"given_name\"` // Uses tag: \"given_name\"\n    LastName    string                    // Uses default: \"last_name\"\n    PhoneNumber string `lit:\"phone\"`      // Uses tag: \"phone\"\n}\n```\n\n#### Custom Naming Strategy\n\nFor more control over naming conventions, you can implement the `DbNamingStrategy` interface and use `RegisterModelWithNaming`:\n\n```go\ntype MyNamingStrategy struct{}\n\nfunc (m MyNamingStrategy) GetTableNameFromStructName(name string) string {\n    return strings.ToLower(name) // e.g., \"User\" -\u003e \"user\"\n}\n\nfunc (m MyNamingStrategy) GetColumnNameFromStructName(name string) string {\n    return strings.ToLower(name) // e.g., \"FirstName\" -\u003e \"firstname\"\n}\n\nfunc init() {\n    lit.RegisterModelWithNaming[User](lit.PostgreSQL, MyNamingStrategy{})\n}\n```\n\nNote: The `lit` tag takes precedence over any naming strategy.\n\n### 8. Custom Drivers\n\nThe `Driver` type is an interface, so you can implement your own driver for databases not built in. Your driver must implement all methods of the `Driver` interface:\n\n```go\ntype cockroachDriver struct{}\n\nfunc (d *cockroachDriver) Name() string                        { return \"CockroachDB\" }\nfunc (d *cockroachDriver) Placeholder(argIndex int) string     { return fmt.Sprintf(\"$%d\", argIndex) }\nfunc (d *cockroachDriver) SupportsBackslashEscape() bool       { return false }\n// ... implement remaining methods\n\nvar CockroachDB lit.Driver = \u0026cockroachDriver{}\n```\n\nThen register models with your custom driver:\n\n```go\nlit.RegisterModel[User](CockroachDB)\n```\n\nSee the [Custom Drivers guide](https://lit.tracewayapp.com/guides/custom-drivers) for the full interface definition and a complete example.\n\n## Contributions\n\nWe welcome all contributions to the lit project. You can open issues or PR and we will review and promptly merge them.\n\n## Roadmap\n\n- [x] ~~Named query parameters~~\n- [x] ~~Add a project homepage~~\n- [ ] Add support for composite primary keys\n- [x] ~~Escaping SQL keywords for field names and table names~~\n- [x] ~~Add support for ClickHouse - we're not doing this as clickhouse has a driver that is basically already doing this~~\n- [x] ~~Add more examples - the usercrud example is mostly complete - we'll add more if we get a git issue filed to do so~~\n- [x] ~~Add project docs~~\n- [x] ~~Add support for named fields `lit:\"column_name\"`~~\n\n## Project Philosophy\n\n- **Developer Written**: All core logic and architectural decisions were made and implemented by an actual developer.\n- **AI Assisted Testing**: AI was utilized to help generate a comprehensive test suite as well as help out with documentation.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftracewayapp%2Flit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftracewayapp%2Flit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftracewayapp%2Flit/lists"}