{"id":37200707,"url":"https://github.com/teacat/rushia","last_synced_at":"2026-01-14T23:08:49.823Z","repository":{"id":53258991,"uuid":"209614430","full_name":"teacat/rushia","owner":"teacat","description":"👷 MySQL query builder with fully functional","archived":true,"fork":false,"pushed_at":"2023-05-18T16:47:28.000Z","size":427,"stargazers_count":19,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-30T09:17:06.400Z","etag":null,"topics":["database","go","golang","mysql","query-builder","sql","sqlite"],"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/teacat.png","metadata":{"files":{"readme":"README-tw.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}},"created_at":"2019-09-19T17:44:44.000Z","updated_at":"2024-07-19T17:37:43.000Z","dependencies_parsed_at":"2024-06-19T13:33:26.872Z","dependency_job_id":null,"html_url":"https://github.com/teacat/rushia","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/teacat/rushia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teacat%2Frushia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teacat%2Frushia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teacat%2Frushia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teacat%2Frushia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/teacat","download_url":"https://codeload.github.com/teacat/rushia/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/teacat%2Frushia/sbom","scorecard":{"id":871306,"data":{"date":"2025-08-11","repo":{"name":"github.com/teacat/rushia","commit":"d92ccd75be728d95c2153b3cbde533a0af0b694f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T04:18:16.723Z","repository_id":53258991,"created_at":"2025-08-24T04:18:16.723Z","updated_at":"2025-08-24T04:18:16.723Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28437930,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T22:37:52.437Z","status":"ssl_error","status_checked_at":"2026-01-14T22:37:31.496Z","response_time":107,"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","go","golang","mysql","query-builder","sql","sqlite"],"created_at":"2026-01-14T23:08:49.171Z","updated_at":"2026-01-14T23:08:49.765Z","avatar_url":"https://github.com/teacat.png","language":"Go","readme":"# Rushia [![GoDoc](https://godoc.org/github.com/teacat/rushia/v3?status.svg)](https://godoc.org/github.com/teacat/rushia/v3) [![Coverage Status](https://coveralls.io/repos/github/teacat/rushia/badge.svg?branch=master)](https://coveralls.io/github/teacat/rushia?branch=master) [![Build Status](https://app.travis-ci.com/teacat/rushia.svg?branch=master)](https://app.travis-ci.com/github/teacat/rushia) [![Go Report Card](https://goreportcard.com/badge/github.com/teacat/rushia)](https://goreportcard.com/report/github.com/teacat/rushia)\n\n一個由 [Golang](https://golang.org/) 撰寫且比起部分 [ORM](https://zh.wikipedia.org/wiki/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84) 還要讚的 [MySQL](https://www.mysql.com/) 指令建置函式庫。彈性高、不需要建構體標籤。原生想法基於 [PHP-MySQLi-Database-Class](https://github.com/joshcam/PHP-MySQLi-Database-Class) 和 [Laravel 查詢建構器](https://laravel.com/docs/8.x/queries) 但多了些功能。\n\n這是一個 SQL 指令建構庫，本身不帶有任何 SQL 連線，適合用於某些套件的基底。\n\n## 特色\n\n-   幾乎全功能的函式庫。\n-   容易理解與記住、且使用方式十分簡單。\n-   SQL 指令建構函式。\n-   資料庫表格建構協助函式。\n-   彈性的建構體映射。\n-   可串連的使用方式。\n-   支援子指令（Sub Query）。\n-   透過預置聲明（[Prepared Statement](https://en.wikipedia.org/wiki/Prepared_statement)），99.9% 避免 SQL 注入攻擊。\n\n## 為什麼？\n\n[Gorm](https://github.com/jinzhu/gorm) 已經是 [Golang](https://golang.org/) 裡的 [ORM](https://zh.wikipedia.org/wiki/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84) 典範，但實際上要操作複雜與關聯性高的 SQL 指令時並不是很合適，而 Rushia 解決了這個問題。Rushia 也試圖不要和建構體扯上關係，不希望使用者需要手動指定任何標籤在建構體中。\n\n## 安裝方式\n\n打開終端機並且透過 `go get` 安裝此套件即可。\n\n```bash\n$ go get github.com/teacat/rushia/v3\n```\n\n## 使用方式\n\nRushia 的使用方式十分直覺與簡易，類似基本的 SQL 指令集但是更加地簡化了。\n\n### 初始化語法\n\n最基本的資料庫執行語法起始於 `NewQuery(...)`，其中可以帶入資料表的名稱，又或者是子指令（Sub Query）。而更為複雜的使用方式請參閱之後的章節。\n\n```go\nq := rushia.NewQuery(\"Users\")\n```\n\n### 複製語法\n\n預設情況下你的所有修改總是會改到同一個 Rushia 語法，如果你的環境可能有多執行緒或是希望複製一份規則額外更改，請使用 `Copy`。\n\n```go\na := rushia.NewQuery(\"Users\")\na.Where(\"Type = ?\", \"VIP\")\n\nb := a.Copy()\nb.Where(\"Name = ?\", \"YamiOdymel\")\n\nBuild(a.Select())\n// 等效於：SELECT * FROM Users WHERE Type = ?\nBuild(b.Select())\n// 等效於：SELECT * FROM Users WHERE Type = ? AND Name = ?\n```\n\n### 建置語法\n\n當完成撰寫一個查詢語法後，必須透過 `Build` 將其建置便能得到建置的語句與其參數。一個語句必須要有 `Select`、`Exists`、`Replace`、`Update`、`Delete`…等作為結尾，否則會無法建置。\n\n```go\nquery, params := rushia.Build(rushia.NewQuery(\"Users\").Select())\n// 等效於：SELECT * FROM Users\n```\n\n### 與其他資料庫套件搭配\n\n由於 Rushia 是一個語法建置套件，這讓你可以得心應手地與自己喜好的資料庫連線函式庫進行搭配。舉例來說你可以使用 [jmoiron/sqlx](https://github.com/jmoiron/sqlx)：\n\n```go\n// 初始化 SQLX 的連線。\ndb, err := sqlx.Open(\"mysql\", \"root:password@tcp(localhost:3306)/db\")\n\n// 透過 Rushia 建置語法。\nq := rushia.NewQuery(\"Users\").Where(\"Usernam = ?\", \"YamiOdymel\").Select()\nquery, params := rushia.Build(q)\n\n// 將相關語法與參數傳入給 SQLX 的函式並執行。\nrows, err := db.Query(query, params...)\n// 等效於：SELECT * FROM Users WHERE Username = ?\n```\n\n又或者是 [go-gorm/gorm](https://github.com/go-gorm/gorm)：\n\n```go\n// 初始化 Gorm 的連線。\ndb, err := gorm.Open(mysql.Open(\"root:password@tcp(localhost:3306)/db\"), \u0026gorm.Config{})\n\n// 透過 Rushia 建置語法。\nq := rushia.NewQuery(\"Users\").Where(\"Username = ?\", \"YamiOdymel\").Select()\nquery, params := rushia.Build(q)\n\n// 將相關語法與參數傳入給 Gorm 的函式並執行。\ndb.Raw(query, params...).Scan(\u0026myUser)\n// 等效於：SELECT * FROM Users WHERE Username = ?\n```\n\n### 結構體映射\n\n你能夠直接將一個建構體傳入 `Insert` 或是 `Update` 之中，其欄位名稱與值都會被自動轉換 (注意！這並不會轉換成 MySQL 最常用的 `snake_case`！)。\n\n```go\ntype User struct {\n\tUsername string\n\tPassword string\n}\nu := User{\n\tUsername: \"YamiOdymel\",\n\tPassword: \"test\",\n}\nrushia.NewQuery(\"Users\").Insert(u)\n// 等效於：INSERT INTO Users (Username, Password) VALUES (?, ?)\n```\n\n#### 結構體標籤\n\n透過指定 `rushia` 結構體標籤，你可以省略一個欄位或是重新命名其欄位在 MySQL 查詢語法裡的名稱。\n\n```go\ntype User struct {\n\tUsername string `rushia:\"-\"`\n\tRealName string `rushia:\"real_name\"`\n\tPassword string\n}\nu := User{\n\tUsername: \"YamiOdymel\",\n\tRealName: \"洨洨安\",\n\tPassword: \"test\",\n}\nrushia.NewQuery(\"Users\").Insert(u)\n// 等效於：INSERT INTO Users (real_name, Password) VALUES (?, ?)\n```\n\n### 省略\n\n透過 `Omit`，你可以省略建構體中的某些欄位。\n\n```go\ntype User struct {\n\tUsername string\n\tPassword string\n\tAge      int    `rushia:\"my_age\"`\n}\nu := User{\n\tUsername: \"YamiOdymel\",\n\tPassword: \"test\",\n\tAge     : \"32\"\n}\nrushia.NewQuery(\"Users\").Omit(\"Username\", \"my_age\").Insert(u)\n// 等效於：INSERT INTO Users (Password) VALUES (?)\n```\n\n### 插入\n\nRushia 提供一個簡短的 `H`（`map[string]interface{}` 別名），這趨近於 [`gin.H`](https://pkg.go.dev/github.com/gin-gonic/gin#H)。建立一個插入語法的時候可以傳入 `H`、`H` 或是結構體。\n\n```go\nrushia.NewQuery(\"Users\").Insert(rushia.H{\n\t\"Username\": \"YamiOdymel\",\n\t\"Password\": \"test\",\n})\n// 等效於：INSERT INTO Users (Username, Password) VALUES (?, ?)\n\nrushia.NewQuery(\"Users\").Insert(map[string]interface{\n\t\"Username\": \"YamiOdymel\",\n\t\"Password\": \"test\",\n})\n// 等效於：INSERT INTO Users (Username, Password) VALUES (?, ?)\n```\n\n### 多筆資料\n\nRushia 允許你透過 `[]H` 或 `[]map[string]interface{}` 一次插入多筆資料。\n\n```go\ndata := []H{\n\t{\n\t\t\"Username\": \"YamiOdymel\",\n\t\t\"Password\": \"test\",\n\t}, {\n\t\t\"Username\": \"Karisu\",\n\t\t\"Password\": \"12345\",\n\t},\n}\nrushia.NewQuery(\"Users\").Insert(data)\n// 等效於：INSERT INTO Users (Username, Password) VALUES (?, ?), (?, ?)\n```\n\n### 覆蓋\n\n覆蓋的用法與插入相同。當有同筆資料時會先進行刪除，然後再插入一筆新的，這對有外鍵的表格來說十分危險。若需要更為安全的方式請使用 `OnDuplicate`（`ON DUPLICATE KEY UPDATE`）函式。\n\n```go\nrushia.NewQuery(\"Users\").Replace(rushia.H{\n\t\"Username\": \"YamiOdymel\",\n\t\"Password\": \"test\",\n})\n// 等效於：REPLACE INTO Users (Username, Password) VALUES (?, ?)\n```\n\n### 當重複時\n\nRushia 支援了插入資料若重複時可以更新該筆資料的指定欄位，這類似「覆蓋」，但這並不會先刪除原先的資料，這種方式僅會在插入時檢查是否重複，若重複則更新該筆資料。\n\n```go\nrushia.NewQuery(\"Users\").As(\"New\").OnDuplicate(rushia.H{\n\t\"UpdatedAt\": rushia.NewExpr(\"New.UpdatedAt\"),\n}).Insert(rushia.H{\n\t\"Username\":  \"YamiOdymel\",\n\t\"UpdatedAt\": rushia.NewExpr(\"NOW()\"),\n})\n// 等效於：INSERT INTO Users (Username, UpdatedAt) VALUES (?, NOW()) AS New ON DUPLICATE KEY UPDATE UpdatedAt = New.UpdatedAt\n\nrushia.NewQuery(\"Users\").OnDuplicate(rushia.H{\n\t\"UpdatedAt\": rushia.NewExpr(\"VALUES(UpdatedAt)\"),\n}).Insert(rushia.H{\n\t\"Username\":  \"YamiOdymel\",\n\t\"UpdatedAt\": rushia.NewExpr(\"NOW()\"),\n})\n// 注意！`VALUES` 這個用法已經在 MySQL 8.0.20 被棄用！請使用上面的方法！\n// 等效於：INSERT INTO Users (Username, UpdatedAt) VALUES (?, NOW()) ON DUPLICATE KEY UPDATE UpdatedAt = VALUES(UpdatedAt)\n```\n\n### 表達式\n\n插入較為複雜的值時，可以使用 `NewExpr` 建立一個新的表達式，便能傳入生指令與相關參數執行像是 `SHA1()` 或者取得目前時間的 `NOW()`，甚至將目前時間加上一年 ⋯ 等。\n\n```go\nrushia.NewQuery(\"Users\").Insert(rushia.H{\n\t\"Username\":  \"YamiOdymel\",\n\t\"Password\":  rushia.NewExpr(\"SHA1(?)\", \"secretpassword+salt\"),\n\t\"Expires\":   rushia.NewExpr(\"NOW() + INTERVAL 1 YEAR\"),\n\t\"CreatedAt\": rushia.NewExpr(\"NOW()\"),\n})\n// 等效於：INSERT INTO Users (Username, Password, Expires, CreatedAt) VALUES (?, SHA1(?), NOW() + INTERVAL 1 YEAR, NOW())\n```\n\n### 筆數限制\n\n`Limit` 能夠限制 SQL 執行的筆數，如果指定 `10`，那就表示只處理最前面 10 筆資料而非全部（例如：選擇、更新、移除）。如果指定 `10, 20`，那就是忽略前面 10 筆，並處理之後的 20 筆資料（`11, 12... 30`）。\n\n```go\nrushia.NewQuery(\"Users\").Limit(10).Update(data)\n// 等效於：UPDATE Users SET ... LIMIT 10\n\nrushia.NewQuery(\"Users\").Limit(10, 20).Select(data)\n// 等效於：SELECT * from Users LIMIT 10, 20\n```\n\n### 筆數偏移\n\n透過 `Offset` 能夠以偏移的方式取得資料，這類似 `Limit` 但參數是反過來的。例如：`10, 20` 則會從 `21` 開始取得 10 筆資料（`21, 22... 30`）。\n\n```go\nrushia.NewQuery(\"Users\").Offset(10, 20).Select()\n// 等效於：SELECT * from Users LIMIT 10 OFFSET 20\n```\n\n### 分頁\n\n`Paginate` 是一個較親近於人類的友善好函式，其參數為：`頁數, 單頁筆數`。例如：`1, 20` 會取得首 20 筆資料，而 `2, 20` 則會取得第二頁的 20 筆資料（基本上為 21 至 40）。\n\n```go\nrushia.NewQuery(\"Users\").Paginate(1, 20).Select()\n// 等效於：SELECT * from Users LIMIT 0, 20\n\nrushia.NewQuery(\"Users\").Paginate(2, 20).Select()\n// 等效於：SELECT * from Users LIMIT 20, 20\n```\n\n### 更新\n\n更新一筆資料在 Rushia 中極為簡單，你只需要指定表格名稱還有資料即可。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"Username = ?\", \"YamiOdymel\").Update(rushia.H{\n\t\"Username\": \"Karisu\",\n\t\"Password\": \"123456\",\n})\n// 等效於：UPDATE Users SET Username = ?, Password = ? WHERE Username = ?\n```\n\n### 片段更新\n\n當你希望某些欄位在零值的時候不要進行更新，那麼你就可以使用 `Patch` 來做片段更新（也叫小修補）。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"Username = ?\", \"YamiOdymel\").Patch(rushia.H{\n\t\"Age\": 0,\n\t\"Username\": \"\",\n\t\"Password\": \"123456\",\n})\n// 等效於：UPDATE Users SET Password = ? WHERE Username = ?\n```\n\n如果你希望有些欄位雖然是零值（如：`false`、`0`）但仍該在 `Patch` 時照樣更新，那麼就可以使用 `Exclude`。傳入資料型態（如：`reflect.Bool`、`reflect.String`）來以型態排除特定欄位、而字串則表示欲忽略的欄位名稱。\n\n排除的資料型態或欄位會在零值時一樣被更新到資料庫中。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"Username = ?\", \"YamiOdymel\").Exclude(\"Username\", reflect.Int).Patch(rushia.H{\n\t\"Age\":      0,\n\t\"Username\": \"\",\n\t\"Password\": \"123456\",\n})\n// 等效於：UPDATE Users SET Age = ?, Password = ?, Username = ? WHERE Username = ?\n```\n\n### 刪除\n\n刪除一筆資料再簡單不過了。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"ID = ?\", 1).Delete()\n// 等效於：DELETE FROM Users WHERE ID = ?\n```\n\n### 選擇與取得\n\n最基本的資料取得在 Rushia 中透過 `Select` 使用。\n\n```go\nrushia.NewQuery(\"Users\").Select()\n// 等效於：SELECT * FROM Users\n```\n\n#### 指定欄位\n\n在 `Select` 中傳遞欄位名稱作為參數，多個欄位由逗點區分，亦能是函式。\n\n```go\nrushia.NewQuery(\"Users\").Select(\"Username\", \"Nickname\")\n// 等效於：SELECT Username, Nickname FROM Users\n\nrushia.NewQuery(\"Users\").Select(rushia.NewExpr(\"COUNT(*) AS Count\"))\n// 等效於：SELECT COUNT(*) AS Count FROM Users\n```\n\n#### 單行資料\n\n如果只想要取得單筆資料，那麼就可以用上 `SelectOne`，這簡單來說就是 `.Limit(1).Select(...)` 的縮寫。\n\n```go\nrushia.NewQuery(\"Users\").SelectOne(\"Username\")\n// 等效於：SELECT Username FROM Users LIMIT 1\n```\n\n#### 排除重複\n\n取得資料的時候可以指定 `Distinct` 過濾重複內容。\n\n```go\nrushia.NewQuery(\"Products\").Distinct().Select()\n// 等效於：SELECT DISTINCT * FROM Products\n```\n\n#### 聯集\n\n可以透過 `Union` 或 `UnionAll` 整合多個表格選取之間的資料。\n\n```go\nlocationQuery := rushia.NewQuery(\"Locations\").Select()\n\nrushia.NewQuery(\"Users\").Union(locationQuery).Select()\n// 等效於：SELECT * FROM Users UNION SELECT * FROM Locations\n\nrushia.NewQuery(\"Users\").UnionAll(locationQuery).Select()\n// 等效於：SELECT * FROM Users UNION ALL SELECT * FROM Locations\n```\n\n### 選擇是否存在\n\n透過 `Exists` 來執行一個 `SELECT EXISTS`。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"Username = ?\", \"YamiOdymel\").Exists()\n// 等效於：SELECT EXISTS(SELECT * FROM Users WHERE Username = ?)\n```\n\n### 表格別名\n\n`As` 能夠替目前的查詢語句賦予表格別名，通常會應用在子查詢。若是在表格加入（JOIN）或是一般場景，則可以使用 `NewAlias`。\n\n```go\nrushia.NewQuery(NewQuery(\"Users\").Select()).As(\"Result\").Where(\"Username = ?\", \"YamiOdymel\").Select())\n// 等效於：SELECT * FROM (SELECT * FROM Users) AS Result WHERE Username = ?\n\nrushia.NewQuery(rushia.NewAlias(\"UserFriendRelationships\", \"relations\")).Where(\"relations.ID = ?\", 5).Select()\n// 等效於： SELECT * FROM UserFriendRelationships AS relations relations.WHERE ID = ?\n```\n\n### 執行生指令\n\nRushia 已經提供了近乎日常中 80% 會用到的方式，但如果好死不死你想使用的功能在那 20% 之中，我們還提供了原生的方法能讓你直接輸入 SQL 指令執行自己想要的鳥東西。一個最基本的生指令（Raw Query）就像這樣。\n\n其中亦能帶有預置聲明（Prepared Statement），也就是指令中的問號符號替代了原本的值。這能避免你的 SQL 指令遭受注入攻擊。\n\n正如標準的 `NewQuery` 一樣，`NewRawQuery` 也需要透過 `Build` 才能建置。而且 `NewRawQuery` 不能使用所有輔助功能，如：`Limit`、`OrderBy`…。\n\n```go\nq := rushia.NewRawQuery(\"SELECT * FROM Users WHERE ID \u003e= ?\", 10)\n```\n\n## 條件宣告\n\n透過 Rushia 宣告 `WHERE` 或 `HAVING` 條件也能夠很輕鬆。這裡是實際應用最常派上用場的條件函式：\n\n| SQL 語法                                                 | 使用方式                                                                                   |\n| -------------------------------------------------------- | ------------------------------------------------------------------------------------------ |\n| `Column = ?`\u003cbr\u003e`Column \u003e ?`                             | `.Where(\"Column = ?\", \"Value\")`\u003cbr\u003e`.Where(\"Column \u003e ?\", \"Value\")`                         |\n| `Column = Column`                                        | `.Where(\"Column = Column\")`                                                                |\n| `Column IN (?, ?)`\u003cbr\u003e`Column NOT IN (?, ?)`             | `.Where(\"Column IN (?, ?)\", \"A\", \"B\")`\u003cbr\u003e`.Where(\"Column NOT IN (?, ?)\", \"A\", \"B\")`       |\n| `Column IN (?, ?)`                                       | `.Where(\"Column IN ?\", []interface{}{\"A\", \"B\"})`                                           |\n| `Column BETWEEN ? AND ?`\u003cbr\u003e`Column NOT BETWEEN ? AND ?` | `.Where(\"Column BETWEEN ? AND ?\", 1, 20)`\u003cbr\u003e`.Where(\"Column NOT BETWEEN ? AND ?\", 1, 20)` |\n| `Column IS NULL`\u003cbr\u003e`Column IS NOT NULL`                 | `.Where(\"Column IS NULL\")`\u003cbr\u003e`.Where(\"Column IS NOT NULL\")`                               |\n| `Column EXISTS Query`\u003cbr\u003e`Column NOT EXISTS Query`       | `.Where(\"Column EXISTS ?\", subQuery)`\u003cbr\u003e`.Where(\"Column NOT EXISTS ?\", subQuery)`         |\n| `Column LIKE ?`\u003cbr\u003e`Column NOT LIKE ?`                   | `.Where(\"Column LIKE ?\", \"Value\")`\u003cbr\u003e`.Where(\"Column NOT LIKE ?\", \"Value\")`               |\n| `(Column = Column OR Column = ?)`                        | `.Where(\"(Column = Column OR Column = ?)\", \"Value\")`                                       |\n\n這些函式總共有幾種變形，分別適用於 `Where`、`OrWhere`、`Having`、`OrHaving`、`JoinWhere`、`OrJoinWhere`。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"ID = ?\", 1).Where(\"Username = ?\", \"admin\").Select()\n// 等效於：SELECT * FROM Users WHERE ID = ? AND Username = ?\n\nrushia.NewQuery(\"Users\").Having(\"ID = ?\", 1).Having(\"Username = ?\", \"admin\").Select()\n// 等效於：SELECT * FROM Users HAVING ID = ? AND Username = ?\n\nrushia.NewQuery(\"Users\").Where(\"ID != CompanyID\").Where(\"DATE(CreatedAt) = DATE(LastLogin)\").Select()\n// 等效於：SELECT * FROM Users WHERE ID != CompanyID AND DATE(CreatedAt) = DATE(LastLogin)\n```\n\n### 預置聲明展開\n\n透過預置聲明（[Prepared Statement](https://en.wikipedia.org/wiki/Prepared_statement)）可以避免 SQL 指令遭受注入攻擊。\n\n在 Rushia 中有個額外的功能，傳入一個 Slice（無論是：`[]interface{}` 或 `[]int`…等）給其中的單個 `?` 會自動展開成為預置聲明。\n\n```go\nrushia.NewQuery(\"Users\").Where(\"ID IN ?\", []interface{}{\"A\", \"B\", \"C\"}).Select()\n// 等效於：SELECT * FROM Users WHERE ID IN (?, ?, ?)\n```\n\n### 脫逸值\n\n與 [mysqljs/mysql](https://github.com/mysqljs/mysql) 套件中的 `??` 雙問號用法相同，你可以透過 `??` 產生出 (\\`) 來脫逸字元。這對於欄位名稱很有用。\n\n```go\nvar ColumnUserID = \"ID\"\nrushia.NewQuery(\"Users\").Where(\"?? = ?\", ColumnUserID, 3).Select()\n// 等效於：SELECT * FROM Users WHERE `ID` = ?\n```\n\n### 排序\n\nRushia 亦支援排序功能，如遞增或遞減，亦能擺放函式。\n\n```go\nrushia.NewQuery(\"Users\").OrderBy(\"ID ASC\").OrderBy(\"Login DESC\").OrderBy(\"RAND()\").Select()\n// 等效於：SELECT * FROM Users ORDER BY ID ASC, Login DESC, RAND()\n```\n\n#### 從值排序\n\n也能夠從值進行排序，只需要傳入一個切片即可。\n\n```go\nrushia.NewQuery(\"Users\").OrderByField(\"UserGroup\", \"SuperUser\", \"Admin\", \"Users\").Select()\n// 等效於：SELECT * FROM Users ORDER BY FIELD (UserGroup, ?, ?, ?) ASC\n```\n\n### 分組\n\n簡單的透過 `GroupBy` 就能夠將資料由指定欄位分組。\n\n```go\nrushia.NewQuery(\"Users\").GroupBy(\"Name\").Select()\n// 等效於：SELECT * FROM Users GROUP BY Name\n```\n\n### 加入表格\n\nRushia 支援多種表格加入方式，如：`InnerJoin`、`LeftJoin`、`RightJoin`、`NaturalJoin`、`CrossJoin`。在 Join 時，最後一個參數預設可以擺入條件式。\n\n```go\nrushia.\n\tNewQuery(\"Products\").\n\tLeftJoin(\"Users\", \"Products.TenantID = Users.TenantID\").\n\tSelect(\"Users.Name\", \"Products.ProductName\")\n// 等效於：SELECT Users.Name, Products.ProductName FROM Products AS Products LEFT JOIN Users AS Users ON (Products.TenantID = Users.TenantID)\n```\n\n但你也可以將加入條件式拆開放到後面定義。\n\n```go\nrushia.\n\tNewQuery(\"Products\").\n\tLeftJoin(\"Users\").\n\tJoinWhere(\"Products.TenantID = Users.TenantID\")\n\tSelect(\"Users.Name\", \"Products.ProductName\")\n// 等效於：SELECT Users.Name, Products.ProductName FROM Products AS Products LEFT JOIN Users AS Users ON (Products.TenantID = Users.TenantID)\n```\n\n#### 條件限制\n\n你亦能透過 `JoinWhere` 或 `OrJoinWhere` 擴展表格加入的限制條件，使用時這個條件總是會加到最後一個 `Join` 的表格。\n\n```go\nrushia.\n\tNewQuery(\"Products\").\n\tLeftJoin(\"Users\", \"Products.TenantID = Users.TenantID\").\n\tOrJoinWhere(\"Users.TenantID = ?\", 5).\n\tSelect(\"Users.Name\", \"Products.ProductName\")\n// 等效於：SELECT Users.Name, Products.ProductName FROM Products AS Products LEFT JOIN Users AS Users ON (Products.TenantID = Users.TenantID OR Users.TenantID = ?)\n```\n\n### 子指令\n\nRushia 支援複雜的子指令，將一個指令語法帶入當成值使用就能夠將其當作子指令。\n\n```go\nsubQuery := rushia.NewQuery(\"VIPUsers\").Select(\"UserID\")\n\nrushia.NewQuery(\"Users\").Where(\"ID IN ?\", subQuery).Select()\n// 等效於：SELECT * FROM Users WHERE ID IN (SELECT UserID FROM VIPUsers)\n```\n\n#### 插入\n\n插入新資料時也可以使用子指令，但必須確保子指令只會回傳一個欄位與單行資料。\n\n```go\nsubQuery := rushia.NewQuery(\"Users\").Where(\"ID = ?\", 6).SelectOne(\"Name\")\n\nrushia.NewQuery(\"Products\").Insert(rushia.H{\n\t\"ProductName\": \"測試商品\",\n\t\"UserID\":      subQuery,\n\t\"LastUpdated\": rushia.NewExpr(\"NOW()\")\n})\n// 等效於：INSERT INTO Products (ProductName, UserID, LastUpdated) VALUES (?, (SELECT Name FROM Users WHERE ID = 6 LIMIT 1), NOW())\n```\n\n#### 加入\n\n就算是加入表格的時候也可以用上子指令，但你需要使用 `As` 為子指令建立別名。\n\n```go\nsubQuery := rushia.NewQuery(\"Users\").As(\"Users\").Where(\"Active = ?\", 1).Select()\n\nrushia.\n\tNewQuery(\"Products\").\n\tLeftJoin(subQuery, \"Products.UserID = Users.ID\").\n\tSelect(\"Users.Username\", \"Products.ProductName\")\n// 等效於：SELECT Users.Username, Products.ProductName FROM Products AS Products LEFT JOIN (SELECT * FROM Users WHERE Active = ?) AS Users ON Products.UserID = Users.ID\n```\n\n### 子指令置換\n\n在使用表達式或生指令的時候可能會希望用上子指令，這個時候可以傳入一個子指令則會替換相對應的 `?` 預置變數。\n\n```go\nsubQuery := rushia.NewQuery(\"Locations\").Select()\nrawQuery := rushia.NewRawQuery(\"SELECT UserID FROM Users WHERE EXISTS (?)\", subQuery)\n\nNewQuery(\"Products\").WhereExists(rawQuery).Select()\n// 等效於：SELECT * FROM Products WHERE EXISTS (SELECT UserID FROM Users WHERE EXISTS (SELECT * FROM Locations))\n```\n\n### 指令關鍵字\n\nRushia 也支援設置指令關鍵字。\n\n```go\nrushia.NewQuery(\"Users\").SetQueryOption(\"FOR UPDATE\").Select()\n// 等效於：SELECT * FROM Users FOR UPDATE\n\nrushia.NewQuery(\"Users\").SetQueryOption(\"SQL_NO_CACHE\").Select()\n// 等效於：SELECT SQL_NO_CACHE * FROM Users\n\nrushia.NewQuery(\"Users\").SetQueryOption(\"LOW_PRIORITY\", \"IGNORE\").Insert(data)\n// Gives: INSERT LOW_PRIORITY IGNORE INTO Users ...\n```\n\n## 複雜場景範例\n\n```go\njobHistories := rushia.NewQuery(\"JobHistories\").\n\tWhere(\"DepartmentID BETWEEN ? AND ?\", 50, 100).\n\tSelect(\"JobID\")\njobs := rushia.NewQuery(\"Jobs\").\n\tWhere(\"JobID IN ?\", jobHistories).\n\tGroupBy(\"JobID\").\n\tSelect(\"JobID\", \"AVG(MinSalary) AS MyAVG\")\nmaxAverage := rushia.NewQuery(jobs).\n\tAs(\"SS\").\n\tSelect(\"MAX(MyAVG)\")\nemployees := rushia.NewQuery(\"Employees\").\n\tGroupBy(\"JobID\").\n\tHaving(\"AVG(Salary) \u003c ?\", maxAverage).\n\tSelect(\"JobID\", \"AVG(Salary)\")\n\n// 等效於：\n// SELECT JobID,\n//        AVG(Salary)\n// FROM   Employees\n// HAVING AVG(Salary) \u003c (SELECT MAX(MyAVG)\n//                       FROM   (SELECT JobID,\n//                                      AVG(MinSalary) AS MyAVG\n//                               FROM   Jobs\n//                               WHERE  JobID IN (SELECT JobID\n//                                                FROM   JobHistories\n//                                                WHERE  DepartmentID BETWEEN 50\n//                                                       AND 100\n//                                               )\n//                               GROUP  BY JobID) AS SS)\n// GROUP  BY job_id;\n\nagents := rushia.NewQuery(\"Agents\").\n\tWhere(\"Commission \u003c ?\", 0.12).\n\tSelect()\ncustomers := rushia.NewQuery(\"Customers\").\n\tWhere(\"Grade = ?\", 3).\n\tWhere(\"CustomerCountry \u003c\u003e ?\", \"India\").\n\tWhere(\"OpeningAmount \u003c ?\", 7000).\n\tWhere(\"EXISTS ?\", agents).\n\tSelect(\"OutstandingAmount\")\norders := rushia.NewQuery(\"Orders\").\n\tWhere(\"OrderAmount \u003e ?\", 2000).\n\tWhere(\"OrderDate \u003c ?\", \"01-SEP-08\").\n\tWhere(\"AdvanceAmount \u003c ?\", rushia.NewExpr(\"ANY (?)\", customers)).\n\tSelect(\"OrderNum\", \"OrderDate\", \"OrderAmount\", \"AdvanceAmount\")\n\n// 等效於：\n// SELECT OrderNum,\n//        OrderDate,\n//        OrderAmount,\n//        AdvanceAmount\n// FROM   Orders\n// WHERE  OrderAmount \u003e 2000\n//        AND OrderDate \u003c '01-SEP-08'\n//        AND AdvanceAmount \u003c ANY (SELECT OutstandingAmount\n//                                 FROM   Customers\n//                                 WHERE  Grade = 3\n//                                        AND CustomerCountry \u003c\u003e 'India'\n//                                        AND OpeningAmount \u003c 7000\n//                                        AND EXISTS (SELECT *\n//                                                    FROM   Agents\n//                                                    WHERE  Commission \u003c 0.12));\n```\n\n## 相關連結\n\n這裡是 Rushia 受啟發，或是和資料庫有所關聯的連結。\n\n-   [kisielk/sqlstruct](http://godoc.org/github.com/kisielk/sqlstruct)\n-   [jmoiron/sqlx](https://github.com/jmoiron/sqlx)\n-   [russross/meddler](https://github.com/russross/meddler)\n-   [jinzhu/gorm](https://github.com/jinzhu/gorm)\n-   [doug-martin/goqu](https://github.com/doug-martin/goqu)\n-   [gocraft/dbr](https://github.com/gocraft/dbr)\n-   [go-ozzo/ozzo-dbx](https://github.com/go-ozzo/ozzo-dbx)\n-   [kyleconroy/sqlc](https://github.com/kyleconroy/sqlc)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteacat%2Frushia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fteacat%2Frushia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fteacat%2Frushia/lists"}