1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
package schema
import (
"database/sql"
"fmt"
"os"
"path"
"runtime"
_ "github.com/mattn/go-sqlite3" // For opening the in-memory database
)
// DotGo writes '<name>.go' source file in the package of the calling function, containing
// SQL statements that match the given schema updates.
//
// The <name>.go file contains a "flattened" render of all given updates and
// can be used to initialize brand new databases using Schema.Fresh().
func DotGo(updates map[int]Update, name string) error {
// Apply all the updates that we have on a pristine database and dump
// the resulting schema.
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
return fmt.Errorf("failed to open schema.go for writing: %w", err)
}
defer db.Close()
schema := NewFromMap(updates)
_, err = schema.Ensure(db)
if err != nil {
return err
}
dump, err := schema.Dump(db)
if err != nil {
return err
}
// Passing 1 to runtime.Caller identifies our caller.
_, filename, _, _ := runtime.Caller(1)
file, err := os.Create(path.Join(path.Dir(filename), name+".go"))
if err != nil {
return fmt.Errorf("failed to open Go file for writing: %w", err)
}
defer file.Close()
pkg := path.Base(path.Dir(filename))
_, err = file.Write(fmt.Appendf(nil, dotGoTemplate, pkg, dump))
if err != nil {
return fmt.Errorf("failed to write to Go file: %w", err)
}
return nil
}
// Template for schema files (can't use backticks since we need to use backticks
// inside the template itself).
const dotGoTemplate = "package %s\n\n" +
"// DO NOT EDIT BY HAND\n" +
"//\n" +
"// This code was generated by the schema.DotGo function. If you need to\n" +
"// modify the database schema, please add a new schema update to update.go\n" +
"// and the run 'make update-schema'.\n" +
"const freshSchema = `\n" +
"%s`\n"
|