@hot-updater/postgres 0.36.7 → 1.0.0-rc.1
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.
- package/dist/index.cjs +238 -1096
- package/dist/index.d.cts +7 -24
- package/dist/index.d.mts +7 -24
- package/dist/index.mjs +240 -1120
- package/package.json +5 -12
- package/sql/bundles.sql +179 -45
- package/sql/get_target_app_version_list.sql +0 -21
- package/sql/get_update_info.spec.ts +0 -171
- package/sql/get_update_info_by_app_version.sql +0 -126
- package/sql/get_update_info_by_fingerprint_hash.sql +0 -125
- package/sql/hash_user_id.sql +0 -30
- package/sql/is_device_eligible.sql +0 -237
- package/sql/prepareSql.ts +0 -11
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/postgres",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0-rc.1",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -34,24 +34,17 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"kysely": "0.28.17",
|
|
36
36
|
"pg": "8.13.1",
|
|
37
|
-
"@hot-updater/core": "0.
|
|
38
|
-
"@hot-updater/plugin-core": "0.
|
|
37
|
+
"@hot-updater/core": "1.0.0-rc.0",
|
|
38
|
+
"@hot-updater/plugin-core": "1.0.0-rc.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@electric-sql/pglite": "0.4.1",
|
|
42
42
|
"@types/node": "^20",
|
|
43
43
|
"@types/pg": "^8.11.10",
|
|
44
44
|
"camelcase-keys": "^9.1.3",
|
|
45
|
+
"kysely-pglite-dialect": "1.2.0",
|
|
45
46
|
"pg-minify": "^1.6.5",
|
|
46
|
-
"@hot-updater/
|
|
47
|
-
"@hot-updater/test-utils": "0.36.7"
|
|
48
|
-
},
|
|
49
|
-
"inlinedDependencies": {
|
|
50
|
-
"camelcase": "8.0.0",
|
|
51
|
-
"camelcase-keys": "9.1.3",
|
|
52
|
-
"map-obj": "5.0.0",
|
|
53
|
-
"pg-minify": "1.8.0",
|
|
54
|
-
"quick-lru": "6.1.2"
|
|
47
|
+
"@hot-updater/test-utils": "1.0.0-rc.1"
|
|
55
48
|
},
|
|
56
49
|
"scripts": {
|
|
57
50
|
"build": "tsdown",
|
package/sql/bundles.sql
CHANGED
|
@@ -1,45 +1,179 @@
|
|
|
1
|
-
-- HotUpdater.
|
|
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
|
-
|
|
1
|
+
-- HotUpdater.schema
|
|
2
|
+
|
|
3
|
+
create table channels (
|
|
4
|
+
id varchar(255) primary key not null,
|
|
5
|
+
name varchar(255) not null
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
create table bundles (
|
|
9
|
+
id uuid primary key not null,
|
|
10
|
+
platform text not null,
|
|
11
|
+
file_hash text not null,
|
|
12
|
+
git_commit_hash text,
|
|
13
|
+
storage_uri text not null,
|
|
14
|
+
archive_byte_size double precision not null,
|
|
15
|
+
metadata json not null default '{}'::json,
|
|
16
|
+
manifest_storage_uri text,
|
|
17
|
+
manifest_file_hash text,
|
|
18
|
+
asset_base_storage_uri text
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
create table bundle_patches (
|
|
22
|
+
id varchar(255) primary key not null,
|
|
23
|
+
bundle_id uuid not null,
|
|
24
|
+
base_bundle_id uuid not null,
|
|
25
|
+
base_file_hash text not null,
|
|
26
|
+
patch_file_hash text not null,
|
|
27
|
+
patch_storage_uri text not null,
|
|
28
|
+
byte_size double precision not null,
|
|
29
|
+
order_index integer not null default 0
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
create table releases (
|
|
33
|
+
id uuid primary key not null,
|
|
34
|
+
revision integer not null,
|
|
35
|
+
scope_key varchar(2048) not null,
|
|
36
|
+
channel_id varchar(255) not null,
|
|
37
|
+
platform text not null,
|
|
38
|
+
kind text not null,
|
|
39
|
+
bundle_id uuid,
|
|
40
|
+
strategy text not null,
|
|
41
|
+
target_app_version text,
|
|
42
|
+
fingerprint_hash text,
|
|
43
|
+
enabled boolean not null,
|
|
44
|
+
should_force_update boolean not null,
|
|
45
|
+
message text,
|
|
46
|
+
rollout_cohort_count integer not null default 1000,
|
|
47
|
+
target_cohorts json not null default '[]'::json,
|
|
48
|
+
operation text not null,
|
|
49
|
+
source_release_id uuid,
|
|
50
|
+
created_at_ms double precision not null,
|
|
51
|
+
updated_at_ms double precision not null
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
create table release_catalogs (
|
|
55
|
+
scope_key varchar(2048) primary key not null,
|
|
56
|
+
catalog_id varchar(255) not null,
|
|
57
|
+
strategy text not null,
|
|
58
|
+
channel_id varchar(255) not null,
|
|
59
|
+
channel_key varchar(1400) not null,
|
|
60
|
+
platform text not null,
|
|
61
|
+
fingerprint_hash text,
|
|
62
|
+
generation double precision not null,
|
|
63
|
+
payload text not null,
|
|
64
|
+
catalog_hash varchar(71) not null,
|
|
65
|
+
byte_size integer not null,
|
|
66
|
+
is_tombstone boolean not null,
|
|
67
|
+
updated_at_ms double precision not null
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
create table bundle_events (
|
|
71
|
+
id uuid primary key not null,
|
|
72
|
+
type text not null,
|
|
73
|
+
install_id text not null,
|
|
74
|
+
user_id text,
|
|
75
|
+
username text,
|
|
76
|
+
from_release_id uuid,
|
|
77
|
+
from_bundle_id uuid,
|
|
78
|
+
to_release_id uuid,
|
|
79
|
+
to_bundle_id uuid not null,
|
|
80
|
+
platform text not null,
|
|
81
|
+
app_version text not null,
|
|
82
|
+
channel text not null,
|
|
83
|
+
cohort text not null,
|
|
84
|
+
update_strategy text,
|
|
85
|
+
fingerprint_hash text,
|
|
86
|
+
sdk_version text,
|
|
87
|
+
received_at_ms double precision not null
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
create table api_keys (
|
|
91
|
+
id varchar(255) primary key not null,
|
|
92
|
+
hash text not null,
|
|
93
|
+
name text not null,
|
|
94
|
+
prefix text not null,
|
|
95
|
+
role text not null,
|
|
96
|
+
created_at_ms double precision not null,
|
|
97
|
+
revoked_at_ms double precision
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
create table private_hot_updater_settings (
|
|
101
|
+
key varchar(255) primary key not null,
|
|
102
|
+
value text not null default '1.0.0'
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
create unique index channels_name_key on channels(name);
|
|
106
|
+
create index bundle_patches_bundle_id_idx on bundle_patches(bundle_id);
|
|
107
|
+
create index bundle_patches_base_bundle_id_idx on bundle_patches(base_bundle_id);
|
|
108
|
+
create index releases_scope_order_idx on releases(scope_key, id);
|
|
109
|
+
create index releases_channel_platform_order_idx on releases(channel_id, platform, id);
|
|
110
|
+
create index releases_bundle_id_idx on releases(bundle_id);
|
|
111
|
+
create index releases_fingerprint_hash_idx on releases(fingerprint_hash);
|
|
112
|
+
create index releases_enabled_idx on releases(enabled);
|
|
113
|
+
create index release_catalogs_channel_idx on release_catalogs(channel_id);
|
|
114
|
+
create index bundle_events_received_at_idx on bundle_events(received_at_ms, id);
|
|
115
|
+
create index bundle_events_install_idx on bundle_events(install_id, received_at_ms, id);
|
|
116
|
+
create index bundle_events_user_id_idx on bundle_events(user_id, received_at_ms, id);
|
|
117
|
+
create index bundle_events_username_idx on bundle_events(username, received_at_ms, id);
|
|
118
|
+
create index bundle_events_to_bundle_idx on bundle_events(type, to_bundle_id, received_at_ms, id);
|
|
119
|
+
create index bundle_events_from_bundle_idx on bundle_events(type, from_bundle_id, received_at_ms, id);
|
|
120
|
+
create index bundle_events_to_release_idx on bundle_events(type, to_release_id, received_at_ms, id);
|
|
121
|
+
create index bundle_events_from_release_idx on bundle_events(type, from_release_id, received_at_ms, id);
|
|
122
|
+
create unique index api_keys_hash_key on api_keys(hash);
|
|
123
|
+
create index api_keys_created_at_idx on api_keys(created_at_ms, id);
|
|
124
|
+
|
|
125
|
+
alter table channels add constraint channels_id_length_check
|
|
126
|
+
check (char_length(id) between 1 and 255);
|
|
127
|
+
alter table channels add constraint channels_name_length_check
|
|
128
|
+
check (char_length(name) between 1 and 255);
|
|
129
|
+
alter table bundles add constraint bundles_archive_byte_size_check
|
|
130
|
+
check (archive_byte_size >= 0 and archive_byte_size <= 9007199254740991);
|
|
131
|
+
alter table bundle_patches add constraint bundle_patches_byte_size_check
|
|
132
|
+
check (byte_size >= 0 and byte_size <= 9007199254740991);
|
|
133
|
+
alter table releases add constraint releases_revision_check
|
|
134
|
+
check (revision >= 1);
|
|
135
|
+
alter table releases add constraint releases_kind_bundle_check
|
|
136
|
+
check ((kind = 'BUNDLE' and bundle_id is not null) or (kind = 'EMBEDDED' and bundle_id is null));
|
|
137
|
+
alter table releases add constraint releases_strategy_target_check
|
|
138
|
+
check ((strategy = 'APP_VERSION' and target_app_version is not null and fingerprint_hash is null) or (strategy = 'FINGERPRINT' and target_app_version is null and fingerprint_hash is not null));
|
|
139
|
+
alter table releases add constraint releases_rollout_cohort_count_check
|
|
140
|
+
check (rollout_cohort_count >= 0 and rollout_cohort_count <= 1000);
|
|
141
|
+
alter table releases add constraint releases_operation_check
|
|
142
|
+
check (operation in ('DEPLOY', 'PROMOTE', 'ROLLBACK'));
|
|
143
|
+
alter table release_catalogs add constraint release_catalogs_strategy_target_check
|
|
144
|
+
check ((strategy = 'APP_VERSION' and fingerprint_hash is null) or (strategy = 'FINGERPRINT' and fingerprint_hash is not null));
|
|
145
|
+
alter table release_catalogs add constraint release_catalogs_generation_check
|
|
146
|
+
check (generation >= 1 and generation <= 9007199254740991);
|
|
147
|
+
alter table release_catalogs add constraint release_catalogs_byte_size_check
|
|
148
|
+
check (byte_size >= 0 and byte_size <= 262144);
|
|
149
|
+
alter table bundle_events add constraint bundle_events_type_check
|
|
150
|
+
check (type in ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED', 'UNCHANGED'));
|
|
151
|
+
alter table bundle_events add constraint bundle_events_platform_check
|
|
152
|
+
check (platform in ('ios', 'android'));
|
|
153
|
+
alter table bundle_events add constraint bundle_events_shape_check
|
|
154
|
+
check (((type in ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED')) and from_bundle_id is not null and update_strategy is not null and update_strategy in ('fingerprint', 'appVersion')) or (type = 'UNCHANGED' and from_bundle_id is null and update_strategy is null));
|
|
155
|
+
alter table bundle_events add constraint bundle_events_received_at_check
|
|
156
|
+
check (received_at_ms >= 0);
|
|
157
|
+
alter table api_keys add constraint api_keys_role_check
|
|
158
|
+
check (role = 'client');
|
|
159
|
+
alter table api_keys add constraint api_keys_created_at_check
|
|
160
|
+
check (created_at_ms >= 0);
|
|
161
|
+
alter table api_keys add constraint api_keys_revoked_at_check
|
|
162
|
+
check (revoked_at_ms is null or revoked_at_ms >= 0);
|
|
163
|
+
|
|
164
|
+
alter table bundle_patches add constraint bundle_patches_bundle_id_fk
|
|
165
|
+
foreign key (bundle_id) references bundles(id) on update restrict on delete cascade;
|
|
166
|
+
alter table bundle_patches add constraint bundle_patches_base_bundle_id_fk
|
|
167
|
+
foreign key (base_bundle_id) references bundles(id) on update restrict on delete cascade;
|
|
168
|
+
alter table releases add constraint releases_channel_id_fk
|
|
169
|
+
foreign key (channel_id) references channels(id) on update restrict on delete restrict;
|
|
170
|
+
alter table releases add constraint releases_bundle_id_fk
|
|
171
|
+
foreign key (bundle_id) references bundles(id) on update restrict on delete restrict;
|
|
172
|
+
alter table releases add constraint releases_source_release_id_fk
|
|
173
|
+
foreign key (source_release_id) references releases(id) on update restrict on delete set null;
|
|
174
|
+
alter table release_catalogs add constraint release_catalogs_channel_id_fk
|
|
175
|
+
foreign key (channel_id) references channels(id) on update restrict on delete restrict;
|
|
176
|
+
|
|
177
|
+
insert into private_hot_updater_settings (key, value)
|
|
178
|
+
values ('schema.core', '1.0.0')
|
|
179
|
+
on conflict (key) do update set value = excluded.value;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
-- HotUpdater.get_target_app_version_list
|
|
2
|
-
|
|
3
|
-
CREATE OR REPLACE FUNCTION get_target_app_version_list (
|
|
4
|
-
app_platform platforms,
|
|
5
|
-
min_bundle_id uuid
|
|
6
|
-
)
|
|
7
|
-
RETURNS TABLE (
|
|
8
|
-
target_app_version text
|
|
9
|
-
)
|
|
10
|
-
LANGUAGE plpgsql
|
|
11
|
-
AS
|
|
12
|
-
$$
|
|
13
|
-
BEGIN
|
|
14
|
-
RETURN QUERY
|
|
15
|
-
SELECT b.target_app_version
|
|
16
|
-
FROM bundles b
|
|
17
|
-
WHERE b.platform = app_platform
|
|
18
|
-
AND b.id >= min_bundle_id
|
|
19
|
-
GROUP BY b.target_app_version;
|
|
20
|
-
END;
|
|
21
|
-
$$;
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { PGlite } from "@electric-sql/pglite";
|
|
2
|
-
import {
|
|
3
|
-
type Bundle,
|
|
4
|
-
type GetBundlesArgs,
|
|
5
|
-
NIL_UUID,
|
|
6
|
-
type UpdateInfo,
|
|
7
|
-
} from "@hot-updater/core";
|
|
8
|
-
import { filterCompatibleAppVersions } from "@hot-updater/js";
|
|
9
|
-
import { setupGetUpdateInfoTestSuite } from "@hot-updater/test-utils";
|
|
10
|
-
import camelcaseKeys from "camelcase-keys";
|
|
11
|
-
import { afterAll, beforeEach, describe } from "vitest";
|
|
12
|
-
|
|
13
|
-
import { prepareSql } from "./prepareSql";
|
|
14
|
-
|
|
15
|
-
const createInsertBundleQuery = (bundle: Bundle) => {
|
|
16
|
-
const rolloutCohortCount = bundle.rolloutCohortCount ?? 1000;
|
|
17
|
-
const targetCohorts = bundle.targetCohorts
|
|
18
|
-
? `ARRAY[${bundle.targetCohorts.map((id) => `'${id}'`).join(",")}]::TEXT[]`
|
|
19
|
-
: "NULL";
|
|
20
|
-
|
|
21
|
-
return `
|
|
22
|
-
INSERT INTO bundles (
|
|
23
|
-
id, file_hash, platform, target_app_version,
|
|
24
|
-
should_force_update, enabled, git_commit_hash, message, channel, storage_uri, fingerprint_hash,
|
|
25
|
-
rollout_cohort_count, target_cohorts
|
|
26
|
-
) VALUES (
|
|
27
|
-
'${bundle.id}',
|
|
28
|
-
'${bundle.fileHash}',
|
|
29
|
-
'${bundle.platform}',
|
|
30
|
-
${bundle.targetAppVersion ? `'${bundle.targetAppVersion}'` : "null"},
|
|
31
|
-
${bundle.shouldForceUpdate},
|
|
32
|
-
${bundle.enabled},
|
|
33
|
-
${bundle.gitCommitHash ? `'${bundle.gitCommitHash}'` : "null"},
|
|
34
|
-
${bundle.message ? `'${bundle.message}'` : "null"},
|
|
35
|
-
'${bundle.channel}',
|
|
36
|
-
'${bundle.storageUri}',
|
|
37
|
-
${bundle.fingerprintHash ? `'${bundle.fingerprintHash}'` : "null"},
|
|
38
|
-
${rolloutCohortCount},
|
|
39
|
-
${targetCohorts}
|
|
40
|
-
) ON CONFLICT (id) DO UPDATE SET
|
|
41
|
-
file_hash = EXCLUDED.file_hash,
|
|
42
|
-
platform = EXCLUDED.platform,
|
|
43
|
-
target_app_version = EXCLUDED.target_app_version,
|
|
44
|
-
should_force_update = EXCLUDED.should_force_update,
|
|
45
|
-
enabled = EXCLUDED.enabled,
|
|
46
|
-
git_commit_hash = EXCLUDED.git_commit_hash,
|
|
47
|
-
message = EXCLUDED.message,
|
|
48
|
-
channel = EXCLUDED.channel,
|
|
49
|
-
storage_uri = EXCLUDED.storage_uri,
|
|
50
|
-
fingerprint_hash = EXCLUDED.fingerprint_hash,
|
|
51
|
-
rollout_cohort_count = EXCLUDED.rollout_cohort_count,
|
|
52
|
-
target_cohorts = EXCLUDED.target_cohorts;
|
|
53
|
-
`;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const createGetUpdateInfo =
|
|
57
|
-
(db: PGlite) =>
|
|
58
|
-
async (
|
|
59
|
-
bundles: Bundle[],
|
|
60
|
-
args: GetBundlesArgs,
|
|
61
|
-
): Promise<UpdateInfo | null> => {
|
|
62
|
-
const {
|
|
63
|
-
bundleId,
|
|
64
|
-
platform,
|
|
65
|
-
minBundleId = NIL_UUID,
|
|
66
|
-
channel = "production",
|
|
67
|
-
_updateStrategy,
|
|
68
|
-
} = args;
|
|
69
|
-
await db.exec(createInsertBundleQuerys(bundles));
|
|
70
|
-
|
|
71
|
-
if (_updateStrategy === "fingerprint") {
|
|
72
|
-
const fingerprintHash = args.fingerprintHash;
|
|
73
|
-
const cohort = args.cohort;
|
|
74
|
-
const cohortSql = cohort ? `'${cohort}'` : "NULL";
|
|
75
|
-
const result = await db.query<{
|
|
76
|
-
id: string;
|
|
77
|
-
should_force_update: boolean;
|
|
78
|
-
message: string;
|
|
79
|
-
status: string;
|
|
80
|
-
storage_uri: string | null;
|
|
81
|
-
file_hash: string | null;
|
|
82
|
-
}>(
|
|
83
|
-
`
|
|
84
|
-
SELECT * FROM get_update_info_by_fingerprint_hash(
|
|
85
|
-
'${platform}',
|
|
86
|
-
'${bundleId}',
|
|
87
|
-
'${minBundleId}',
|
|
88
|
-
'${channel}',
|
|
89
|
-
'${fingerprintHash}',
|
|
90
|
-
${cohortSql}
|
|
91
|
-
);
|
|
92
|
-
`,
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
if (!result.rows[0]) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const row = result.rows[0];
|
|
100
|
-
return camelcaseKeys(row) as UpdateInfo;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const appVersion = args.appVersion;
|
|
104
|
-
const { rows: appVersionList } = await db.query<{
|
|
105
|
-
target_app_version: string;
|
|
106
|
-
}>(
|
|
107
|
-
`
|
|
108
|
-
SELECT target_app_version FROM get_target_app_version_list('${platform}', '${minBundleId}');
|
|
109
|
-
`,
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
const targetAppVersionList = filterCompatibleAppVersions(
|
|
113
|
-
appVersionList?.map((group) => group.target_app_version) ?? [],
|
|
114
|
-
appVersion,
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const cohort = args.cohort;
|
|
118
|
-
const cohortSql = cohort ? `'${cohort}'` : "NULL";
|
|
119
|
-
const result = await db.query<{
|
|
120
|
-
id: string;
|
|
121
|
-
should_force_update: boolean;
|
|
122
|
-
message: string;
|
|
123
|
-
status: string;
|
|
124
|
-
storage_uri: string | null;
|
|
125
|
-
file_hash: string | null;
|
|
126
|
-
}>(
|
|
127
|
-
`
|
|
128
|
-
SELECT * FROM get_update_info_by_app_version(
|
|
129
|
-
'${platform}',
|
|
130
|
-
'${appVersion}',
|
|
131
|
-
'${bundleId}',
|
|
132
|
-
'${minBundleId ?? NIL_UUID}',
|
|
133
|
-
'${channel}',
|
|
134
|
-
ARRAY[${targetAppVersionList.map((v) => `'${v}'`).join(",")}]::text[],
|
|
135
|
-
${cohortSql}
|
|
136
|
-
);
|
|
137
|
-
`,
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
if (!result.rows[0]) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const row = result.rows[0];
|
|
145
|
-
return camelcaseKeys(row) as UpdateInfo;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const createInsertBundleQuerys = (bundles: Bundle[]) => {
|
|
149
|
-
return bundles.map(createInsertBundleQuery).join("\n");
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const db = new PGlite();
|
|
153
|
-
|
|
154
|
-
const sql = await prepareSql();
|
|
155
|
-
await db.exec(sql);
|
|
156
|
-
const getUpdateInfo = createGetUpdateInfo(db);
|
|
157
|
-
|
|
158
|
-
describe("getUpdateInfo", () => {
|
|
159
|
-
beforeEach(async () => {
|
|
160
|
-
await db.exec("DELETE FROM bundle_patches");
|
|
161
|
-
await db.exec("DELETE FROM bundles");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
afterAll(async () => {
|
|
165
|
-
await db.close();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
setupGetUpdateInfoTestSuite({
|
|
169
|
-
getUpdateInfo: getUpdateInfo,
|
|
170
|
-
});
|
|
171
|
-
});
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
-- HotUpdater.get_update_info_by_app_version
|
|
2
|
-
|
|
3
|
-
DROP FUNCTION IF EXISTS get_update_info_by_app_version;
|
|
4
|
-
|
|
5
|
-
CREATE OR REPLACE FUNCTION get_update_info_by_app_version (
|
|
6
|
-
app_platform platforms,
|
|
7
|
-
app_version text,
|
|
8
|
-
bundle_id uuid,
|
|
9
|
-
min_bundle_id uuid,
|
|
10
|
-
target_channel text,
|
|
11
|
-
target_app_version_list text[],
|
|
12
|
-
cohort TEXT DEFAULT NULL
|
|
13
|
-
)
|
|
14
|
-
RETURNS TABLE (
|
|
15
|
-
id uuid,
|
|
16
|
-
should_force_update boolean,
|
|
17
|
-
message text,
|
|
18
|
-
status text,
|
|
19
|
-
storage_uri text,
|
|
20
|
-
file_hash text
|
|
21
|
-
)
|
|
22
|
-
LANGUAGE plpgsql
|
|
23
|
-
AS
|
|
24
|
-
$$
|
|
25
|
-
DECLARE
|
|
26
|
-
NIL_UUID CONSTANT uuid := '00000000-0000-0000-0000-000000000000';
|
|
27
|
-
BEGIN
|
|
28
|
-
RETURN QUERY
|
|
29
|
-
WITH candidate_bundles AS (
|
|
30
|
-
SELECT
|
|
31
|
-
b.id,
|
|
32
|
-
b.should_force_update,
|
|
33
|
-
b.message,
|
|
34
|
-
b.storage_uri,
|
|
35
|
-
b.file_hash,
|
|
36
|
-
b.rollout_cohort_count,
|
|
37
|
-
b.target_cohorts
|
|
38
|
-
FROM bundles b
|
|
39
|
-
WHERE b.enabled = TRUE
|
|
40
|
-
AND b.platform = app_platform
|
|
41
|
-
AND b.id >= min_bundle_id
|
|
42
|
-
AND b.target_app_version IN (SELECT unnest(target_app_version_list))
|
|
43
|
-
AND b.channel = target_channel
|
|
44
|
-
),
|
|
45
|
-
current_candidate AS (
|
|
46
|
-
SELECT
|
|
47
|
-
cb.id,
|
|
48
|
-
is_cohort_eligible(
|
|
49
|
-
cb.id,
|
|
50
|
-
cohort,
|
|
51
|
-
cb.rollout_cohort_count,
|
|
52
|
-
cb.target_cohorts
|
|
53
|
-
) AS is_eligible
|
|
54
|
-
FROM candidate_bundles cb
|
|
55
|
-
WHERE cb.id = bundle_id
|
|
56
|
-
LIMIT 1
|
|
57
|
-
),
|
|
58
|
-
eligible_update_candidate AS (
|
|
59
|
-
SELECT
|
|
60
|
-
cb.id,
|
|
61
|
-
cb.should_force_update,
|
|
62
|
-
cb.message,
|
|
63
|
-
'UPDATE' AS status,
|
|
64
|
-
cb.storage_uri,
|
|
65
|
-
cb.file_hash
|
|
66
|
-
FROM candidate_bundles cb
|
|
67
|
-
WHERE cb.id > bundle_id
|
|
68
|
-
AND is_cohort_eligible(
|
|
69
|
-
cb.id,
|
|
70
|
-
cohort,
|
|
71
|
-
cb.rollout_cohort_count,
|
|
72
|
-
cb.target_cohorts
|
|
73
|
-
)
|
|
74
|
-
ORDER BY cb.id DESC
|
|
75
|
-
LIMIT 1
|
|
76
|
-
),
|
|
77
|
-
rollback_candidate AS (
|
|
78
|
-
SELECT
|
|
79
|
-
cb.id,
|
|
80
|
-
TRUE AS should_force_update,
|
|
81
|
-
cb.message,
|
|
82
|
-
'ROLLBACK' AS status,
|
|
83
|
-
cb.storage_uri,
|
|
84
|
-
cb.file_hash
|
|
85
|
-
FROM candidate_bundles cb
|
|
86
|
-
WHERE cb.id < bundle_id
|
|
87
|
-
AND NOT EXISTS (
|
|
88
|
-
SELECT 1
|
|
89
|
-
FROM current_candidate
|
|
90
|
-
WHERE current_candidate.is_eligible = TRUE
|
|
91
|
-
)
|
|
92
|
-
AND NOT EXISTS (SELECT 1 FROM eligible_update_candidate)
|
|
93
|
-
ORDER BY cb.id DESC
|
|
94
|
-
LIMIT 1
|
|
95
|
-
),
|
|
96
|
-
final_result AS (
|
|
97
|
-
SELECT * FROM eligible_update_candidate
|
|
98
|
-
UNION ALL
|
|
99
|
-
SELECT * FROM rollback_candidate
|
|
100
|
-
WHERE NOT EXISTS (SELECT 1 FROM eligible_update_candidate)
|
|
101
|
-
)
|
|
102
|
-
SELECT *
|
|
103
|
-
FROM final_result
|
|
104
|
-
WHERE final_result.id != bundle_id
|
|
105
|
-
|
|
106
|
-
UNION ALL
|
|
107
|
-
|
|
108
|
-
SELECT
|
|
109
|
-
NIL_UUID AS id,
|
|
110
|
-
TRUE AS should_force_update,
|
|
111
|
-
NULL AS message,
|
|
112
|
-
'ROLLBACK' AS status,
|
|
113
|
-
NULL AS storage_uri,
|
|
114
|
-
NULL AS file_hash
|
|
115
|
-
WHERE (SELECT COUNT(*) FROM final_result) = 0
|
|
116
|
-
AND bundle_id != NIL_UUID
|
|
117
|
-
AND bundle_id > min_bundle_id
|
|
118
|
-
AND NOT EXISTS (
|
|
119
|
-
SELECT 1
|
|
120
|
-
FROM current_candidate
|
|
121
|
-
WHERE current_candidate.is_eligible = TRUE
|
|
122
|
-
)
|
|
123
|
-
AND NOT EXISTS (SELECT 1 FROM eligible_update_candidate)
|
|
124
|
-
AND NOT EXISTS (SELECT 1 FROM rollback_candidate);
|
|
125
|
-
END;
|
|
126
|
-
$$;
|