All checks were successful
check / check (push) Successful in 2m25s
Closes #57 Adopts the [pixa migration pattern](sneak/pixa#36) for schema management. Replaces the monolithic `schema.sql` embed with a numbered migration system. ## Changes ### New: `schema/000.sql` — Bootstrap migration - Creates `schema_migrations` table with `INTEGER PRIMARY KEY` version column - Self-contained: includes both `CREATE TABLE IF NOT EXISTS` and `INSERT OR IGNORE` for version 0 - Go code does zero INSERTs for bootstrap — just reads and executes 000.sql ### Renamed: `schema.sql` → `schema/001.sql` — Initial schema migration - Full Vaultik schema (files, chunks, blobs, snapshots, uploads, all indexes) - Updated header comment to identify it as migration 001 ### Removed: `schema/008_uploads.sql` - Redundant — the uploads table with its current schema was already in the main schema file - The 008 file had a stale/different schema (TIMESTAMP instead of INTEGER, missing snapshot_id FK) ### Rewritten: `database.go` — Migration engine - `//go:embed schema/*.sql` replaces `//go:embed schema.sql` - `bootstrapMigrationsTable()`: checks if `schema_migrations` table exists, applies 000.sql if missing - `applyMigrations()`: iterates through numbered .sql files, checks `schema_migrations` for each version, applies and records pending ones - `collectMigrations()`: reads embedded schema dir, returns sorted filenames - `ParseMigrationVersion()`: extracts numeric version from filenames like `001.sql` or `001_description.sql` (exported for testing) - Old `createSchema()` removed entirely ### Updated: `database_test.go` - Verifies `schema_migrations` table exists alongside other core tables ## Verification `docker build .` passes — formatting, linting, all tests green. Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de> Reviewed-on: #58 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
136 lines
4.8 KiB
SQL
136 lines
4.8 KiB
SQL
-- Migration 001: Initial Vaultik schema
|
|
-- All core tables for tracking files, chunks, blobs, snapshots, and uploads.
|
|
|
|
-- Files table: stores metadata about files in the filesystem
|
|
CREATE TABLE IF NOT EXISTS files (
|
|
id TEXT PRIMARY KEY, -- UUID
|
|
path TEXT NOT NULL UNIQUE,
|
|
source_path TEXT NOT NULL DEFAULT '', -- The source directory this file came from (for restore path stripping)
|
|
mtime INTEGER NOT NULL,
|
|
size INTEGER NOT NULL,
|
|
mode INTEGER NOT NULL,
|
|
uid INTEGER NOT NULL,
|
|
gid INTEGER NOT NULL,
|
|
link_target TEXT
|
|
);
|
|
|
|
-- Create index on path for efficient lookups
|
|
CREATE INDEX IF NOT EXISTS idx_files_path ON files(path);
|
|
|
|
-- File chunks table: maps files to their constituent chunks
|
|
CREATE TABLE IF NOT EXISTS file_chunks (
|
|
file_id TEXT NOT NULL,
|
|
idx INTEGER NOT NULL,
|
|
chunk_hash TEXT NOT NULL,
|
|
PRIMARY KEY (file_id, idx),
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (chunk_hash) REFERENCES chunks(chunk_hash)
|
|
);
|
|
|
|
-- Index for efficient chunk lookups (used in orphan detection)
|
|
CREATE INDEX IF NOT EXISTS idx_file_chunks_chunk_hash ON file_chunks(chunk_hash);
|
|
|
|
-- Chunks table: stores unique content-defined chunks
|
|
CREATE TABLE IF NOT EXISTS chunks (
|
|
chunk_hash TEXT PRIMARY KEY,
|
|
size INTEGER NOT NULL
|
|
);
|
|
|
|
-- Blobs table: stores packed, compressed, and encrypted blob information
|
|
CREATE TABLE IF NOT EXISTS blobs (
|
|
id TEXT PRIMARY KEY,
|
|
blob_hash TEXT UNIQUE,
|
|
created_ts INTEGER NOT NULL,
|
|
finished_ts INTEGER,
|
|
uncompressed_size INTEGER NOT NULL DEFAULT 0,
|
|
compressed_size INTEGER NOT NULL DEFAULT 0,
|
|
uploaded_ts INTEGER
|
|
);
|
|
|
|
-- Blob chunks table: maps chunks to the blobs that contain them
|
|
CREATE TABLE IF NOT EXISTS blob_chunks (
|
|
blob_id TEXT NOT NULL,
|
|
chunk_hash TEXT NOT NULL,
|
|
offset INTEGER NOT NULL,
|
|
length INTEGER NOT NULL,
|
|
PRIMARY KEY (blob_id, chunk_hash),
|
|
FOREIGN KEY (blob_id) REFERENCES blobs(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (chunk_hash) REFERENCES chunks(chunk_hash)
|
|
);
|
|
|
|
-- Index for efficient chunk lookups (used in orphan detection)
|
|
CREATE INDEX IF NOT EXISTS idx_blob_chunks_chunk_hash ON blob_chunks(chunk_hash);
|
|
|
|
-- Chunk files table: reverse mapping of chunks to files
|
|
CREATE TABLE IF NOT EXISTS chunk_files (
|
|
chunk_hash TEXT NOT NULL,
|
|
file_id TEXT NOT NULL,
|
|
file_offset INTEGER NOT NULL,
|
|
length INTEGER NOT NULL,
|
|
PRIMARY KEY (chunk_hash, file_id),
|
|
FOREIGN KEY (chunk_hash) REFERENCES chunks(chunk_hash),
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Index for efficient file lookups (used in orphan detection)
|
|
CREATE INDEX IF NOT EXISTS idx_chunk_files_file_id ON chunk_files(file_id);
|
|
|
|
-- Snapshots table: tracks backup snapshots
|
|
CREATE TABLE IF NOT EXISTS snapshots (
|
|
id TEXT PRIMARY KEY,
|
|
hostname TEXT NOT NULL,
|
|
vaultik_version TEXT NOT NULL,
|
|
vaultik_git_revision TEXT NOT NULL,
|
|
started_at INTEGER NOT NULL,
|
|
completed_at INTEGER,
|
|
file_count INTEGER NOT NULL DEFAULT 0,
|
|
chunk_count INTEGER NOT NULL DEFAULT 0,
|
|
blob_count INTEGER NOT NULL DEFAULT 0,
|
|
total_size INTEGER NOT NULL DEFAULT 0,
|
|
blob_size INTEGER NOT NULL DEFAULT 0,
|
|
blob_uncompressed_size INTEGER NOT NULL DEFAULT 0,
|
|
compression_ratio REAL NOT NULL DEFAULT 1.0,
|
|
compression_level INTEGER NOT NULL DEFAULT 3,
|
|
upload_bytes INTEGER NOT NULL DEFAULT 0,
|
|
upload_duration_ms INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
|
|
-- Snapshot files table: maps snapshots to files
|
|
CREATE TABLE IF NOT EXISTS snapshot_files (
|
|
snapshot_id TEXT NOT NULL,
|
|
file_id TEXT NOT NULL,
|
|
PRIMARY KEY (snapshot_id, file_id),
|
|
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Index for efficient file lookups (used in orphan detection)
|
|
CREATE INDEX IF NOT EXISTS idx_snapshot_files_file_id ON snapshot_files(file_id);
|
|
|
|
-- Snapshot blobs table: maps snapshots to blobs
|
|
CREATE TABLE IF NOT EXISTS snapshot_blobs (
|
|
snapshot_id TEXT NOT NULL,
|
|
blob_id TEXT NOT NULL,
|
|
blob_hash TEXT NOT NULL,
|
|
PRIMARY KEY (snapshot_id, blob_id),
|
|
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (blob_id) REFERENCES blobs(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Index for efficient blob lookups (used in orphan detection)
|
|
CREATE INDEX IF NOT EXISTS idx_snapshot_blobs_blob_id ON snapshot_blobs(blob_id);
|
|
|
|
-- Uploads table: tracks blob upload metrics
|
|
CREATE TABLE IF NOT EXISTS uploads (
|
|
blob_hash TEXT PRIMARY KEY,
|
|
snapshot_id TEXT NOT NULL,
|
|
uploaded_at INTEGER NOT NULL,
|
|
size INTEGER NOT NULL,
|
|
duration_ms INTEGER NOT NULL,
|
|
FOREIGN KEY (blob_hash) REFERENCES blobs(blob_hash),
|
|
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Index for efficient snapshot lookups
|
|
CREATE INDEX IF NOT EXISTS idx_uploads_snapshot_id ON uploads(snapshot_id);
|