Your first query: ClickHouse and SQLite
Every file of the ClickHouse and SQLite versions side by side, with the lines that differ marked. 4 parameter or column types differ in Go.
Configuration
sgl.yamldiffers
ClickHouse
SQLite
1
version: 11
version: 12
2
3
databases:3
databases:4
- name: tasks4
- name: tasks5
dialect: clickhouse5
dialect: sqlite6
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
ClickHouse
SQLite
1
CREATE TABLE tasks (1
CREATE TABLE tasks (2
id UInt64,2
id INTEGER PRIMARY KEY,3
title String,3
title TEXT NOT NULL,4
completed UInt8 DEFAULT 0,4
completed INTEGER NOT NULL DEFAULT 0,5
created_at DateTime DEFAULT now()5
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP6
) ENGINE = MergeTree() ORDER BY id;6
);db/migrations/0001_init.down.sqlidentical
ClickHouse
SQLite
1
DROP TABLE tasks;1
DROP TABLE tasks;Queries
CreateTaskdiffers
ClickHouse · db/queries/tasks.sql
SQLite · db/queries/tasks.sql
1
-- sgl.query(CreateTask, exec)1
-- sgl.query(CreateTask, one)2
INSERT INTO tasks (id, title) VALUES ({id:UInt64}, {title:String});2
INSERT INTO tasks (title) VALUES (?) RETURNING id, title, completed, created_at;GetTaskonly ClickHouse
ClickHouse · db/queries/tasks.sql
SQLite · not in this version
1
-- sgl.query(GetTask, one)2
SELECT id, title, completed, created_at FROM tasks WHERE id = {id:UInt64};ListTasksidentical
ClickHouse · db/queries/tasks.sql
SQLite · 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
ClickHouse · db/queries/tasks.sql
SQLite · db/queries/tasks.sql
1
-- sgl.query(CompleteTask, asyncexec)1
-- sgl.query(CompleteTask, execrows)2
ALTER TABLE tasks UPDATE completed = 1 WHERE id = {id:UInt64};2
UPDATE tasks SET completed = 1 WHERE id = ?;What sgl generates
CreateTaskdiffers
ClickHouse
SQLite
1
func (queries *Queries) CreateTask(ctx context.Context, params CreateTaskParams) error1
func (queries *Queries) CreateTask(ctx context.Context, title string) (CreateTaskRow, error)2
2
3
type CreateTaskParams struct {3
type CreateTaskRow struct {4
ID uint644
ID int64 `json:"id"`5
Title string5
Title string `json:"title"`6
Completed int64 `json:"completed"`7
CreatedAt string `json:"created_at"`6
}8
}GetTaskonly ClickHouse
ClickHouse
SQLite · not in this version
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
}ListTasksdiffers
ClickHouse
SQLite
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 uint64 `json:"id"`4
ID int64 `json:"id"`5
Title string `json:"title"`5
Title string `json:"title"`6
Completed uint8 `json:"completed"`6
Completed int64 `json:"completed"`7
CreatedAt time.Time `json:"created_at"`7
CreatedAt string `json:"created_at"`8
}8
}CompleteTaskdiffers
ClickHouse
SQLite
1
func (queries *Queries) CompleteTask(ctx context.Context, id uint64) error1
func (queries *Queries) CompleteTask(ctx context.Context, id int64) (int64, error)The program
example.godiffers
ClickHouse
SQLite
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/clickhouse/001_first_query/internal/store"9
"seagull.sh/seagull/examples/sqlite/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
//22
// Takes database (*sql.DB) which is a migrated database.15
// Takes database (*sql.DB) which is a migrated database.23
// Takes output (io.Writer) which receives the task list.16
// Takes output (io.Writer) which receives the task list.24
//17
//25
// Returns error when a query fails.18
// Returns error when a query fails.26
func run(ctx context.Context, database *sql.DB, output io.Writer) error {19
func run(ctx context.Context, database *sql.DB, output io.Writer) error {27
queries := store.New(database)20
queries := store.New(database)28
21
29
tasks := []store.CreateTaskParams{22
feed, err := queries.CreateTask(ctx, "Feed the seagulls")30
{ID: 1, Title: "Feed the seagulls"},23
if err != nil {31
{ID: 2, Title: "Count the chips"},24
return fmt.Errorf("creating a task: %w", err)32
}25
}33
for _, task := range tasks {26
if _, err := queries.CreateTask(ctx, "Count the chips"); err != nil {34
if err := queries.CreateTask(ctx, task); err != nil {27
return fmt.Errorf("creating a task: %w", err)35
return fmt.Errorf("creating task %d: %w", task.ID, err)36
}37
}28
}38
29
39
feed, err := queries.GetTask(ctx, 1)30
completed, err := queries.CompleteTask(ctx, feed.ID)40
if err != nil {31
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 {46
return fmt.Errorf("completing task %d: %w", feed.ID, err)32
return fmt.Errorf("completing task %d: %w", feed.ID, err)47
}33
}48
fmt.Fprintf(output, "completed task %d\n", feed.ID)34
fmt.Fprintf(output, "completed %d task\n", completed)49
35
50
listed, err := queries.ListTasks(ctx)36
tasks, err := queries.ListTasks(ctx)51
if err != nil {37
if err != nil {52
return fmt.Errorf("listing tasks: %w", err)38
return fmt.Errorf("listing tasks: %w", err)53
}39
}54
for _, task := range listed {40
for _, task := range tasks {55
fmt.Fprintf(output, "%d\t%-18s completed=%d\n", task.ID, task.Title, task.Completed)41
fmt.Fprintf(output, "%d\t%-18s completed=%d\n", task.ID, task.Title, task.Completed)56
}42
}57
return nil43
return nil58
}44
}Go type differences
The same SQL types map to different Go types, because each database reports them differently.
| Query | Field | ClickHouse | SQLite |
|---|---|---|---|
| ListTasks | column id | uint64 | int64 |
| ListTasks | column completed | uint8 | int64 |
| ListTasks | column created_at | time.Time | string |
| CompleteTask | parameter id | uint64 | int64 |