Add dump command (#23)

Adds `dbmate dump` command to write the database schema to a file.

The intent is for this file to be checked in to the codebase, similar to Rails' `schema.rb` (or `structure.sql`) file. This allows developers to share a single file documenting the database schema, and makes it considerably easier to review PRs which add (or change) migrations.

The existing `up`, `migrate`, and `rollback` commands will automatically trigger a schema dump, unless `--no-dump-schema` is passed.

Closes https://github.com/amacneil/dbmate/issues/5
This commit is contained in:
Adrian Macneil 2018-01-22 20:38:40 -08:00 committed by GitHub
parent 54a9fbc859
commit d855ee1ada
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 578 additions and 34 deletions

View file

@ -1,11 +1,13 @@
package dbmate
import (
"bytes"
"database/sql"
"fmt"
"net/url"
"os"
"regexp"
"strings"
_ "github.com/mattn/go-sqlite3" // sqlite driver for database/sql
)
@ -56,6 +58,44 @@ func (drv SQLiteDriver) DropDatabase(u *url.URL) error {
return os.Remove(path)
}
func sqliteSchemaMigrationsDump(db *sql.DB) ([]byte, error) {
// load applied migrations
migrations, err := queryColumn(db,
"select quote(version) from schema_migrations order by version asc")
if err != nil {
return nil, err
}
// build schema_migrations table data
var buf bytes.Buffer
buf.WriteString("-- Dbmate schema migrations\n")
if len(migrations) > 0 {
buf.WriteString("INSERT INTO schema_migrations (version) VALUES\n (" +
strings.Join(migrations, "),\n (") +
");\n")
}
return buf.Bytes(), nil
}
// DumpSchema returns the current database schema
func (drv SQLiteDriver) DumpSchema(u *url.URL, db *sql.DB) ([]byte, error) {
path := sqlitePath(u)
schema, err := runCommand("sqlite3", path, ".schema")
if err != nil {
return nil, err
}
migrations, err := sqliteSchemaMigrationsDump(db)
if err != nil {
return nil, err
}
schema = append(schema, migrations...)
return trimLeadingSQLComments(schema)
}
// DatabaseExists determines whether the database exists
func (drv SQLiteDriver) DatabaseExists(u *url.URL) (bool, error) {
_, err := os.Stat(sqlitePath(u))
@ -71,8 +111,8 @@ func (drv SQLiteDriver) DatabaseExists(u *url.URL) (bool, error) {
// CreateMigrationsTable creates the schema_migrations table
func (drv SQLiteDriver) CreateMigrationsTable(db *sql.DB) error {
_, err := db.Exec(`create table if not exists schema_migrations (
version varchar(255) primary key)`)
_, err := db.Exec("create table if not exists schema_migrations " +
"(version varchar(255) primary key)")
return err
}