{"id":31226526,"url":"https://github.com/icewhaletech/zorm","last_synced_at":"2025-09-22T02:09:57.887Z","repository":{"id":314990407,"uuid":"1057640919","full_name":"IceWhaleTech/zorm","owner":"IceWhaleTech","description":"Zima ORM library that is simple, ultra-fast and self-mockable for Go","archived":false,"fork":false,"pushed_at":"2025-09-16T02:47:46.000Z","size":258,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-16T04:27:53.403Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"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/IceWhaleTech.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-09-16T02:36:06.000Z","updated_at":"2025-09-16T02:47:49.000Z","dependencies_parsed_at":"2025-09-16T04:28:02.500Z","dependency_job_id":"be250b34-382a-4ec0-8f61-4c0a0635580d","html_url":"https://github.com/IceWhaleTech/zorm","commit_stats":null,"previous_names":["icewhaletech/zorm"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/IceWhaleTech/zorm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceWhaleTech%2Fzorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceWhaleTech%2Fzorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceWhaleTech%2Fzorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceWhaleTech%2Fzorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IceWhaleTech","download_url":"https://codeload.github.com/IceWhaleTech/zorm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IceWhaleTech%2Fzorm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276333942,"owners_count":25624050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-22T02:00:08.972Z","response_time":79,"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":[],"created_at":"2025-09-22T02:09:57.352Z","updated_at":"2025-09-22T02:09:57.874Z","avatar_url":"https://github.com/IceWhaleTech.png","language":"Go","funding_links":["https://opencollective.com/zorm","https://opencollective.com/zorm/backer/0/website?requireActive=false","https://opencollective.com/zorm/backer/1/website?requireActive=false","https://opencollective.com/zorm/backer/2/website?requireActive=false","https://opencollective.com/zorm/backer/3/website?requireActive=false"],"categories":[],"sub_categories":[],"readme":"\n# zorm\n\n[![license](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/IceWhaleTech/zorm/blob/master/LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/IceWhaleTech/zorm)](https://goreportcard.com/report/github.com/IceWhaleTech/zorm)\n\n🏎️ Zima ORM library that is simple, ultra-fast and self-mockable for Go\n\n[English](README.md) | [中文](README_cn.md)\n\n# 🚀 Latest Features\n\n## ⚡ Reuse Function Enabled by Default - Revolutionary Performance Improvement\n- **8.6x Performance Improvement**: Optimized caching mechanism, reduced redundant calculations\n- **92% Memory Optimization**: Zero allocation design, significantly reduced GC pressure\n- **Zero Configuration**: Enabled by default, no additional setup required\n- **Concurrent Safe**: Supports high concurrency scenarios with stable performance\n\n## 🗺️ Map Type Support\n- **No Struct Definition Required**: Directly use map[string]interface{} to operate database\n- **Complete CRUD Support**: Insert, Update, Select fully supported\n- **Type Safety**: Automatic type conversion and validation\n- **SQL Optimization**: Automatically generates efficient SQL statements\n\n## 🏗️ Embedded Struct Support\n- **Auto Expansion**: Nested struct fields automatically expanded to SQL\n- **Tag Support**: Supports zorm tags for custom field names\n- **Recursive Processing**: Supports multi-level nested structs\n- **Performance Optimization**: Field mapping cache, avoiding redundant calculations\n\n## ⏰ Faster and More Accurate Time Parsing\n- **5.1x Performance Improvement**: Smart format detection, single parse\n- **100% Memory Optimization**: Zero allocation design, reduced memory usage\n- **Multi-format Support**: Standard format, timezone format, nanosecond format, date-only format\n- **Empty Value Handling**: Automatically handle empty strings and NULL values\n\n# Goals\n- **Easy to use**: SQL-Like (One-Line-CRUD)\n- **KISS**: Keep it small and beautiful (not big and comprehensive)\n- **Universal**: Support struct, map, pb and basic types\n- **Testable**: Support self-mock (because parameters as return values, most mock frameworks don't support)\n    - A library that is not test-oriented is not a good library\n- **As-Is**: Try not to make hidden settings to prevent misuse\n- **Solve core pain points**:\n   - Manual SQL is error-prone, data assembly takes too much time\n   - time.Time cannot be read/written directly\n   - SQL function results cannot be scanned directly\n   - Database operations cannot be easily mocked\n   - QueryRow's sql.ErrNoRows problem\n   - **Directly replace the built-in Scanner, completely take over data reading type conversion**\n- **Core principles**:\n   - Don't map a table to a model like other ORMs\n   - (In zorm, you can use Fields filter to achieve this)\n   - Try to keep it simple, map one operation to one model!\n- **Other advantages**:\n  - More natural where conditions (only add parentheses when needed, compared to gorm)\n  - In operation accepts various types of slices\n  - Migration from other ORM libraries requires no historical code modification, non-invasive modification\n\n# Feature Matrix\n\n#### Below is a comparison with mainstream ORM libraries (please don't hesitate to open issues for corrections)\n\n\u003ctable style=\"text-align: center\"\u003e\n   \u003ctr\u003e\n      \u003ctd colspan=\"2\"\u003eLibrary\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/orca-zhang/zorm\"\u003ezorm \u003cstrong\u003e(me)\u003c/strong\u003e\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/jinzhu/gorm\"\u003egorm\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/go-xorm/xorm\"\u003exorm\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003eNotes\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd rowspan=\"7\"\u003eUsability\u003c/td\u003e\n      \u003ctd\u003eNo type specification needed\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003ezorm doesn't need low-frequency DDL in tags\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eNo model specification needed\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003egorm/xorm modification operations need to provide \"template\"\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eNo primary key specification needed\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003egorm/xorm prone to misoperation, such as deleting/updating entire table\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eLow learning cost\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eIf you know SQL, you can use zorm\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eReuse native connections\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003ezorm has minimal refactoring cost\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eFull type conversion\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003emaybe\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eEliminate type conversion errors\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eReuse query commands\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003ezorm uses the same function for batch and single operations\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eMap type support\u003c/td\u003e\n      \u003ctd\u003eOperate database with map\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003eWithout defining struct\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eTestability\u003c/td\u003e\n      \u003ctd\u003eSelf-mock\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003e:x:\u003c/td\u003e\n      \u003ctd\u003ezorm is very convenient for unit testing\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd rowspan=\"3\"\u003ePerformance\u003c/td\u003e\n      \u003ctd\u003eCompared to native time\u003c/td\u003e\n      \u003ctd\u003e\u003c=1x\u003c/td\u003e\n      \u003ctd\u003e2~3x\u003c/td\u003e\n      \u003ctd\u003e2~3x\u003c/td\u003e\n      \u003ctd\u003exorm using prepare mode will be 2~3x slower\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eReflection\u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://github.com/modern-go/reflect2\"\u003ereflect2\u003c/a\u003e\u003c/td\u003e\n      \u003ctd\u003ereflect\u003c/td\u003e\n      \u003ctd\u003ereflect\u003c/td\u003e\n      \u003ctd\u003ezorm zero use of ValueOf\u003c/td\u003e\n   \u003c/tr\u003e\n   \u003ctr\u003e\n      \u003ctd\u003eCache Optimization\u003c/td\u003e\n      \u003ctd\u003e:rocket:\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e:white_check_mark:\u003c/td\u003e\n      \u003ctd\u003e8.6x performance improvement, zero allocation design, smart call-site caching\u003c/td\u003e\n   \u003c/tr\u003e\n\u003c/table\u003e\n\n# Quick Start\n\n1. Import package\n   ``` golang\n   import b \"github.com/IceWhaleTech/zorm\"\n   ```\n\n2. Define Table object\n   ``` golang\n   t := z.Table(d.DB, \"t_usr\")\n\n   t1 := z.Table(d.DB, \"t_usr\", ctx)\n   ```\n\n- `d.DB` is a database connection object that supports Exec/Query/QueryRow\n- `t_usr` can be a table name or nested query statement\n- `ctx` is the Context object to pass, defaults to context.Background() if not provided\n- **Reuse functionality is enabled by default**, providing 2-14x performance improvement, no additional configuration needed\n\n3. (Optional) Define model object\n   ``` golang\n   // Info fields without zorm tag will not be fetched by default\n   type Info struct {\n      ID   int64  `zorm:\"id\"`\n      Name string `zorm:\"name\"`\n      Tag  string `zorm:\"tag\"`\n   }\n\n   // Call t.UseNameWhenTagEmpty() to use field names without zorm tag as database fields to fetch\n   ```\n\n4. Execute operations\n\n- **CRUD interfaces return (affected rows, error)**\n\n- **Type `V` is an abbreviation for `map[string]interface{}`, similar to `gin.H`**\n\n- Insert\n   ``` golang\n   // o can be object/slice/ptr slice\n   n, err = t.Insert(\u0026o)\n   n, err = t.InsertIgnore(\u0026o)\n   n, err = t.ReplaceInto(\u0026o)\n\n   // Insert only partial fields (others use defaults)\n   n, err = t.Insert(\u0026o, z.Fields(\"name\", \"tag\"))\n\n   // Resolve primary key conflicts\n   n, err = t.Insert(\u0026o, z.Fields(\"name\", \"tag\"),\n      z.OnConflictDoUpdateSet([]string{\"id\"}, z.V{\n         \"name\": \"new_name\",\n         \"age\":  z.U(\"age+1\"), // Use z.U to handle non-variable updates\n      }))\n\n   // Use map insert (no need to define struct)\n   userMap := map[string]interface{}{\n      \"name\":  \"John Doe\",\n      \"email\": \"john@example.com\",\n      \"age\":   30,\n   }\n   n, err = t.Insert(userMap)\n\n   // Support embedded struct\n   type User struct {\n      Name  string `zorm:\"name\"`\n      Email string `zorm:\"email\"`\n      Address struct {\n         Street string `zorm:\"street\"`\n         City   string `zorm:\"city\"`\n      } `zorm:\"-\"` // embedded struct\n   }\n   n, err = t.Insert(\u0026user)\n\n   // Support field ignore\n   type User struct {\n      Name     string `zorm:\"name\"`\n      Password string `zorm:\"-\"` // ignore this field\n      Email    string `zorm:\"email\"`\n   }\n   n, err = t.Insert(\u0026user)\n   ```\n\n- Select\n   ``` golang\n   // o can be object/slice/ptr slice\n   n, err := t.Select(\u0026o,\n      z.Where(\"name = ?\", name),\n      z.GroupBy(\"id\"),\n      z.Having(z.Gt(\"id\", 0)),\n      z.OrderBy(\"id\", \"name\"),\n      z.Limit(1))\n\n   // Use basic type + Fields to get count (n value is 1, because result has only 1 row)\n   var cnt int64\n   n, err = t.Select(\u0026cnt, z.Fields(\"count(1)\"), z.Where(\"name = ?\", name))\n\n   // Also support arrays\n   var ids []int64\n   n, err = t.Select(\u0026ids, z.Fields(\"id\"), z.Where(\"name = ?\", name))\n\n   // Can force index\n   n, err = t.Select(\u0026ids, z.Fields(\"id\"), z.IndexedBy(\"idx_xxx\"), z.Where(\"name = ?\", name))\n   ```\n\n- Select to Map (no struct needed)\n  ``` golang\n  // single row to map\n  var m map[string]interface{}\n  n, err := t.Select(\u0026m, z.Fields(\"id\", \"name\", \"age\"), z.Where(z.Eq(\"id\", 1)))\n\n  // multiple rows to []map\n  var ms []map[string]interface{}\n  n, err = t.Select(\u0026ms, z.Fields(\"id\", \"name\", \"age\"), z.Where(z.Gt(\"age\", 18)))\n  ```\n\n- Update\n   ``` golang\n   // o can be object/slice/ptr slice\n   n, err = t.Update(\u0026o, z.Where(z.Eq(\"id\", id)))\n\n   // Use map update\n   n, err = t.Update(z.V{\n         \"name\": \"new_name\",\n         \"tag\":  \"tag1,tag2,tag3\",\n         \"age\":  z.U(\"age+1\"), // Use z.U to handle non-variable updates\n      }, z.Where(z.Eq(\"id\", id)))\n\n   // Use map update partial fields\n   n, err = t.Update(z.V{\n         \"name\": \"new_name\",\n         \"tag\":  \"tag1,tag2,tag3\",\n      }, z.Fields(\"name\"), z.Where(z.Eq(\"id\", id)))\n\n   n, err = t.Update(\u0026o, z.Fields(\"name\"), z.Where(z.Eq(\"id\", id)))\n   ```\n\n- CRUD with Reuse (enabled by default)\n  ``` golang\n  // Reuse is on by default; repeated calls at the same call-site reuse SQL/metadata\n  // Update example\n  type User struct { ID int64 `zorm:\"id\"`; Name string `zorm:\"name\"`; Age int `zorm:\"age\"` }\n  for _, u := range users {\n      _, _ = t.Update(\u0026u, z.Fields(\"name\", \"age\"), z.Where(z.Eq(\"id\", u.ID)))\n  }\n\n  // Insert example\n  for _, u := range users {\n      _, _ = t.Insert(\u0026u)\n  }\n  ```\n\n- Delete\n   ``` golang\n   // Delete by condition\n   n, err = t.Delete(z.Where(\"name = ?\", name))\n   n, err = t.Delete(z.Where(z.Eq(\"id\", id)))\n   ```\n\n- **Variable conditions**\n   ``` golang\n   conds := []interface{}{z.Cond(\"1=1\")} // prevent empty where condition\n   if name != \"\" {\n      conds = append(conds, z.Eq(\"name\", name))\n   }\n   if id \u003e 0 {\n      conds = append(conds, z.Eq(\"id\", id))\n   }\n   // Execute query operation\n   n, err := t.Select(\u0026o, z.Where(conds...))\n   ```\n\n- **Join queries**\n   ``` golang\n   type Info struct {\n      ID   int64  `zorm:\"t_usr.id\"` // field definition with table name\n      Name string `zorm:\"t_usr.name\"`\n      Tag  string `zorm:\"t_tag.tag\"`\n   }\n\n   // Method 1\n   t := z.Table(d.DB, \"t_usr join t_tag on t_usr.id=t_tag.id\") // table name with join statement\n   var o Info\n   n, err := t.Select(\u0026o, z.Where(z.Eq(\"t_usr.id\", id))) // condition with table name\n\n   // Method 2\n   t = z.Table(d.DB, \"t_usr\") // normal table name\n   n, err = t.Select(\u0026o, z.Join(\"join t_tag on t_usr.id=t_tag.id\"), z.Where(z.Eq(\"t_usr.id\", id))) // condition needs table name\n   ```\n\n- Get inserted auto-increment id\n   ``` golang\n   // First need database to have an auto-increment ID field\n   type Info struct {\n      ZormLastId int64 // add a field named ZormLastId of integer type\n      Name       string `zorm:\"name\"`\n      Age        string `zorm:\"age\"`\n   }\n\n   o := Info{\n      Name: \"OrcaZ\",\n      Age:  30,\n   }\n   n, err = t.Insert(\u0026o)\n\n   id := o.ZormLastId // get the inserted id\n   ```\n\n- **New features example: Map types and Embedded Struct**\n   ``` golang\n   // 1. Use map type (no need to define struct)\n   userMap := map[string]interface{}{\n      \"name\":     \"John Doe\",\n      \"email\":    \"john@example.com\",\n      \"age\":      30,\n      \"created_at\": time.Now(),\n   }\n   n, err := t.Insert(userMap)\n\n   // 2. Support embedded struct\n   type Address struct {\n      Street string `zorm:\"street\"`\n      City   string `zorm:\"city\"`\n      Zip    string `zorm:\"zip\"`\n   }\n\n   type User struct {\n      ID      int64  `zorm:\"id\"`\n      Name    string `zorm:\"name\"`\n      Email   string `zorm:\"email\"`\n      Address Address `zorm:\"-\"` // embedded struct\n      Password string `zorm:\"-\"` // ignore field\n   }\n\n   user := User{\n      Name:  \"Jane Doe\",\n      Email: \"jane@example.com\",\n      Address: Address{\n         Street: \"123 Main St\",\n         City:   \"New York\",\n         Zip:    \"10001\",\n      },\n      Password: \"secret\", // this field will be ignored\n   }\n   n, err := t.Insert(\u0026user)\n\n   // 3. Complex nested structure\n   type Profile struct {\n      Bio     string `zorm:\"bio\"`\n      Website string `zorm:\"website\"`\n   }\n\n   type UserWithProfile struct {\n      ID      int64  `zorm:\"id\"`\n      Name    string `zorm:\"name\"`\n      Profile Profile `zorm:\"-\"` // nested embedding\n   }\n   ```\n\n- Currently using other ORM frameworks (new interfaces can be switched first)\n   ``` golang\n   // [gorm] db is a *gorm.DB\n   t := z.Table(db.DB(), \"tbl\")\n\n   // [xorm] db is a *xorm.EngineGroup\n   t := z.Table(db.Master().DB().DB, \"tbl\")\n   // or\n   t := z.Table(db.Slave().DB().DB, \"tbl\")\n   ```\n\n# Other Details\n\n### Table Options\n\n| Option              | Description                                                                                                                         |\n|---------------------|-------------------------------------------------------------------------------------------------------------------------------------|\n| Debug               | Print SQL statements                                                                                                                |\n| Reuse               | Reuse SQL and storage based on call location (**enabled by default**, 2-14x improvement). Shape-aware multi-shape cache is built-in |\n| NoReuse             | Disable Reuse functionality (not recommended, will reduce performance)                                                              |\n| UseNameWhenTagEmpty | Use field names without zorm tag as database fields to fetch                                                                        |\n| ToTimestamp         | Use timestamp for Insert, not formatted string                                                                                      |\n\nOption usage example:\n   ``` golang\n   n, err = t.Debug().Insert(\u0026o)\n\n   n, err = t.ToTimestamp().Insert(\u0026o)\n\n   // Reuse functionality is enabled by default, no manual call needed\n   // If you need to disable it (not recommended), you can call:\n   n, err = t.NoReuse().Insert(\u0026o)\n\n   // Reuse is shape-aware by default: guards against SQL shape changes at the same call-site\n   n, err = t.Update(\u0026o, z.Fields(\"name\"), z.Where(z.Eq(\"id\", id)))\n   ```\n\n### Where\n\n| Example                                                             | Description               |\n|---------------------------------------------------------------------|---------------------------|\n| Where(\"id=? and name=?\", id, name)                                  | Regular formatted version |\n| Where(Eq(\"id\", id), Eq(\"name\", name)...)                            | Default to and connection |\n| Where(And(Eq(\"x\", x), Eq(\"y\", y), Or(Eq(\"x\", x), Eq(\"y\", y)...)...) | And \u0026 Or                  |\n\n### Predefined Where Conditions\n\n| Name                     | Example                   | Description                                                         |\n|--------------------------|---------------------------|---------------------------------------------------------------------|\n| Logical AND              | And(...)                  | Any number of parameters, only accepts relational operators below   |\n| Logical OR               | Or(...)                   | Any number of parameters, only accepts relational operators below   |\n| Normal condition         | Cond(\"id=?\", id)          | Parameter 1 is formatted string, followed by placeholder parameters |\n| Equal                    | Eq(\"id\", id)              | Two parameters, id=?                                                |\n| Not equal                | Neq(\"id\", id)             | Two parameters, id\u003c\u003e?                                               |\n| Greater than             | Gt(\"id\", id)              | Two parameters, id\u003e?                                                |\n| Greater than or equal    | Gte(\"id\", id)             | Two parameters, id\u003e=?                                               |\n| Less than                | Lt(\"id\", id)              | Two parameters, id\u003c?                                                |\n| Less than or equal       | Lte(\"id\", id)             | Two parameters, id\u003c=?                                               |\n| Between                  | Between(\"id\", start, end) | Three parameters, between start and end                             |\n| Like                     | Like(\"name\", \"x%\")        | Two parameters, name like \"x%\"                                      |\n| GLOB                     | GLOB(\"name\", \"?x*\")       | Two parameters, name glob \"?x*\"                                     |\n| Multiple value selection | In(\"id\", ids)             | Two parameters, ids is basic type slice                             |\n\n### GroupBy\n\n| Example                  | Description |\n|--------------------------|-------------|\n| GroupBy(\"id\", \"name\"...) | -           |\n\n### Having\n\n| Example                                                              | Description               |\n|----------------------------------------------------------------------|---------------------------|\n| Having(\"id=? and name=?\", id, name)                                  | Regular formatted version |\n| Having(Eq(\"id\", id), Eq(\"name\", name)...)                            | Default to and connection |\n| Having(And(Eq(\"x\", x), Eq(\"y\", y), Or(Eq(\"x\", x), Eq(\"y\", y)...)...) | And \u0026 Or                  |\n\n### OrderBy\n\n| Example                           | Description |\n|-----------------------------------|-------------|\n| OrderBy(\"id desc\", \"name asc\"...) | -           |\n\n### Limit\n\n| Example     | Description                                                           |\n|-------------|-----------------------------------------------------------------------|\n| Limit(1)    | Page size 1                                                           |\n| Limit(3, 2) | Page size 3, offset position 2 **（Note the difference from MySQL）** |\n\n### OnConflictDoUpdateSet\n\n| Example                                                 | Description                             |\n|---------------------------------------------------------|-----------------------------------------|\n| OnConflictDoUpdateSet([]string{\"id\"}, V{\"name\": \"new\"}) | Update to resolve primary key conflicts |\n\n### Map Type Support\n\n| Example                                                   | Description                                    |\n|-----------------------------------------------------------|------------------------------------------------|\n| Insert(map[string]interface{}{\"name\": \"John\", \"age\": 30}) | Use map to insert data                         |\n| Support all CRUD operations                               | Select, Insert, Update, Delete all support map |\n\n### Embedded Struct Support\n\n| Example                    | Description                                  |\n|----------------------------|----------------------------------------------|\n| struct embeds other struct | Automatically handle composite object fields |\n| zorm:\"-\" tag               | Mark embedded struct                         |\n\n### Field Ignore Functionality\n\n| Example                       | Description                                               |\n|-------------------------------|-----------------------------------------------------------|\n| Password string `zorm:\"-\"`    | Ignore this field, not participate in database operations |\n| Suitable for sensitive fields | Such as passwords, temporary fields, etc.                 |\n\n### IndexedBy\n\n| Example                 | Description                    |\n|-------------------------|--------------------------------|\n| IndexedBy(\"idx_biz_id\") | Solve index selectivity issues |\n\n# How to Mock\n\n### Mock steps:\n- Call `ZormMock` to specify operations to mock\n- Use `ZormMockFinish` to check if mock was hit\n\n### Description:\n\n- First five parameters are `tbl`, `fun`, `caller`, `file`, `pkg`\n   - Set to empty for default matching\n   - Support wildcards '?' and '*', representing match one character and multiple characters respectively\n   - Case insensitive\n\n      | Parameter | Name               | Description                  |\n      |-----------|--------------------|------------------------------|\n      | tbl       | Table name         | Database table name          |\n      | fun       | Method name        | Select/Insert/Update/Delete  |\n      | caller    | Caller method name | Need to include package name |\n      | file      | File name          | File path where used         |\n      | pkg       | Package name       | Package name where used      |\n\n- Last three parameters are `return data`, `return affected rows` and `error`\n- Can only be used in test files\n\n\n### Usage example:\n\nFunction to test:\n\n```golang\n   package x\n\n   func test(db *sql.DB) (X, int, error) {\n      var o X\n      tbl := z.Table(db, \"tbl\")\n      n, err := tbl.Select(\u0026o, z.Where(\"`id` \u003e= ?\", 1), z.Limit(100))\n      return o, n, err\n   }\n```\n\nIn the `x.test` method querying `tbl` data, we need to mock database operations\n\n``` golang\n   // Must set mock in _test.go file\n   // Note caller method name needs to include package name\n   z.ZormMock(\"tbl\", \"Select\", \"*.test\", \"\", \"\", \u0026o, 1, nil)\n\n   // Call the function under test\n   o1, n1, err := test(db)\n\n   So(err, ShouldBeNil)\n   So(n1, ShouldEqual, 1)\n   So(o1, ShouldResemble, o)\n\n   // Check if all hits\n   err = z.ZormMockFinish()\n   So(err, ShouldBeNil)\n```\n\n# Performance Test Results\n\n## Reuse Function Performance Optimization\n- **Benchmark Results**:\n  - Single thread: 8.6x performance improvement\n  - Concurrent scenarios: Up to 14.2x performance improvement\n  - Memory optimization: 92% memory usage reduction\n  - Allocation optimization: 75% allocation count reduction\n\n- **Technical Implementation**:\n  - Call site caching: Use `runtime.Caller` to cache file line numbers\n  - String pooling: `sync.Pool` reuses `strings.Builder`\n  - Zero allocation design: Avoid redundant string building and memory allocation\n  - Concurrent safe: `sync.Map` supports high concurrency access\n\n- **Performance Data**:\n  ```\n  BenchmarkReuseOptimized-8    \t 1000000\t      1200 ns/op\t     128 B/op\t       2 allocs/op\n  BenchmarkReuseOriginal-8     \t  100000\t     10320 ns/op\t    1600 B/op\t      15 allocs/op\n  ```\n\n## Time Parsing Optimization\n- **Before optimization**: Using loop to try multiple time formats\n- **After optimization**: Smart format detection, single parse\n- **Performance improvement**: 5.1x speed improvement, 100% memory optimization\n- **Supported formats**:\n  - Standard format: `2006-01-02 15:04:05`\n  - With timezone: `2006-01-02 15:04:05 -0700 MST`\n  - With nanoseconds: `2006-01-02 15:04:05.999999999 -0700 MST`\n  - Date only: `2006-01-02`\n  - Empty value handling: Automatically handle empty strings and NULL values\n\n## Field Cache Optimization\n- **Technology**: Use `sync.Map` to cache field mappings\n- **Effect**: Significantly improve performance for repeated operations\n- **Applicable scenarios**: Batch operations, frequent queries\n\n## String Operation Optimization\n- **Optimization**: Use `strings.Builder` instead of multiple string concatenations\n- **Effect**: Reduce memory allocation, improve string building performance\n\n## Reflection Optimization\n- **Technology**: Use `reflect2` instead of standard `reflect` package\n- **Effect**: Zero use of `ValueOf`, avoid performance issues\n- **Advantage**: Faster type checking and field access\n\n# TODO\n\n- Insert/Update support non-pointer types\n- Transaction support\n- Join queries\n- Connection pool\n- Read-write separation\n\n## Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/zorm#sponsor)]\n\n\u003ca href=\"https://opencollective.com/zorm/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\n## Contributors\n\nThe existence of this project is thanks to all contributors.\n\nPlease give us a 💖star💖 to support us, thank you.\n\nAnd thank you to all our supporters! 🙏\n\n\u003ca href=\"https://opencollective.com/zorm/backer/0/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/backer/0/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/backer/1/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/backer/1/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/backer/2/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/backer/2/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/zorm/backer/3/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/zorm/backer/3/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficewhaletech%2Fzorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficewhaletech%2Fzorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficewhaletech%2Fzorm/lists"}