commit a24460e0ccf866029a77761295d46ce6904d2f4e Author: Matthias Schild Date: Tue Sep 1 00:56:15 2026 +0200 feat: initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3997bea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.db \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5cc8764 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# PoC of Go with GORM and Migrations + +- This PoC creates a simple entity, with migrations and calls for Sqlite, but should work with Postgres too +- Migrations are embedded into the applications so they can be applied on startup + +## Learning + +- The table names are specified using the TableName function (see entities.go) +- gorm.Model requires the basic columns, see 0001_init.up.sql +- Migration scripts have the name structure `{version}_{title}.up.{extension}` and `{version}_{title}.down.{extension}` \ No newline at end of file diff --git a/entities.go b/entities.go new file mode 100644 index 0000000..080faf9 --- /dev/null +++ b/entities.go @@ -0,0 +1,15 @@ +package main + +import ( + "gorm.io/gorm" +) + +type EntryEntity struct { + gorm.Model + Message string + Timestamp string +} + +func (EntryEntity) TableName() string { + return "entries" +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..273f398 --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module ormtest + +go 1.25.4 + +require ( + github.com/golang-migrate/migrate/v4 v4.19.1 + gorm.io/driver/sqlite v1.6.0 + gorm.io/gorm v1.31.1 +) + +require ( + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + golang.org/x/text v0.32.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..353826f --- /dev/null +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= +github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= +gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= +gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg= +gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= diff --git a/main.go b/main.go new file mode 100644 index 0000000..b75a362 --- /dev/null +++ b/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "context" + "embed" + "fmt" + "time" + + "github.com/golang-migrate/migrate/v4" + _ "github.com/golang-migrate/migrate/v4/database/sqlite3" + "github.com/golang-migrate/migrate/v4/source/iofs" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +//go:embed migrations/*.sql +var migrations embed.FS + +func main() { + ctx := context.Background() + + // Execute migrations + migrationsFS, err := iofs.New(migrations, "migrations") + if err != nil { + panic(err) + } + migrator, err := migrate.NewWithSourceInstance("iofs", migrationsFS, "sqlite3://test.db") + if err != nil { + panic(err) + } + if err := migrator.Up(); err != nil && err != migrate.ErrNoChange { + panic(err) + } + + // Connect to database + db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } + + // Insert + err = gorm.G[EntryEntity](db).Create(ctx, &EntryEntity{ + Message: "Hello World", + Timestamp: time.Now().Format(time.RFC3339), + }) + if err != nil { + panic(err) + } + + fmt.Println("successfully added an entry") + + // Read + entries, err := gorm.G[EntryEntity](db).Find(ctx) + if err != nil { + panic(err) + } + + fmt.Println("successfully read all entries") + for _, entry := range entries { + fmt.Printf("- [%04d][%s]: %s\n", entry.ID, entry.Timestamp, entry.Message) + } +} diff --git a/migrations/0001_init.up.sql b/migrations/0001_init.up.sql new file mode 100644 index 0000000..9729b4a --- /dev/null +++ b/migrations/0001_init.up.sql @@ -0,0 +1,11 @@ +CREATE TABLE entries ( + -- GORM required + id INTEGER PRIMARY KEY AUTOINCREMENT, + created_at DATETIME NOT NULL, + updated_at DATETIME NOT NULL, + deleted_at DATETIME, + + -- My columns + message TEXT NOT NULL, + timestamp TEXT NOT NULL +); \ No newline at end of file