From 1d35bea1c5945c337dc8fbd6056f46ea6fed6bf3 Mon Sep 17 00:00:00 2001 From: m Date: Sun, 12 Jul 2026 09:28:20 +0200 Subject: [PATCH] add migration system --- backend/cmd/server/main.go | 6 ++ backend/go.mod | 2 + backend/go.sum | 7 ++ backend/internal/db/files.sql.go | 96 ------------------- .../db/{placeholder.sql.go => health.sql.go} | 2 +- backend/internal/db/migrate.go | 36 +++++++ .../internal/db/migrations/001_init.down.sql | 1 + .../internal/db/migrations/001_init.up.sql | 3 + backend/internal/db/migrations/schema.sql | 20 ---- backend/internal/db/models.go | 24 ----- backend/internal/db/queries/files.sql | 15 --- backend/internal/db/queries/health.sql | 2 + backend/internal/handlers/files.go | 27 ++---- backend/sqlc.yaml | 2 +- 14 files changed, 67 insertions(+), 176 deletions(-) delete mode 100644 backend/internal/db/files.sql.go rename backend/internal/db/{placeholder.sql.go => health.sql.go} (92%) create mode 100644 backend/internal/db/migrate.go create mode 100644 backend/internal/db/migrations/001_init.down.sql create mode 100644 backend/internal/db/migrations/001_init.up.sql delete mode 100644 backend/internal/db/migrations/schema.sql delete mode 100644 backend/internal/db/queries/files.sql create mode 100644 backend/internal/db/queries/health.sql diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 5b870d1..4a72ead 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -15,12 +15,18 @@ func main() { port = "8080" } + migrationsPath := "file://internal/db/migrations" + database, err := db.Connect() if err != nil { log.Fatalf("Failed to connect to database: %v", err) } defer database.Close() + if err := db.RunMigrations(database, migrationsPath); err != nil { + log.Fatalf("Failed to run migrations: %v", err) + } + queries := db.New(database) h := handlers.New(queries) diff --git a/backend/go.mod b/backend/go.mod index c046b68..b35dbad 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -20,6 +20,7 @@ require ( github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.19.2 // indirect + github.com/golang-migrate/migrate/v4 v4.19.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect @@ -27,6 +28,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mutecomm/go-sqlcipher/v4 v4.4.0 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/quic-go/qpack v0.6.0 // indirect diff --git a/backend/go.sum b/backend/go.sum index f861ada..01186f6 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -9,6 +9,7 @@ github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gE github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= @@ -29,6 +30,8 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= +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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -51,12 +54,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mutecomm/go-sqlcipher/v4 v4.4.0 h1:sV1tWCWGAVlPhNGT95Q+z/txFxuhAYWwHD1afF5bMZg= +github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= @@ -88,6 +94,7 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= diff --git a/backend/internal/db/files.sql.go b/backend/internal/db/files.sql.go deleted file mode 100644 index b1b584d..0000000 --- a/backend/internal/db/files.sql.go +++ /dev/null @@ -1,96 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.31.1 -// source: files.sql - -package db - -import ( - "context" -) - -const createFile = `-- name: CreateFile :one -INSERT INTO files ( - name,storage_key,checksum,created_at,updated_at,deleted_at -) VALUES ( - ?, ?, ?,date(),date(),date() -) -RETURNING id, name, storage_key, checksum, created_at, updated_at, deleted_at -` - -type CreateFileParams struct { - Name string `json:"name"` - StorageKey string `json:"storage_key"` - Checksum string `json:"checksum"` -} - -func (q *Queries) CreateFile(ctx context.Context, arg CreateFileParams) (File, error) { - row := q.db.QueryRowContext(ctx, createFile, arg.Name, arg.StorageKey, arg.Checksum) - var i File - err := row.Scan( - &i.ID, - &i.Name, - &i.StorageKey, - &i.Checksum, - &i.CreatedAt, - &i.UpdatedAt, - &i.DeletedAt, - ) - return i, err -} - -const getFile = `-- name: GetFile :one -SELECT id, name, storage_key, checksum, created_at, updated_at, deleted_at FROM files -WHERE id = ? LIMIT 1 -` - -func (q *Queries) GetFile(ctx context.Context, id string) (File, error) { - row := q.db.QueryRowContext(ctx, getFile, id) - var i File - err := row.Scan( - &i.ID, - &i.Name, - &i.StorageKey, - &i.Checksum, - &i.CreatedAt, - &i.UpdatedAt, - &i.DeletedAt, - ) - return i, err -} - -const listFiles = `-- name: ListFiles :many -SELECT id, name, storage_key, checksum, created_at, updated_at, deleted_at FROM files -ORDER BY name -` - -func (q *Queries) ListFiles(ctx context.Context) ([]File, error) { - rows, err := q.db.QueryContext(ctx, listFiles) - if err != nil { - return nil, err - } - defer rows.Close() - var items []File - for rows.Next() { - var i File - if err := rows.Scan( - &i.ID, - &i.Name, - &i.StorageKey, - &i.Checksum, - &i.CreatedAt, - &i.UpdatedAt, - &i.DeletedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} diff --git a/backend/internal/db/placeholder.sql.go b/backend/internal/db/health.sql.go similarity index 92% rename from backend/internal/db/placeholder.sql.go rename to backend/internal/db/health.sql.go index 0505e95..f779be8 100644 --- a/backend/internal/db/placeholder.sql.go +++ b/backend/internal/db/health.sql.go @@ -1,7 +1,7 @@ // Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 -// source: placeholder.sql +// source: health.sql package db diff --git a/backend/internal/db/migrate.go b/backend/internal/db/migrate.go new file mode 100644 index 0000000..f00469c --- /dev/null +++ b/backend/internal/db/migrate.go @@ -0,0 +1,36 @@ +package db + +import ( + "database/sql" + "fmt" + "log" + + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/database/sqlite" + "github.com/golang-migrate/migrate/v4/source/file" +) + +func RunMigrations(database *sql.DB, migrationsURL string) error { + sourceDriver, err := (&file.File{}).Open(migrationsURL) + if err != nil { + return fmt.Errorf("open migrations source: %w", err) + } + + dbDriver, err := sqlite.WithInstance(database, &sqlite.Config{}) + if err != nil { + return fmt.Errorf("create sqlite driver: %w", err) + } + + m, err := migrate.NewWithInstance("file", sourceDriver, "sqlite", dbDriver) + if err != nil { + return fmt.Errorf("create migrate instance: %w", err) + } + defer m.Close() + + if err := m.Up(); err != nil && err != migrate.ErrNoChange { + return fmt.Errorf("run migrations: %w", err) + } + + log.Println("Database migrations applied successfully") + return nil +} diff --git a/backend/internal/db/migrations/001_init.down.sql b/backend/internal/db/migrations/001_init.down.sql new file mode 100644 index 0000000..fce3daf --- /dev/null +++ b/backend/internal/db/migrations/001_init.down.sql @@ -0,0 +1 @@ +-- Rollback 001_init diff --git a/backend/internal/db/migrations/001_init.up.sql b/backend/internal/db/migrations/001_init.up.sql new file mode 100644 index 0000000..c709c31 --- /dev/null +++ b/backend/internal/db/migrations/001_init.up.sql @@ -0,0 +1,3 @@ +-- VaultDrop 001: Initial schema +-- This is a placeholder. Add your first CREATE TABLE here. +SELECT 1; diff --git a/backend/internal/db/migrations/schema.sql b/backend/internal/db/migrations/schema.sql deleted file mode 100644 index 54bf01d..0000000 --- a/backend/internal/db/migrations/schema.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE files ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL, - storage_key TEXT NOT NULL, - checksum TEXT NOT NULL, - created_at INTEGER NOT NULL, - updated_at INTEGER NOT NULL, - deleted_at INTEGER -); - -CREATE TABLE tags ( - id TEXT PRIMARY KEY, - name TEXT NOT NULL -); - -CREATE TABLE file_tags ( - file_id TEXT NOT NULL, - tag_id TEXT NOT NULL, - PRIMARY KEY (file_id, tag_id) -); diff --git a/backend/internal/db/models.go b/backend/internal/db/models.go index 9160ac7..21f493e 100644 --- a/backend/internal/db/models.go +++ b/backend/internal/db/models.go @@ -3,27 +3,3 @@ // sqlc v1.31.1 package db - -import ( - "database/sql" -) - -type File struct { - ID string `json:"id"` - Name string `json:"name"` - StorageKey string `json:"storage_key"` - Checksum string `json:"checksum"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` - DeletedAt sql.NullInt64 `json:"deleted_at"` -} - -type FileTag struct { - FileID string `json:"file_id"` - TagID string `json:"tag_id"` -} - -type Tag struct { - ID string `json:"id"` - Name string `json:"name"` -} diff --git a/backend/internal/db/queries/files.sql b/backend/internal/db/queries/files.sql deleted file mode 100644 index e062652..0000000 --- a/backend/internal/db/queries/files.sql +++ /dev/null @@ -1,15 +0,0 @@ --- name: GetFile :one -SELECT * FROM files -WHERE id = ? LIMIT 1; - --- name: ListFiles :many -SELECT * FROM files -ORDER BY name; - --- name: CreateFile :one -INSERT INTO files ( - name,storage_key,checksum,created_at,updated_at,deleted_at -) VALUES ( - ?, ?, ?,date(),date(),date() -) -RETURNING *; \ No newline at end of file diff --git a/backend/internal/db/queries/health.sql b/backend/internal/db/queries/health.sql new file mode 100644 index 0000000..c98cd10 --- /dev/null +++ b/backend/internal/db/queries/health.sql @@ -0,0 +1,2 @@ +-- name: GetHealth :one +SELECT 1 AS ok; diff --git a/backend/internal/handlers/files.go b/backend/internal/handlers/files.go index 3c87dc7..09cda66 100644 --- a/backend/internal/handlers/files.go +++ b/backend/internal/handlers/files.go @@ -1,8 +1,6 @@ package handlers import ( - "context" - "fmt" "net/http" "os" "path" @@ -10,7 +8,6 @@ import ( "strconv" "github.com/gin-gonic/gin" - "github.com/vaultdrop/backend/internal/db" "github.com/vaultdrop/backend/internal/service" ) @@ -172,8 +169,6 @@ func (h *Handlers) GetFile(c *gin.Context) { func (h *Handlers) UploadFile(c *gin.Context) { - ctx := context.Background() - file, err := c.FormFile("file") if err != nil { @@ -220,20 +215,14 @@ func (h *Handlers) UploadFile(c *gin.Context) { } checksum := service.CreateSHA256Hash(fileByte) - // save generate meta data - createFileParams := db.CreateFileParams{ - Name: file.Filename, - StorageKey: dst, - Checksum: string(checksum[:]), - } - - dbFile, err := h.queries.CreateFile(ctx, createFileParams) - - if err != nil { - fmt.Println(err) - } - - fmt.Println(dbFile.Checksum) + // TODO: re-enable once files table + query are added + // createFileParams := db.CreateFileParams{ + // Name: file.Filename, + // StorageKey: dst, + // Checksum: string(checksum[:]), + // } + // dbFile, err := h.queries.CreateFile(ctx, createFileParams) + _ = checksum c.JSON(http.StatusOK, gin.H{ "error": gin.H{ diff --git a/backend/sqlc.yaml b/backend/sqlc.yaml index 3f455af..97e2551 100644 --- a/backend/sqlc.yaml +++ b/backend/sqlc.yaml @@ -2,7 +2,7 @@ version: "2" sql: - engine: "sqlite" queries: "internal/db/queries/" - schema: "internal/db/migrations/schema.sql" + schema: "internal/db/migrations" gen: go: package: "db"