Your first query: SQLite and TimescaleDB
Every file of the SQLite and TimescaleDB versions side by side, with the lines that differ marked. 4 parameter or column types differ in Go.
Configuration
sgl.yamldiffers
SQLite
TimescaleDB
1
version: 11
version: 12
2
3
databases:3
databases:4
- name: tasks4
- name: tasks5
dialect: sqlite5
dialect: postgres6
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/store11
driver: database/sql12
doc_comments: true13
migrate:14
dsn: ${env:DATABASE_URL}Migrations
db/migrations/0001_init.up.sqldiffers
SQLite
TimescaleDB
1
CREATE TABLE tasks (1
CREATE TABLE tasks (2
id INTEGER PRIMARY KEY,2
id BIGSERIAL PRIMARY KEY,3
title TEXT NOT NULL,3
title TEXT NOT NULL,4
completed INTEGER NOT NULL DEFAULT 0,4
completed BOOLEAN NOT NULL DEFAULT false,5
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP5
created_at TIMESTAMPTZ NOT NULL DEFAULT now()6
);6
);7
8
COMMENT ON TABLE tasks IS 'Jobs to do around the harbour.';9
COMMENT ON COLUMN tasks.completed IS 'Whether the job is done.';db/migrations/0001_init.down.sqlidentical
SQLite
TimescaleDB
1
DROP TABLE tasks;1
DROP TABLE tasks;Queries
CreateTaskdiffers
SQLite · db/queries/tasks.sql
TimescaleDB · db/queries/tasks.sql
1
-- CreateTask adds a task and returns it with the id and creation time the database2
-- gave it.1
-- sgl.query(CreateTask, one)3
-- sgl.query(CreateTask, one)2
INSERT INTO tasks (title) VALUES (?) RETURNING id, title, completed, created_at;4
INSERT INTO tasks (title) VALUES ($1) RETURNING id, title, completed, created_at;ListTasksdiffers
SQLite · db/queries/tasks.sql
TimescaleDB · db/queries/tasks.sql
1
-- ListTasks returns every task, oldest first.1
-- sgl.query(ListTasks, many)2
-- sgl.query(ListTasks, many)2
SELECT id, title, completed, created_at FROM tasks ORDER BY id;3
SELECT id, title, completed, created_at FROM tasks ORDER BY id;CompleteTaskdiffers
SQLite · db/queries/tasks.sql
TimescaleDB · db/queries/tasks.sql
1
-- CompleteTask marks a task done and returns how many tasks it changed.1
-- sgl.query(CompleteTask, execrows)2
-- sgl.query(CompleteTask, execrows)2
UPDATE tasks SET completed = 1 WHERE id = ?;3
UPDATE tasks SET completed = true WHERE id = $1;What sgl generates
CreateTaskdiffers
SQLite
TimescaleDB
1
func (queries *Queries) CreateTask(ctx context.Context, title string) (CreateTaskRow, error)1
func (queries *Queries) CreateTask(ctx context.Context, title string) (CreateTaskRow, error)2
2
3
type CreateTaskRow struct {3
type CreateTaskRow struct {4
ID int64 `json:"id"`4
ID int64 `json:"id"`5
Title string `json:"title"`5
Title string `json:"title"`6
Completed int64 `json:"completed"`6
Completed bool `json:"completed"`7
CreatedAt string `json:"created_at"`7
CreatedAt time.Time `json:"created_at"`8
}8
}ListTasksdiffers
SQLite
TimescaleDB
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 int64 `json:"id"`5
Title string `json:"title"`5
Title string `json:"title"`6
Completed int64 `json:"completed"`6
Completed bool `json:"completed"`7
CreatedAt string `json:"created_at"`7
CreatedAt time.Time `json:"created_at"`8
}8
}CompleteTaskidentical
SQLite
TimescaleDB
1
func (queries *Queries) CompleteTask(ctx context.Context, id int64) (int64, error)1
func (queries *Queries) CompleteTask(ctx context.Context, id int64) (int64, error)The program
example.godiffers
SQLite
TimescaleDB
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/postgres/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. The id column is BIGSERIAL, so ID is int64, and14
// created_at is TIMESTAMPTZ, so CreatedAt is a time.Time; the example leaves it out of15
// the output, as it changes on every run.14
//16
//15
// Takes database (*sql.DB) which is a migrated database.17
// sgl.yaml sets go.doc_comments, so the comment above each query in tasks.sql becomes its18
// method's doc comment, and the migration's COMMENT ON TABLE and COMMENT ON COLUMN become19
// the doc comments of the Tasks model and its Completed field: open internal/store to see20
// them, or hover over queries.CreateTask in an editor.21
//22
// Takes database (*sql.DB) which is a migrated database, opened with pgx's database/sql23
// driver.16
// Takes output (io.Writer) which receives the task list.24
// Takes output (io.Writer) which receives the task list.17
//25
//18
// Returns error when a query fails.26
// Returns error when a query fails.19
func run(ctx context.Context, database *sql.DB, output io.Writer) error {27
func run(ctx context.Context, database *sql.DB, output io.Writer) error {20
queries := store.New(database)28
queries := store.New(database)21
29
22
feed, err := queries.CreateTask(ctx, "Feed the seagulls")30
feed, err := queries.CreateTask(ctx, "Feed the seagulls")23
if err != nil {31
if err != nil {24
return fmt.Errorf("creating a task: %w", err)32
return fmt.Errorf("creating a task: %w", err)25
}33
}26
if _, err := queries.CreateTask(ctx, "Count the chips"); err != nil {34
if _, err := queries.CreateTask(ctx, "Count the chips"); err != nil {27
return fmt.Errorf("creating a task: %w", err)35
return fmt.Errorf("creating a task: %w", err)28
}36
}29
37
30
completed, err := queries.CompleteTask(ctx, feed.ID)38
completed, err := queries.CompleteTask(ctx, feed.ID)31
if err != nil {39
if err != nil {32
return fmt.Errorf("completing task %d: %w", feed.ID, err)40
return fmt.Errorf("completing task %d: %w", feed.ID, err)33
}41
}34
fmt.Fprintf(output, "completed %d task\n", completed)42
fmt.Fprintf(output, "completed %d task\n", completed)35
43
36
tasks, err := queries.ListTasks(ctx)44
tasks, err := queries.ListTasks(ctx)37
if err != nil {45
if err != nil {38
return fmt.Errorf("listing tasks: %w", err)46
return fmt.Errorf("listing tasks: %w", err)39
}47
}40
for _, task := range tasks {48
for _, task := range tasks {41
fmt.Fprintf(output, "%d\t%-18s completed=%d\n", task.ID, task.Title, task.Completed)49
fmt.Fprintf(output, "%d\t%-18s completed=%t\n", task.ID, task.Title, task.Completed)42
}50
}43
return nil51
return nil44
}52
}Go type differences
The same SQL types map to different Go types, because each database reports them differently.
| Query | Field | SQLite | TimescaleDB |
|---|---|---|---|
| CreateTask | column completed | int64 | bool |
| CreateTask | column created_at | string | time.Time |
| ListTasks | column completed | int64 | bool |
| ListTasks | column created_at | string | time.Time |