summaryrefslogtreecommitdiff
path: root/migrations/20241002003606_global_sequence.sql
blob: 198b585e64648d384648e46d5dcaee503e1f2c9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
create table event_sequence (
	last_value bigint
		not null
);

create unique index event_sequence_singleton
on event_sequence (0);

-- Attempt to assign events sent so far a globally-unique sequence number,
-- maintaining an approximation of the order they were sent in. This can
-- introduce small ordering anomalies (where the resulting sequence differs
-- from the order they were sent in) for events that were sent close in time;
-- I've gone with chronological order here as it's the closest thing we have to
-- a global ordering, and because the results will be intuitive to most users.
create temporary table raw_event (
	type text
		not null,
	at text
		not null,
	channel text
		unique,
	message text
		unique,
	check ((channel is not null and message is null) or (message is not null and channel is null))
);

insert into raw_event (type, at, channel)
select
	'channel' as type,
	created_at as at,
	id as channel
from channel;

insert into raw_event (type, at, message)
select
	'message' as type,
	sent_at as at,
	id as message
from message;

create temporary table event (
	type text
		not null,
	sequence
		unique
		not null,
	at text
		not null,
	channel text
		unique,
	message text
		unique,
	check ((channel is not null and message is null) or (message is not null and channel is null))
);

insert into event
select
	type,
	rank() over (order by at) - 1 as sequence,
	at,
	channel,
	message
from raw_event;

drop table raw_event;

alter table channel rename to old_channel;
alter table message rename to old_message;

create table channel (
	id text
		not null
		primary key,
	name text
		unique
		not null,
	created_sequence bigint
		unique
		not null,
	created_at text
		not null
);

insert into channel
select
	c.id,
	c.name,
	e.sequence,
	c.created_at
from old_channel as c join event as e
	on e.channel = c.id;

create table message (
	id text
		not null
		primary key,
	channel text
		not null
		references channel (id),
	sender text
		not null
		references login (id),
	sent_sequence bigint
		unique
		not null,
	sent_at text
		not null,
	body text
		not null
);

insert into message
select
	m.id,
	m.channel,
	m.sender,
	e.sequence,
	m.sent_at,
	m.body
from old_message as m join event as e
	on e.message = m.id;

insert into event_sequence
select coalesce(max(sequence), 0) from event;

drop table event;