···178178 actor_did text not null,
179179 subject_uri text not null,
180180181181- state text not null default 'unread' check(state in ('unread', 'read')),
182182- type text not null check(type in ('follow', 'reaction', 'comment')),
181181+ state integer not null default 0,
182182+ type text not null,
183183184184 created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
185185···217217 is_deleted boolean not null default false,
218218 created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
219219220220- foreign key (did) references profiles(did) on delete cascade
220220+ foreign key (did) references profiles(did) on delete cascade,
221221 unique (did, rkey)
222222 );
223223···234234 if err != nil {
235235 return nil, fmt.Errorf("failed to execute db create statement: %w", err)
236236 }
237237+238238+ // This migration removes the type constraint on the notification type as
239239+ // it was painful to add new types. It also changes state to an integer
240240+ // check instead of text.
241241+ runMigration(conn, logger, "simplify-notification-constraints", func(tx *sql.Tx) error {
242242+ // Create new table with state as integer and no type constraint
243243+ _, err := tx.Exec(`
244244+ create table if not exists notifications_new (
245245+ id integer primary key autoincrement,
246246+247247+ recipient_did text not null,
248248+ actor_did text not null,
249249+ subject_uri text not null,
250250+251251+ state integer not null default 0,
252252+ type text not null,
253253+254254+ created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
255255+256256+ foreign key (recipient_did) references profiles(did) on delete cascade,
257257+ foreign key (actor_did) references profiles(did) on delete cascade
258258+ );
259259+ `)
260260+ if err != nil {
261261+ return err
262262+ }
263263+264264+ // Copy data, converting state from text to integer
265265+ _, err = tx.Exec(`
266266+ insert into notifications_new (id, recipient_did, actor_did, subject_uri, state, type, created_at)
267267+ select
268268+ id,
269269+ recipient_did,
270270+ actor_did,
271271+ subject_uri,
272272+ case state
273273+ when 'unread' then 0
274274+ when 'read' then 1
275275+ else 0
276276+ end,
277277+ type,
278278+ created_at
279279+ from notifications;
280280+ `)
281281+ if err != nil {
282282+ return err
283283+ }
284284+285285+ // Drop old table
286286+ _, err = tx.Exec(`drop table notifications`)
287287+ if err != nil {
288288+ return err
289289+ }
290290+291291+ // Rename new table
292292+ _, err = tx.Exec(`alter table notifications_new rename to notifications`)
293293+ return err
294294+ })
237295238296 return &DB{
239297 db,
+6-6
internal/db/notification.go
···1616 NotificationTypeReply NotificationType = "reply"
1717)
18181919-type NotificationState string
1919+type NotificationState int
20202121const (
2222- NotificationStateUnread NotificationState = "unread"
2323- NotificationStateRead NotificationState = "read"
2222+ NotificationStateUnread NotificationState = 0
2323+ NotificationStateRead NotificationState = 1
2424)
25252626type NotificationWithBskyHandle struct {
···124124}
125125126126func GetUnreadNotificationCount(e Execer, recipientDid string) (int, error) {
127127- query := `select count(*) from notifications where recipient_did = ? and state = 'unread';`
127127+ query := `select count(*) from notifications where recipient_did = ? and state = 0;`
128128129129 var count int
130130 row := e.QueryRow(query, recipientDid)
···138138func MarkAllNotificationsAsRead(e Execer, did string) error {
139139 query := `
140140 update notifications
141141- set state = 'read'
142142- where recipient_did = ? and state = 'unread';
141141+ set state = 1
142142+ where recipient_did = ? and state = 0;
143143 `
144144145145 _, err := e.Exec(query, did)
-26
migrations/update_notification_type.sql
···11--- This script should be used and updated whenever a new notification type
22--- constraint needs to be added.
33-44-BEGIN TRANSACTION;
55-66-ALTER TABLE notifications RENAME TO notifications_old;
77-88-CREATE TABLE notifications (
99- id INTEGER PRIMARY KEY AUTOINCREMENT,
1010- recipient_did TEXT NOT NULL,
1111- actor_did TEXT NOT NULL,
1212- subject_uri TEXT NOT NULL,
1313- state TEXT NOT NULL DEFAULT 'unread' CHECK(state IN ('unread', 'read')),
1414- type TEXT NOT NULL CHECK(type IN ('follow', 'reaction', 'comment', 'reply')),
1515- created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
1616- FOREIGN KEY (recipient_did) REFERENCES profiles(did) ON DELETE CASCADE,
1717- FOREIGN KEY (actor_did) REFERENCES profiles(did) ON DELETE CASCADE
1818-);
1919-2020-INSERT INTO notifications (id, recipient_did, actor_did, subject_uri, state, type, created_at)
2121-SELECT id, recipient_did, actor_did, subject_uri, state, type, created_at
2222-FROM notifications_old;
2323-2424-DROP TABLE notifications_old;
2525-2626-COMMIT;