Your first query: SQLite and ClickHouse
Every file of the SQLite and ClickHouse versions side by side, with the lines that differ marked. 4 parameter or column types differ in Go.
Configuration
sgl.yamldiffers
SQLite
ClickHouse
1
version: 11
version: 12
2
3
databases:3
databases:4
- name: tasks4
- name: tasks5
dialect: sqlite5
dialect: clickhouse6
migrations: db/migrations6
migrations: db/migrations7
queries: db/queries7
queries: db/queries8
go:8
go:9
package: store9
package: store10
out: internal/store10
out: internal/storeMigrations
db/migrations/0001_init.up.sqldiffers
SQLite
ClickHouse
1
CREATE TABLE tasks (1
CREATE TABLE tasks (2
id INTEGER PRIMARY KEY,2
id UInt64,3
title TEXT NOT NULL,3
title String,4
completed INTEGER NOT NULL DEFAULT 0,4
completed UInt8 DEFAULT 0,5
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP5
created_at DateTime DEFAULT now()6
);6
) ENGINE = MergeTree() ORDER BY id;db/migrations/0001_init.down.sqlidentical
SQLite
ClickHouse
1
DROP TABLE tasks;1
DROP TABLE tasks;Queries
CreateTaskdiffers
SQLite · db/queries/tasks.sql
ClickHouse · db/queries/tasks.sql
1
-- sgl.query(CreateTask, one)1
-- sgl.query(CreateTask, exec)2
INSERT INTO tasks (title) VALUES (?) RETURNING id, title, completed, created_at;2
INSERT INTO tasks (id, title) VALUES ({id:UInt64}, {title:String});ListTasksidentical
SQLite · db/queries/tasks.sql
ClickHouse · db/queries/tasks.sql
1
-- sgl.query(ListTasks, many)1
-- sgl.query(ListTasks, many)2
SELECT id, title, completed, created_at FROM tasks ORDER BY id;2
SELECT id, title, completed, created_at FROM tasks ORDER BY id;CompleteTaskdiffers
SQLite · db/queries/tasks.sql
ClickHouse · db/queries/tasks.sql
1
-- sgl.query(CompleteTask, execrows)1
-- sgl.query(CompleteTask, asyncexec)2
UPDATE tasks SET completed = 1 WHERE id = ?;2
ALTER TABLE tasks UPDATE completed = 1 WHERE id = {id:UInt64};GetTaskonly ClickHouse
SQLite · not in this version
ClickHouse · db/queries/tasks.sql
1
-- sgl.query(GetTask, one)2
SELECT id, title, completed, created_at FROM tasks WHERE id = {id:UInt64};What sgl generates
CreateTaskdiffers
SQLite
ClickHouse
1
func (queries *Queries) CreateTask(ctx context.Context, title string) (CreateTaskRow, error)1
func (queries *Queries) CreateTask(ctx context.Context, params CreateTaskParams) error2
2
3
type CreateTaskRow struct {3
type CreateTaskParams struct {4
ID int64 `json:"id"`4
ID uint645
Title string `json:"title"`5
Title string6
Completed int64 `json:"completed"`7
CreatedAt string `json:"created_at"`8
}6
}ListTasksdiffers
SQLite
ClickHouse
1
func (queries *Queries) ListTasks(ctx context.Context) ([]ListTasksRow, error)1
func (queries *Queries) ListTasks(ctx context.Context) ([]ListTasksRow, error)2
2
3
type ListTasksRow struct {3
type ListTasksRow struct {4
ID int64 `json:"id"`4
ID uint64 `json:"id"`5
Title string `json:"title"`5
Title string `json:"title"`6
Completed int64 `json:"completed"`6
Completed uint8 `json:"completed"`7
CreatedAt string `json:"created_at"`7
CreatedAt time.Time `json:"created_at"`8
}8
}CompleteTaskdiffers
SQLite
ClickHouse
1
func (queries *Queries) CompleteTask(ctx context.Context, id int64) (int64, error)1
func (queries *Queries) CompleteTask(ctx context.Context, id uint64) errorGetTaskonly ClickHouse
SQLite · not in this version
ClickHouse
1
func (queries *Queries) GetTask(ctx context.Context, id uint64) (GetTaskRow, error)2
3
type GetTaskRow struct {4
ID uint64 `json:"id"`5
Title string `json:"title"`6
Completed uint8 `json:"completed"`7
CreatedAt time.Time `json:"created_at"`8
}The program
example.godiffers
SQLite
ClickHouse
1
package main1
package main2
2
3
import (3
import (4
"context"4
"context"5
"database/sql"5
"database/sql"6
"fmt"6
"fmt"7
"io"7
"io"8
8
9
"seagull.sh/seagull/examples/sqlite/001_first_query/internal/store"9
"seagull.sh/seagull/examples/clickhouse/001_first_query/internal/store"10
)10
)11
11
12
// run adds two tasks, completes the first and lists them all, through the methods sgl12
// run adds two tasks, completes the first and lists them all, through the methods sgl13
// generated from db/queries/tasks.sql.13
// generated from db/queries/tasks.sql.14
//14
//15
// ClickHouse has no auto-increment and no RETURNING, so the caller chooses each task's id16
// and reads a task back with GetTask. CompleteTask uses ALTER TABLE ... UPDATE, which17
// queues a mutation that the server applies in the background, so the query is declared18
// asyncexec and returns only an error (concept 36 explains why). The connection sets19
// mutations_sync=2, which makes the server finish the mutation before it replies, so the20
// list below already shows the task completed.21
//15
// Takes database (*sql.DB) which is a migrated database.22
// Takes database (*sql.DB) which is a migrated database.16
// Takes output (io.Writer) which receives the task list.23
// Takes output (io.Writer) which receives the task list.17
//24
//18
// Returns error when a query fails.25
// Returns error when a query fails.19
func run(ctx context.Context, database *sql.DB, output io.Writer) error {26
func run(ctx context.Context, database *sql.DB, output io.Writer) error {20
queries := store.New(database)27
queries := store.New(database)21
28
22
feed, err := queries.CreateTask(ctx, "Feed the seagulls")29
tasks := []store.CreateTaskParams{23
if err != nil {30
{ID: 1, Title: "Feed the seagulls"},24
return fmt.Errorf("creating a task: %w", err)31
{ID: 2, Title: "Count the chips"},25
}32
}26
if _, err := queries.CreateTask(ctx, "Count the chips"); err != nil {33
for _, task := range tasks {27
return fmt.Errorf("creating a task: %w", err)34
if err := queries.CreateTask(ctx, task); err != nil {35
return fmt.Errorf("creating task %d: %w", task.ID, err)36
}28
}37
}29
38
30
completed, err := queries.CompleteTask(ctx, feed.ID)39
feed, err := queries.GetTask(ctx, 1)31
if err != nil {40
if err != nil {41
return fmt.Errorf("getting task 1: %w", err)42
}43
fmt.Fprintf(output, "created task %d, %s\n", feed.ID, feed.Title)44
45
if err := queries.CompleteTask(ctx, feed.ID); err != nil {32
return fmt.Errorf("completing task %d: %w", feed.ID, err)46
return fmt.Errorf("completing task %d: %w", feed.ID, err)33
}47
}34
fmt.Fprintf(output, "completed %d task\n", completed)48
fmt.Fprintf(output, "completed task %d\n", feed.ID)35
49
36
tasks, err := queries.ListTasks(ctx)50
listed, err := queries.ListTasks(ctx)37
if err != nil {51
if err != nil {38
return fmt.Errorf("listing tasks: %w", err)52
return fmt.Errorf("listing tasks: %w", err)39
}53
}40
for _, task := range tasks {54
for _, task := range listed {41
fmt.Fprintf(output, "%d\t%-18s completed=%d\n", task.ID, task.Title, task.Completed)55
fmt.Fprintf(output, "%d\t%-18s completed=%d\n", task.ID, task.Title, task.Completed)42
}56
}43
return nil57
return nil44
}58
}Go type differences
The same SQL types map to different Go types, because each database reports them differently.
| Query | Field | SQLite | ClickHouse |
|---|---|---|---|
| ListTasks | column id | int64 | uint64 |
| ListTasks | column completed | int64 | uint8 |
| ListTasks | column created_at | string | time.Time |
| CompleteTask | parameter id | int64 | uint64 |