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