package sqlite import ( "context" "database/sql" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type MigrateFunc func(ctx context.Context, tx *sql.Tx) error var documentStoreMigrations = []MigrateFunc{ documentStoreMigrationBaseSchema, documentStoreMigrationAddIDIndex, documentStoreMigrationAddRevisionColumn, } func documentStoreMigrationBaseSchema(ctx context.Context, tx *sql.Tx) error { query := ` CREATE TABLE IF NOT EXISTS documents ( id TEXT PRIMARY KEY, collection TEXT NOT NULL, data TEXT, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, UNIQUE(id, collection) ON CONFLICT REPLACE ); ` if _, err := tx.ExecContext(ctx, query); err != nil { return errors.WithStack(err) } return nil } func documentStoreMigrationAddIDIndex(ctx context.Context, tx *sql.Tx) error { query := ` CREATE INDEX IF NOT EXISTS collection_idx ON documents (collection); ` if _, err := tx.ExecContext(ctx, query); err != nil { return errors.WithStack(err) } return nil } func documentStoreMigrationAddRevisionColumn(ctx context.Context, tx *sql.Tx) error { query := `PRAGMA table_info(documents)` rows, err := tx.QueryContext(ctx, query) if err != nil { return errors.WithStack(err) } defer func() { if err := rows.Close(); err != nil { logger.Error(ctx, "could not close rows", logger.CapturedE(errors.WithStack(err))) } }() var hasRevisionColumn bool for rows.Next() { var ( id int name string dataType string nullable int defaultValue any primaryKey int ) if err := rows.Scan(&id, &name, &dataType, &nullable, &defaultValue, &primaryKey); err != nil { return errors.WithStack(err) } if name == "revision" { hasRevisionColumn = true break } } if err := rows.Err(); err != nil { return errors.WithStack(err) } if !hasRevisionColumn { query = `ALTER TABLE documents ADD COLUMN revision INTEGER DEFAULT 0` if _, err := tx.ExecContext(ctx, query); err != nil { return errors.WithStack(err) } } return nil }