add migration system

This commit is contained in:
m
2026-07-12 09:28:20 +02:00
parent c2e0c9fce4
commit 1d35bea1c5
14 changed files with 67 additions and 176 deletions
+6
View File
@@ -15,12 +15,18 @@ func main() {
port = "8080" port = "8080"
} }
migrationsPath := "file://internal/db/migrations"
database, err := db.Connect() database, err := db.Connect()
if err != nil { if err != nil {
log.Fatalf("Failed to connect to database: %v", err) log.Fatalf("Failed to connect to database: %v", err)
} }
defer database.Close() defer database.Close()
if err := db.RunMigrations(database, migrationsPath); err != nil {
log.Fatalf("Failed to run migrations: %v", err)
}
queries := db.New(database) queries := db.New(database)
h := handlers.New(queries) h := handlers.New(queries)
+2
View File
@@ -20,6 +20,7 @@ require (
github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.2 // 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/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // 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/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // 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/ncruces/go-strftime v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect
+7
View File
@@ -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.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 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.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 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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= 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-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 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= 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 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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= 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/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 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 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 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= 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= 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/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 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= 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 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-96
View File
@@ -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
}
@@ -1,7 +1,7 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.31.1 // sqlc v1.31.1
// source: placeholder.sql // source: health.sql
package db package db
+36
View File
@@ -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
}
@@ -0,0 +1 @@
-- Rollback 001_init
@@ -0,0 +1,3 @@
-- VaultDrop 001: Initial schema
-- This is a placeholder. Add your first CREATE TABLE here.
SELECT 1;
-20
View File
@@ -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)
);
-24
View File
@@ -3,27 +3,3 @@
// sqlc v1.31.1 // sqlc v1.31.1
package db 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"`
}
-15
View File
@@ -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 *;
+2
View File
@@ -0,0 +1,2 @@
-- name: GetHealth :one
SELECT 1 AS ok;
+8 -19
View File
@@ -1,8 +1,6 @@
package handlers package handlers
import ( import (
"context"
"fmt"
"net/http" "net/http"
"os" "os"
"path" "path"
@@ -10,7 +8,6 @@ import (
"strconv" "strconv"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/vaultdrop/backend/internal/db"
"github.com/vaultdrop/backend/internal/service" "github.com/vaultdrop/backend/internal/service"
) )
@@ -172,8 +169,6 @@ func (h *Handlers) GetFile(c *gin.Context) {
func (h *Handlers) UploadFile(c *gin.Context) { func (h *Handlers) UploadFile(c *gin.Context) {
ctx := context.Background()
file, err := c.FormFile("file") file, err := c.FormFile("file")
if err != nil { if err != nil {
@@ -220,20 +215,14 @@ func (h *Handlers) UploadFile(c *gin.Context) {
} }
checksum := service.CreateSHA256Hash(fileByte) checksum := service.CreateSHA256Hash(fileByte)
// save generate meta data // TODO: re-enable once files table + query are added
createFileParams := db.CreateFileParams{ // createFileParams := db.CreateFileParams{
Name: file.Filename, // Name: file.Filename,
StorageKey: dst, // StorageKey: dst,
Checksum: string(checksum[:]), // Checksum: string(checksum[:]),
} // }
// dbFile, err := h.queries.CreateFile(ctx, createFileParams)
dbFile, err := h.queries.CreateFile(ctx, createFileParams) _ = checksum
if err != nil {
fmt.Println(err)
}
fmt.Println(dbFile.Checksum)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"error": gin.H{ "error": gin.H{
+1 -1
View File
@@ -2,7 +2,7 @@ version: "2"
sql: sql:
- engine: "sqlite" - engine: "sqlite"
queries: "internal/db/queries/" queries: "internal/db/queries/"
schema: "internal/db/migrations/schema.sql" schema: "internal/db/migrations"
gen: gen:
go: go:
package: "db" package: "db"