Base Project
This commit is contained in:
170
docs/sqlc/config.md
Normal file
170
docs/sqlc/config.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# sqlc.yaml — Configuration Reference (Version 2)
|
||||
|
||||
sqlc sử dụng **Configuration Version 2** khi khai báo `version: "2"` ở đầu file. Dưới đây là bộ quy tắc và danh sách đầy đủ các key.
|
||||
|
||||
---
|
||||
|
||||
## Cấu trúc tổng thể
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
|
||||
sql:
|
||||
- engine: "<engine>"
|
||||
queries: "<path>"
|
||||
schema: "<path>"
|
||||
gen:
|
||||
go:
|
||||
package: "<name>"
|
||||
out: "<path>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Các key cấp gốc (root-level)
|
||||
|
||||
| Key | Kiểu | Bắt buộc | Mô tả |
|
||||
| ----------- | ----- | -------- | ------------------------------------------------------------------------ |
|
||||
| `version` | `"2"` | ✅ | Khai báo phiên bản cấu hình. Giá trị `"2"` cho Version 2. |
|
||||
| `sql` | list | ✅ | Danh sách các block cấu hình, mỗi block sinh code cho một ngôn ngữ đích. |
|
||||
| `overrides` | map | ❌ | (Deprecated v1) — Không dùng trong v2, thay bằng `gen.<lang>.overrides`. |
|
||||
| `rename` | map | ❌ | (Deprecated v1) — Không dùng trong v2, thay bằng `gen.<lang>.rename`. |
|
||||
|
||||
---
|
||||
|
||||
## Các key bên trong mỗi phần tử của `sql[]`
|
||||
|
||||
| Key | Kiểu | Bắt buộc | Mô tả |
|
||||
| ------------------------ | ----------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `engine` | string | ✅ | CSDL mục tiêu. Giá trị: `"postgresql"`, `"mysql"`, `"sqlite"`. |
|
||||
| `queries` | string / string[] | ✅ | Đường dẫn tới thư mục/file chứa các query `.sql`. Có thể là mảng nhiều path. |
|
||||
| `schema` | string / string[] | ✅ | Đường dẫn tới thư mục/file chứa schema DDL (`.sql`). |
|
||||
| `strict_function_checks` | bool | ❌ | Nếu `true`, sqlc sẽ báo lỗi khi gọi function không tồn tại trong schema. Mặc định `false`. |
|
||||
| `strict_order_by` | bool | ❌ | Nếu `true`, yêu cầu tất cả column trong `ORDER BY` phải tồn tại. Mặc định `false` (chỉ cho PostgreSQL). |
|
||||
| `query_parameter_limit` | int | ❌ | Giới hạn số lượng parameter trong một query. Mặc định `1` (nếu > 1 thì sqlc ưu tiên sinh `sql.NamedArg`). Đặt `0` để bỏ giới hạn. |
|
||||
| `codegen` | list | ❌ | Danh sách cấu hình cho **plugin codegen** bên ngoài. Mỗi item có `out`, `plugin`, `options`. |
|
||||
| `gen` | map | ✅ (ít nhất 1) | Map các ngôn ngữ sinh code. Các key con: `go`, `kotlin`, `python`, `json`, `typescript`, `java`, `swift`, `rust`, `csharp`. |
|
||||
|
||||
---
|
||||
|
||||
## Các key bên trong `gen.go`
|
||||
|
||||
| Key | Kiểu | Bắt buộc | Mô tả |
|
||||
| -------------------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `out` | string | ✅ | Thư mục output cho Go code sinh ra. |
|
||||
| `package` | string | ✅ | Tên Go package. |
|
||||
| `sql_package` | string | ❌ | Package SQL driver. Giá trị: `"database/sql"`, `"pgx/v4"`, `"pgx/v5"`, `"lib/pq"`. Mặc định `"database/sql"`. |
|
||||
| `sql_driver` | string | ❌ | Tên driver cụ thể, dùng để sinh import đúng. VD: `"github.com/jackc/pgx/v5/stdlib"`. |
|
||||
| `emit_json_tags` | bool | ❌ | Nếu `true`, sinh `json:"column_name"` tag cho struct field. Mặc định `false`. |
|
||||
| `emit_db_tags` | bool | ❌ | Nếu `true`, sinh `db:"column_name"` tag. Mặc định `false`. |
|
||||
| `emit_prepared_queries` | bool | ❌ | Nếu `true`, sinh method `Prepare` cho mỗi query. Mặc định `false`. |
|
||||
| `emit_interface` | bool | ❌ | Nếu `true`, sinh interface ` Querier` thay vì chỉ struct. Mặc định `false`. |
|
||||
| `emit_empty_slices` | bool | ❌ | Nếu `true`, trả về `[]T` rỗng thay vì `nil` khi không có row. Mặc định `false`. |
|
||||
| `emit_result_struct_pointers` | bool | ❌ | Sinh con trỏ `*T` cho result struct. Mặc định `false`. |
|
||||
| `emit_params_struct_pointers` | bool | ❌ | Sinh con trỏ `*T` cho params struct. Mặc định `false`. |
|
||||
| `emit_method_with_db_argument` | bool | ❌ | Nếu `true`, mỗi method nhận thêm `DB` argument, cho phép dùng transaction dễ hơn. Mặc định `false`. |
|
||||
| `emit_pointers_for_null_types` | bool | ❌ | Nếu `true`, dùng con trỏ cho null type thay vì `sql.Null*`. Mặc định `false`. |
|
||||
| `emit_enum_valid_method` | bool | ❌ | Sinh method `Valid()` cho enum type. Mặc định `false`. |
|
||||
| `emit_all_enum_values` | bool | ❌ | Sinh constant cho tất cả giá trị enum. Mặc định `false`. |
|
||||
| `emit_build_tags` | string | ❌ | Thêm Go build tag vào file sinh ra. VD: `"//go:build linux"`. |
|
||||
| `json_tags_case_style` | string | ❌ | Style cho JSON tag. Giá trị: `"camel"`, `"pascal"`, `"snake"`, `"none"`. Mặc định phụ thuộc vào `emit_json_tags`. |
|
||||
| `output_db_file_name` | string | ❌ | Tên file chứa `DB` struct. Mặc định `"db.go"`. |
|
||||
| `output_models_file_name` | string | ❌ | Tên file chứa model struct. Mặc định `"models.go"`. |
|
||||
| `output_querier_file_name` | string | ❌ | Tên file chứa interface. Mặc định `"querier.go"`. |
|
||||
| `output_files_suffix` | string | ❌ | Hậu tố cho file query. Mặc định `""`. VD: `"_sql"` → `user_sql.go`. |
|
||||
| `inflection_exclude_table_names` | list | ❌ | Danh sách tên table không áp dụng quy tắc số nhiều. VD: `["user"]`. |
|
||||
| `overrides` | list | ❌ | Ghi đè kiểu dữ liệu cho column cụ thể hoặc cho kiểu Go toàn cục (xem chi tiết bên dưới). |
|
||||
| `rename` | map | ❌ | Map đổi tên. Key = tên cần đổi, Value = tên mới. Dùng để rename struct field. |
|
||||
| `import` | string | ❌ | Import path của Go module dùng trong generated code. |
|
||||
|
||||
---
|
||||
|
||||
## Cấu trúc của `overrides[]` (bên trong `gen.go`)
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
- db_type: "uuid"
|
||||
go_type: "github.com/google/uuid.UUID"
|
||||
- db_type: "timestamptz"
|
||||
go_type: "time.Time"
|
||||
- column: "users.status"
|
||||
go_type: "UserStatus"
|
||||
go_struct_tag:
|
||||
tags:
|
||||
json: "status,omitempty"
|
||||
- db_type: "text"
|
||||
go_type:
|
||||
import: "github.com/lib/pq"
|
||||
type: "StringArray"
|
||||
nullable: true
|
||||
```
|
||||
|
||||
| Key | Mô tả |
|
||||
| --------------- | ------------------------------------------------------------------------- |
|
||||
| `db_type` | Kiểu dữ liệu SQL cần ghi đè. Dùng cùng với `go_type`. |
|
||||
| `column` | Đường dẫn `"table.column"` cụ thể. Ưu tiên cao hơn `db_type`. |
|
||||
| `go_type` | Kiểu Go thay thế. Có thể là string hoặc object `{import, type, pointer}`. |
|
||||
| `nullable` | bool — Nếu `true`, áp dụng cho phiên bản nullable của kiểu. |
|
||||
| `go_struct_tag` | Custom struct tag cho field. |
|
||||
|
||||
---
|
||||
|
||||
## `gen.json`
|
||||
|
||||
| Key | Kiểu | Bắt buộc | Mô tả |
|
||||
| ---------- | ------ | -------- | --------------------------------------------------- |
|
||||
| `out` | string | ✅ | Thư mục output file JSON. |
|
||||
| `indent` | string | ❌ | Ký tự indent. Mặc định `" "`. |
|
||||
| `filename` | string | ❌ | Tên file output. Mặc định `"codegen_request.json"`. |
|
||||
|
||||
---
|
||||
|
||||
## `gen.typescript`
|
||||
|
||||
| Key | Kiểu | Bắt buộc | Mô tả |
|
||||
| ------------------- | ------ | -------- | ------------------------------------------------------ |
|
||||
| `out` | string | ✅ | Thư mục output. |
|
||||
| `plugin` | string | ❌ | Tên plugin (nếu dùng plugin ngoài). |
|
||||
| `runtime` | string | ❌ | Runtime cho generated code: `"node"` hoặc `"browser"`. |
|
||||
| `driver` | string | ❌ | Driver: `"pg"` hoặc `"pg-query-stream"`. |
|
||||
| `emit_json_tags` | bool | ❌ | Sinh JSON tag cho property. |
|
||||
| `emit_result_types` | bool | ❌ | Sinh interface cho result. |
|
||||
|
||||
---
|
||||
|
||||
## Ví dụ hoàn chỉnh
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
|
||||
sql:
|
||||
- engine: "postgresql"
|
||||
queries: "query/"
|
||||
schema: "schema/"
|
||||
gen:
|
||||
go:
|
||||
package: "db"
|
||||
out: "db"
|
||||
sql_package: "pgx/v5"
|
||||
emit_json_tags: true
|
||||
emit_interface: true
|
||||
emit_empty_slices: true
|
||||
emit_prepared_queries: false
|
||||
json_tags_case_style: "camel"
|
||||
overrides:
|
||||
- db_type: "uuid"
|
||||
go_type: "github.com/google/uuid.UUID"
|
||||
- db_type: "timestamptz"
|
||||
go_type: "time.Time"
|
||||
- column: "orders.status"
|
||||
go_type:
|
||||
import: "warehouse-management/types"
|
||||
type: "OrderStatus"
|
||||
pointer: true
|
||||
inflection_exclude_table_names:
|
||||
- "status"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Tóm lại**: Key bắt buộc tối thiểu cho một config sqlc v2 hoạt động là `version`, `sql[].engine`, `sql[].queries`, `sql[].schema`, và ít nhất một block `gen.<lang>` với `out` + `package` (hoặc tương đương cho ngôn ngữ khác).
|
||||
400
docs/sqlc/query.md
Normal file
400
docs/sqlc/query.md
Normal file
@@ -0,0 +1,400 @@
|
||||
# Bộ quy tắc viết file query trong sqlc
|
||||
|
||||
---
|
||||
|
||||
## 1. Cấu trúc cơ bản
|
||||
|
||||
Mỗi file query là một file `.sql` thông thường, nhưng chứa **sqlc annotation** ở dạng SQL comment để sqlc phân tích metadata.
|
||||
|
||||
```sql
|
||||
-- name: <TênMethod> <:command>
|
||||
-- <comment mô tả (tuỳ chọn)>
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
```
|
||||
|
||||
**Cú pháp annotation:**
|
||||
|
||||
```
|
||||
-- name: <MethodName> <:command>
|
||||
```
|
||||
|
||||
- `MethodName` → Tên method sẽ được sinh trong Go code (phải là identifier hợp lệ, khuyến nghị dùng **camelCase** hoặc **PascalCase**).
|
||||
- `:command` → Loại thao tác, quyết định kiểu trả về.
|
||||
|
||||
---
|
||||
|
||||
## 2. Các loại `:command`
|
||||
|
||||
| Command | Kiểu trả về (Go) | Dùng khi |
|
||||
| ------------- | --------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `:one` | `(T, error)` | Trả về **đúng 1 row**. Nếu không tìm thấy → `sql.ErrNoRows`. |
|
||||
| `:many` | `([]T, error)` | Trả về **danh sách rows**. Có thể rỗng. |
|
||||
| `:exec` | `(sql.Result, error)` | Thực thi **không trả về row** (INSERT/UPDATE/DELETE không cần data trả về). |
|
||||
| `:execrows` | `(int64, error)` | Giống `:exec` nhưng trả về **số rows affected**. |
|
||||
| `:execresult` | `(sql.Result, error)` | Giống `:exec`, trả về `sql.Result` đầy đủ (có `.LastInsertId()` + `.RowsAffected()`). |
|
||||
| `:copyfrom` | `(int64, error)` | Dùng cho PostgreSQL `COPY FROM`, truyền slice struct. |
|
||||
|
||||
---
|
||||
|
||||
## 3. Quy tắc viết annotation
|
||||
|
||||
### 3.1. Annotation phải nằm **ngay trên** câu query
|
||||
|
||||
```sql
|
||||
-- ✅ ĐÚNG: annotation ngay trên query
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- ❌ SAI: có dòng trống giữa annotation và query
|
||||
-- name: GetUser :one
|
||||
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
```
|
||||
|
||||
### 3.2. Mỗi query phải kết thúc bằng dấu `;`
|
||||
|
||||
```sql
|
||||
-- ✅ ĐÚNG
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- ❌ SAI: thiếu dấu ;
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1
|
||||
```
|
||||
|
||||
### 3.3. Tên method **không được trùng** trong cùng một file (hoặc cùng package queries)
|
||||
|
||||
```sql
|
||||
-- ❌ SAI: trùng tên
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- name: GetUser :many
|
||||
SELECT * FROM users WHERE role = $1;
|
||||
```
|
||||
|
||||
### 3.4. Có thể viết nhiều query trong 1 file
|
||||
|
||||
```sql
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- name: ListUsers :many
|
||||
SELECT * FROM users ORDER BY created_at DESC;
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (id, username, email)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Tham số (Parameters)
|
||||
|
||||
### 4.1. PostgreSQL — dùng positional params `$1, $2, ...`
|
||||
|
||||
```sql
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (username, email, password_hash)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
```
|
||||
|
||||
### 4.2. Sử dụng `sqlc.arg()` — **khuyến nghị dùng** vì rõ ràng hơn
|
||||
|
||||
```sql
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (username, email, password_hash)
|
||||
VALUES (sqlc.arg(username), sqlc.arg(email), sqlc.arg(password_hash))
|
||||
RETURNING *;
|
||||
```
|
||||
|
||||
> Khi dùng `sqlc.arg()`, sqlc sinh **tên param có ý nghĩa** trong Go struct thay vì `ID`/`Column2` không rõ ràng.
|
||||
|
||||
### 4.3. `sqlc.narg()` — nullable parameter
|
||||
|
||||
Dùng khi tham số có thể là `NULL`:
|
||||
|
||||
```sql
|
||||
-- name: SearchUsers :many
|
||||
SELECT * FROM users
|
||||
WHERE (
|
||||
sqlc.narg(username) IS NULL OR username = sqlc.narg(username)
|
||||
)
|
||||
AND (
|
||||
sqlc.narg(email) IS NULL OR email = sqlc.narg(email)
|
||||
);
|
||||
```
|
||||
|
||||
sqlc sẽ sinh kiểu `NullString` hoặc con trỏ `*string` (tuỳ config) cho các param này.
|
||||
|
||||
### 4.4. Truyền struct/array — `sqlc.arg()` với nhiều field
|
||||
|
||||
```sql
|
||||
-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
username = COALESCE(sqlc.arg(username), username),
|
||||
email = COALESCE(sqlc.arg(email), email)
|
||||
WHERE id = sqlc.arg(id)
|
||||
RETURNING *;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. `RETURNING *` — Khuyến nghị dùng với `:one` / `:many`
|
||||
|
||||
Khi `INSERT`, `UPDATE`, `DELETE` mà bạn muốn nhận lại dữ liệu, hãy dùng `RETURNING *`:
|
||||
|
||||
```sql
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (username, email)
|
||||
VALUES ($1, $2)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUser :one
|
||||
UPDATE users SET email = $2 WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :one
|
||||
DELETE FROM users WHERE id = $1
|
||||
RETURNING *;
|
||||
```
|
||||
|
||||
Nếu không có `RETURNING *`, phải dùng `:exec` hoặc `:execrows`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Quy tắc cho `SELECT *`
|
||||
|
||||
sqlc sẽ phân tích schema và thay `*` bằng danh sách cột cụ thể trong code sinh ra. Tuy nhiên:
|
||||
|
||||
```sql
|
||||
-- ✅ Khuyến nghị: chỉ định cột rõ ràng
|
||||
-- name: GetUser :one
|
||||
SELECT id, username, email, created_at FROM users WHERE id = $1;
|
||||
|
||||
-- ✅ Cũng hợp lệ: dùng *
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
```
|
||||
|
||||
> **Khi JOIN nhiều bảng**, KHÔNG nên dùng `SELECT *` vì có thể trùng tên cột. Nên alias rõ ràng.
|
||||
|
||||
---
|
||||
|
||||
## 7. JOIN và Alias
|
||||
|
||||
```sql
|
||||
-- name: GetUserWithRole :one
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.email,
|
||||
r.name AS role_name
|
||||
FROM users u
|
||||
JOIN user_roles ur ON u.id = ur.user_id
|
||||
JOIN roles r ON ur.role_id = r.id
|
||||
WHERE u.id = $1;
|
||||
```
|
||||
|
||||
sqlc sẽ sinh struct với các field `ID`, `Username`, `Email`, `RoleName`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Sử dụng `sqlc.embed()`
|
||||
|
||||
Dùng khi muốn **nhúng toàn bộ một struct** vào kết quả (từ sqlc v1.18+):
|
||||
|
||||
```sql
|
||||
-- name: GetUserWithRole :one
|
||||
SELECT
|
||||
sqlc.embed(u),
|
||||
r.name AS role_name
|
||||
FROM users u
|
||||
JOIN user_roles ur ON u.id = ur.user_id
|
||||
JOIN roles r ON ur.role_id = r.id
|
||||
WHERE u.id = $1;
|
||||
```
|
||||
|
||||
→ Go struct sinh ra sẽ có dạng:
|
||||
|
||||
```go
|
||||
type GetUserWithRoleRow struct {
|
||||
User // embedded struct từ bảng users
|
||||
RoleName string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Sử dụng `sqlc.slice()` — IN clause
|
||||
|
||||
Dùng cho `WHERE id IN ($1, $2, ...)` với số lượng phần tử động:
|
||||
|
||||
```sql
|
||||
-- name: GetUsersByIDs :many
|
||||
SELECT * FROM users
|
||||
WHERE id = ANY(sqlc.slice(ids));
|
||||
```
|
||||
|
||||
hoặc với PostgreSQL:
|
||||
|
||||
```sql
|
||||
-- name: GetUsersByIDs :many
|
||||
SELECT * FROM users
|
||||
WHERE id = ANY($1::uuid[]);
|
||||
```
|
||||
|
||||
Nhưng `sqlc.slice()` được khuyến nghị hơn vì sqlc sẽ tự xử lý kiểu.
|
||||
|
||||
---
|
||||
|
||||
## 10. Sub-query và CTE
|
||||
|
||||
sqlc hỗ trợ đầy đủ:
|
||||
|
||||
```sql
|
||||
-- name: GetUserStats :one
|
||||
WITH user_orders AS (
|
||||
SELECT user_id, COUNT(*) AS order_count
|
||||
FROM orders
|
||||
GROUP BY user_id
|
||||
)
|
||||
SELECT u.*, COALESCE(uo.order_count, 0) AS order_count
|
||||
FROM users u
|
||||
LEFT JOIN user_orders uo ON u.id = uo.user_id
|
||||
WHERE u.id = $1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. CASE expression
|
||||
|
||||
```sql
|
||||
-- name: ListUsersWithStatus :many
|
||||
SELECT
|
||||
id,
|
||||
username,
|
||||
CASE
|
||||
WHEN deleted_at IS NOT NULL THEN 'deleted'
|
||||
WHEN last_login_at > NOW() - INTERVAL '30 days' THEN 'active'
|
||||
ELSE 'inactive'
|
||||
END AS status
|
||||
FROM users;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Transaction — không viết trong file query
|
||||
|
||||
sqlc **không quản lý transaction** trong file `.sql`. Transaction được xử lý ở tầng ứng dụng Go:
|
||||
|
||||
```go
|
||||
// Trong Go code (không phải file .sql)
|
||||
tx, _ := db.BeginTx(ctx, nil)
|
||||
q := New(tx) // tạo Queries instance với tx
|
||||
q.CreateUser(ctx, ...)
|
||||
q.CreateUserRole(ctx, ...)
|
||||
tx.Commit()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Comment thường vs sqlc annotation
|
||||
|
||||
```sql
|
||||
-- Đây là comment thường, sqlc bỏ qua
|
||||
-- name: GetUser :one ← Đây là sqlc annotation
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
/*
|
||||
Multi-line comment cũng được
|
||||
sqlc bỏ qua
|
||||
*/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Quy tắc đặt tên file
|
||||
|
||||
| Quy ước | Ví dụ |
|
||||
| ------------------------------------------------------------------ | ----------------------------------------- |
|
||||
| 1 file = 1 bảng chính | `users.sql`, `orders.sql`, `products.sql` |
|
||||
| Đặt tên theo **feature/domain** | `auth.sql`, `inventory.sql` |
|
||||
| File nằm trong thư mục được chỉ định ở `queries` trong `sqlc.yaml` | `./db/queries/` |
|
||||
|
||||
---
|
||||
|
||||
## 15. Toàn bộ mẫu tham khảo
|
||||
|
||||
```sql
|
||||
-- name: GetUser :one
|
||||
SELECT * FROM users WHERE id = sqlc.arg(id);
|
||||
|
||||
-- name: GetUserByEmail :one
|
||||
SELECT * FROM users WHERE email = sqlc.arg(email);
|
||||
|
||||
-- name: ListUsers :many
|
||||
SELECT * FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT sqlc.arg(limit) OFFSET sqlc.arg(offset);
|
||||
|
||||
-- name: SearchUsers :many
|
||||
SELECT * FROM users
|
||||
WHERE (
|
||||
sqlc.narg(username) IS NULL OR username ILIKE '%' || sqlc.narg(username) || '%'
|
||||
)
|
||||
AND (
|
||||
sqlc.narg(email) IS NULL OR email ILIKE '%' || sqlc.narg(email) || '%'
|
||||
);
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (id, username, email, password_hash)
|
||||
VALUES (
|
||||
sqlc.arg(id),
|
||||
sqlc.arg(username),
|
||||
sqlc.arg(email),
|
||||
sqlc.arg(password_hash)
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
username = COALESCE(sqlc.arg(username), username),
|
||||
email = COALESCE(sqlc.arg(email), email)
|
||||
WHERE id = sqlc.arg(id)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :execrows
|
||||
DELETE FROM users WHERE id = sqlc.arg(id);
|
||||
|
||||
-- name: GetUsersByIDs :many
|
||||
SELECT * FROM users WHERE id = ANY(sqlc.slice(ids));
|
||||
|
||||
-- name: CountUsers :one
|
||||
SELECT COUNT(*) AS count FROM users;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tóm tắt nhanh
|
||||
|
||||
| Quy tắc | Mô tả |
|
||||
| -------------------------- | ----------------------------------------------------- |
|
||||
| Annotation format | `-- name: MethodName :command` |
|
||||
| Phải có `;` kết thúc | Mỗi query kết thúc bằng dấu chấm phẩy |
|
||||
| Annotation ngay trên query | Không có dòng trống ở giữa |
|
||||
| Tên method không trùng | Trong cùng package queries |
|
||||
| Dùng `sqlc.arg()` | Khuyến nghị thay vì `$1` để sinh tên param có ý nghĩa |
|
||||
| Dùng `sqlc.narg()` | Cho nullable parameter |
|
||||
| Dùng `sqlc.slice()` | Cho `IN (...)` dynamic |
|
||||
| Dùng `sqlc.embed()` | Để nhúng struct khi JOIN |
|
||||
| `RETURNING *` | Khi cần dữ liệu trả về với INSERT/UPDATE/DELETE |
|
||||
| Transaction | Không viết trong `.sql`, xử lý ở Go code |
|
||||
Reference in New Issue
Block a user