From 1ac86d9c0417c5cb0dd114cf5c03ff75dc5bf8c9 Mon Sep 17 00:00:00 2001 From: Matt Kilgore Date: Thu, 1 May 2025 15:03:08 -0400 Subject: [PATCH] Real Migrations System (#645) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- Taskfile.yml | 23 +- backend/app/api/main.go | 64 +--- backend/app/tools/migrations/main.go | 108 ------ backend/go.mod | 66 ++-- backend/go.sum | 162 ++++----- .../internal/data/migrations/migrations.go | 63 ++-- .../postgres/20241027025146_init.sql | 59 ++-- .../postgres/20250112202302_catchup.sql | 2 - .../postgres/20250112202302_sync_children.go | 38 ++ .../data/migrations/postgres/atlas.sum | 3 - .../internal/data/migrations/postgres/main.go | 4 + .../sqlite3/20220929052825_init.sql | 329 +++++++++++++++--- .../20221001210956_group_invitations.sql | 4 - .../sqlite3/20221009173029_add_user_roles.sql | 14 - .../20221020043305_allow_nesting_types.sql | 28 -- .../20221101041931_add_archived_field.sql | 22 -- .../20221113012312_add_asset_id_field.sql | 24 -- .../20221203053132_add_token_roles.sql | 4 - .../20221205230404_drop_document_tokens.sql | 5 - ...20221205234214_add_maintenance_entries.sql | 2 - .../20221205234812_cascade_delete_roles.sql | 16 - .../20230227024134_add_scheduled_date.sql | 12 - .../20230305065819_add_notifier_types.sql | 6 - ...230305071524_add_group_id_to_notifiers.sql | 20 -- ...1006213457_add_primary_attachment_flag.sql | 12 - .../sqlite3/20241226183416_sync_children.go | 51 +++ .../sqlite3/20241226183416_sync_childs.sql | 24 -- .../data/migrations/sqlite3/atlas.sum | 16 - .../internal/data/migrations/sqlite3/main.go | 4 + .../internal/data/repo/repo_maintenance.go | 10 +- backend/internal/data/repo/repo_users_test.go | 2 +- 31 files changed, 581 insertions(+), 616 deletions(-) delete mode 100644 backend/app/tools/migrations/main.go delete mode 100644 backend/internal/data/migrations/postgres/20250112202302_catchup.sql create mode 100644 backend/internal/data/migrations/postgres/20250112202302_sync_children.go delete mode 100644 backend/internal/data/migrations/postgres/atlas.sum create mode 100644 backend/internal/data/migrations/postgres/main.go delete mode 100644 backend/internal/data/migrations/sqlite3/20221001210956_group_invitations.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221009173029_add_user_roles.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221020043305_allow_nesting_types.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221101041931_add_archived_field.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221113012312_add_asset_id_field.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221203053132_add_token_roles.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221205230404_drop_document_tokens.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221205234214_add_maintenance_entries.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20221205234812_cascade_delete_roles.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20230227024134_add_scheduled_date.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20230305065819_add_notifier_types.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20230305071524_add_group_id_to_notifiers.sql delete mode 100644 backend/internal/data/migrations/sqlite3/20231006213457_add_primary_attachment_flag.sql create mode 100644 backend/internal/data/migrations/sqlite3/20241226183416_sync_children.go delete mode 100644 backend/internal/data/migrations/sqlite3/20241226183416_sync_childs.sql delete mode 100644 backend/internal/data/migrations/sqlite3/atlas.sum create mode 100644 backend/internal/data/migrations/sqlite3/main.go diff --git a/Taskfile.yml b/Taskfile.yml index ecdf6755..c3a043c2 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -11,6 +11,7 @@ tasks: desc: Install development dependencies cmds: - go install github.com/swaggo/swag/cmd/swag@latest + - go install github.com/pressly/goose/v3/cmd/goose@v3.8.0 - cd backend && go mod tidy - cd frontend && pnpm install --shamefully-hoist @@ -137,28 +138,6 @@ tasks: sources: - "./backend/internal/data/ent/schema/**/*" - db:migration: - desc: Runs the database diff engine to generate a SQL migration files - deps: - - db:generate - cmds: - - cd backend && go run app/tools/migrations/main.go {{ .CLI_ARGS }} - - db:migration:postgresql: - env: - HBOX_DATABASE_DRIVER: postgres - HBOX_DATABASE_USERNAME: homebox - HBOX_DATABASE_PASSWORD: homebox - HBOX_DATABASE_DATABASE: homebox - HBOX_DATABASE_HOST: localhost - HBOX_DATABASE_PORT: 5432 - HBOX_DATABASE_SSL_MODE: disable - desc: Runs the database diff engine to generate a SQL migration files for postgresql - deps: - - db:generate - cmds: - - cd backend && go run app/tools/migrations/main.go {{ .CLI_ARGS }} - ui:watch: desc: Starts the vitest test runner in watch mode dir: frontend diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 245315b2..e0c4407c 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -6,15 +6,11 @@ import ( "fmt" "net/http" "os" - "path/filepath" "strings" "time" + + "github.com/pressly/goose/v3" - "github.com/google/uuid" - "github.com/sysadminsmedia/homebox/backend/internal/sys/analytics" - - atlas "ariga.io/atlas/sql/migrate" - "entgo.io/ent/dialect/sql/schema" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -27,12 +23,15 @@ import ( "github.com/sysadminsmedia/homebox/backend/internal/core/services" "github.com/sysadminsmedia/homebox/backend/internal/core/services/reporting/eventbus" "github.com/sysadminsmedia/homebox/backend/internal/data/ent" - "github.com/sysadminsmedia/homebox/backend/internal/data/migrations" + "github.com/sysadminsmedia/homebox/backend/internal/data/migrations" "github.com/sysadminsmedia/homebox/backend/internal/data/repo" + "github.com/sysadminsmedia/homebox/backend/internal/sys/analytics" "github.com/sysadminsmedia/homebox/backend/internal/sys/config" "github.com/sysadminsmedia/homebox/backend/internal/web/mid" _ "github.com/lib/pq" + _ "github.com/sysadminsmedia/homebox/backend/internal/data/migrations/postgres" + _ "github.com/sysadminsmedia/homebox/backend/internal/data/migrations/sqlite3" _ "github.com/sysadminsmedia/homebox/backend/pkgs/cgofreesqlite" ) @@ -134,52 +133,19 @@ func run(cfg *config.Config) error { Str("database", cfg.Database.Database). Msg("failed opening connection to {driver} database at {host}:{port}/{database}") } - defer func(c *ent.Client) { - err := c.Close() - if err != nil { - log.Fatal().Err(err).Msg("failed to close database connection") - } - }(c) - // Always create a random temporary directory for migrations - tempUUID, err := uuid.NewUUID() + goose.SetBaseFS(migrations.Migrations(strings.ToLower(cfg.Database.Driver))) + err = goose.SetDialect(strings.ToLower(cfg.Database.Driver)) if err != nil { + log.Fatal().Str("driver", cfg.Database.Driver).Msg("unsupported database driver") + return fmt.Errorf("unsupported database driver: %s", cfg.Database.Driver) + } + + err = goose.Up(c.Sql(), strings.ToLower(cfg.Database.Driver)) + if err != nil { + log.Error().Err(err).Msg("failed to migrate database") return err } - temp := filepath.Join(os.TempDir(), fmt.Sprintf("homebox-%s", tempUUID.String())) - - err = migrations.Write(temp, cfg.Database.Driver) - if err != nil { - return err - } - - dir, err := atlas.NewLocalDir(temp) - if err != nil { - return err - } - - options := []schema.MigrateOption{ - schema.WithDir(dir), - schema.WithDropColumn(true), - schema.WithDropIndex(true), - } - - err = c.Schema.Create(context.Background(), options...) - if err != nil { - log.Error(). - Err(err). - Str("driver", cfg.Database.Driver). - Str("url", databaseURL). - Msg("failed creating schema resources") - return err - } - - defer func() { - err := os.RemoveAll(temp) - if err != nil { - log.Error().Err(err).Msg("failed to remove temporary directory for database migrations") - } - }() collectFuncs := []currencies.CollectorFunc{ currencies.CollectDefaults(), diff --git a/backend/app/tools/migrations/main.go b/backend/app/tools/migrations/main.go deleted file mode 100644 index fd952cc8..00000000 --- a/backend/app/tools/migrations/main.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "context" - "fmt" - "github.com/sysadminsmedia/homebox/backend/internal/sys/config" - "log" - "os" - "path/filepath" - "strings" - - "github.com/sysadminsmedia/homebox/backend/internal/data/ent/migrate" - - atlas "ariga.io/atlas/sql/migrate" - _ "ariga.io/atlas/sql/sqlite" - "entgo.io/ent/dialect" - "entgo.io/ent/dialect/sql/schema" - - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" -) - -func main() { - cfg, err := config.New(build(), "Homebox inventory management system") - if err != nil { - panic(err) - } - sqlDialect := "" - switch strings.ToLower(cfg.Database.Driver) { - case "sqlite3": - sqlDialect = dialect.SQLite - case "postgres": - sqlDialect = dialect.Postgres - default: - log.Fatalf("unsupported database driver: %s", cfg.Database.Driver) - } - ctx := context.Background() - // Create a local migration directory able to understand Atlas migration file format for replay. - safePath := filepath.Clean(fmt.Sprintf("internal/data/migrations/%s", sqlDialect)) - dir, err := atlas.NewLocalDir(safePath) - if err != nil { - log.Fatalf("failed creating atlas migration directory: %v", err) - } - // Migrate diff options. - opts := []schema.MigrateOption{ - schema.WithDir(dir), // provide migration directory - schema.WithMigrationMode(schema.ModeReplay), // provide migration mode - schema.WithDialect(sqlDialect), // Ent dialect to use - schema.WithFormatter(atlas.DefaultFormatter), - schema.WithDropIndex(true), - schema.WithDropColumn(true), - } - if len(os.Args) != 2 { - log.Fatalln("migration name is required. Use: 'go run -mod=mod ent/migrate/main.go '") - } - - if sqlDialect == dialect.Postgres { - if !validatePostgresSSLMode(cfg.Database.SslMode) { - log.Fatalf("invalid sslmode: %s", cfg.Database.SslMode) - } - } - - databaseURL := "" - switch { - case cfg.Database.Driver == "sqlite3": - databaseURL = fmt.Sprintf("sqlite://%s", cfg.Database.SqlitePath) - case cfg.Database.Driver == "postgres": - databaseURL = fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Database, cfg.Database.SslMode) - default: - log.Fatalf("unsupported database driver: %s", cfg.Database.Driver) - } - - // Generate migrations using Atlas support for MySQL (note the Ent dialect option passed above). - err = migrate.NamedDiff(ctx, databaseURL, os.Args[1], opts...) - if err != nil { - log.Fatalf("failed generating migration file: %v", err) - } - - fmt.Println("Migration file generated successfully.") -} - -var ( - version = "nightly" - commit = "HEAD" - buildTime = "now" -) - -func build() string { - short := commit - if len(short) > 7 { - short = short[:7] - } - - return fmt.Sprintf("%s, commit %s, built at %s", version, short, buildTime) -} - -func validatePostgresSSLMode(sslMode string) bool { - validModes := map[string]bool{ - "": true, - "disable": true, - "allow": true, - "prefer": true, - "require": true, - "verify-ca": true, - "verify-full": true, - } - return validModes[strings.ToLower(strings.TrimSpace(sslMode))] -} diff --git a/backend/go.mod b/backend/go.mod index d0a071e3..5178b0e6 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -3,41 +3,45 @@ module github.com/sysadminsmedia/homebox/backend go 1.23.0 require ( - ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 - entgo.io/ent v0.14.3 - github.com/ardanlabs/conf/v3 v3.4.0 + entgo.io/ent v0.14.4 + github.com/ardanlabs/conf/v3 v3.7.2 github.com/containrrr/shoutrrr v0.8.0 github.com/go-chi/chi/v5 v5.2.1 - github.com/go-playground/validator/v10 v10.25.0 + github.com/go-playground/validator/v10 v10.26.0 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/google/uuid v1.6.0 github.com/gorilla/schema v1.4.1 github.com/hay-kot/httpkit v0.0.11 github.com/lib/pq v1.10.9 - github.com/mattn/go-sqlite3 v1.14.24 + github.com/mattn/go-sqlite3 v1.14.28 github.com/olahol/melody v1.2.1 github.com/pkg/errors v0.9.1 - github.com/rs/zerolog v1.33.0 - github.com/shirou/gopsutil/v4 v4.24.9 + github.com/pressly/goose/v3 v3.24.2 + github.com/rs/zerolog v1.34.0 + github.com/shirou/gopsutil/v4 v4.25.3 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.10.0 github.com/swaggo/http-swagger/v2 v2.0.2 github.com/swaggo/swag v1.16.4 github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/writer/standard v1.2.5 - golang.org/x/crypto v0.35.0 - modernc.org/sqlite v1.36.0 + golang.org/x/crypto v0.37.0 + modernc.org/sqlite v1.37.0 ) require ( - github.com/ebitengine/purego v0.8.0 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + ariga.io/atlas v0.32.0 // indirect + github.com/ebitengine/purego v0.8.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect + github.com/mfridman/interpolate v0.0.2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/sethvargo/go-retry v0.3.0 // indirect + github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zclconf/go-cty-yaml v1.1.0 // indirect + go.uber.org/multierr v1.11.0 // indirect ) require ( @@ -49,16 +53,16 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fogleman/gg v1.3.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect - github.com/go-openapi/inflect v0.21.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/go-openapi/inflect v0.21.2 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/hcl/v2 v2.23.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -72,17 +76,17 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/swaggo/files/v2 v2.0.2 // indirect github.com/yeqown/reedsolomon v1.0.0 // indirect - github.com/zclconf/go-cty v1.16.0 // indirect - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect - golang.org/x/image v0.23.0 - golang.org/x/mod v0.23.0 // indirect - golang.org/x/net v0.36.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.30.0 // indirect + github.com/zclconf/go-cty v1.16.2 // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect + golang.org/x/image v0.26.0 + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + golang.org/x/tools v0.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/libc v1.61.13 // indirect + modernc.org/libc v1.63.0 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.8.2 // indirect + modernc.org/memory v1.10.0 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 53ec7832..26734342 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,7 +1,7 @@ -ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 h1:nX4HXncwIdvQ8/8sIUIf1nyCkK8qdBaHQ7EtzPpuiGE= -ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w= -entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ= -entgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM= +ariga.io/atlas v0.32.0 h1:y+77nueMrExLiKlz1CcPKh/nU7VSlWfBbwCShsJyvCw= +ariga.io/atlas v0.32.0/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w= +entgo.io/ent v0.14.4 h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI= +entgo.io/ent v0.14.4/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -10,8 +10,8 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/ardanlabs/conf/v3 v3.4.0 h1:Qy7/doJjhsv7Lvzqd9tbvH8fAZ9jzqKtwnwcmZ+sxGs= -github.com/ardanlabs/conf/v3 v3.4.0/go.mod h1:OIi6NK95fj8jKFPdZ/UmcPlY37JBg99hdP9o5XmNK9c= +github.com/ardanlabs/conf/v3 v3.7.2 h1:s2VBuDJM6OQfR0erDuopiZ+dHUQVqGxZeLrTsls03dw= +github.com/ardanlabs/conf/v3 v3.7.2/go.mod h1:XlL9P0quWP4m1weOVFmlezabinbZLI05niDof/+Ochk= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec= @@ -21,38 +21,39 @@ 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/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/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE= -github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= +github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= -github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/inflect v0.21.2 h1:0gClGlGcxifcJR56zwvhaOulnNgnhc4qTAkob5ObnSM= +github.com/go-openapi/inflect v0.21.2/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8= -github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= @@ -64,11 +65,10 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +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/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= @@ -91,8 +91,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= +github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -102,8 +102,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= +github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= +github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= @@ -118,17 +120,21 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/pressly/goose/v3 v3.24.2 h1:c/ie0Gm8rnIVKvnDQ/scHErv46jrDv9b4I0WRcFJzYU= +github.com/pressly/goose/v3 v3.24.2/go.mod h1:kjefwFB0eR4w30Td2Gj2Mznyw94vSP+2jJYkOVNbD1k= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/shirou/gopsutil/v4 v4.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI= -github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= +github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= +github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= +github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -139,10 +145,10 @@ github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSy github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= +github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= +github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yeqown/go-qrcode/v2 v2.2.5 h1:HCOe2bSjkhZyYoyyNaXNzh4DJZll6inVJQQw+8228Zk= github.com/yeqown/go-qrcode/v2 v2.2.5/go.mod h1:uHpt9CM0V1HeXLz+Wg5MN50/sI/fQhfkZlOM+cOTHxw= github.com/yeqown/go-qrcode/writer/standard v1.2.5 h1:m+5BUIcbsaG2md76FIqI/oZULrAju8tsk47eOohovQ0= @@ -151,65 +157,65 @@ github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zclconf/go-cty v1.16.0 h1:xPKEhst+BW5D0wxebMZkxgapvOE/dw7bFTlgSc9nD6w= -github.com/zclconf/go-cty v1.16.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70= +github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0= github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= -golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= -golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY= +golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= -modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo= -modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo= +modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA= +modernc.org/cc/v4 v4.26.0/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.26.0 h1:gVzXaDzGeBYJ2uXTOpR8FR7OlksDOe9jxnjhIKCsiTc= +modernc.org/ccgo/v4 v4.26.0/go.mod h1:Sem8f7TFUtVXkG2fiaChQtyyfkqhJBg/zjEJBkmuAVY= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw= -modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8= -modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/libc v1.63.0 h1:wKzb61wOGCzgahQBORb1b0dZonh8Ufzl/7r4Yf1D5YA= +modernc.org/libc v1.63.0/go.mod h1:wDzH1mgz1wUIEwottFt++POjGRO9sgyQKrpXaz3x89E= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI= -modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU= +modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4= +modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.36.0 h1:EQXNRn4nIS+gfsKeUTymHIz1waxuv5BzU7558dHSfH8= -modernc.org/sqlite v1.36.0/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU= +modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= +modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/backend/internal/data/migrations/migrations.go b/backend/internal/data/migrations/migrations.go index ae8852f4..01839220 100644 --- a/backend/internal/data/migrations/migrations.go +++ b/backend/internal/data/migrations/migrations.go @@ -1,50 +1,31 @@ -// Package migrations provides a way to embed the migrations into the binary. +// Package migrations package migrations import ( "embed" - "fmt" - "os" - "path" + "github.com/rs/zerolog/log" ) -//go:embed all:sqlite3 all:postgres -var Files embed.FS +//go:embed all:postgres +var postgresFiles embed.FS -// Write writes the embedded migrations to a temporary directory. -// It returns an error and a cleanup function. The cleanup function -// should be called when the migrations are no longer needed. -func Write(temp string, dialect string) error { - allowedDialects := map[string]bool{"sqlite3": true, "postgres": true} - if !allowedDialects[dialect] { - return fmt.Errorf("unsupported dialect: %s", dialect) +//go:embed all:sqlite3 +var sqliteFiles embed.FS + +// Migrations returns the embedded file system containing the SQL migration files +// for the specified SQL dialect. It uses the "embed" package to include the +// migration files in the binary at build time. The function takes a string +// parameter "dialect" which specifies the SQL dialect to use. It returns an +// embedded file system containing the migration files for the specified dialect. +func Migrations(dialect string) embed.FS { + switch dialect { + case "postgres": + return postgresFiles + case "sqlite3": + return sqliteFiles + default: + log.Fatal().Str("dialect", dialect).Msg("unknown sql dialect") } - - err := os.MkdirAll(temp, 0o755) - if err != nil { - return err - } - - fsDir, err := Files.ReadDir(dialect) - if err != nil { - return err - } - - for _, f := range fsDir { - if f.IsDir() { - continue - } - - b, err := Files.ReadFile(path.Join(dialect, f.Name())) - if err != nil { - return err - } - - err = os.WriteFile(path.Join(temp, f.Name()), b, 0o644) - if err != nil { - return err - } - } - - return nil + // This should never get hit, but just in case + return sqliteFiles } diff --git a/backend/internal/data/migrations/postgres/20241027025146_init.sql b/backend/internal/data/migrations/postgres/20241027025146_init.sql index a1ebcb70..204b4167 100644 --- a/backend/internal/data/migrations/postgres/20241027025146_init.sql +++ b/backend/internal/data/migrations/postgres/20241027025146_init.sql @@ -1,58 +1,57 @@ +-- +goose Up -- Create "groups" table -CREATE TABLE "groups" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "currency" character varying NOT NULL DEFAULT 'usd', PRIMARY KEY ("id")); +CREATE TABLE IF NOT EXISTS "groups" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "currency" character varying NOT NULL DEFAULT 'usd', PRIMARY KEY ("id")); -- Create "documents" table -CREATE TABLE "documents" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "title" character varying NOT NULL, "path" character varying NOT NULL, "group_documents" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "documents_groups_documents" FOREIGN KEY ("group_documents") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "documents" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "title" character varying NOT NULL, "path" character varying NOT NULL, "group_documents" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "documents_groups_documents" FOREIGN KEY ("group_documents") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "locations" table -CREATE TABLE "locations" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "group_locations" uuid NOT NULL, "location_children" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "locations_groups_locations" FOREIGN KEY ("group_locations") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "locations_locations_children" FOREIGN KEY ("location_children") REFERENCES "locations" ("id") ON UPDATE NO ACTION ON DELETE SET NULL); +CREATE TABLE IF NOT EXISTS "locations" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "group_locations" uuid NOT NULL, "location_children" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "locations_groups_locations" FOREIGN KEY ("group_locations") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "locations_locations_children" FOREIGN KEY ("location_children") REFERENCES "locations" ("id") ON UPDATE NO ACTION ON DELETE SET NULL); -- Create "items" table -CREATE TABLE "items" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "import_ref" character varying NULL, "notes" character varying NULL, "quantity" bigint NOT NULL DEFAULT 1, "insured" boolean NOT NULL DEFAULT false, "archived" boolean NOT NULL DEFAULT false, "asset_id" bigint NOT NULL DEFAULT 0, "serial_number" character varying NULL, "model_number" character varying NULL, "manufacturer" character varying NULL, "lifetime_warranty" boolean NOT NULL DEFAULT false, "warranty_expires" timestamptz NULL, "warranty_details" character varying NULL, "purchase_time" timestamptz NULL, "purchase_from" character varying NULL, "purchase_price" double precision NOT NULL DEFAULT 0, "sold_time" timestamptz NULL, "sold_to" character varying NULL, "sold_price" double precision NOT NULL DEFAULT 0, "sold_notes" character varying NULL, "group_items" uuid NOT NULL, "item_children" uuid NULL, "location_items" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "items_groups_items" FOREIGN KEY ("group_items") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "items_items_children" FOREIGN KEY ("item_children") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE SET NULL, CONSTRAINT "items_locations_items" FOREIGN KEY ("location_items") REFERENCES "locations" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "items" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "import_ref" character varying NULL, "notes" character varying NULL, "quantity" bigint NOT NULL DEFAULT 1, "insured" boolean NOT NULL DEFAULT false, "archived" boolean NOT NULL DEFAULT false, "asset_id" bigint NOT NULL DEFAULT 0, "serial_number" character varying NULL, "model_number" character varying NULL, "manufacturer" character varying NULL, "lifetime_warranty" boolean NOT NULL DEFAULT false, "warranty_expires" timestamptz NULL, "warranty_details" character varying NULL, "purchase_time" timestamptz NULL, "purchase_from" character varying NULL, "purchase_price" double precision NOT NULL DEFAULT 0, "sold_time" timestamptz NULL, "sold_to" character varying NULL, "sold_price" double precision NOT NULL DEFAULT 0, "sold_notes" character varying NULL, "group_items" uuid NOT NULL, "item_children" uuid NULL, "location_items" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "items_groups_items" FOREIGN KEY ("group_items") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "items_items_children" FOREIGN KEY ("item_children") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE SET NULL, CONSTRAINT "items_locations_items" FOREIGN KEY ("location_items") REFERENCES "locations" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "item_archived" to table: "items" -CREATE INDEX "item_archived" ON "items" ("archived"); +CREATE INDEX IF NOT EXISTS "item_archived" ON "items" ("archived"); -- Create index "item_asset_id" to table: "items" -CREATE INDEX "item_asset_id" ON "items" ("asset_id"); +CREATE INDEX IF NOT EXISTS "item_asset_id" ON "items" ("asset_id"); -- Create index "item_manufacturer" to table: "items" -CREATE INDEX "item_manufacturer" ON "items" ("manufacturer"); +CREATE INDEX IF NOT EXISTS "item_manufacturer" ON "items" ("manufacturer"); -- Create index "item_model_number" to table: "items" -CREATE INDEX "item_model_number" ON "items" ("model_number"); +CREATE INDEX IF NOT EXISTS "item_model_number" ON "items" ("model_number"); -- Create index "item_name" to table: "items" -CREATE INDEX "item_name" ON "items" ("name"); +CREATE INDEX IF NOT EXISTS "item_name" ON "items" ("name"); -- Create index "item_serial_number" to table: "items" -CREATE INDEX "item_serial_number" ON "items" ("serial_number"); +CREATE INDEX IF NOT EXISTS "item_serial_number" ON "items" ("serial_number"); -- Create "attachments" table -CREATE TABLE "attachments" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "type" character varying NOT NULL DEFAULT 'attachment', "primary" boolean NOT NULL DEFAULT false, "document_attachments" uuid NOT NULL, "item_attachments" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "attachments_documents_attachments" FOREIGN KEY ("document_attachments") REFERENCES "documents" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "attachments_items_attachments" FOREIGN KEY ("item_attachments") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "attachments" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "type" character varying NOT NULL DEFAULT 'attachment', "primary" boolean NOT NULL DEFAULT false, "document_attachments" uuid NOT NULL, "item_attachments" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "attachments_documents_attachments" FOREIGN KEY ("document_attachments") REFERENCES "documents" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "attachments_items_attachments" FOREIGN KEY ("item_attachments") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "users" table -CREATE TABLE "users" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, "is_superuser" boolean NOT NULL DEFAULT false, "superuser" boolean NOT NULL DEFAULT false, "role" character varying NOT NULL DEFAULT 'user', "activated_on" timestamptz NULL, "group_users" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "users_groups_users" FOREIGN KEY ("group_users") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "users" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, "is_superuser" boolean NOT NULL DEFAULT false, "superuser" boolean NOT NULL DEFAULT false, "role" character varying NOT NULL DEFAULT 'user', "activated_on" timestamptz NULL, "group_users" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "users_groups_users" FOREIGN KEY ("group_users") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "users_email_key" to table: "users" -CREATE UNIQUE INDEX "users_email_key" ON "users" ("email"); +CREATE UNIQUE INDEX IF NOT EXISTS "users_email_key" ON "users" ("email"); -- Create "auth_tokens" table -CREATE TABLE "auth_tokens" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "token" bytea NOT NULL, "expires_at" timestamptz NOT NULL, "user_auth_tokens" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "auth_tokens_users_auth_tokens" FOREIGN KEY ("user_auth_tokens") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "auth_tokens" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "token" bytea NOT NULL, "expires_at" timestamptz NOT NULL, "user_auth_tokens" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "auth_tokens_users_auth_tokens" FOREIGN KEY ("user_auth_tokens") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "auth_tokens_token_key" to table: "auth_tokens" -CREATE UNIQUE INDEX "auth_tokens_token_key" ON "auth_tokens" ("token"); --- Create index "authtokens_token" to table: "auth_tokens" -CREATE INDEX "authtokens_token" ON "auth_tokens" ("token"); +CREATE UNIQUE INDEX IF NOT EXISTS "auth_tokens_token_key" ON "auth_tokens" ("token"); -- Create "auth_roles" table -CREATE TABLE "auth_roles" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "role" character varying NOT NULL DEFAULT 'user', "auth_tokens_roles" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "auth_roles_auth_tokens_roles" FOREIGN KEY ("auth_tokens_roles") REFERENCES "auth_tokens" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "auth_roles" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "role" character varying NOT NULL DEFAULT 'user', "auth_tokens_roles" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "auth_roles_auth_tokens_roles" FOREIGN KEY ("auth_tokens_roles") REFERENCES "auth_tokens" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "auth_roles_auth_tokens_roles_key" to table: "auth_roles" -CREATE UNIQUE INDEX "auth_roles_auth_tokens_roles_key" ON "auth_roles" ("auth_tokens_roles"); +CREATE UNIQUE INDEX IF NOT EXISTS "auth_roles_auth_tokens_roles_key" ON "auth_roles" ("auth_tokens_roles"); -- Create "group_invitation_tokens" table -CREATE TABLE "group_invitation_tokens" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "token" bytea NOT NULL, "expires_at" timestamptz NOT NULL, "uses" bigint NOT NULL DEFAULT 0, "group_invitation_tokens" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "group_invitation_tokens_groups_invitation_tokens" FOREIGN KEY ("group_invitation_tokens") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "group_invitation_tokens" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "token" bytea NOT NULL, "expires_at" timestamptz NOT NULL, "uses" bigint NOT NULL DEFAULT 0, "group_invitation_tokens" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "group_invitation_tokens_groups_invitation_tokens" FOREIGN KEY ("group_invitation_tokens") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "group_invitation_tokens_token_key" to table: "group_invitation_tokens" -CREATE UNIQUE INDEX "group_invitation_tokens_token_key" ON "group_invitation_tokens" ("token"); +CREATE UNIQUE INDEX IF NOT EXISTS "group_invitation_tokens_token_key" ON "group_invitation_tokens" ("token"); -- Create "item_fields" table -CREATE TABLE "item_fields" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "type" character varying NOT NULL, "text_value" character varying NULL, "number_value" bigint NULL, "boolean_value" boolean NOT NULL DEFAULT false, "time_value" timestamptz NOT NULL, "item_fields" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "item_fields_items_fields" FOREIGN KEY ("item_fields") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "item_fields" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "type" character varying NOT NULL, "text_value" character varying NULL, "number_value" bigint NULL, "boolean_value" boolean NOT NULL DEFAULT false, "time_value" timestamptz NOT NULL, "item_fields" uuid NULL, PRIMARY KEY ("id"), CONSTRAINT "item_fields_items_fields" FOREIGN KEY ("item_fields") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "labels" table -CREATE TABLE "labels" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "color" character varying NULL, "group_labels" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "labels_groups_labels" FOREIGN KEY ("group_labels") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "labels" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "description" character varying NULL, "color" character varying NULL, "group_labels" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "labels_groups_labels" FOREIGN KEY ("group_labels") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "label_items" table -CREATE TABLE "label_items" ("label_id" uuid NOT NULL, "item_id" uuid NOT NULL, PRIMARY KEY ("label_id", "item_id"), CONSTRAINT "label_items_item_id" FOREIGN KEY ("item_id") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "label_items_label_id" FOREIGN KEY ("label_id") REFERENCES "labels" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "label_items" ("label_id" uuid NOT NULL, "item_id" uuid NOT NULL, PRIMARY KEY ("label_id", "item_id"), CONSTRAINT "label_items_item_id" FOREIGN KEY ("item_id") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "label_items_label_id" FOREIGN KEY ("label_id") REFERENCES "labels" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "maintenance_entries" table -CREATE TABLE "maintenance_entries" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "date" timestamptz NULL, "scheduled_date" timestamptz NULL, "name" character varying NOT NULL, "description" character varying NULL, "cost" double precision NOT NULL DEFAULT 0, "item_id" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "maintenance_entries_items_maintenance_entries" FOREIGN KEY ("item_id") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "maintenance_entries" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "date" timestamptz NULL, "scheduled_date" timestamptz NULL, "name" character varying NOT NULL, "description" character varying NULL, "cost" double precision NOT NULL DEFAULT 0, "item_id" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "maintenance_entries_items_maintenance_entries" FOREIGN KEY ("item_id") REFERENCES "items" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create "notifiers" table -CREATE TABLE "notifiers" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "url" character varying NOT NULL, "is_active" boolean NOT NULL DEFAULT true, "group_id" uuid NOT NULL, "user_id" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "notifiers_groups_notifiers" FOREIGN KEY ("group_id") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "notifiers_users_notifiers" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); +CREATE TABLE IF NOT EXISTS "notifiers" ("id" uuid NOT NULL, "created_at" timestamptz NOT NULL, "updated_at" timestamptz NOT NULL, "name" character varying NOT NULL, "url" character varying NOT NULL, "is_active" boolean NOT NULL DEFAULT true, "group_id" uuid NOT NULL, "user_id" uuid NOT NULL, PRIMARY KEY ("id"), CONSTRAINT "notifiers_groups_notifiers" FOREIGN KEY ("group_id") REFERENCES "groups" ("id") ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT "notifiers_users_notifiers" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON UPDATE NO ACTION ON DELETE CASCADE); -- Create index "notifier_group_id" to table: "notifiers" -CREATE INDEX "notifier_group_id" ON "notifiers" ("group_id"); +CREATE INDEX IF NOT EXISTS "notifier_group_id" ON "notifiers" ("group_id"); -- Create index "notifier_group_id_is_active" to table: "notifiers" -CREATE INDEX "notifier_group_id_is_active" ON "notifiers" ("group_id", "is_active"); +CREATE INDEX IF NOT EXISTS "notifier_group_id_is_active" ON "notifiers" ("group_id", "is_active"); -- Create index "notifier_user_id" to table: "notifiers" -CREATE INDEX "notifier_user_id" ON "notifiers" ("user_id"); +CREATE INDEX IF NOT EXISTS "notifier_user_id" ON "notifiers" ("user_id"); -- Create index "notifier_user_id_is_active" to table: "notifiers" -CREATE INDEX "notifier_user_id_is_active" ON "notifiers" ("user_id", "is_active"); +CREATE INDEX IF NOT EXISTS "notifier_user_id_is_active" ON "notifiers" ("user_id", "is_active"); diff --git a/backend/internal/data/migrations/postgres/20250112202302_catchup.sql b/backend/internal/data/migrations/postgres/20250112202302_catchup.sql deleted file mode 100644 index 94dc388c..00000000 --- a/backend/internal/data/migrations/postgres/20250112202302_catchup.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Modify "items" table -ALTER TABLE "items" ADD COLUMN "sync_child_items_locations" boolean NOT NULL DEFAULT false; diff --git a/backend/internal/data/migrations/postgres/20250112202302_sync_children.go b/backend/internal/data/migrations/postgres/20250112202302_sync_children.go new file mode 100644 index 00000000..592137be --- /dev/null +++ b/backend/internal/data/migrations/postgres/20250112202302_sync_children.go @@ -0,0 +1,38 @@ +package postgres + +import ( + "context" + "database/sql" + "fmt" + "github.com/pressly/goose/v3" +) + +//nolint:gochecknoinits +func init() { + goose.AddMigrationContext(Up20250112202302, Down20250112202302) +} + +func Up20250112202302(ctx context.Context, tx *sql.Tx) error { + columnName := "sync_child_items_locations" + query := ` + SELECT column_name + FROM information_schema.columns + WHERE table_name = 'items' AND column_name = 'sync_child_items_locations'; + ` + err := tx.QueryRowContext(ctx, query).Scan(&columnName) + if err != nil { + // Column does not exist, proceed with migration + _, err = tx.ExecContext(ctx, ` + ALTER TABLE "items" ADD COLUMN "sync_child_items_locations" boolean NOT NULL DEFAULT false; + `) + if err != nil { + return fmt.Errorf("failed to execute migration: %w", err) + } + } + return nil +} + +func Down20250112202302(ctx context.Context, tx *sql.Tx) error { + // This migration is a no-op for Postgres. + return nil +} diff --git a/backend/internal/data/migrations/postgres/atlas.sum b/backend/internal/data/migrations/postgres/atlas.sum deleted file mode 100644 index 7ca02ddb..00000000 --- a/backend/internal/data/migrations/postgres/atlas.sum +++ /dev/null @@ -1,3 +0,0 @@ -h1:3uDJVgJuOnlMCx2Ma6EC8WhM6Kiv/1ioXEyEQkeotnU= -20241027025146_init.sql h1:PJhm+pjGRtFfgmGu7MwJo8+bVelVfU5LB+LZ/c8nnGE= -20250112202302_catchup.sql h1:DCzm15PdJewaPY7hzhFWiBJqYxEDd0ZKGOUhK0/1hgc= diff --git a/backend/internal/data/migrations/postgres/main.go b/backend/internal/data/migrations/postgres/main.go new file mode 100644 index 00000000..eaf9e197 --- /dev/null +++ b/backend/internal/data/migrations/postgres/main.go @@ -0,0 +1,4 @@ +// Package postgres provides the PostgreSQL database migration +package postgres + +// This file exists to make Goose happy. It really doesn't do anything else. diff --git a/backend/internal/data/migrations/sqlite3/20220929052825_init.sql b/backend/internal/data/migrations/sqlite3/20220929052825_init.sql index 579d559d..2133d961 100644 --- a/backend/internal/data/migrations/sqlite3/20220929052825_init.sql +++ b/backend/internal/data/migrations/sqlite3/20220929052825_init.sql @@ -1,40 +1,289 @@ --- create "attachments" table -CREATE TABLE `attachments` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `type` text NOT NULL DEFAULT 'attachment', `document_attachments` uuid NOT NULL, `item_attachments` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `attachments_documents_attachments` FOREIGN KEY (`document_attachments`) REFERENCES `documents` (`id`) ON DELETE CASCADE, CONSTRAINT `attachments_items_attachments` FOREIGN KEY (`item_attachments`) REFERENCES `items` (`id`) ON DELETE CASCADE); --- create "auth_tokens" table -CREATE TABLE `auth_tokens` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `token` blob NOT NULL, `expires_at` datetime NOT NULL, `user_auth_tokens` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `auth_tokens_users_auth_tokens` FOREIGN KEY (`user_auth_tokens`) REFERENCES `users` (`id`) ON DELETE CASCADE); --- create index "auth_tokens_token_key" to table: "auth_tokens" -CREATE UNIQUE INDEX `auth_tokens_token_key` ON `auth_tokens` (`token`); --- create index "authtokens_token" to table: "auth_tokens" -CREATE INDEX `authtokens_token` ON `auth_tokens` (`token`); --- create "documents" table -CREATE TABLE `documents` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `title` text NOT NULL, `path` text NOT NULL, `group_documents` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `documents_groups_documents` FOREIGN KEY (`group_documents`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- create "document_tokens" table -CREATE TABLE `document_tokens` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `token` blob NOT NULL, `uses` integer NOT NULL DEFAULT 1, `expires_at` datetime NOT NULL, `document_document_tokens` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `document_tokens_documents_document_tokens` FOREIGN KEY (`document_document_tokens`) REFERENCES `documents` (`id`) ON DELETE CASCADE); --- create index "document_tokens_token_key" to table: "document_tokens" -CREATE UNIQUE INDEX `document_tokens_token_key` ON `document_tokens` (`token`); --- create index "documenttoken_token" to table: "document_tokens" -CREATE INDEX `documenttoken_token` ON `document_tokens` (`token`); --- create "groups" table -CREATE TABLE `groups` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `currency` text NOT NULL DEFAULT 'usd', PRIMARY KEY (`id`)); --- create "items" table -CREATE TABLE `items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT 1, `insured` bool NOT NULL DEFAULT false, `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT false, `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT 0, `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT 0, `sold_notes` text NULL, `group_items` uuid NOT NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE); --- create index "item_name" to table: "items" -CREATE INDEX `item_name` ON `items` (`name`); --- create index "item_manufacturer" to table: "items" -CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`); --- create index "item_model_number" to table: "items" -CREATE INDEX `item_model_number` ON `items` (`model_number`); --- create index "item_serial_number" to table: "items" -CREATE INDEX `item_serial_number` ON `items` (`serial_number`); --- create "item_fields" table -CREATE TABLE `item_fields` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `type` text NOT NULL, `text_value` text NULL, `number_value` integer NULL, `boolean_value` bool NOT NULL DEFAULT false, `time_value` datetime NOT NULL, `item_fields` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `item_fields_items_fields` FOREIGN KEY (`item_fields`) REFERENCES `items` (`id`) ON DELETE CASCADE); --- create "labels" table -CREATE TABLE `labels` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `color` text NULL, `group_labels` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `labels_groups_labels` FOREIGN KEY (`group_labels`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- create "locations" table -CREATE TABLE `locations` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `group_locations` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `locations_groups_locations` FOREIGN KEY (`group_locations`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- create "users" table -CREATE TABLE `users` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `email` text NOT NULL, `password` text NOT NULL, `is_superuser` bool NOT NULL DEFAULT false, `group_users` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `users_groups_users` FOREIGN KEY (`group_users`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- create index "users_email_key" to table: "users" -CREATE UNIQUE INDEX `users_email_key` ON `users` (`email`); --- create "label_items" table -CREATE TABLE `label_items` (`label_id` uuid NOT NULL, `item_id` uuid NOT NULL, PRIMARY KEY (`label_id`, `item_id`), CONSTRAINT `label_items_label_id` FOREIGN KEY (`label_id`) REFERENCES `labels` (`id`) ON DELETE CASCADE, CONSTRAINT `label_items_item_id` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE); +-- +goose Up +create table if not exists groups +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + currency text default 'usd' not null +); + +create table if not exists documents +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + title text not null, + path text not null, + group_documents uuid not null + constraint documents_groups_documents + references groups + on delete cascade +); + +create table if not exists group_invitation_tokens +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + token blob not null, + expires_at datetime not null, + uses integer default 0 not null, + group_invitation_tokens uuid + constraint group_invitation_tokens_groups_invitation_tokens + references groups + on delete cascade +); + +create unique index if not exists group_invitation_tokens_token_key + on group_invitation_tokens (token); + +create table if not exists labels +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + description text, + color text, + group_labels uuid not null + constraint labels_groups_labels + references groups + on delete cascade +); + +create table if not exists locations +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + description text, + group_locations uuid not null + constraint locations_groups_locations + references groups + on delete cascade, + location_children uuid + constraint locations_locations_children + references locations + on delete set null +); + +create table if not exists items +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + description text, + import_ref text, + notes text, + quantity integer default 1 not null, + insured bool default false not null, + archived bool default false not null, + asset_id integer default 0 not null, + serial_number text, + model_number text, + manufacturer text, + lifetime_warranty bool default false not null, + warranty_expires datetime, + warranty_details text, + purchase_time datetime, + purchase_from text, + purchase_price real default 0 not null, + sold_time datetime, + sold_to text, + sold_price real default 0 not null, + sold_notes text, + group_items uuid not null + constraint items_groups_items + references groups + on delete cascade, + item_children uuid + constraint items_items_children + references items + on delete set null, + location_items uuid + constraint items_locations_items + references locations + on delete cascade +); + +create table if not exists attachments +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + type text default 'attachment' not null, + "primary" bool default false not null, + document_attachments uuid not null + constraint attachments_documents_attachments + references documents + on delete cascade, + item_attachments uuid not null + constraint attachments_items_attachments + references items + on delete cascade +); + +create table if not exists item_fields +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + description text, + type text not null, + text_value text, + number_value integer, + boolean_value bool default false not null, + time_value datetime not null, + item_fields uuid + constraint item_fields_items_fields + references items + on delete cascade +); + +create index if not exists item_archived + on items (archived); + +create index if not exists item_asset_id + on items (asset_id); + +create index if not exists item_manufacturer + on items (manufacturer); + +create index if not exists item_model_number + on items (model_number); + +create index if not exists item_name + on items (name); + +create index if not exists item_serial_number + on items (serial_number); + +create table if not exists label_items +( + label_id uuid not null + constraint label_items_label_id + references labels + on delete cascade, + item_id uuid not null + constraint label_items_item_id + references items + on delete cascade, + primary key (label_id, item_id) +); + +create table if not exists maintenance_entries +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + date datetime, + scheduled_date datetime, + name text not null, + description text, + cost real default 0 not null, + item_id uuid not null + constraint maintenance_entries_items_maintenance_entries + references items + on delete cascade +); + +create table if not exists users +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + email text not null, + password text not null, + is_superuser bool default false not null, + superuser bool default false not null, + role text default 'user' not null, + activated_on datetime, + group_users uuid not null + constraint users_groups_users + references groups + on delete cascade +); + +create table if not exists auth_tokens +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + token blob not null, + expires_at datetime not null, + user_auth_tokens uuid + constraint auth_tokens_users_auth_tokens + references users + on delete cascade +); + +create table if not exists auth_roles +( + id integer not null + primary key autoincrement, + role text default 'user' not null, + auth_tokens_roles uuid + constraint auth_roles_auth_tokens_roles + references auth_tokens + on delete cascade +); + +create unique index if not exists auth_roles_auth_tokens_roles_key + on auth_roles (auth_tokens_roles); + +create unique index if not exists auth_tokens_token_key + on auth_tokens (token); + +create index if not exists authtokens_token + on auth_tokens (token); + +create table if not exists notifiers +( + id uuid not null + primary key, + created_at datetime not null, + updated_at datetime not null, + name text not null, + url text not null, + is_active bool default true not null, + group_id uuid not null + constraint notifiers_groups_notifiers + references groups + on delete cascade, + user_id uuid not null + constraint notifiers_users_notifiers + references users + on delete cascade +); + +create index if not exists notifier_group_id + on notifiers (group_id); + +create index if not exists notifier_group_id_is_active + on notifiers (group_id, is_active); + +create index if not exists notifier_user_id + on notifiers (user_id); + +create index if not exists notifier_user_id_is_active + on notifiers (user_id, is_active); + +create unique index if not exists users_email_key + on users (email); + diff --git a/backend/internal/data/migrations/sqlite3/20221001210956_group_invitations.sql b/backend/internal/data/migrations/sqlite3/20221001210956_group_invitations.sql deleted file mode 100644 index 30ecec02..00000000 --- a/backend/internal/data/migrations/sqlite3/20221001210956_group_invitations.sql +++ /dev/null @@ -1,4 +0,0 @@ --- create "group_invitation_tokens" table -CREATE TABLE `group_invitation_tokens` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `token` blob NOT NULL, `expires_at` datetime NOT NULL, `uses` integer NOT NULL DEFAULT 0, `group_invitation_tokens` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `group_invitation_tokens_groups_invitation_tokens` FOREIGN KEY (`group_invitation_tokens`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- create index "group_invitation_tokens_token_key" to table: "group_invitation_tokens" -CREATE UNIQUE INDEX `group_invitation_tokens_token_key` ON `group_invitation_tokens` (`token`); diff --git a/backend/internal/data/migrations/sqlite3/20221009173029_add_user_roles.sql b/backend/internal/data/migrations/sqlite3/20221009173029_add_user_roles.sql deleted file mode 100644 index 95c6ab07..00000000 --- a/backend/internal/data/migrations/sqlite3/20221009173029_add_user_roles.sql +++ /dev/null @@ -1,14 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_users" table -CREATE TABLE `new_users` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `email` text NOT NULL, `password` text NOT NULL, `is_superuser` bool NOT NULL DEFAULT false, `role` text NOT NULL DEFAULT 'user', `superuser` bool NOT NULL DEFAULT false, `activated_on` datetime NULL, `group_users` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `users_groups_users` FOREIGN KEY (`group_users`) REFERENCES `groups` (`id`) ON DELETE CASCADE); --- copy rows from old table "users" to new temporary table "new_users" -INSERT INTO `new_users` (`id`, `created_at`, `updated_at`, `name`, `email`, `password`, `is_superuser`, `group_users`) SELECT `id`, `created_at`, `updated_at`, `name`, `email`, `password`, `is_superuser`, `group_users` FROM `users`; --- drop "users" table after copying rows -DROP TABLE `users`; --- rename temporary table "new_users" to "users" -ALTER TABLE `new_users` RENAME TO `users`; --- create index "users_email_key" to table: "users" -CREATE UNIQUE INDEX `users_email_key` ON `users` (`email`); --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20221020043305_allow_nesting_types.sql b/backend/internal/data/migrations/sqlite3/20221020043305_allow_nesting_types.sql deleted file mode 100644 index 7f246588..00000000 --- a/backend/internal/data/migrations/sqlite3/20221020043305_allow_nesting_types.sql +++ /dev/null @@ -1,28 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_items" table -CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT 1, `insured` bool NOT NULL DEFAULT false, `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT false, `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT 0, `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT 0, `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE); --- copy rows from old table "items" to new temporary table "new_items" -INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `location_items` FROM `items`; --- drop "items" table after copying rows -DROP TABLE `items`; --- rename temporary table "new_items" to "items" -ALTER TABLE `new_items` RENAME TO `items`; --- create index "item_name" to table: "items" -CREATE INDEX `item_name` ON `items` (`name`); --- create index "item_manufacturer" to table: "items" -CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`); --- create index "item_model_number" to table: "items" -CREATE INDEX `item_model_number` ON `items` (`model_number`); --- create index "item_serial_number" to table: "items" -CREATE INDEX `item_serial_number` ON `items` (`serial_number`); --- create "new_locations" table -CREATE TABLE `new_locations` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `group_locations` uuid NOT NULL, `location_children` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `locations_groups_locations` FOREIGN KEY (`group_locations`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `locations_locations_children` FOREIGN KEY (`location_children`) REFERENCES `locations` (`id`) ON DELETE SET NULL); --- copy rows from old table "locations" to new temporary table "new_locations" -INSERT INTO `new_locations` (`id`, `created_at`, `updated_at`, `name`, `description`, `group_locations`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `group_locations` FROM `locations`; --- drop "locations" table after copying rows -DROP TABLE `locations`; --- rename temporary table "new_locations" to "locations" -ALTER TABLE `new_locations` RENAME TO `locations`; --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20221101041931_add_archived_field.sql b/backend/internal/data/migrations/sqlite3/20221101041931_add_archived_field.sql deleted file mode 100644 index db3962b5..00000000 --- a/backend/internal/data/migrations/sqlite3/20221101041931_add_archived_field.sql +++ /dev/null @@ -1,22 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_items" table -CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT 1, `insured` bool NOT NULL DEFAULT false, `archived` bool NOT NULL DEFAULT false, `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT false, `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT 0, `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT 0, `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE); --- copy rows from old table "items" to new temporary table "new_items" -INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items` FROM `items`; --- drop "items" table after copying rows -DROP TABLE `items`; --- rename temporary table "new_items" to "items" -ALTER TABLE `new_items` RENAME TO `items`; --- create index "item_name" to table: "items" -CREATE INDEX `item_name` ON `items` (`name`); --- create index "item_manufacturer" to table: "items" -CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`); --- create index "item_model_number" to table: "items" -CREATE INDEX `item_model_number` ON `items` (`model_number`); --- create index "item_serial_number" to table: "items" -CREATE INDEX `item_serial_number` ON `items` (`serial_number`); --- create index "item_archived" to table: "items" -CREATE INDEX `item_archived` ON `items` (`archived`); --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20221113012312_add_asset_id_field.sql b/backend/internal/data/migrations/sqlite3/20221113012312_add_asset_id_field.sql deleted file mode 100644 index 5bcf3adb..00000000 --- a/backend/internal/data/migrations/sqlite3/20221113012312_add_asset_id_field.sql +++ /dev/null @@ -1,24 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_items" table -CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT 1, `insured` bool NOT NULL DEFAULT false, `archived` bool NOT NULL DEFAULT false, `asset_id` integer NOT NULL DEFAULT 0, `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT false, `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT 0, `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT 0, `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE); --- copy rows from old table "items" to new temporary table "new_items" -INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items` FROM `items`; --- drop "items" table after copying rows -DROP TABLE `items`; --- rename temporary table "new_items" to "items" -ALTER TABLE `new_items` RENAME TO `items`; --- create index "item_name" to table: "items" -CREATE INDEX `item_name` ON `items` (`name`); --- create index "item_manufacturer" to table: "items" -CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`); --- create index "item_model_number" to table: "items" -CREATE INDEX `item_model_number` ON `items` (`model_number`); --- create index "item_serial_number" to table: "items" -CREATE INDEX `item_serial_number` ON `items` (`serial_number`); --- create index "item_archived" to table: "items" -CREATE INDEX `item_archived` ON `items` (`archived`); --- create index "item_asset_id" to table: "items" -CREATE INDEX `item_asset_id` ON `items` (`asset_id`); --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20221203053132_add_token_roles.sql b/backend/internal/data/migrations/sqlite3/20221203053132_add_token_roles.sql deleted file mode 100644 index 6f6d00a2..00000000 --- a/backend/internal/data/migrations/sqlite3/20221203053132_add_token_roles.sql +++ /dev/null @@ -1,4 +0,0 @@ --- create "auth_roles" table -CREATE TABLE `auth_roles` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `role` text NOT NULL DEFAULT 'user', `auth_tokens_roles` uuid NULL, CONSTRAINT `auth_roles_auth_tokens_roles` FOREIGN KEY (`auth_tokens_roles`) REFERENCES `auth_tokens` (`id`) ON DELETE SET NULL); --- create index "auth_roles_auth_tokens_roles_key" to table: "auth_roles" -CREATE UNIQUE INDEX `auth_roles_auth_tokens_roles_key` ON `auth_roles` (`auth_tokens_roles`); diff --git a/backend/internal/data/migrations/sqlite3/20221205230404_drop_document_tokens.sql b/backend/internal/data/migrations/sqlite3/20221205230404_drop_document_tokens.sql deleted file mode 100644 index e130abef..00000000 --- a/backend/internal/data/migrations/sqlite3/20221205230404_drop_document_tokens.sql +++ /dev/null @@ -1,5 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; -DROP TABLE `document_tokens`; --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; \ No newline at end of file diff --git a/backend/internal/data/migrations/sqlite3/20221205234214_add_maintenance_entries.sql b/backend/internal/data/migrations/sqlite3/20221205234214_add_maintenance_entries.sql deleted file mode 100644 index 2491ec4e..00000000 --- a/backend/internal/data/migrations/sqlite3/20221205234214_add_maintenance_entries.sql +++ /dev/null @@ -1,2 +0,0 @@ --- create "maintenance_entries" table -CREATE TABLE `maintenance_entries` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `date` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `cost` real NOT NULL DEFAULT 0, `item_id` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `maintenance_entries_items_maintenance_entries` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE); diff --git a/backend/internal/data/migrations/sqlite3/20221205234812_cascade_delete_roles.sql b/backend/internal/data/migrations/sqlite3/20221205234812_cascade_delete_roles.sql deleted file mode 100644 index 8a37c118..00000000 --- a/backend/internal/data/migrations/sqlite3/20221205234812_cascade_delete_roles.sql +++ /dev/null @@ -1,16 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_auth_roles" table -CREATE TABLE `new_auth_roles` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `role` text NOT NULL DEFAULT 'user', `auth_tokens_roles` uuid NULL, CONSTRAINT `auth_roles_auth_tokens_roles` FOREIGN KEY (`auth_tokens_roles`) REFERENCES `auth_tokens` (`id`) ON DELETE CASCADE); --- copy rows from old table "auth_roles" to new temporary table "new_auth_roles" -INSERT INTO `new_auth_roles` (`id`, `role`, `auth_tokens_roles`) SELECT `id`, `role`, `auth_tokens_roles` FROM `auth_roles`; --- drop "auth_roles" table after copying rows -DROP TABLE `auth_roles`; --- rename temporary table "new_auth_roles" to "auth_roles" -ALTER TABLE `new_auth_roles` RENAME TO `auth_roles`; --- create index "auth_roles_auth_tokens_roles_key" to table: "auth_roles" -CREATE UNIQUE INDEX `auth_roles_auth_tokens_roles_key` ON `auth_roles` (`auth_tokens_roles`); --- delete where tokens is null -DELETE FROM `auth_roles` WHERE `auth_tokens_roles` IS NULL; --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20230227024134_add_scheduled_date.sql b/backend/internal/data/migrations/sqlite3/20230227024134_add_scheduled_date.sql deleted file mode 100644 index a43ecfb0..00000000 --- a/backend/internal/data/migrations/sqlite3/20230227024134_add_scheduled_date.sql +++ /dev/null @@ -1,12 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_maintenance_entries" table -CREATE TABLE `new_maintenance_entries` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `date` datetime NULL, `scheduled_date` datetime NULL, `name` text NOT NULL, `description` text NULL, `cost` real NOT NULL DEFAULT 0, `item_id` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `maintenance_entries_items_maintenance_entries` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE); --- copy rows from old table "maintenance_entries" to new temporary table "new_maintenance_entries" -INSERT INTO `new_maintenance_entries` (`id`, `created_at`, `updated_at`, `date`, `name`, `description`, `cost`, `item_id`) SELECT `id`, `created_at`, `updated_at`, `date`, `name`, `description`, `cost`, `item_id` FROM `maintenance_entries`; --- drop "maintenance_entries" table after copying rows -DROP TABLE `maintenance_entries`; --- rename temporary table "new_maintenance_entries" to "maintenance_entries" -ALTER TABLE `new_maintenance_entries` RENAME TO `maintenance_entries`; --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20230305065819_add_notifier_types.sql b/backend/internal/data/migrations/sqlite3/20230305065819_add_notifier_types.sql deleted file mode 100644 index 09b1824a..00000000 --- a/backend/internal/data/migrations/sqlite3/20230305065819_add_notifier_types.sql +++ /dev/null @@ -1,6 +0,0 @@ --- create "notifiers" table -CREATE TABLE `notifiers` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `url` text NOT NULL, `is_active` bool NOT NULL DEFAULT true, `user_id` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `notifiers_users_notifiers` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE); --- create index "notifier_user_id" to table: "notifiers" -CREATE INDEX `notifier_user_id` ON `notifiers` (`user_id`); --- create index "notifier_user_id_is_active" to table: "notifiers" -CREATE INDEX `notifier_user_id_is_active` ON `notifiers` (`user_id`, `is_active`); diff --git a/backend/internal/data/migrations/sqlite3/20230305071524_add_group_id_to_notifiers.sql b/backend/internal/data/migrations/sqlite3/20230305071524_add_group_id_to_notifiers.sql deleted file mode 100644 index 5f0f16d8..00000000 --- a/backend/internal/data/migrations/sqlite3/20230305071524_add_group_id_to_notifiers.sql +++ /dev/null @@ -1,20 +0,0 @@ --- disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- create "new_notifiers" table -CREATE TABLE `new_notifiers` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `url` text NOT NULL, `is_active` bool NOT NULL DEFAULT true, `group_id` uuid NOT NULL, `user_id` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `notifiers_groups_notifiers` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `notifiers_users_notifiers` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE); --- copy rows from old table "notifiers" to new temporary table "new_notifiers" -INSERT INTO `new_notifiers` (`id`, `created_at`, `updated_at`, `name`, `url`, `is_active`, `user_id`) SELECT `id`, `created_at`, `updated_at`, `name`, `url`, `is_active`, `user_id` FROM `notifiers`; --- drop "notifiers" table after copying rows -DROP TABLE `notifiers`; --- rename temporary table "new_notifiers" to "notifiers" -ALTER TABLE `new_notifiers` RENAME TO `notifiers`; --- create index "notifier_user_id" to table: "notifiers" -CREATE INDEX `notifier_user_id` ON `notifiers` (`user_id`); --- create index "notifier_user_id_is_active" to table: "notifiers" -CREATE INDEX `notifier_user_id_is_active` ON `notifiers` (`user_id`, `is_active`); --- create index "notifier_group_id" to table: "notifiers" -CREATE INDEX `notifier_group_id` ON `notifiers` (`group_id`); --- create index "notifier_group_id_is_active" to table: "notifiers" -CREATE INDEX `notifier_group_id_is_active` ON `notifiers` (`group_id`, `is_active`); --- enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20231006213457_add_primary_attachment_flag.sql b/backend/internal/data/migrations/sqlite3/20231006213457_add_primary_attachment_flag.sql deleted file mode 100644 index b7506c16..00000000 --- a/backend/internal/data/migrations/sqlite3/20231006213457_add_primary_attachment_flag.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- Create "new_attachments" table -CREATE TABLE `new_attachments` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `type` text NOT NULL DEFAULT 'attachment', `primary` bool NOT NULL DEFAULT false, `document_attachments` uuid NOT NULL, `item_attachments` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `attachments_documents_attachments` FOREIGN KEY (`document_attachments`) REFERENCES `documents` (`id`) ON DELETE CASCADE, CONSTRAINT `attachments_items_attachments` FOREIGN KEY (`item_attachments`) REFERENCES `items` (`id`) ON DELETE CASCADE); --- Copy rows from old table "attachments" to new temporary table "new_attachments" -INSERT INTO `new_attachments` (`id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments`) SELECT `id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments` FROM `attachments`; --- Drop "attachments" table after copying rows -DROP TABLE `attachments`; --- Rename temporary table "new_attachments" to "attachments" -ALTER TABLE `new_attachments` RENAME TO `attachments`; --- Enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/20241226183416_sync_children.go b/backend/internal/data/migrations/sqlite3/20241226183416_sync_children.go new file mode 100644 index 00000000..7ea34330 --- /dev/null +++ b/backend/internal/data/migrations/sqlite3/20241226183416_sync_children.go @@ -0,0 +1,51 @@ +package sqlite3 + +import ( + "context" + "database/sql" + "fmt" + "github.com/pressly/goose/v3" +) + +//nolint:gochecknoinits +func init() { + goose.AddMigrationContext(Up20241226183416, Down20241226183416) +} + +func Up20241226183416(ctx context.Context, tx *sql.Tx) error { + // Check if the 'sync_child_items_locations' column exists in the 'items' table + columnName := "sync_child_items_locations" + query := ` + SELECT name + FROM pragma_table_info('items') + WHERE name = 'sync_child_items_locations'; + ` + err := tx.QueryRowContext(ctx, query).Scan(&columnName) + if err != nil { + // Column does not exist, proceed with migration + _, err = tx.ExecContext(ctx, ` + PRAGMA foreign_keys = off; + + ALTER TABLE items + ADD COLUMN sync_child_items_locations BOOLEAN NOT NULL DEFAULT FALSE; + + CREATE INDEX IF NOT EXISTS item_name ON items(name); + CREATE INDEX IF NOT EXISTS item_manufacturer ON items(manufacturer); + CREATE INDEX IF NOT EXISTS item_model_number ON items(model_number); + CREATE INDEX IF NOT EXISTS item_serial_number ON items(serial_number); + CREATE INDEX IF NOT EXISTS item_archived ON items(archived); + CREATE INDEX IF NOT EXISTS item_asset_id ON items(asset_id); + + PRAGMA foreign_keys = on; + `) + if err != nil { + return fmt.Errorf("failed to execute migration: %w", err) + } + } + return nil +} + +func Down20241226183416(ctx context.Context, tx *sql.Tx) error { + // This migration is a no-op for SQLite. + return nil +} diff --git a/backend/internal/data/migrations/sqlite3/20241226183416_sync_childs.sql b/backend/internal/data/migrations/sqlite3/20241226183416_sync_childs.sql deleted file mode 100644 index 0a9b17c8..00000000 --- a/backend/internal/data/migrations/sqlite3/20241226183416_sync_childs.sql +++ /dev/null @@ -1,24 +0,0 @@ --- Disable the enforcement of foreign-keys constraints -PRAGMA foreign_keys = off; --- Create "new_items" table -CREATE TABLE `new_items` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `name` text NOT NULL, `description` text NULL, `import_ref` text NULL, `notes` text NULL, `quantity` integer NOT NULL DEFAULT (1), `insured` bool NOT NULL DEFAULT (false), `archived` bool NOT NULL DEFAULT (false), `asset_id` integer NOT NULL DEFAULT (0), `sync_child_items_locations` bool NOT NULL DEFAULT (false), `serial_number` text NULL, `model_number` text NULL, `manufacturer` text NULL, `lifetime_warranty` bool NOT NULL DEFAULT (false), `warranty_expires` datetime NULL, `warranty_details` text NULL, `purchase_time` datetime NULL, `purchase_from` text NULL, `purchase_price` real NOT NULL DEFAULT (0), `sold_time` datetime NULL, `sold_to` text NULL, `sold_price` real NOT NULL DEFAULT (0), `sold_notes` text NULL, `group_items` uuid NOT NULL, `item_children` uuid NULL, `location_items` uuid NULL, PRIMARY KEY (`id`), CONSTRAINT `items_groups_items` FOREIGN KEY (`group_items`) REFERENCES `groups` (`id`) ON DELETE CASCADE, CONSTRAINT `items_items_children` FOREIGN KEY (`item_children`) REFERENCES `items` (`id`) ON DELETE SET NULL, CONSTRAINT `items_locations_items` FOREIGN KEY (`location_items`) REFERENCES `locations` (`id`) ON DELETE CASCADE); --- Copy rows from old table "items" to new temporary table "new_items" -INSERT INTO `new_items` (`id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `asset_id`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items`) SELECT `id`, `created_at`, `updated_at`, `name`, `description`, `import_ref`, `notes`, `quantity`, `insured`, `archived`, `asset_id`, `serial_number`, `model_number`, `manufacturer`, `lifetime_warranty`, `warranty_expires`, `warranty_details`, `purchase_time`, `purchase_from`, `purchase_price`, `sold_time`, `sold_to`, `sold_price`, `sold_notes`, `group_items`, `item_children`, `location_items` FROM `items`; --- Drop "items" table after copying rows -DROP TABLE `items`; --- Rename temporary table "new_items" to "items" -ALTER TABLE `new_items` RENAME TO `items`; --- Create index "item_name" to table: "items" -CREATE INDEX `item_name` ON `items` (`name`); --- Create index "item_manufacturer" to table: "items" -CREATE INDEX `item_manufacturer` ON `items` (`manufacturer`); --- Create index "item_model_number" to table: "items" -CREATE INDEX `item_model_number` ON `items` (`model_number`); --- Create index "item_serial_number" to table: "items" -CREATE INDEX `item_serial_number` ON `items` (`serial_number`); --- Create index "item_archived" to table: "items" -CREATE INDEX `item_archived` ON `items` (`archived`); --- Create index "item_asset_id" to table: "items" -CREATE INDEX `item_asset_id` ON `items` (`asset_id`); --- Enable back the enforcement of foreign-keys constraints -PRAGMA foreign_keys = on; diff --git a/backend/internal/data/migrations/sqlite3/atlas.sum b/backend/internal/data/migrations/sqlite3/atlas.sum deleted file mode 100644 index aa212b0b..00000000 --- a/backend/internal/data/migrations/sqlite3/atlas.sum +++ /dev/null @@ -1,16 +0,0 @@ -h1:lHvusH+dq770FHk3fVAVqZqcW2Q0c9wR+uhouqrzXuw= -20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q= -20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw= -20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU= -20221020043305_allow_nesting_types.sql h1:4AyJpZ7l7SSJtJAQETYY802FHJ64ufYPJTqvwdiGn3M= -20221101041931_add_archived_field.sql h1:L2WxiOh1svRn817cNURgqnEQg6DIcodZ1twK4tvxW94= -20221113012312_add_asset_id_field.sql h1:DjD7e1PS8OfxGBWic8h0nO/X6CNnHEMqQjDCaaQ3M3Q= -20221203053132_add_token_roles.sql h1:wFTIh+KBoHfLfy/L0ZmJz4cNXKHdACG9ZK/yvVKjF0M= -20221205230404_drop_document_tokens.sql h1:9dCbNFcjtsT6lEhkxCn/vYaGRmQrl1LefdEJgvkfhGg= -20221205234214_add_maintenance_entries.sql h1:B56VzCuDsed1k3/sYUoKlOkP90DcdLufxFK0qYvoafU= -20221205234812_cascade_delete_roles.sql h1:VIiaImR48nCHF3uFbOYOX1E79Ta5HsUBetGaSAbh9Gk= -20230227024134_add_scheduled_date.sql h1:8qO5OBZ0AzsfYEQOAQQrYIjyhSwM+v1A+/ylLSoiyoc= -20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0= -20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4= -20231006213457_add_primary_attachment_flag.sql h1:J4tMSJQFa7vaj0jpnh8YKTssdyIjRyq6RXDXZIzDDu4= -20241226183416_sync_childs.sql h1:L9EWCzgz68OEw0r6Ryv0BdC6ViJbd/C/pt9o/FkSsbk= diff --git a/backend/internal/data/migrations/sqlite3/main.go b/backend/internal/data/migrations/sqlite3/main.go new file mode 100644 index 00000000..033c319e --- /dev/null +++ b/backend/internal/data/migrations/sqlite3/main.go @@ -0,0 +1,4 @@ +// Package sqlite3 provides the SQLite3 database migration +package sqlite3 + +// This file exists to make Goose happy. It really doesn't do anything else. diff --git a/backend/internal/data/repo/repo_maintenance.go b/backend/internal/data/repo/repo_maintenance.go index c488efd7..262f893b 100644 --- a/backend/internal/data/repo/repo_maintenance.go +++ b/backend/internal/data/repo/repo_maintenance.go @@ -2,6 +2,7 @@ package repo import ( "context" + "fmt" "time" "github.com/google/uuid" @@ -50,17 +51,22 @@ func (r *MaintenanceEntryRepository) GetAllMaintenance(ctx context.Context, grou ), ) - if filters.Status == MaintenanceFilterStatusScheduled { + switch filters.Status { + case MaintenanceFilterStatusScheduled: query = query.Where(maintenanceentry.Or( maintenanceentry.DateIsNil(), maintenanceentry.DateEQ(time.Time{}), )) - } else if filters.Status == MaintenanceFilterStatusCompleted { + case MaintenanceFilterStatusCompleted: query = query.Where( maintenanceentry.Not(maintenanceentry.Or( maintenanceentry.DateIsNil(), maintenanceentry.DateEQ(time.Time{})), )) + case MaintenanceFilterStatusBoth: + // No additional filters needed + default: + return nil, fmt.Errorf("unknown status %s", filters.Status) } entries, err := query.WithItem().Order(maintenanceentry.ByScheduledDate()).All(ctx) diff --git a/backend/internal/data/repo/repo_users_test.go b/backend/internal/data/repo/repo_users_test.go index ef85f442..abf62580 100644 --- a/backend/internal/data/repo/repo_users_test.go +++ b/backend/internal/data/repo/repo_users_test.go @@ -78,7 +78,7 @@ func TestUserRepo_GetAll(t *testing.T) { allUsers, err := tRepos.Users.GetAll(ctx) require.NoError(t, err) - assert.Equal(t, len(created), len(allUsers)) + assert.Len(t, allUsers, len(created)) for _, usr := range created { for _, usr2 := range allUsers {