Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Commit ed0aca4

Browse files
kalbasitclaude
andcommitted
docs: add README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 68a8d2d commit ed0aca4

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

README.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# sqlc-multi-db
2+
3+
A code generator that wraps [sqlc](https://sqlc.dev/)-generated code to provide a unified interface across multiple database engines (SQLite, PostgreSQL, MySQL).
4+
5+
## Overview
6+
7+
When using sqlc with multiple database backends, each engine generates its own `Querier` interface and model types. `sqlc-multi-db` reads the `Querier` interface from your PostgreSQL-generated package and produces:
8+
9+
- `generated_querier.go` — a common `Querier` interface in the parent package
10+
- `generated_models.go` — common domain model types (converted from engine-specific types)
11+
- `generated_errors.go` — shared sentinel errors (`ErrNotFound`, `ErrMismatchedSlices`)
12+
- `generated_wrapper_sqlite.go` — SQLite wrapper implementing the common `Querier`
13+
- `generated_wrapper_postgres.go` — PostgreSQL wrapper implementing the common `Querier`
14+
- `generated_wrapper_mysql.go` — MySQL/MariaDB wrapper implementing the common `Querier`
15+
16+
The wrappers handle engine differences automatically:
17+
18+
- **MySQL `INSERT ... RETURNING`**: Simulated using `LastInsertId` + a `GetByID` query
19+
- **MySQL `UPDATE ... RETURNING`**: Simulated using `RowsAffected` + a `GetByID` query
20+
- **Bulk operations** (`@bulk-for` annotation): SQLite/MySQL loop over slices; PostgreSQL delegates directly
21+
- **Nullable types**: `sql.NullString`, `sql.NullInt64`, etc. are converted to/from common models
22+
23+
## Requirements
24+
25+
- Go 1.24+ (uses the `tool` directive in `go.mod`)
26+
- sqlc with queries for all three engines: `query.sqlite.sql`, `query.postgres.sql`, `query.mysql.sql`
27+
- sqlc output packages named `sqlitedb`, `postgresdb`, `mysqldb` (siblings of the target package)
28+
29+
## Installation
30+
31+
Add `sqlc-multi-db` as a tool in your `go.mod`:
32+
33+
```bash
34+
go get -tool github.com/kalbasit/sqlc-multi-db@latest
35+
```
36+
37+
Or manually add the directives:
38+
39+
```
40+
tool github.com/kalbasit/sqlc-multi-db
41+
42+
require github.com/kalbasit/sqlc-multi-db vX.Y.Z
43+
```
44+
45+
## Usage
46+
47+
Add a `generate.go` file in your database package (e.g., `pkg/database/generate.go`):
48+
49+
```go
50+
package database
51+
52+
//go:generate go tool github.com/kalbasit/sqlc-multi-db postgresdb/querier.go
53+
```
54+
55+
Then run:
56+
57+
```bash
58+
go generate ./pkg/database
59+
```
60+
61+
### Expected Directory Layout
62+
63+
```
64+
pkg/database/
65+
sqlitedb/ # sqlc-generated (sqlite engine)
66+
postgresdb/ # sqlc-generated (postgres engine) ← source of truth
67+
mysqldb/ # sqlc-generated (mysql engine)
68+
database.go # your Open() factory
69+
errors.go # your custom errors (IsDeadlockError, etc.)
70+
generate.go # //go:generate directive
71+
generated_errors.go # generated
72+
generated_models.go # generated
73+
generated_querier.go # generated
74+
generated_wrapper_sqlite.go # generated
75+
generated_wrapper_postgres.go # generated
76+
generated_wrapper_mysql.go # generated
77+
```
78+
79+
## Bulk Operations (`@bulk-for`)
80+
81+
sqlc does not natively support bulk inserts on MySQL/SQLite the same way PostgreSQL does with `UNNEST`. Use the `@bulk-for` annotation to declare that a query is the bulk variant of a single-row query:
82+
83+
```sql
84+
-- name: AddBookTag :exec
85+
INSERT INTO book_tags (book_id, tag_id) VALUES (?, ?);
86+
87+
-- name: AddBookTags :exec @bulk-for AddBookTag
88+
INSERT INTO book_tags (book_id, tag_id)
89+
SELECT unnest(@book_ids::bigint[]), unnest(@tag_ids::bigint[]);
90+
```
91+
92+
The generator will:
93+
- On **PostgreSQL**: delegate `AddBookTags` directly to the underlying sqlc implementation
94+
- On **SQLite/MySQL**: generate a loop that calls `AddBookTag` once per element
95+
96+
## Example
97+
98+
The [`example/`](./example/) directory contains a working multi-engine project with `books`, `tags`, and `book_tags` tables demonstrating all supported features.
99+
100+
```bash
101+
cd example
102+
103+
# Generate sqlc code for all three engines
104+
sqlc generate
105+
106+
# Generate the multi-db wrappers
107+
go generate ./pkg/database
108+
109+
# Build to verify everything compiles
110+
go build ./...
111+
```
112+
113+
## Generated Files
114+
115+
All generated files start with a `// Code generated by sqlc-multi-db. DO NOT EDIT.` header and are prefixed with `generated_`. Do not edit them manually; re-run `go generate` instead.
116+
117+
## Library Usage
118+
119+
The generator logic is also available as a library:
120+
121+
```go
122+
import "github.com/kalbasit/sqlc-multi-db/generator"
123+
124+
generator.Run("/path/to/postgresdb/querier.go")
125+
```
126+
127+
## License
128+
129+
MIT

0 commit comments

Comments
 (0)