@hot-updater/supabase 1.0.0-rc.2 → 1.0.0-rc.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,617 +1,203 @@
1
1
  -- HotUpdater.schema
2
2
 
3
- CREATE TABLE public.hot_updater_v1_channels (
4
- id text COLLATE "C" PRIMARY KEY NOT NULL
5
- CHECK (pg_catalog.char_length(id) BETWEEN 1 AND 255),
6
- name text COLLATE "C" NOT NULL UNIQUE
7
- CHECK (pg_catalog.char_length(name) BETWEEN 1 AND 255)
8
- );
9
-
10
- CREATE TABLE public.hot_updater_v1_bundles (
11
- id uuid PRIMARY KEY NOT NULL,
12
- platform text NOT NULL,
13
- file_hash text NOT NULL,
14
- git_commit_hash text,
15
- storage_uri text NOT NULL,
16
- archive_byte_size double precision NOT NULL CHECK (
17
- archive_byte_size BETWEEN 0 AND 9007199254740991
18
- ),
19
- metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
20
- manifest_storage_uri text,
21
- manifest_file_hash text,
22
- asset_base_storage_uri text
23
- );
24
-
25
- CREATE TABLE public.hot_updater_v1_bundle_patches (
26
- id varchar(255) PRIMARY KEY NOT NULL,
27
- bundle_id uuid NOT NULL,
28
- base_bundle_id uuid NOT NULL,
29
- base_file_hash text NOT NULL,
30
- patch_file_hash text NOT NULL,
31
- patch_storage_uri text NOT NULL,
32
- byte_size double precision NOT NULL CHECK (
33
- byte_size BETWEEN 0 AND 9007199254740991
34
- ),
35
- order_index integer NOT NULL DEFAULT 0,
36
- CONSTRAINT hot_updater_v1_bundle_patches_bundle_id_fk FOREIGN KEY (bundle_id)
37
- REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE CASCADE,
38
- CONSTRAINT hot_updater_v1_bundle_patches_base_bundle_id_fk FOREIGN KEY (base_bundle_id)
39
- REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE CASCADE
40
- );
41
-
42
- CREATE TABLE public.hot_updater_v1_releases (
43
- id uuid PRIMARY KEY NOT NULL,
44
- revision integer NOT NULL CHECK (revision >= 1),
45
- scope_key varchar(2048) COLLATE "C" NOT NULL,
46
- channel_id text COLLATE "C" NOT NULL,
47
- platform text NOT NULL,
48
- kind text NOT NULL CHECK (
49
- (kind = 'BUNDLE' AND bundle_id IS NOT NULL)
50
- OR (kind = 'EMBEDDED' AND bundle_id IS NULL)
51
- ),
52
- bundle_id uuid,
53
- strategy text NOT NULL,
54
- target_app_version text,
55
- fingerprint_hash text,
56
- enabled boolean NOT NULL,
57
- should_force_update boolean NOT NULL,
58
- message text,
59
- rollout_cohort_count integer NOT NULL DEFAULT 1000
60
- CHECK (rollout_cohort_count BETWEEN 0 AND 1000),
61
- target_cohorts jsonb NOT NULL DEFAULT '[]'::jsonb,
62
- operation text NOT NULL CHECK (operation IN ('DEPLOY', 'PROMOTE', 'ROLLBACK')),
63
- source_release_id uuid,
64
- created_at_ms double precision NOT NULL,
65
- updated_at_ms double precision NOT NULL,
66
- CONSTRAINT hot_updater_v1_releases_strategy_target_check CHECK (
67
- (strategy = 'APP_VERSION' AND target_app_version IS NOT NULL AND fingerprint_hash IS NULL)
68
- OR (strategy = 'FINGERPRINT' AND target_app_version IS NULL AND fingerprint_hash IS NOT NULL)
69
- ),
70
- CONSTRAINT hot_updater_v1_releases_channel_id_fk FOREIGN KEY (channel_id)
71
- REFERENCES public.hot_updater_v1_channels(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
72
- CONSTRAINT hot_updater_v1_releases_bundle_id_fk FOREIGN KEY (bundle_id)
73
- REFERENCES public.hot_updater_v1_bundles(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
74
- CONSTRAINT hot_updater_v1_releases_source_release_id_fk FOREIGN KEY (source_release_id)
75
- REFERENCES public.hot_updater_v1_releases(id) ON UPDATE RESTRICT ON DELETE SET NULL
76
- );
77
-
78
- CREATE TABLE public.hot_updater_v1_release_catalogs (
79
- scope_key varchar(2048) COLLATE "C" PRIMARY KEY NOT NULL,
80
- catalog_id varchar(255) COLLATE "C" NOT NULL,
81
- strategy text NOT NULL,
82
- channel_id text COLLATE "C" NOT NULL,
83
- channel_key varchar(1400) COLLATE "C" NOT NULL,
84
- platform text NOT NULL,
85
- fingerprint_hash text,
86
- generation double precision NOT NULL
87
- CHECK (generation BETWEEN 1 AND 9007199254740991),
88
- payload text NOT NULL,
89
- catalog_hash varchar(71) COLLATE "C" NOT NULL,
90
- byte_size integer NOT NULL CHECK (byte_size BETWEEN 0 AND 262144),
91
- is_tombstone boolean NOT NULL,
92
- updated_at_ms double precision NOT NULL,
93
- CONSTRAINT hot_updater_v1_release_catalogs_strategy_target_check CHECK (
94
- (strategy = 'APP_VERSION' AND fingerprint_hash IS NULL)
95
- OR (strategy = 'FINGERPRINT' AND fingerprint_hash IS NOT NULL)
96
- ),
97
- CONSTRAINT hot_updater_v1_release_catalogs_channel_id_fk FOREIGN KEY (channel_id)
98
- REFERENCES public.hot_updater_v1_channels(id) ON UPDATE RESTRICT ON DELETE RESTRICT
99
- );
100
-
101
- CREATE TABLE public.hot_updater_v1_bundle_events (
102
- id uuid PRIMARY KEY NOT NULL,
103
- type text NOT NULL,
104
- install_id text COLLATE "C" NOT NULL,
105
- user_id text COLLATE "C",
106
- username text,
107
- from_release_id uuid,
108
- from_bundle_id uuid,
109
- to_release_id uuid,
110
- to_bundle_id uuid NOT NULL,
111
- platform text COLLATE "C" NOT NULL,
112
- app_version text NOT NULL,
113
- channel text COLLATE "C" NOT NULL,
114
- cohort text NOT NULL,
115
- update_strategy text,
116
- fingerprint_hash text,
117
- sdk_version text,
118
- received_at_ms double precision NOT NULL,
119
- CONSTRAINT hot_updater_v1_bundle_events_type_check CHECK (
120
- type IN ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED', 'UNCHANGED')
121
- ),
122
- CONSTRAINT hot_updater_v1_bundle_events_platform_check CHECK (
123
- platform IN ('ios', 'android')
124
- ),
125
- CONSTRAINT hot_updater_v1_bundle_events_shape_check CHECK (
126
- (type IN ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED')
127
- AND from_bundle_id IS NOT NULL
128
- AND update_strategy IS NOT NULL
129
- AND update_strategy IN ('fingerprint', 'appVersion'))
130
- OR (type = 'UNCHANGED'
131
- AND from_bundle_id IS NULL
132
- AND update_strategy IS NULL)
133
- ),
134
- CONSTRAINT hot_updater_v1_bundle_events_received_at_check CHECK (received_at_ms >= 0)
135
- );
136
-
137
- CREATE TABLE public.hot_updater_v1_bundle_installations (
138
- install_id text COLLATE "C" PRIMARY KEY NOT NULL,
139
- id uuid NOT NULL,
140
- user_id text COLLATE "C",
141
- username text,
142
- to_bundle_id uuid NOT NULL,
143
- type text NOT NULL CHECK (
144
- type IN ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED', 'UNCHANGED')
145
- ),
146
- platform text COLLATE "C" NOT NULL CHECK (platform IN ('ios', 'android')),
147
- app_version text NOT NULL,
148
- channel text COLLATE "C" NOT NULL,
149
- cohort text NOT NULL,
150
- received_at_ms double precision NOT NULL CHECK (received_at_ms >= 0)
151
- );
152
-
153
- CREATE TABLE public.hot_updater_v1_api_keys (
154
- id text PRIMARY KEY NOT NULL,
155
- hash text NOT NULL,
156
- name text NOT NULL,
157
- prefix text NOT NULL,
158
- role text NOT NULL CHECK (role = 'client'),
159
- created_at_ms double precision NOT NULL CHECK (created_at_ms >= 0),
160
- revoked_at_ms double precision CHECK (
161
- revoked_at_ms IS NULL OR revoked_at_ms >= 0
162
- )
163
- );
164
-
165
- CREATE TABLE public.hot_updater_v1_private_settings (
166
- key varchar(255) PRIMARY KEY NOT NULL,
167
- value text NOT NULL DEFAULT '1.0.0'
168
- );
169
-
170
- CREATE INDEX hot_updater_v1_releases_scope_order_idx ON public.hot_updater_v1_releases(scope_key, id);
171
- CREATE INDEX hot_updater_v1_releases_channel_platform_order_idx
172
- ON public.hot_updater_v1_releases(channel_id, platform, id);
173
- CREATE INDEX hot_updater_v1_releases_bundle_id_idx ON public.hot_updater_v1_releases(bundle_id);
174
- CREATE INDEX hot_updater_v1_releases_fingerprint_hash_idx ON public.hot_updater_v1_releases(fingerprint_hash);
175
- CREATE INDEX hot_updater_v1_releases_enabled_idx ON public.hot_updater_v1_releases(enabled);
176
- CREATE INDEX hot_updater_v1_release_catalogs_channel_idx ON public.hot_updater_v1_release_catalogs(channel_id);
177
- CREATE INDEX hot_updater_v1_bundle_patches_bundle_id_idx ON public.hot_updater_v1_bundle_patches(bundle_id);
178
- CREATE INDEX hot_updater_v1_bundle_patches_base_bundle_id_idx
179
- ON public.hot_updater_v1_bundle_patches(base_bundle_id);
180
- CREATE INDEX hot_updater_v1_bundle_events_received_at_idx
181
- ON public.hot_updater_v1_bundle_events(received_at_ms, id);
182
- CREATE INDEX hot_updater_v1_bundle_events_install_idx
183
- ON public.hot_updater_v1_bundle_events(install_id, type, received_at_ms, id);
184
- CREATE INDEX hot_updater_v1_bundle_installations_user_id_idx
185
- ON public.hot_updater_v1_bundle_installations(user_id, install_id);
186
- CREATE INDEX hot_updater_v1_bundle_installations_received_at_idx
187
- ON public.hot_updater_v1_bundle_installations(received_at_ms);
188
- CREATE INDEX hot_updater_v1_bundle_events_from_bundle_idx
189
- ON public.hot_updater_v1_bundle_events(type, platform, channel, from_bundle_id, received_at_ms, id);
190
- CREATE INDEX hot_updater_v1_bundle_events_to_bundle_idx
191
- ON public.hot_updater_v1_bundle_events(type, platform, channel, to_bundle_id, received_at_ms, id);
192
- CREATE INDEX hot_updater_v1_bundle_installations_scope_idx
193
- ON public.hot_updater_v1_bundle_installations(platform, channel, received_at_ms);
194
- CREATE INDEX hot_updater_v1_bundle_installations_bundle_idx
195
- ON public.hot_updater_v1_bundle_installations(platform, channel, to_bundle_id, received_at_ms);
196
- CREATE UNIQUE INDEX hot_updater_v1_api_keys_hash_key
197
- ON public.hot_updater_v1_api_keys(hash);
198
- CREATE INDEX hot_updater_v1_api_keys_created_at_idx
199
- ON public.hot_updater_v1_api_keys(created_at_ms, id);
200
-
201
- ALTER TABLE public.hot_updater_v1_channels ENABLE ROW LEVEL SECURITY;
202
- ALTER TABLE public.hot_updater_v1_bundles ENABLE ROW LEVEL SECURITY;
203
- ALTER TABLE public.hot_updater_v1_bundle_patches ENABLE ROW LEVEL SECURITY;
204
- ALTER TABLE public.hot_updater_v1_releases ENABLE ROW LEVEL SECURITY;
205
- ALTER TABLE public.hot_updater_v1_release_catalogs ENABLE ROW LEVEL SECURITY;
206
- ALTER TABLE public.hot_updater_v1_bundle_events ENABLE ROW LEVEL SECURITY;
207
- ALTER TABLE public.hot_updater_v1_bundle_installations ENABLE ROW LEVEL SECURITY;
208
- ALTER TABLE public.hot_updater_v1_api_keys ENABLE ROW LEVEL SECURITY;
209
- ALTER TABLE public.hot_updater_v1_private_settings ENABLE ROW LEVEL SECURITY;
210
-
211
- INSERT INTO public.hot_updater_v1_private_settings (key, value)
212
- VALUES ('schema.core', '1.0.0')
213
- ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
214
- CREATE FUNCTION public.hot_updater_v1_commit(p_commit jsonb)
3
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1__hu_write" ("id" varchar(36) COLLATE "C" NOT NULL, "failed_op" bigint, PRIMARY KEY ("id"));
4
+
5
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundles" ("id" varchar(36) COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "git_commit_hash" varchar(255) COLLATE "C", "metadata" jsonb NOT NULL, "manifest_storage_uri" text COLLATE "C" NOT NULL, "manifest_file_hash" text COLLATE "C" NOT NULL, "asset_base_storage_uri" text COLLATE "C" NOT NULL, "_refs_bundle_patches_bundle_id" bigint NOT NULL DEFAULT 0, "_refs_bundle_patches_base_bundle_id" bigint NOT NULL DEFAULT 0, "_refs_releases_bundle_id" bigint NOT NULL DEFAULT 0, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
6
+
7
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundles_byPlatform" ON "hot_updater_v1_bundles" ("platform", "id");
8
+
9
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundle_patches" ("id" varchar(255) COLLATE "C" NOT NULL, "bundle_id" varchar(36) COLLATE "C" NOT NULL, "base_bundle_id" varchar(36) COLLATE "C" NOT NULL, "base_file_hash" text COLLATE "C" NOT NULL, "patch_file_hash" text COLLATE "C" NOT NULL, "patch_storage_uri" text COLLATE "C" NOT NULL, "byte_size" bigint NOT NULL, "order_index" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
10
+
11
+ CREATE UNIQUE INDEX IF NOT EXISTS "hot_updater_v1_bundle_patches_pair" ON "hot_updater_v1_bundle_patches" ("bundle_id", "base_bundle_id");
12
+
13
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_patches_byBundle" ON "hot_updater_v1_bundle_patches" ("bundle_id", "order_index", "id");
14
+
15
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_patches_byBase" ON "hot_updater_v1_bundle_patches" ("base_bundle_id", "bundle_id", "id");
16
+
17
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_releases" ("id" varchar(36) COLLATE "C" NOT NULL, "revision" bigint NOT NULL, "scope_key" varchar(2048) COLLATE "C" NOT NULL, "channel_id" varchar(1408) COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "kind" varchar(16) COLLATE "C" NOT NULL, "bundle_id" varchar(36) COLLATE "C", "strategy" varchar(16) COLLATE "C" NOT NULL, "target_app_version" text COLLATE "C", "fingerprint_hash" varchar(255) COLLATE "C", "enabled" boolean NOT NULL, "should_force_update" boolean NOT NULL, "message" text COLLATE "C", "rollout_cohort_count" bigint NOT NULL, "target_cohorts" jsonb NOT NULL, "operation" varchar(16) COLLATE "C" NOT NULL, "source_release_id" varchar(36) COLLATE "C", "created_at_ms" bigint NOT NULL, "updated_at_ms" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
18
+
19
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_releases_byScope" ON "hot_updater_v1_releases" ("scope_key", "id");
20
+
21
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_releases_byScopeEnabled" ON "hot_updater_v1_releases" ("scope_key", "enabled", "id");
22
+
23
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_releases_byChannelPlatform" ON "hot_updater_v1_releases" ("channel_id", "platform", "id");
24
+
25
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_releases_byChannelPlatformEnabled" ON "hot_updater_v1_releases" ("channel_id", "platform", "enabled", "id");
26
+
27
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_releases_byBundle" ON "hot_updater_v1_releases" ("bundle_id", "id");
28
+
29
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_release_catalogs" ("scope_key" varchar(2048) COLLATE "C" NOT NULL, "catalog_id" varchar(255) COLLATE "C" NOT NULL, "strategy" varchar(16) COLLATE "C" NOT NULL, "channel_id" varchar(1408) COLLATE "C" NOT NULL, "channel_key" varchar(1400) COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "fingerprint_hash" varchar(255) COLLATE "C", "generation" bigint NOT NULL, "payload" text COLLATE "C" NOT NULL, "catalog_hash" varchar(71) COLLATE "C" NOT NULL, "byte_size" bigint NOT NULL, "is_tombstone" boolean NOT NULL, "updated_at_ms" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("scope_key"));
30
+
31
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_channels" ("id" varchar(1408) COLLATE "C" NOT NULL, "name" varchar(255) COLLATE "C" NOT NULL, "_refs_releases_channel_id" bigint NOT NULL DEFAULT 0, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
32
+
33
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_channels_all" ON "hot_updater_v1_channels" ("name", "id");
34
+
35
+ CREATE UNIQUE INDEX IF NOT EXISTS "hot_updater_v1_channels_name" ON "hot_updater_v1_channels" ("name");
36
+
37
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundle_totals" ("platform_key" varchar(16) COLLATE "C" NOT NULL, "_shard" bigint NOT NULL, "bundles" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("platform_key", "_shard"));
38
+
39
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundle_events" ("id" varchar(36) COLLATE "C" NOT NULL, "type" varchar(32) COLLATE "C" NOT NULL, "install_id" varchar(255) COLLATE "C" NOT NULL, "user_id" varchar(255) COLLATE "C", "from_release_id" varchar(36) COLLATE "C", "from_bundle_id" varchar(36) COLLATE "C", "to_release_id" varchar(36) COLLATE "C", "to_bundle_id" varchar(36) COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "app_version" text COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "metadata" jsonb NOT NULL, "received_at_ms" bigint NOT NULL, "day" bigint, "movement_install_id" text COLLATE "C", "bundle_ref" jsonb, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
40
+
41
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_events_recent" ON "hot_updater_v1_bundle_events" ("channel", "platform", "day", "received_at_ms", "id");
42
+
43
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_events_movementsByInstall" ON "hot_updater_v1_bundle_events" ("movement_install_id", "received_at_ms", "id");
44
+
45
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundle_events__byBundle" ("platform" varchar(16) COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "type" varchar(32) COLLATE "C" NOT NULL, "bundle_ref" text COLLATE "C" NOT NULL, "day" bigint NOT NULL, "received_at_ms" bigint NOT NULL, "id" varchar(36) COLLATE "C" NOT NULL, PRIMARY KEY ("platform", "channel", "type", "bundle_ref", "day", "received_at_ms", "id"));
46
+
47
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_events_byDay" ON "hot_updater_v1_bundle_events" ("day", "received_at_ms", "id");
48
+
49
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_bundle_event_heads" ("install_id" varchar(255) COLLATE "C" NOT NULL, "id" varchar(36) COLLATE "C" NOT NULL, "type" varchar(32) COLLATE "C" NOT NULL, "user_id" varchar(255) COLLATE "C", "from_release_id" varchar(36) COLLATE "C", "from_bundle_id" varchar(36) COLLATE "C", "to_release_id" varchar(36) COLLATE "C", "to_bundle_id" varchar(36) COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "app_version" text COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "metadata" jsonb NOT NULL, "received_at_ms" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("install_id"));
50
+
51
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_event_heads_byUser" ON "hot_updater_v1_bundle_event_heads" ("user_id", "install_id");
52
+
53
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_bundle_event_heads__retention" ON "hot_updater_v1_bundle_event_heads" ("received_at_ms", "install_id");
54
+
55
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_overview" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "downloads" bigint NOT NULL, "launches" bigint NOT NULL, "failed_launches" bigint NOT NULL, "failed_updates" bigint NOT NULL, "patch_downloads" bigint NOT NULL, "patch_fallbacks" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
56
+
57
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_overview__retention" ON "hot_updater_v1_insights_overview" ("bucket_start_ms", "identity", "_shard");
58
+
59
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_sketches" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "launch_users" text COLLATE "C", "activity_users" text COLLATE "C", "failed_users" text COLLATE "C", "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
60
+
61
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_sketches__retention" ON "hot_updater_v1_insights_sketches" ("bucket_start_ms", "identity", "_shard");
62
+
63
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_overview_daily" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "downloads" bigint NOT NULL, "launches" bigint NOT NULL, "failed_launches" bigint NOT NULL, "failed_updates" bigint NOT NULL, "patch_downloads" bigint NOT NULL, "patch_fallbacks" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
64
+
65
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_overview_daily__retention" ON "hot_updater_v1_insights_overview_daily" ("bucket_start_ms", "identity", "_shard");
66
+
67
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_sketches_daily" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "launch_users" text COLLATE "C", "activity_users" text COLLATE "C", "failed_users" text COLLATE "C", "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
68
+
69
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_sketches_daily__retention" ON "hot_updater_v1_insights_sketches_daily" ("bucket_start_ms", "identity", "_shard");
70
+
71
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_overview_lifetime" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "downloads" bigint NOT NULL, "launches" bigint NOT NULL, "failed_launches" bigint NOT NULL, "failed_updates" bigint NOT NULL, "patch_downloads" bigint NOT NULL, "patch_fallbacks" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
72
+
73
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_sketches_lifetime" ("identity" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "failed_users" text COLLATE "C", "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("identity", "bucket_start_ms", "_shard"));
74
+
75
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_distribution" ("channel" text COLLATE "C" NOT NULL, "platform" varchar(16) COLLATE "C" NOT NULL, "app_version" text COLLATE "C" NOT NULL, "release_id" varchar(36) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "latest_installations" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("channel", "platform", "app_version", "release_id", "bucket_start_ms", "_shard"));
76
+
77
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_distribution_byScope" ON "hot_updater_v1_insights_distribution" ("channel", "platform", "bucket_start_ms", "app_version", "release_id", "_shard");
78
+
79
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_distribution_byVersion" ON "hot_updater_v1_insights_distribution" ("channel", "platform", "app_version", "bucket_start_ms", "release_id", "_shard");
80
+
81
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_distribution__retention" ON "hot_updater_v1_insights_distribution" ("bucket_start_ms", "channel", "platform", "app_version", "release_id", "_shard");
82
+
83
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_latest_by_bundle" ("platform" varchar(16) COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "bundle_field" varchar(16) COLLATE "C" NOT NULL, "bundle_id" varchar(36) COLLATE "C" NOT NULL, "type" varchar(32) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "installations" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("platform", "channel", "bundle_field", "bundle_id", "type", "bucket_start_ms", "_shard"));
84
+
85
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_latest_by_bundle__retention" ON "hot_updater_v1_insights_latest_by_bundle" ("bucket_start_ms", "platform", "channel", "bundle_field", "bundle_id", "type", "_shard");
86
+
87
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_outcomes" ("platform" varchar(16) COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "type" varchar(32) COLLATE "C" NOT NULL, "bundle_ref" varchar(41) COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "_shard" bigint NOT NULL, "events" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("platform", "channel", "type", "bundle_ref", "bucket_start_ms", "_shard"));
88
+
89
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_outcomes__retention" ON "hot_updater_v1_insights_outcomes" ("bucket_start_ms", "platform", "channel", "type", "bundle_ref", "_shard");
90
+
91
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_insights_failures" ("platform" varchar(16) COLLATE "C" NOT NULL, "channel" text COLLATE "C" NOT NULL, "bucket_start_ms" bigint NOT NULL, "release_id" varchar(36) COLLATE "C" NOT NULL, "stage" varchar(16) COLLATE "C" NOT NULL, "reason" varchar(64) COLLATE "C" NOT NULL, "detail" varchar(160) COLLATE "C" NOT NULL, "_shard" bigint NOT NULL, "events" bigint NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("platform", "channel", "bucket_start_ms", "release_id", "stage", "reason", "detail", "_shard"));
92
+
93
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_insights_failures__retention" ON "hot_updater_v1_insights_failures" ("bucket_start_ms", "platform", "channel", "release_id", "stage", "reason", "detail", "_shard");
94
+
95
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_api_keys" ("id" varchar(255) COLLATE "C" NOT NULL, "hash" varchar(64) COLLATE "C" NOT NULL, "name" varchar(64) COLLATE "C" NOT NULL, "prefix" varchar(16) COLLATE "C" NOT NULL, "role" varchar(16) COLLATE "C" NOT NULL, "created_at_ms" bigint NOT NULL, "revoked_at_ms" bigint, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("id"));
96
+
97
+ CREATE INDEX IF NOT EXISTS "hot_updater_v1_api_keys_byCreated" ON "hot_updater_v1_api_keys" ("created_at_ms", "id");
98
+
99
+ CREATE UNIQUE INDEX IF NOT EXISTS "hot_updater_v1_api_keys_hash" ON "hot_updater_v1_api_keys" ("hash");
100
+
101
+ CREATE TABLE IF NOT EXISTS "hot_updater_v1_private_hot_updater_settings" ("key" varchar(255) COLLATE "C" NOT NULL, "value" varchar(255) COLLATE "C" NOT NULL, "_v" bigint NOT NULL DEFAULT 0, PRIMARY KEY ("key"));
102
+
103
+ ALTER TABLE "hot_updater_v1_bundles" ENABLE ROW LEVEL SECURITY;
104
+
105
+ ALTER TABLE "hot_updater_v1_bundle_patches" ENABLE ROW LEVEL SECURITY;
106
+
107
+ ALTER TABLE "hot_updater_v1_releases" ENABLE ROW LEVEL SECURITY;
108
+
109
+ ALTER TABLE "hot_updater_v1_release_catalogs" ENABLE ROW LEVEL SECURITY;
110
+
111
+ ALTER TABLE "hot_updater_v1_channels" ENABLE ROW LEVEL SECURITY;
112
+
113
+ ALTER TABLE "hot_updater_v1_bundle_totals" ENABLE ROW LEVEL SECURITY;
114
+
115
+ ALTER TABLE "hot_updater_v1_bundle_events" ENABLE ROW LEVEL SECURITY;
116
+
117
+ ALTER TABLE "hot_updater_v1_bundle_events__byBundle" ENABLE ROW LEVEL SECURITY;
118
+
119
+ ALTER TABLE "hot_updater_v1_bundle_event_heads" ENABLE ROW LEVEL SECURITY;
120
+
121
+ ALTER TABLE "hot_updater_v1_insights_overview" ENABLE ROW LEVEL SECURITY;
122
+
123
+ ALTER TABLE "hot_updater_v1_insights_sketches" ENABLE ROW LEVEL SECURITY;
124
+
125
+ ALTER TABLE "hot_updater_v1_insights_overview_daily" ENABLE ROW LEVEL SECURITY;
126
+
127
+ ALTER TABLE "hot_updater_v1_insights_sketches_daily" ENABLE ROW LEVEL SECURITY;
128
+
129
+ ALTER TABLE "hot_updater_v1_insights_overview_lifetime" ENABLE ROW LEVEL SECURITY;
130
+
131
+ ALTER TABLE "hot_updater_v1_insights_sketches_lifetime" ENABLE ROW LEVEL SECURITY;
132
+
133
+ ALTER TABLE "hot_updater_v1_insights_distribution" ENABLE ROW LEVEL SECURITY;
134
+
135
+ ALTER TABLE "hot_updater_v1_insights_latest_by_bundle" ENABLE ROW LEVEL SECURITY;
136
+
137
+ ALTER TABLE "hot_updater_v1_insights_outcomes" ENABLE ROW LEVEL SECURITY;
138
+
139
+ ALTER TABLE "hot_updater_v1_insights_failures" ENABLE ROW LEVEL SECURITY;
140
+
141
+ ALTER TABLE "hot_updater_v1_api_keys" ENABLE ROW LEVEL SECURITY;
142
+
143
+ ALTER TABLE "hot_updater_v1_private_hot_updater_settings" ENABLE ROW LEVEL SECURITY;
144
+
145
+ ALTER TABLE "hot_updater_v1__hu_write" ENABLE ROW LEVEL SECURITY;
146
+
147
+ CREATE OR REPLACE FUNCTION public.hot_updater_v1_apply(p_statements jsonb)
215
148
  RETURNS jsonb
216
149
  LANGUAGE plpgsql
217
150
  SECURITY INVOKER
218
- SET search_path = pg_catalog
219
- AS $$
151
+ SET search_path = public, pg_temp
152
+ AS $apply$
220
153
  DECLARE
221
- v_change jsonb;
222
- v_change_index integer := -1;
223
- v_expectation jsonb;
224
- v_expected double precision;
225
- v_actual double precision;
226
- v_found boolean;
227
- v_bundle public.hot_updater_v1_bundles;
228
- v_patch public.hot_updater_v1_bundle_patches;
229
- v_release public.hot_updater_v1_releases;
230
- v_catalog public.hot_updater_v1_release_catalogs;
231
- v_channel public.hot_updater_v1_channels;
232
- v_api_key public.hot_updater_v1_api_keys;
154
+ item jsonb;
155
+ statement text;
156
+ shape text;
157
+ target text;
158
+ found record;
159
+ rows jsonb;
160
+ changed bigint;
161
+ results jsonb := '[]'::jsonb;
233
162
  BEGIN
234
- IF pg_catalog.jsonb_typeof(p_commit) IS DISTINCT FROM 'object'
235
- OR pg_catalog.jsonb_typeof(p_commit->'changes') IS DISTINCT FROM 'array'
236
- OR (
237
- p_commit ? 'expectations'
238
- AND pg_catalog.jsonb_typeof(p_commit->'expectations') IS DISTINCT FROM 'array'
239
- )
240
- THEN
241
- RAISE EXCEPTION 'Hot Updater commit has an invalid envelope'
242
- USING ERRCODE = '22023';
243
- END IF;
244
-
245
- FOR v_expectation IN
246
- SELECT value
247
- FROM pg_catalog.jsonb_array_elements(
248
- COALESCE(p_commit->'expectations', '[]'::jsonb)
249
- ) AS expectation(value)
250
- LOOP
251
- IF v_expectation->>'model' = 'releases' THEN
252
- PERFORM pg_catalog.pg_advisory_xact_lock(
253
- pg_catalog.hashtextextended(
254
- 'hot_updater_v1:release:' || (v_expectation->>'id'),
255
- 0
256
- )
257
- );
258
- SELECT release.revision::double precision
259
- INTO v_actual
260
- FROM public.hot_updater_v1_releases AS release
261
- WHERE release.id = (v_expectation->>'id')::uuid
262
- FOR UPDATE;
263
- v_found := FOUND;
264
- v_expected := (v_expectation->>'revision')::double precision;
265
- ELSIF v_expectation->>'model' = 'releaseCatalogs' THEN
266
- PERFORM pg_catalog.pg_advisory_xact_lock(
267
- pg_catalog.hashtextextended(
268
- 'hot_updater_v1:catalog:' || (v_expectation->>'scopeKey'),
269
- 0
270
- )
271
- );
272
- SELECT catalog.generation
273
- INTO v_actual
274
- FROM public.hot_updater_v1_release_catalogs AS catalog
275
- WHERE catalog.scope_key = v_expectation->>'scopeKey'
276
- FOR UPDATE;
277
- v_found := FOUND;
278
- v_expected := (v_expectation->>'generation')::double precision;
279
- ELSE
280
- RAISE EXCEPTION 'Unsupported Hot Updater commit expectation'
281
- USING ERRCODE = '22023';
163
+ FOR item IN SELECT value FROM jsonb_array_elements(p_statements) LOOP
164
+ statement := item->>'sql';
165
+ FOR target IN SELECT (regexp_matches(statement, '(?:FROM|INTO|UPDATE|JOIN) "([^"]+)"', 'g'))[1] LOOP
166
+ IF NOT target = ANY (ARRAY['hot_updater_v1_bundles', 'hot_updater_v1_bundle_patches', 'hot_updater_v1_releases', 'hot_updater_v1_release_catalogs', 'hot_updater_v1_channels', 'hot_updater_v1_bundle_totals', 'hot_updater_v1_bundle_events', 'hot_updater_v1_bundle_events__byBundle', 'hot_updater_v1_bundle_event_heads', 'hot_updater_v1_insights_overview', 'hot_updater_v1_insights_sketches', 'hot_updater_v1_insights_overview_daily', 'hot_updater_v1_insights_sketches_daily', 'hot_updater_v1_insights_overview_lifetime', 'hot_updater_v1_insights_sketches_lifetime', 'hot_updater_v1_insights_distribution', 'hot_updater_v1_insights_latest_by_bundle', 'hot_updater_v1_insights_outcomes', 'hot_updater_v1_insights_failures', 'hot_updater_v1_api_keys', 'hot_updater_v1_private_hot_updater_settings', 'hot_updater_v1__hu_write']) THEN
167
+ RAISE EXCEPTION 'hot_updater_v1_apply: % is not a Hot Updater table', target USING ERRCODE = '42501';
168
+ END IF;
169
+ END LOOP;
170
+ shape := regexp_replace(regexp_replace(statement, '^INSERT INTO "[^"]+" \(', 'INSERT INTO ('), '"[^"]*"', '"', 'g');
171
+ IF shape !~ '^(SELECT|INSERT INTO|UPDATE|DELETE FROM) '
172
+ OR shape ~ '"[[:space:]]*\('
173
+ OR shape ~ '[;''\\]|--|/\*'
174
+ OR regexp_replace(shape, '\m(SELECT|FROM|WHERE|AND|OR|NOT|EXISTS|INSERT|INTO|VALUES|UPDATE|SET|DELETE|ORDER|BY|ASC|DESC|LIMIT|IS|NULL|ON|CONFLICT|DO|JOIN|FOR|bigint|double|precision|boolean|jsonb|i|b)\M', '', 'gi') !~ '^[[:space:]"(),.*=<>+0-9$:-]*$' THEN
175
+ RAISE EXCEPTION 'hot_updater_v1_apply: statement not allowed' USING ERRCODE = '42501';
282
176
  END IF;
283
-
284
- IF (v_expected IS NULL AND v_found)
285
- OR (v_expected IS NOT NULL AND (NOT v_found OR v_actual <> v_expected))
286
- THEN
287
- RETURN pg_catalog.jsonb_build_object(
288
- 'committed', false,
289
- 'conflict', pg_catalog.jsonb_build_object(
290
- 'changeIndex', -1,
291
- 'reason', 'version_conflict',
292
- 'model', v_expectation->>'model',
293
- 'key', COALESCE(
294
- v_expectation->>'id',
295
- v_expectation->>'scopeKey'
296
- ),
297
- 'expectedVersion', v_expected,
298
- 'actualVersion', CASE WHEN v_found THEN v_actual ELSE NULL END
299
- )
300
- );
177
+ IF statement ~ '^SELECT ' THEN
178
+ rows := '[]'::jsonb;
179
+ FOR found IN EXECUTE statement USING item->'params' LOOP
180
+ rows := rows || jsonb_build_array(to_jsonb(found));
181
+ END LOOP;
182
+ results := results || jsonb_build_array(jsonb_build_object('rows', rows, 'changes', 0));
183
+ ELSE
184
+ EXECUTE statement USING item->'params';
185
+ GET DIAGNOSTICS changed = ROW_COUNT;
186
+ results := results || jsonb_build_array(jsonb_build_object('rows', '[]'::jsonb, 'changes', changed));
301
187
  END IF;
302
188
  END LOOP;
303
-
304
- BEGIN
305
- FOR v_change_index, v_change IN
306
- SELECT ordinal - 1, value
307
- FROM pg_catalog.jsonb_array_elements(p_commit->'changes')
308
- WITH ORDINALITY AS change(value, ordinal)
309
- ORDER BY ordinal
310
- LOOP
311
- CASE v_change->>'model'
312
- WHEN 'channels' THEN
313
- CASE v_change->>'operation'
314
- WHEN 'insert' THEN
315
- IF v_change->>'onConflict' <> 'ignore' THEN
316
- RAISE EXCEPTION 'Channel insert requires onConflict ignore'
317
- USING ERRCODE = '22023';
318
- END IF;
319
- v_channel := pg_catalog.jsonb_populate_record(
320
- NULL::public.hot_updater_v1_channels,
321
- v_change->'row'
322
- );
323
- INSERT INTO public.hot_updater_v1_channels (id, name)
324
- VALUES (v_channel.id, v_channel.name)
325
- ON CONFLICT (name) DO NOTHING;
326
- WHEN 'delete' THEN
327
- BEGIN
328
- DELETE FROM public.hot_updater_v1_channels
329
- WHERE id = v_change->'where'->>'id';
330
- IF NOT FOUND THEN RAISE no_data_found; END IF;
331
- EXCEPTION
332
- WHEN foreign_key_violation THEN RAISE SQLSTATE 'HU001';
333
- END;
334
- ELSE
335
- RAISE EXCEPTION 'Unsupported Channel change'
336
- USING ERRCODE = '22023';
337
- END CASE;
338
-
339
- WHEN 'bundles' THEN
340
- CASE v_change->>'operation'
341
- WHEN 'insert' THEN
342
- v_bundle := pg_catalog.jsonb_populate_record(
343
- NULL::public.hot_updater_v1_bundles,
344
- v_change->'row'
345
- );
346
- INSERT INTO public.hot_updater_v1_bundles (
347
- id, platform, file_hash, git_commit_hash, storage_uri,
348
- archive_byte_size, metadata, manifest_storage_uri, manifest_file_hash,
349
- asset_base_storage_uri
350
- ) VALUES (
351
- v_bundle.id, v_bundle.platform, v_bundle.file_hash,
352
- v_bundle.git_commit_hash, v_bundle.storage_uri,
353
- v_bundle.archive_byte_size, v_bundle.metadata,
354
- v_bundle.manifest_storage_uri,
355
- v_bundle.manifest_file_hash, v_bundle.asset_base_storage_uri
356
- );
357
- WHEN 'update' THEN
358
- SELECT bundle.* INTO v_bundle
359
- FROM public.hot_updater_v1_bundles AS bundle
360
- WHERE bundle.id = (v_change->'where'->>'id')::uuid
361
- FOR UPDATE;
362
- IF NOT FOUND THEN RAISE no_data_found; END IF;
363
- v_bundle := pg_catalog.jsonb_populate_record(
364
- v_bundle,
365
- v_change->'update'
366
- );
367
- UPDATE public.hot_updater_v1_bundles SET
368
- platform = v_bundle.platform,
369
- file_hash = v_bundle.file_hash,
370
- git_commit_hash = v_bundle.git_commit_hash,
371
- storage_uri = v_bundle.storage_uri,
372
- archive_byte_size = v_bundle.archive_byte_size,
373
- metadata = v_bundle.metadata,
374
- manifest_storage_uri = v_bundle.manifest_storage_uri,
375
- manifest_file_hash = v_bundle.manifest_file_hash,
376
- asset_base_storage_uri = v_bundle.asset_base_storage_uri
377
- WHERE id = v_bundle.id;
378
- WHEN 'delete' THEN
379
- BEGIN
380
- DELETE FROM public.hot_updater_v1_bundles
381
- WHERE id = (v_change->'where'->>'id')::uuid;
382
- IF NOT FOUND THEN RAISE no_data_found; END IF;
383
- EXCEPTION
384
- WHEN foreign_key_violation THEN RAISE SQLSTATE 'HU001';
385
- END;
386
- ELSE
387
- RAISE EXCEPTION 'Unsupported Bundle change'
388
- USING ERRCODE = '22023';
389
- END CASE;
390
-
391
- WHEN 'bundlePatches' THEN
392
- CASE v_change->>'operation'
393
- WHEN 'insert' THEN
394
- v_patch := pg_catalog.jsonb_populate_record(
395
- NULL::public.hot_updater_v1_bundle_patches,
396
- v_change->'row'
397
- );
398
- INSERT INTO public.hot_updater_v1_bundle_patches (
399
- id, bundle_id, base_bundle_id, base_file_hash,
400
- patch_file_hash, patch_storage_uri, byte_size, order_index
401
- ) VALUES (
402
- v_patch.id, v_patch.bundle_id, v_patch.base_bundle_id,
403
- v_patch.base_file_hash, v_patch.patch_file_hash,
404
- v_patch.patch_storage_uri, v_patch.byte_size,
405
- v_patch.order_index
406
- );
407
- WHEN 'delete' THEN
408
- DELETE FROM public.hot_updater_v1_bundle_patches
409
- WHERE bundle_id = (v_change->'where'->>'bundleId')::uuid;
410
- ELSE
411
- RAISE EXCEPTION 'Unsupported Bundle patch change'
412
- USING ERRCODE = '22023';
413
- END CASE;
414
-
415
- WHEN 'releases' THEN
416
- CASE v_change->>'operation'
417
- WHEN 'insert' THEN
418
- v_release := pg_catalog.jsonb_populate_record(
419
- NULL::public.hot_updater_v1_releases,
420
- v_change->'row'
421
- );
422
- INSERT INTO public.hot_updater_v1_releases SELECT v_release.*;
423
- WHEN 'update' THEN
424
- SELECT release.* INTO v_release
425
- FROM public.hot_updater_v1_releases AS release
426
- WHERE release.id = (v_change->'where'->>'id')::uuid
427
- FOR UPDATE;
428
- IF NOT FOUND THEN RAISE no_data_found; END IF;
429
- v_release := pg_catalog.jsonb_populate_record(
430
- v_release,
431
- v_change->'update'
432
- );
433
- UPDATE public.hot_updater_v1_releases SET
434
- revision = v_release.revision,
435
- scope_key = v_release.scope_key,
436
- target_app_version = v_release.target_app_version,
437
- fingerprint_hash = v_release.fingerprint_hash,
438
- enabled = v_release.enabled,
439
- should_force_update = v_release.should_force_update,
440
- message = v_release.message,
441
- rollout_cohort_count = v_release.rollout_cohort_count,
442
- target_cohorts = v_release.target_cohorts,
443
- updated_at_ms = v_release.updated_at_ms
444
- WHERE id = v_release.id;
445
- WHEN 'delete' THEN
446
- DELETE FROM public.hot_updater_v1_releases
447
- WHERE id = (v_change->'where'->>'id')::uuid;
448
- IF NOT FOUND THEN RAISE no_data_found; END IF;
449
- ELSE
450
- RAISE EXCEPTION 'Unsupported Release change'
451
- USING ERRCODE = '22023';
452
- END CASE;
453
-
454
- WHEN 'releaseCatalogs' THEN
455
- IF v_change->>'operation' <> 'put' THEN
456
- RAISE EXCEPTION 'Unsupported Release catalog change'
457
- USING ERRCODE = '22023';
458
- END IF;
459
- v_catalog := pg_catalog.jsonb_populate_record(
460
- NULL::public.hot_updater_v1_release_catalogs,
461
- v_change->'row'
462
- );
463
- INSERT INTO public.hot_updater_v1_release_catalogs SELECT v_catalog.*
464
- ON CONFLICT (scope_key) DO UPDATE SET
465
- catalog_id = EXCLUDED.catalog_id,
466
- strategy = EXCLUDED.strategy,
467
- channel_id = EXCLUDED.channel_id,
468
- channel_key = EXCLUDED.channel_key,
469
- platform = EXCLUDED.platform,
470
- fingerprint_hash = EXCLUDED.fingerprint_hash,
471
- generation = EXCLUDED.generation,
472
- payload = EXCLUDED.payload,
473
- catalog_hash = EXCLUDED.catalog_hash,
474
- byte_size = EXCLUDED.byte_size,
475
- is_tombstone = EXCLUDED.is_tombstone,
476
- updated_at_ms = EXCLUDED.updated_at_ms;
477
-
478
- WHEN 'apiKeys' THEN
479
- CASE v_change->>'operation'
480
- WHEN 'insert' THEN
481
- IF v_change->>'onConflict' <> 'ignore' THEN
482
- RAISE EXCEPTION
483
- 'API key insert requires onConflict ignore'
484
- USING ERRCODE = '22023';
485
- END IF;
486
- v_api_key := pg_catalog.jsonb_populate_record(
487
- NULL::public.hot_updater_v1_api_keys,
488
- v_change->'row'
489
- );
490
- INSERT INTO public.hot_updater_v1_api_keys (
491
- id, hash, name, prefix, role, created_at_ms, revoked_at_ms
492
- ) VALUES (
493
- v_api_key.id, v_api_key.hash, v_api_key.name,
494
- v_api_key.prefix, v_api_key.role,
495
- v_api_key.created_at_ms, v_api_key.revoked_at_ms
496
- ) ON CONFLICT (hash) DO NOTHING;
497
- WHEN 'update' THEN
498
- UPDATE public.hot_updater_v1_api_keys
499
- SET revoked_at_ms = (
500
- v_change->'update'->>'revokedAtMs'
501
- )::double precision
502
- WHERE id = v_change->'where'->>'id';
503
- IF NOT FOUND THEN RAISE no_data_found; END IF;
504
- ELSE
505
- RAISE EXCEPTION 'Unsupported API key change'
506
- USING ERRCODE = '22023';
507
- END CASE;
508
-
509
- ELSE
510
- RAISE EXCEPTION 'Unsupported commit model at index %', v_change_index
511
- USING ERRCODE = '22023';
512
- END CASE;
513
- END LOOP;
514
- EXCEPTION
515
- WHEN no_data_found THEN
516
- RETURN pg_catalog.jsonb_build_object(
517
- 'committed', false,
518
- 'conflict', pg_catalog.jsonb_build_object(
519
- 'changeIndex', v_change_index,
520
- 'reason', 'not_found'
521
- )
522
- );
523
- WHEN SQLSTATE 'HU001' THEN
524
- RETURN pg_catalog.jsonb_build_object(
525
- 'committed', false,
526
- 'conflict', pg_catalog.jsonb_build_object(
527
- 'changeIndex', v_change_index,
528
- 'reason', 'referenced'
529
- )
530
- );
531
- END;
532
-
533
- RETURN pg_catalog.jsonb_build_object('committed', true);
189
+ RETURN results;
534
190
  END;
535
- $$;
191
+ $apply$;
536
192
 
537
- REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_commit(jsonb)
538
- FROM PUBLIC, anon, authenticated;
539
- GRANT EXECUTE ON FUNCTION public.hot_updater_v1_commit(jsonb)
540
- TO service_role;
193
+ REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_apply(jsonb) FROM PUBLIC, anon, authenticated;
541
194
 
542
- CREATE FUNCTION public.hot_updater_v1_delete_channel(p_id text)
543
- RETURNS jsonb
544
- LANGUAGE plpgsql
545
- SECURITY INVOKER
546
- SET search_path = pg_catalog
547
- AS $$
548
- BEGIN
549
- BEGIN
550
- DELETE FROM public.hot_updater_v1_channels
551
- WHERE id = p_id;
552
-
553
- IF NOT FOUND THEN
554
- RETURN pg_catalog.jsonb_build_object(
555
- 'deleted', false,
556
- 'reason', 'not_found'
557
- );
558
- END IF;
559
- EXCEPTION
560
- WHEN foreign_key_violation THEN
561
- RETURN pg_catalog.jsonb_build_object(
562
- 'deleted', false,
563
- 'reason', 'not_empty'
564
- );
565
- END;
566
-
567
- RETURN pg_catalog.jsonb_build_object('deleted', true);
568
- END;
569
- $$;
570
-
571
- REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_delete_channel(text)
572
- FROM PUBLIC, anon, authenticated;
573
- GRANT EXECUTE ON FUNCTION public.hot_updater_v1_delete_channel(text)
574
- TO service_role;
575
-
576
- -- The event insert gates the snapshot replacement in the same SQL statement.
577
- CREATE FUNCTION public.hot_updater_v1_record_insights(p_event jsonb, p_installation jsonb)
578
- RETURNS void
579
- LANGUAGE sql
580
- SECURITY DEFINER
581
- SET search_path = ''
582
- AS $$
583
- WITH accepted_event AS (
584
- INSERT INTO public.hot_updater_v1_bundle_events
585
- SELECT * FROM pg_catalog.jsonb_populate_record(
586
- NULL::public.hot_updater_v1_bundle_events, p_event
587
- )
588
- ON CONFLICT (id) DO NOTHING RETURNING id
589
- )
590
- INSERT INTO public.hot_updater_v1_bundle_installations
591
- SELECT candidate.*
592
- FROM pg_catalog.jsonb_populate_record(
593
- NULL::public.hot_updater_v1_bundle_installations, p_installation
594
- ) AS candidate
595
- CROSS JOIN accepted_event
596
- ON CONFLICT (install_id) DO UPDATE SET
597
- id = excluded.id,
598
- user_id = excluded.user_id,
599
- username = excluded.username,
600
- to_bundle_id = excluded.to_bundle_id,
601
- type = excluded.type,
602
- platform = excluded.platform,
603
- app_version = excluded.app_version,
604
- channel = excluded.channel,
605
- cohort = excluded.cohort,
606
- received_at_ms = excluded.received_at_ms
607
- WHERE (excluded.received_at_ms, excluded.id) >
608
- (hot_updater_v1_bundle_installations.received_at_ms,
609
- hot_updater_v1_bundle_installations.id);
610
- $$;
611
-
612
- REVOKE EXECUTE ON FUNCTION public.hot_updater_v1_record_insights(jsonb, jsonb)
613
- FROM PUBLIC, anon, authenticated;
614
- GRANT EXECUTE ON FUNCTION public.hot_updater_v1_record_insights(jsonb, jsonb)
615
- TO service_role;
616
-
617
- NOTIFY pgrst, 'reload schema';
195
+ GRANT EXECUTE ON FUNCTION public.hot_updater_v1_apply(jsonb) TO service_role;
196
+
197
+ INSERT INTO "hot_updater_v1_private_hot_updater_settings" ("key", "value", "_v") VALUES ('schema.engine', '1', 0) ON CONFLICT ("key") DO UPDATE SET "value" = excluded."value";
198
+
199
+ INSERT INTO "hot_updater_v1_private_hot_updater_settings" ("key", "value", "_v") VALUES ('schema.core', '1.0.0', 0) ON CONFLICT ("key") DO UPDATE SET "value" = excluded."value";
200
+
201
+ INSERT INTO "hot_updater_v1_private_hot_updater_settings" ("key", "value", "_v") VALUES ('schema.insights', '1.2.0', 0) ON CONFLICT ("key") DO UPDATE SET "value" = excluded."value";
202
+
203
+ INSERT INTO "hot_updater_v1_private_hot_updater_settings" ("key", "value", "_v") VALUES ('schema.apiKeys', '1.0.0', 0) ON CONFLICT ("key") DO UPDATE SET "value" = excluded."value";