-
Notifications
You must be signed in to change notification settings - Fork 876
chore: Initial database scaffolding #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 4 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
a5af7f4
chore: Initial database scaffolding
kylecarbs aab10d1
Run tests in CI
kylecarbs 52a4cf4
Use Docker instead of binaries on the host
kylecarbs 2796d96
Skip database tests on non-Linux operating systems
kylecarbs c8788af
chore: Add golangci-lint and codecov
kylecarbs 3a7e909
Use consistent file names
kylecarbs 49781ff
Merge branch 'codequality' into database
kylecarbs 3539581
Merge branch 'main' into database
kylecarbs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
############################################################################### | ||
# COPY PASTA OF .gitignore | ||
############################################################################### | ||
node_modules | ||
node_modules | ||
vendor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Package database connects to external services for stateful storage. | ||
// | ||
// Query functions are generated using sqlc. | ||
// | ||
// To modify the database schema: | ||
// 1. Add a new migration using "create_migration.sh" in database/migrations/ | ||
// 2. Run "make database/generate" in the root to generate models. | ||
// 3. Add/Edit queries in "query.sql" and run "make database/generate" to create Go code. | ||
package database | ||
|
||
import ( | ||
"context" | ||
"database/sql" | ||
"errors" | ||
|
||
"golang.org/x/xerrors" | ||
) | ||
|
||
// Store contains all queryable database functions. | ||
// It extends the generated interface to add transaction support. | ||
type Store interface { | ||
querier | ||
|
||
InTx(context.Context, func(Store) error) error | ||
} | ||
|
||
// DBTX represents a database connection or transaction. | ||
type DBTX interface { | ||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error) | ||
PrepareContext(context.Context, string) (*sql.Stmt, error) | ||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) | ||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row | ||
} | ||
|
||
// New creates a new database store using a SQL database connection. | ||
func New(sdb *sql.DB) Store { | ||
return &sqlQuerier{ | ||
db: sdb, | ||
sdb: sdb, | ||
} | ||
} | ||
|
||
type sqlQuerier struct { | ||
sdb *sql.DB | ||
db DBTX | ||
} | ||
|
||
// InTx performs database operations inside a transaction. | ||
func (q *sqlQuerier) InTx(ctx context.Context, fn func(Store) error) error { | ||
if q.sdb == nil { | ||
return nil | ||
} | ||
tx, err := q.sdb.Begin() | ||
if err != nil { | ||
return xerrors.Errorf("begin transaction: %w", err) | ||
} | ||
defer func() { | ||
rerr := tx.Rollback() | ||
if rerr == nil || errors.Is(rerr, sql.ErrTxDone) { | ||
// no need to do anything, tx committed successfully | ||
return | ||
} | ||
// couldn't roll back for some reason, extend returned error | ||
err = xerrors.Errorf("defer (%s): %w", rerr.Error(), err) | ||
}() | ||
err = fn(&sqlQuerier{db: tx}) | ||
if err != nil { | ||
return xerrors.Errorf("execute transaction: %w", err) | ||
} | ||
err = tx.Commit() | ||
if err != nil { | ||
return xerrors.Errorf("commit transaction: %w", err) | ||
} | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package database | ||
|
||
import "context" | ||
|
||
// NewInMemory returns an in-memory store of the database. | ||
func NewInMemory() Store { | ||
return &memoryQuerier{} | ||
} | ||
|
||
type memoryQuerier struct{} | ||
|
||
// InTx doesn't rollback data properly for in-memory yet. | ||
func (q *memoryQuerier) InTx(ctx context.Context, fn func(Store) error) error { | ||
return fn(q) | ||
} | ||
|
||
func (q *memoryQuerier) ExampleQuery(ctx context.Context) error { | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- Code generated by 'make database/generate'. DO NOT EDIT. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"database/sql" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"runtime" | ||
|
||
"github.com/coder/coder/database" | ||
"github.com/coder/coder/database/postgres" | ||
) | ||
|
||
func main() { | ||
connection, closeFn, err := postgres.Open() | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer closeFn() | ||
db, err := sql.Open("postgres", connection) | ||
if err != nil { | ||
panic(err) | ||
} | ||
err = database.Migrate(context.Background(), "postgres", db) | ||
if err != nil { | ||
panic(err) | ||
} | ||
cmd := exec.Command( | ||
"pg_dump", | ||
"--schema-only", | ||
connection, | ||
"--no-privileges", | ||
"--no-owner", | ||
"--no-comments", | ||
|
||
// We never want to manually generate | ||
// queries executing against this table. | ||
"--exclude-table=schema_migrations", | ||
) | ||
cmd.Env = []string{ | ||
"PGTZ=UTC", | ||
"PGCLIENTENCODING=UTF8", | ||
} | ||
var output bytes.Buffer | ||
cmd.Stdout = &output | ||
cmd.Stderr = os.Stderr | ||
err = cmd.Run() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
for _, sed := range []string{ | ||
// Remove all comments. | ||
"/^--/d", | ||
// Public is implicit in the schema. | ||
"s/ public\\./ /", | ||
// Remove database settings. | ||
"s/SET.*;//g", | ||
// Remove select statements. These aren't useful | ||
// to a reader of the dump. | ||
"s/SELECT.*;//g", | ||
// Removes multiple newlines. | ||
"/^$/N;/^\\n$/D", | ||
} { | ||
cmd := exec.Command("sed", "-e", sed) | ||
cmd.Stdin = bytes.NewReader(output.Bytes()) | ||
output = bytes.Buffer{} | ||
cmd.Stdout = &output | ||
cmd.Stderr = os.Stderr | ||
err = cmd.Run() | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
|
||
dump := fmt.Sprintf("-- Code generated by 'make database/generate'. DO NOT EDIT.\n%s", output.Bytes()) | ||
_, mainPath, _, ok := runtime.Caller(0) | ||
if !ok { | ||
panic("couldn't get caller path") | ||
} | ||
err = ioutil.WriteFile(filepath.Join(mainPath, "..", "..", "dump.sql"), []byte(dump), 0644) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package database | ||
|
||
import ( | ||
"context" | ||
"database/sql" | ||
"embed" | ||
"errors" | ||
|
||
"github.com/golang-migrate/migrate/v4" | ||
"github.com/golang-migrate/migrate/v4/database/postgres" | ||
"github.com/golang-migrate/migrate/v4/source/iofs" | ||
"golang.org/x/xerrors" | ||
) | ||
|
||
//go:embed migrations/*.sql | ||
var migrations embed.FS | ||
|
||
// Migrate runs SQL migrations to ensure the database schema is up-to-date. | ||
func Migrate(ctx context.Context, dbName string, db *sql.DB) error { | ||
sourceDriver, err := iofs.New(migrations, "migrations") | ||
if err != nil { | ||
return xerrors.Errorf("create iofs: %w", err) | ||
} | ||
dbDriver, err := postgres.WithInstance(db, &postgres.Config{}) | ||
if err != nil { | ||
return xerrors.Errorf("wrap postgres connection: %w", err) | ||
} | ||
m, err := migrate.NewWithInstance("", sourceDriver, dbName, dbDriver) | ||
if err != nil { | ||
return xerrors.Errorf("migrate: %w", err) | ||
} | ||
err = m.Up() | ||
if err != nil { | ||
if errors.Is(err, migrate.ErrNoChange) { | ||
// It's OK if no changes happened! | ||
return nil | ||
} | ||
return xerrors.Errorf("up: %w", err) | ||
} | ||
srcErr, dbErr := m.Close() | ||
if srcErr != nil { | ||
return xerrors.Errorf("close source: %w", err) | ||
} | ||
if dbErr != nil { | ||
return xerrors.Errorf("close database: %w", err) | ||
} | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//go:build linux | ||
|
||
package database_test | ||
|
||
import ( | ||
"context" | ||
"database/sql" | ||
"testing" | ||
|
||
"github.com/coder/coder/database" | ||
"github.com/coder/coder/database/postgres" | ||
"github.com/stretchr/testify/require" | ||
"go.uber.org/goleak" | ||
) | ||
|
||
func TestMain(m *testing.M) { | ||
goleak.VerifyTestMain(m) | ||
} | ||
|
||
func TestMigrate(t *testing.T) { | ||
t.Parallel() | ||
|
||
connection, closeFn, err := postgres.Open() | ||
require.NoError(t, err) | ||
defer closeFn() | ||
db, err := sql.Open("postgres", connection) | ||
require.NoError(t, err) | ||
err = database.Migrate(context.Background(), "postgres", db) | ||
require.NoError(t, err) | ||
} |
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/env bash | ||
cd "$(dirname "$0")" | ||
|
||
if [ -z "$1" ]; then | ||
echo "First argument is the migration name!" | ||
exit 1 | ||
fi | ||
|
||
migrate create -ext sql -dir . -seq $1 | ||
|
||
echo "After making adjustments, run \"make database/generate\" to generate models." |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, our CI is actually doing something now 🎉