Chuyển đến nội dung
Phase 2.1: chuyển store sang sqlc

Phase 2.1: chuyển store sang sqlc

15 tháng 10, 2026

Đã xảy ra gì

Giai đoạn 2.1 chuyển mọi query trong internal/store/pg sang queries/*.sql và để sqlc v1.31.1 sinh ra code Go chạy chúng. Các file viết tay giờ chỉ dựng tham số từ tenant scope, gọi method được sinh ra và chuyển đổi kết quả. sqlc chạy qua go run ở một phiên bản được ghim, nên nó không nằm trong go.mod hay binary. make generate sinh lại code và make sqlc-check thất bại khi code bị stale. Không cần escape hatch nào. Các test của giai đoạn 2 vẫn qua mà không sửa, trừ test kiểm tra audit chỉ thêm vào (append-only), giờ đọc các file query.

Các type override (uuid.UUID của stdlib, time.Time, json.RawMessage, store.Role, store.TenantKind) cùng hai lần rename làm cho hầu hết row struct được sinh ra có các field giống hệt type của store, nên các mapper là phép chuyển đổi struct của Go như store.User(u). Một thay đổi schema mà type của store không theo kịp giờ sẽ không compile được.

Điều bất ngờ

  • Weight của Hugo là số nguyên. Khi giai đoạn 2 và 2.1 cùng weight 2, Hugo sắp theo title và đặt 2.1 lên trước. Giờ mọi file phase và learning doc đều có weight = phase x 10.
  • Bộ sinh trang plan và template đọc số giai đoạn như số nguyên và cần được hỗ trợ số thập phân.

Review tìm thấy gì

Không có lỗi. Ba mục nhẹ đã sửa: test append-only giờ kiểm tra mọi file query, vì một lệnh purge có thể xuất hiện ở bất kỳ file nào (một lệnh delete from audit_events thử nghiệm làm nó thất bại); make generate xóa các *.sql.go cũ trước, vì sqlc không bao giờ xóa output; và bộ sinh plan cắt dấu chấm cuối sau số giai đoạn thập phân. Để lại như đã biết: dạng filter ($n is null or col = $n) có thể làm index không được dùng khi Postgres chuyển sang generic plan, và API được sinh ra được export bên trong package pg.

Một lần review thứ hai cho cả PR thấy code ổn còn tài liệu khóa học sai ở vài chỗ, tất cả đã sửa:

  • Bài học bảo người đọc tìm db.statement trong Tempo. otelpgx v0.13 theo semantic convention mới hơn và ghi db.query.text, và nó đặt tên span theo động từ SQL, bỏ qua comment của sqlc. Bài học giờ đưa ra query TraceQL.
  • Các bài tập “phá quy tắc tenant” xóa predicate, làm mất tham số @tenant_id, nên build thất bại trước khi test cô lập chạy được. Các bài tập giờ giữ tham số (@tenant_id::uuid is not null) và cho thấy lỗi compile như một bài học thứ hai.
  • Contract của giai đoạn 4 vẫn nói pgx.CollectRows và một AND created_by = $n dựng bằng chuỗi. Các bước của nó giờ dùng file query, member predicate sqlc.narg, và một insert unnest cho batch message, vì sqlc không diễn đạt được danh sách VALUES có độ dài thay đổi.
  • Nhỏ hơn: sqlc đặt comment đầu file lên Go doc của method đầu tiên, nên các file query bỏ phần header; make generate chạy sqlc compile trước khi xóa output cũ; sơ đồ kiến trúc, số lượng giai đoạn và yêu cầu cgo đã được cập nhật.

Bước tiếp theo

Push và mở PR, merge, tag phase-02.1, rồi giai đoạn 3.

Bản ghi công việc lịch sử, không phải căn cứ lâu dài. Hãy ưu tiên docs/specs/ADR cho các quyết định hiện hành.