Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
658718056e | ||
|
|
0d45841bc6 |
@@ -14,13 +14,13 @@ A PostgreSQL schema migration tool that generates and applies migrations by comp
|
|||||||
### As a Library
|
### As a Library
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go get git.petrovv.com/go-migrate
|
go get git.petrovv.com/nikola/go_sql_schema_migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
### CLI Tool
|
### CLI Tool
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go install git.petrovv.com/go-migrate/cmd/go-migrate@latest
|
go install git.petrovv.com/nikola/go_sql_schema_migrate/cmd/go-migrate@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -28,7 +28,7 @@ go install git.petrovv.com/go-migrate/cmd/go-migrate@latest
|
|||||||
### Library
|
### Library
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "git.petrovv.com/go-migrate"
|
import "git.petrovv.com/nikola/go_sql_schema_migrate"
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
db, _ := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/db")
|
db, _ := pgxpool.New(ctx, "postgres://user:pass@localhost:5432/db")
|
||||||
|
|||||||
+70
-10
@@ -2,6 +2,7 @@ package go_sql_schema_migrate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -509,7 +510,7 @@ func parseAlterTableAddConstraint(schema *Schema, stmt string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSchemaFile(schema *Schema, sql string) {
|
func ParseSchemaFile(schema *Schema, sql string) {
|
||||||
// Split into statements
|
// Split into statements
|
||||||
statements := strings.Split(sql, ";")
|
statements := strings.Split(sql, ";")
|
||||||
|
|
||||||
@@ -548,7 +549,7 @@ func parseSchemaFile(schema *Schema, sql string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSchemaFiles(dir string) ([]SchemaFile, error) {
|
func LoadSchemaFiles(dir string) ([]SchemaFile, error) {
|
||||||
files, err := os.ReadDir(dir)
|
files, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -576,8 +577,8 @@ func loadSchemaFiles(dir string) ([]SchemaFile, error) {
|
|||||||
return schemaFiles, nil
|
return schemaFiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDesiredSchema(dir string) (*Schema, error) {
|
func LoadDesiredSchema(dir string) (*Schema, error) {
|
||||||
files, err := loadSchemaFiles(dir)
|
files, err := LoadSchemaFiles(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -588,7 +589,7 @@ func loadDesiredSchema(dir string) (*Schema, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
parseSchemaFile(schema, f.SQL)
|
ParseSchemaFile(schema, f.SQL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema, nil
|
return schema, nil
|
||||||
@@ -981,11 +982,6 @@ func parseForeignKey(def string) *ForeignKey {
|
|||||||
return fk
|
return fk
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadDesiredSchema loads schema definitions from SQL files in the given directory
|
|
||||||
func LoadDesiredSchema(dir string) (*Schema, error) {
|
|
||||||
return loadDesiredSchema(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMigrations compares the current database schema with the desired schema
|
// GetMigrations compares the current database schema with the desired schema
|
||||||
// and returns a list of SQL migration statements
|
// and returns a list of SQL migration statements
|
||||||
func GetMigrations(ctx context.Context, db *pgxpool.Pool, schemaDir string) ([]string, error) {
|
func GetMigrations(ctx context.Context, db *pgxpool.Pool, schemaDir string) ([]string, error) {
|
||||||
@@ -1004,3 +1000,67 @@ func GetMigrations(ctx context.Context, db *pgxpool.Pool, schemaDir string) ([]s
|
|||||||
// Compare and generate migration SQL
|
// Compare and generate migration SQL
|
||||||
return CompareSchemas(currentSchema, desiredSchema), nil
|
return CompareSchemas(currentSchema, desiredSchema), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadSchemaFilesEmbed(dir string, fs embed.FS) ([]SchemaFile, error) {
|
||||||
|
files, err := fs.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var schemaFiles []SchemaFile
|
||||||
|
for _, f := range files {
|
||||||
|
if !f.IsDir() && strings.HasSuffix(f.Name(), ".sql") {
|
||||||
|
content, err := fs.ReadFile(filepath.Join(dir, f.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
schemaFiles = append(schemaFiles, SchemaFile{
|
||||||
|
Name: f.Name(),
|
||||||
|
SQL: string(content),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by filename (natural sort for numbered files)
|
||||||
|
sort.Slice(schemaFiles, func(i, j int) bool {
|
||||||
|
return schemaFiles[i].Name < schemaFiles[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
return schemaFiles, nil
|
||||||
|
}
|
||||||
|
func LoadDesiredSchemaEmbed(dir string, fs embed.FS) (*Schema, error) {
|
||||||
|
files, err := LoadSchemaFilesEmbed(dir, fs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
schema := &Schema{
|
||||||
|
Types: make(map[string]string),
|
||||||
|
Tables: make(map[string]*Table),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
ParseSchemaFile(schema, f.SQL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMigrationsEmbed compares the current database schema with the desired schema
|
||||||
|
// and returns a list of SQL migration statements
|
||||||
|
func GetMigrationsEmbed(ctx context.Context, db *pgxpool.Pool, schemaDir string, fs embed.FS) ([]string, error) {
|
||||||
|
// Load current database schema
|
||||||
|
currentSchema, err := GetCurrentSchema(ctx, db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get current schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load desired schema from files
|
||||||
|
desiredSchema, err := LoadDesiredSchemaEmbed(schemaDir, fs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load desired schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare and generate migration SQL
|
||||||
|
return CompareSchemas(currentSchema, desiredSchema), nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user