@hot-updater/postgres 1.0.0-rc.1 → 1.0.0-rc.14

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 CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
20
20
  value: mod,
21
21
  enumerable: true
22
22
  }) : target, mod));
@@ -25,7 +25,7 @@ let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
25
25
  let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/internal");
26
26
  let kysely = require("kysely");
27
27
  let pg = require("pg");
28
- pg = __toESM(pg);
28
+ pg = __toESM(pg, 1);
29
29
  //#region src/postgresQuery.ts
30
30
  const applyOrder = (order, clause) => {
31
31
  const directed = clause.direction === "asc" ? order.asc() : order.desc();
@@ -51,6 +51,11 @@ const countPostgresRows = async (db, input, where) => {
51
51
  const query = rows.select(({ fn }) => fn.countAll().as("count"));
52
52
  return Number((await query.executeTakeFirstOrThrow()).count);
53
53
  }
54
+ case "bundle_events": {
55
+ let rows = db.selectFrom("bundle_events");
56
+ if (where !== void 0) rows = rows.where(where);
57
+ return Number((await rows.select(({ fn }) => fn.countAll().as("count")).executeTakeFirstOrThrow()).count);
58
+ }
54
59
  }
55
60
  };
56
61
  const findManyPostgresRows = async (db, input, where) => {
@@ -152,6 +157,28 @@ const buildWhere = (where) => {
152
157
  return expression;
153
158
  };
154
159
  const createPostgresImplementation = (db) => ({
160
+ async recordInsights({ event }) {
161
+ await db.transaction().execute(async (transaction) => {
162
+ await transaction.insertInto("bundle_events").values(event).onConflict((oc) => oc.column("id").doNothing()).execute();
163
+ await kysely.sql`INSERT INTO bundle_event_heads (install_id, id, received_at_ms, user_id, platform, channel, type, from_bundle_id, to_bundle_id)
164
+ SELECT install_id, id, received_at_ms, user_id, platform, channel, type, from_bundle_id, to_bundle_id
165
+ FROM bundle_events WHERE id = ${event.id}
166
+ ON CONFLICT(install_id) DO UPDATE SET
167
+ id = excluded.id, received_at_ms = excluded.received_at_ms, user_id = excluded.user_id,
168
+ platform = excluded.platform, channel = excluded.channel, type = excluded.type,
169
+ from_bundle_id = excluded.from_bundle_id, to_bundle_id = excluded.to_bundle_id
170
+ WHERE (excluded.received_at_ms, excluded.id) > (bundle_event_heads.received_at_ms, bundle_event_heads.id)`.execute(transaction);
171
+ });
172
+ },
173
+ async findLatestInsightsEvents(input) {
174
+ const where = buildWhere((0, _hot_updater_plugin_core_internal.latestInsightsWhere)(input));
175
+ return (await kysely.sql`SELECT event.* FROM (SELECT id, install_id FROM bundle_event_heads WHERE ${where} ORDER BY install_id ASC LIMIT ${"installId" in input ? 1 : input.limit}) AS head JOIN bundle_events AS event ON event.id = head.id ORDER BY head.install_id ASC`.execute(db)).rows;
176
+ },
177
+ async countLatestInsightsEvents(input) {
178
+ const where = kysely.sql`(${kysely.sql.join((0, _hot_updater_plugin_core_internal.latestInsightsCountGroups)(input).map((where) => kysely.sql`(${buildWhere(where)})`), kysely.sql` OR `)})`;
179
+ const result = await kysely.sql`SELECT COUNT(*) AS count FROM bundle_event_heads WHERE ${where}`.execute(db);
180
+ return Number(result.rows[0]?.count ?? 0);
181
+ },
155
182
  async create(input) {
156
183
  switch (input.model) {
157
184
  case "bundles": return db.insertInto("bundles").values(input.data).returningAll().executeTakeFirstOrThrow();
@@ -286,7 +313,11 @@ const createPostgresImplementation = (db) => ({
286
313
  });
287
314
  const postgres = (config) => {
288
315
  const { dialect, ...poolConfig } = config;
289
- const adapter = (0, _hot_updater_plugin_core_internal.createDatabasePluginAdapter)("postgres", dialect !== void 0 ? createPostgresImplementation(new kysely.Kysely({ dialect })) : createPostgresImplementation(new kysely.Kysely({ dialect: new kysely.PostgresDialect({ pool: new Pool(poolConfig) }) })));
316
+ const implementation = dialect !== void 0 ? createPostgresImplementation(new kysely.Kysely({ dialect })) : (() => {
317
+ const pool = new Pool(poolConfig);
318
+ return createPostgresImplementation(new kysely.Kysely({ dialect: new kysely.PostgresDialect({ pool }) }));
319
+ })();
320
+ const adapter = (0, _hot_updater_plugin_core_internal.createDatabasePluginAdapter)("postgres", implementation);
290
321
  return (0, _hot_updater_plugin_core.createDatabasePlugin)({
291
322
  name: "postgres",
292
323
  models: adapter.models,
package/dist/index.d.cts CHANGED
@@ -1,11 +1,9 @@
1
- import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
2
1
  import { Dialect } from "kysely";
3
2
  import { PoolConfig } from "pg";
4
-
5
3
  //#region src/postgres.d.ts
6
4
  type PostgresConfig = PoolConfig & {
7
5
  readonly dialect?: Dialect;
8
6
  };
9
- declare const postgres: (config: PostgresConfig) => _$_hot_updater_plugin_core0.DatabasePlugin;
7
+ declare const postgres: (config: PostgresConfig) => import("@hot-updater/plugin-core").DatabasePlugin;
10
8
  //#endregion
11
9
  export { PostgresConfig, postgres };
package/dist/index.d.mts CHANGED
@@ -1,11 +1,9 @@
1
- import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
2
1
  import { Dialect } from "kysely";
3
2
  import { PoolConfig } from "pg";
4
-
5
3
  //#region src/postgres.d.ts
6
4
  type PostgresConfig = PoolConfig & {
7
5
  readonly dialect?: Dialect;
8
6
  };
9
- declare const postgres: (config: PostgresConfig) => _$_hot_updater_plugin_core0.DatabasePlugin;
7
+ declare const postgres: (config: PostgresConfig) => import("@hot-updater/plugin-core").DatabasePlugin;
10
8
  //#endregion
11
9
  export { PostgresConfig, postgres };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createDatabasePlugin } from "@hot-updater/plugin-core";
2
- import { DatabaseRowReferencedError, createDatabasePluginAdapter } from "@hot-updater/plugin-core/internal";
2
+ import { DatabaseRowReferencedError, createDatabasePluginAdapter, latestInsightsCountGroups, latestInsightsWhere } from "@hot-updater/plugin-core/internal";
3
3
  import { Kysely, PostgresDialect, sql } from "kysely";
4
4
  import pg from "pg";
5
5
  //#region src/postgresQuery.ts
@@ -27,6 +27,11 @@ const countPostgresRows = async (db, input, where) => {
27
27
  const query = rows.select(({ fn }) => fn.countAll().as("count"));
28
28
  return Number((await query.executeTakeFirstOrThrow()).count);
29
29
  }
30
+ case "bundle_events": {
31
+ let rows = db.selectFrom("bundle_events");
32
+ if (where !== void 0) rows = rows.where(where);
33
+ return Number((await rows.select(({ fn }) => fn.countAll().as("count")).executeTakeFirstOrThrow()).count);
34
+ }
30
35
  }
31
36
  };
32
37
  const findManyPostgresRows = async (db, input, where) => {
@@ -128,6 +133,28 @@ const buildWhere = (where) => {
128
133
  return expression;
129
134
  };
130
135
  const createPostgresImplementation = (db) => ({
136
+ async recordInsights({ event }) {
137
+ await db.transaction().execute(async (transaction) => {
138
+ await transaction.insertInto("bundle_events").values(event).onConflict((oc) => oc.column("id").doNothing()).execute();
139
+ await sql`INSERT INTO bundle_event_heads (install_id, id, received_at_ms, user_id, platform, channel, type, from_bundle_id, to_bundle_id)
140
+ SELECT install_id, id, received_at_ms, user_id, platform, channel, type, from_bundle_id, to_bundle_id
141
+ FROM bundle_events WHERE id = ${event.id}
142
+ ON CONFLICT(install_id) DO UPDATE SET
143
+ id = excluded.id, received_at_ms = excluded.received_at_ms, user_id = excluded.user_id,
144
+ platform = excluded.platform, channel = excluded.channel, type = excluded.type,
145
+ from_bundle_id = excluded.from_bundle_id, to_bundle_id = excluded.to_bundle_id
146
+ WHERE (excluded.received_at_ms, excluded.id) > (bundle_event_heads.received_at_ms, bundle_event_heads.id)`.execute(transaction);
147
+ });
148
+ },
149
+ async findLatestInsightsEvents(input) {
150
+ const where = buildWhere(latestInsightsWhere(input));
151
+ return (await sql`SELECT event.* FROM (SELECT id, install_id FROM bundle_event_heads WHERE ${where} ORDER BY install_id ASC LIMIT ${"installId" in input ? 1 : input.limit}) AS head JOIN bundle_events AS event ON event.id = head.id ORDER BY head.install_id ASC`.execute(db)).rows;
152
+ },
153
+ async countLatestInsightsEvents(input) {
154
+ const where = sql`(${sql.join(latestInsightsCountGroups(input).map((where) => sql`(${buildWhere(where)})`), sql` OR `)})`;
155
+ const result = await sql`SELECT COUNT(*) AS count FROM bundle_event_heads WHERE ${where}`.execute(db);
156
+ return Number(result.rows[0]?.count ?? 0);
157
+ },
131
158
  async create(input) {
132
159
  switch (input.model) {
133
160
  case "bundles": return db.insertInto("bundles").values(input.data).returningAll().executeTakeFirstOrThrow();
@@ -262,7 +289,11 @@ const createPostgresImplementation = (db) => ({
262
289
  });
263
290
  const postgres = (config) => {
264
291
  const { dialect, ...poolConfig } = config;
265
- const adapter = createDatabasePluginAdapter("postgres", dialect !== void 0 ? createPostgresImplementation(new Kysely({ dialect })) : createPostgresImplementation(new Kysely({ dialect: new PostgresDialect({ pool: new Pool(poolConfig) }) })));
292
+ const implementation = dialect !== void 0 ? createPostgresImplementation(new Kysely({ dialect })) : (() => {
293
+ const pool = new Pool(poolConfig);
294
+ return createPostgresImplementation(new Kysely({ dialect: new PostgresDialect({ pool }) }));
295
+ })();
296
+ const adapter = createDatabasePluginAdapter("postgres", implementation);
266
297
  return createDatabasePlugin({
267
298
  name: "postgres",
268
299
  models: adapter.models,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/postgres",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.1",
4
+ "version": "1.0.0-rc.14",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.mjs",
@@ -34,8 +34,8 @@
34
34
  "dependencies": {
35
35
  "kysely": "0.28.17",
36
36
  "pg": "8.13.1",
37
- "@hot-updater/core": "1.0.0-rc.0",
38
- "@hot-updater/plugin-core": "1.0.0-rc.1"
37
+ "@hot-updater/core": "1.0.0-rc.14",
38
+ "@hot-updater/plugin-core": "1.0.0-rc.14"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@electric-sql/pglite": "0.4.1",
@@ -44,7 +44,7 @@
44
44
  "camelcase-keys": "^9.1.3",
45
45
  "kysely-pglite-dialect": "1.2.0",
46
46
  "pg-minify": "^1.6.5",
47
- "@hot-updater/test-utils": "1.0.0-rc.1"
47
+ "@hot-updater/test-utils": "1.0.0-rc.14"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsdown",
package/sql/bundles.sql CHANGED
@@ -70,23 +70,32 @@ create table release_catalogs (
70
70
  create table bundle_events (
71
71
  id uuid primary key not null,
72
72
  type text not null,
73
- install_id text not null,
74
- user_id text,
75
- username text,
73
+ install_id text collate "C" not null,
74
+ user_id text collate "C",
76
75
  from_release_id uuid,
77
76
  from_bundle_id uuid,
78
77
  to_release_id uuid,
79
78
  to_bundle_id uuid not null,
80
- platform text not null,
79
+ platform text collate "C" not null,
81
80
  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,
81
+ channel text collate "C" not null,
82
+ metadata JSONB NOT NULL,
87
83
  received_at_ms double precision not null
88
84
  );
89
85
 
86
+
87
+ create table bundle_event_heads (
88
+ install_id text collate "C" primary key not null,
89
+ id uuid not null,
90
+ received_at_ms double precision not null,
91
+ user_id text collate "C",
92
+ platform text collate "C" not null,
93
+ channel text collate "C" not null,
94
+ type text not null,
95
+ from_bundle_id uuid,
96
+ to_bundle_id uuid not null
97
+ );
98
+
90
99
  create table api_keys (
91
100
  id varchar(255) primary key not null,
92
101
  hash text not null,
@@ -112,13 +121,9 @@ create index releases_fingerprint_hash_idx on releases(fingerprint_hash);
112
121
  create index releases_enabled_idx on releases(enabled);
113
122
  create index release_catalogs_channel_idx on release_catalogs(channel_id);
114
123
  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);
124
+ create index bundle_events_install_idx on bundle_events(install_id, type, received_at_ms, id);
125
+ create index bundle_events_from_bundle_idx on bundle_events(type, platform, channel, from_bundle_id, received_at_ms, id);
126
+ create index bundle_events_to_bundle_idx on bundle_events(type, platform, channel, to_bundle_id, received_at_ms, id);
122
127
  create unique index api_keys_hash_key on api_keys(hash);
123
128
  create index api_keys_created_at_idx on api_keys(created_at_ms, id);
124
129
 
@@ -147,11 +152,11 @@ alter table release_catalogs add constraint release_catalogs_generation_check
147
152
  alter table release_catalogs add constraint release_catalogs_byte_size_check
148
153
  check (byte_size >= 0 and byte_size <= 262144);
149
154
  alter table bundle_events add constraint bundle_events_type_check
150
- check (type in ('UPDATE_APPLIED', 'RECOVERED', 'RELEASE_ADOPTED', 'UNCHANGED'));
155
+ check (type in ('UPDATE_DOWNLOADED', 'UPDATE_APPLIED', 'RECOVERED', 'UNCHANGED'));
151
156
  alter table bundle_events add constraint bundle_events_platform_check
152
157
  check (platform in ('ios', 'android'));
153
158
  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));
159
+ check (((type in ('UPDATE_DOWNLOADED', 'UPDATE_APPLIED', 'RECOVERED')) and from_bundle_id is not null) or (type = 'UNCHANGED' and from_bundle_id is null));
155
160
  alter table bundle_events add constraint bundle_events_received_at_check
156
161
  check (received_at_ms >= 0);
157
162
  alter table api_keys add constraint api_keys_role_check
@@ -177,3 +182,10 @@ alter table release_catalogs add constraint release_catalogs_channel_id_fk
177
182
  insert into private_hot_updater_settings (key, value)
178
183
  values ('schema.core', '1.0.0')
179
184
  on conflict (key) do update set value = excluded.value;
185
+
186
+
187
+ CREATE INDEX bundle_events_latest_idx ON bundle_events(install_id, received_at_ms, id);
188
+ CREATE INDEX bundle_event_heads_user_idx ON bundle_event_heads(user_id, install_id);
189
+ CREATE INDEX bundle_event_heads_scope_idx ON bundle_event_heads(platform, channel, received_at_ms);
190
+ CREATE INDEX bundle_event_heads_from_idx ON bundle_event_heads(type, platform, channel, from_bundle_id, received_at_ms);
191
+ CREATE INDEX bundle_event_heads_to_idx ON bundle_event_heads(type, platform, channel, to_bundle_id, received_at_ms);