Files
apocapoc-api/internal/infrastructure/persistence/sqlite/migrations.go
T
david 9f673bfca3 Refactor habit entries: remove soft delete and add smart pagination
Remove soft delete from HabitEntry:
- Eliminate DeletedAt field from entity and database
- Change UnmarkHabit from soft delete to hard delete
- Simplify all queries removing deleted_at checks
- Update migration to remove deleted_at column

Add date filtering and smart pagination to GetHabitEntries:
- Support optional from/to date parameters
- Implement intelligent pagination rules:
  * No date range: pagination required
  * Date range > 1 year: pagination required
  * Date range ≤ 1 year: pagination optional
- Pagination defaults (page=1, limit=50) only when required
- Return metadata with total count, page, and limit

Technical improvements:
- Cleaner codebase without soft delete complexity
- Better performance (no filtering in queries)
- More intuitive API with flexible pagination
- Comprehensive test coverage for validation rules
2025-11-26 16:33:40 +01:00

70 lines
1.7 KiB
Go

package sqlite
import (
"database/sql"
)
func RunMigrations(db *sql.DB) error {
migrations := []string{
createUsersTable,
createHabitsTable,
createHabitEntriesTable,
createIndexes,
}
for _, migration := range migrations {
if _, err := db.Exec(migration); err != nil {
return err
}
}
return nil
}
const createUsersTable = `
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
timezone TEXT DEFAULT 'UTC',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`
const createHabitsTable = `
CREATE TABLE IF NOT EXISTS habits (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
type TEXT CHECK(type IN ('BOOLEAN', 'COUNTER', 'VALUE')),
frequency TEXT CHECK(frequency IN ('DAILY', 'WEEKLY', 'MONTHLY')),
specific_days TEXT,
specific_dates TEXT,
carry_over BOOLEAN DEFAULT 0,
target_value REAL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
archived_at DATETIME,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
`
const createHabitEntriesTable = `
CREATE TABLE IF NOT EXISTS habit_entries (
id TEXT PRIMARY KEY,
habit_id TEXT NOT NULL,
scheduled_date DATE NOT NULL,
completed_at DATETIME NOT NULL,
value REAL,
FOREIGN KEY (habit_id) REFERENCES habits(id) ON DELETE CASCADE,
UNIQUE(habit_id, scheduled_date)
);
`
const createIndexes = `
CREATE INDEX IF NOT EXISTS idx_habits_user ON habits(user_id);
CREATE INDEX IF NOT EXISTS idx_habits_active ON habits(user_id, archived_at);
CREATE INDEX IF NOT EXISTS idx_entries_habit ON habit_entries(habit_id);
CREATE INDEX IF NOT EXISTS idx_entries_scheduled ON habit_entries(scheduled_date);
`