Snooze, the handled-occurrence watermark and the skip watermark need somewhere to live that survives a process death. They go in their own table rather than as columns on alarms: a missing row is the initial record, and the FK cascade means deleting an alarm cannot leave orphaned ring state behind. Schema v2 is exported and committed alongside v1, so MIGRATION_1_2 is reviewable and testable rather than taken on faith. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
370 lines
11 KiB
JSON
370 lines
11 KiB
JSON
{
|
|
"formatVersion": 1,
|
|
"database": {
|
|
"version": 2,
|
|
"identityHash": "5e5fd3a9d31d77a7aa57306836ab19ad",
|
|
"entities": [
|
|
{
|
|
"tableName": "alarms",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `hour` INTEGER NOT NULL, `minute` INTEGER NOT NULL, `label` TEXT NOT NULL, `enabled` INTEGER NOT NULL, `repeat_days` INTEGER NOT NULL, `skip_next_occurrence` INTEGER NOT NULL, `ringtone_uri` TEXT, `vibrate` INTEGER, `snooze_minutes` INTEGER, `snooze_limit` INTEGER, `volume_ramp_seconds` INTEGER, `dismiss_challenge` TEXT, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL)",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "hour",
|
|
"columnName": "hour",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "minute",
|
|
"columnName": "minute",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "label",
|
|
"columnName": "label",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "enabled",
|
|
"columnName": "enabled",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "repeatDays",
|
|
"columnName": "repeat_days",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "skipNextOccurrence",
|
|
"columnName": "skip_next_occurrence",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "ringtoneUri",
|
|
"columnName": "ringtone_uri",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "vibrate",
|
|
"columnName": "vibrate",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "snoozeMinutes",
|
|
"columnName": "snooze_minutes",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "snoozeLimit",
|
|
"columnName": "snooze_limit",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "volumeRampSeconds",
|
|
"columnName": "volume_ramp_seconds",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "dismissChallenge",
|
|
"columnName": "dismiss_challenge",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "createdAt",
|
|
"columnName": "created_at",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "updatedAt",
|
|
"columnName": "updated_at",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_alarms_enabled",
|
|
"unique": false,
|
|
"columnNames": [
|
|
"enabled"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_alarms_enabled` ON `${TABLE_NAME}` (`enabled`)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "alarm_states",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`alarm_id` INTEGER NOT NULL, `snoozed_until` INTEGER, `snooze_count` INTEGER NOT NULL, `ringing_since` INTEGER, `handled_occurrence` INTEGER, `skipped_occurrence` INTEGER, PRIMARY KEY(`alarm_id`), FOREIGN KEY(`alarm_id`) REFERENCES `alarms`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "alarmId",
|
|
"columnName": "alarm_id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "snoozedUntil",
|
|
"columnName": "snoozed_until",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "snoozeCount",
|
|
"columnName": "snooze_count",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "ringingSince",
|
|
"columnName": "ringing_since",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "handledOccurrence",
|
|
"columnName": "handled_occurrence",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "skippedOccurrence",
|
|
"columnName": "skipped_occurrence",
|
|
"affinity": "INTEGER"
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": false,
|
|
"columnNames": [
|
|
"alarm_id"
|
|
]
|
|
},
|
|
"foreignKeys": [
|
|
{
|
|
"table": "alarms",
|
|
"onDelete": "CASCADE",
|
|
"onUpdate": "NO ACTION",
|
|
"columns": [
|
|
"alarm_id"
|
|
],
|
|
"referencedColumns": [
|
|
"id"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "timers",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `label` TEXT NOT NULL, `duration_millis` INTEGER NOT NULL, `state` TEXT NOT NULL, `remaining_millis` INTEGER NOT NULL, `started_at_elapsed_realtime_millis` INTEGER, `ends_at_elapsed_realtime_millis` INTEGER, `ends_at_wall_clock_millis` INTEGER, `ringtone_uri` TEXT, `sort_order` INTEGER NOT NULL, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL)",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "label",
|
|
"columnName": "label",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "durationMillis",
|
|
"columnName": "duration_millis",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "state",
|
|
"columnName": "state",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "remainingMillis",
|
|
"columnName": "remaining_millis",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "startedAtElapsedRealtimeMillis",
|
|
"columnName": "started_at_elapsed_realtime_millis",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "endsAtElapsedRealtimeMillis",
|
|
"columnName": "ends_at_elapsed_realtime_millis",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "endsAtWallClockMillis",
|
|
"columnName": "ends_at_wall_clock_millis",
|
|
"affinity": "INTEGER"
|
|
},
|
|
{
|
|
"fieldPath": "ringtoneUri",
|
|
"columnName": "ringtone_uri",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "sortOrder",
|
|
"columnName": "sort_order",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "createdAt",
|
|
"columnName": "created_at",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "updatedAt",
|
|
"columnName": "updated_at",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_timers_sort_order",
|
|
"unique": false,
|
|
"columnNames": [
|
|
"sort_order"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_timers_sort_order` ON `${TABLE_NAME}` (`sort_order`)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "world_clocks",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `zone_id` TEXT NOT NULL, `label` TEXT, `sort_order` INTEGER NOT NULL)",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "zoneId",
|
|
"columnName": "zone_id",
|
|
"affinity": "TEXT",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "label",
|
|
"columnName": "label",
|
|
"affinity": "TEXT"
|
|
},
|
|
{
|
|
"fieldPath": "sortOrder",
|
|
"columnName": "sort_order",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_world_clocks_zone_id",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"zone_id"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_world_clocks_zone_id` ON `${TABLE_NAME}` (`zone_id`)"
|
|
},
|
|
{
|
|
"name": "index_world_clocks_sort_order",
|
|
"unique": false,
|
|
"columnNames": [
|
|
"sort_order"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE INDEX IF NOT EXISTS `index_world_clocks_sort_order` ON `${TABLE_NAME}` (`sort_order`)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"tableName": "stopwatch_laps",
|
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `lap_index` INTEGER NOT NULL, `split_millis` INTEGER NOT NULL, `cumulative_millis` INTEGER NOT NULL)",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "id",
|
|
"columnName": "id",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "lapIndex",
|
|
"columnName": "lap_index",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "splitMillis",
|
|
"columnName": "split_millis",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
},
|
|
{
|
|
"fieldPath": "cumulativeMillis",
|
|
"columnName": "cumulative_millis",
|
|
"affinity": "INTEGER",
|
|
"notNull": true
|
|
}
|
|
],
|
|
"primaryKey": {
|
|
"autoGenerate": true,
|
|
"columnNames": [
|
|
"id"
|
|
]
|
|
},
|
|
"indices": [
|
|
{
|
|
"name": "index_stopwatch_laps_lap_index",
|
|
"unique": true,
|
|
"columnNames": [
|
|
"lap_index"
|
|
],
|
|
"orders": [],
|
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_stopwatch_laps_lap_index` ON `${TABLE_NAME}` (`lap_index`)"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"setupQueries": [
|
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5e5fd3a9d31d77a7aa57306836ab19ad')"
|
|
]
|
|
}
|
|
} |