@hot-updater/server 1.0.0-rc.0 → 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/_virtual/_rolldown/runtime.cjs +1 -1
- package/dist/adapters/databaseConstraintErrors.cjs +0 -1
- package/dist/adapters/databasePluginUtils.cjs +14 -1
- package/dist/adapters/databasePluginUtils.mjs +14 -2
- package/dist/adapters/drizzle.cjs +9 -4
- package/dist/adapters/drizzle.d.cts +0 -1
- package/dist/adapters/drizzle.d.mts +0 -1
- package/dist/adapters/drizzle.mjs +10 -4
- package/dist/adapters/drizzleCrud.cjs +93 -3
- package/dist/adapters/drizzleCrud.mjs +93 -5
- package/dist/adapters/drizzleLazyDB.cjs +2 -0
- package/dist/adapters/drizzleLazyDB.mjs +2 -0
- package/dist/adapters/drizzleQuery.cjs +3 -2
- package/dist/adapters/drizzleQuery.mjs +3 -1
- package/dist/adapters/kysely.cjs +1 -1
- package/dist/adapters/kysely.d.cts +0 -1
- package/dist/adapters/kysely.d.mts +0 -1
- package/dist/adapters/kysely.mjs +2 -1
- package/dist/adapters/kyselyCrud.cjs +44 -5
- package/dist/adapters/kyselyCrud.mjs +45 -6
- package/dist/adapters/kyselyQuery.cjs +2 -2
- package/dist/adapters/kyselyQuery.mjs +2 -1
- package/dist/adapters/mongodb.cjs +36 -1
- package/dist/adapters/mongodb.d.cts +1 -1
- package/dist/adapters/mongodb.d.mts +1 -1
- package/dist/adapters/mongodb.mjs +36 -0
- package/dist/adapters/mongodbCollections.cjs +2 -0
- package/dist/adapters/mongodbCollections.mjs +2 -0
- package/dist/adapters/mongodbQuery.cjs +17 -4
- package/dist/adapters/mongodbQuery.mjs +17 -4
- package/dist/adapters/mongodbReads.cjs +88 -30
- package/dist/adapters/mongodbReads.mjs +88 -29
- package/dist/adapters/mongodbWrites.cjs +1 -2
- package/dist/adapters/mongodbWrites.mjs +1 -1
- package/dist/adapters/prisma.cjs +44 -7
- package/dist/adapters/prisma.d.cts +0 -1
- package/dist/adapters/prisma.d.mts +0 -1
- package/dist/adapters/prisma.mjs +44 -6
- package/dist/adapters/prismaInsights.cjs +99 -0
- package/dist/adapters/prismaInsights.mjs +97 -0
- package/dist/adapters/prismaQuery.cjs +0 -1
- package/dist/adapters/prismaRows.cjs +7 -8
- package/dist/adapters/prismaRows.mjs +8 -8
- package/dist/apiKeys.cjs +6 -2
- package/dist/apiKeys.d.cts +0 -1
- package/dist/apiKeys.d.mts +0 -1
- package/dist/apiKeys.mjs +3 -3
- package/dist/createHotUpdaterCore.cjs +27 -12
- package/dist/createHotUpdaterCore.d.cts +8 -8
- package/dist/createHotUpdaterCore.d.mts +8 -8
- package/dist/createHotUpdaterCore.mjs +26 -12
- package/dist/db/createBundleDiff.cjs +2 -2
- package/dist/db/createBundleDiff.d.cts +1 -5
- package/dist/db/createBundleDiff.d.mts +1 -5
- package/dist/db/databasePluginCore.cjs +0 -1
- package/dist/db/fixedMigrator.cjs +2 -2
- package/dist/db/fixedMigrator.mjs +2 -2
- package/dist/db/fixedMigratorMongo.cjs +6 -4
- package/dist/db/fixedMigratorMongo.mjs +6 -4
- package/dist/db/index.d.cts +0 -1
- package/dist/db/index.d.mts +0 -1
- package/dist/db/releaseCatalog.cjs +0 -1
- package/dist/db/releaseCatalog.d.cts +0 -1
- package/dist/db/releaseCatalog.d.mts +0 -1
- package/dist/db/schema/insightsCollation.cjs +14 -0
- package/dist/db/schema/insightsCollation.mjs +14 -0
- package/dist/db/schema/sql.cjs +11 -7
- package/dist/db/schema/sql.mjs +8 -8
- package/dist/db/schemaGenerators.cjs +29 -9
- package/dist/db/schemaGenerators.mjs +29 -9
- package/dist/db/schemaReadiness.cjs +2 -0
- package/dist/db/schemaReadiness.d.cts +1 -0
- package/dist/db/schemaReadiness.d.mts +1 -0
- package/dist/db/schemaReadiness.mjs +2 -0
- package/dist/db/sqlMigrationExecution.cjs +1 -1
- package/dist/db/sqlMigrationExecution.mjs +1 -0
- package/dist/db/types.cjs +3 -1
- package/dist/db/types.d.cts +3 -6
- package/dist/db/types.d.mts +3 -6
- package/dist/db/types.mjs +2 -2
- package/dist/db/updateArtifacts.cjs +0 -1
- package/dist/handler.cjs +5 -5
- package/dist/handler.d.cts +1 -2
- package/dist/handler.d.mts +1 -2
- package/dist/handler.mjs +5 -5
- package/dist/handlerReleaseCatalogRoutes.cjs +0 -1
- package/dist/handlerReleaseManagementRoutes.cjs +0 -1
- package/dist/handlerTypes.d.cts +0 -1
- package/dist/handlerTypes.d.mts +0 -1
- package/dist/handlerVersionRoutes.d.cts +1 -0
- package/dist/handlerVersionRoutes.d.mts +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/insights/domain.d.cts +92 -0
- package/dist/insights/domain.d.mts +92 -0
- package/dist/insights/errors.cjs +15 -0
- package/dist/insights/errors.mjs +14 -0
- package/dist/{analytics → insights}/eventInput.cjs +61 -16
- package/dist/{analytics → insights}/eventInput.mjs +61 -18
- package/dist/insights/provider.cjs +332 -0
- package/dist/insights/provider.d.cts +6 -0
- package/dist/insights/provider.d.mts +6 -0
- package/dist/insights/provider.mjs +332 -0
- package/dist/insights/queryInput.cjs +93 -0
- package/dist/insights/queryInput.mjs +91 -0
- package/dist/insights/routes.cjs +58 -0
- package/dist/insights/routes.mjs +56 -0
- package/dist/insights/types.d.cts +32 -0
- package/dist/insights/types.d.mts +32 -0
- package/dist/node.d.cts +0 -1
- package/dist/node.d.mts +0 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/schema/index.cjs +17 -3
- package/dist/schema/index.mjs +4 -4
- package/dist/schema/v1_0_0.cjs +64 -35
- package/dist/schema/v1_0_0.mjs +64 -36
- package/dist/storageAccess.cjs +0 -1
- package/dist/types/index.d.cts +0 -1
- package/dist/types/index.d.mts +0 -1
- package/package.json +7 -7
- package/src/adapters/databasePluginTestDatabase.ts +15 -5
- package/src/adapters/databasePluginUtils.ts +24 -0
- package/src/adapters/drizzle.spec.ts +203 -5
- package/src/adapters/drizzle.ts +16 -4
- package/src/adapters/drizzleCrud.ts +200 -9
- package/src/adapters/drizzleLazyDB.ts +33 -6
- package/src/adapters/kysely.spec.ts +62 -0
- package/src/adapters/kysely.ts +7 -1
- package/src/adapters/kyselyCrud.ts +115 -7
- package/src/adapters/kyselyInsights.spec.ts +168 -0
- package/src/adapters/mongodb.integration.spec.ts +483 -0
- package/src/adapters/mongodb.spec.ts +89 -0
- package/src/adapters/mongodb.ts +59 -1
- package/src/adapters/mongodbCollections.ts +16 -0
- package/src/adapters/mongodbQuery.ts +22 -3
- package/src/adapters/mongodbReads.ts +78 -2
- package/src/adapters/mongodbTestClient.ts +107 -6
- package/src/adapters/mongodbTestFilter.ts +5 -1
- package/src/adapters/mongodbWrites.ts +1 -0
- package/src/adapters/prisma.spec.ts +270 -0
- package/src/adapters/prisma.ts +75 -2
- package/src/adapters/prismaInsights.ts +190 -0
- package/src/adapters/prismaRows.ts +17 -10
- package/src/adapters/prismaTestClient.ts +89 -7
- package/src/apiKeys.integration.spec.ts +3 -3
- package/src/createHotUpdaterCore.ts +30 -16
- package/src/db/databasePluginUpdateCheck.bench.ts +10 -0
- package/src/db/fixedMigrator.spec.ts +63 -0
- package/src/db/fixedMigratorMongo.spec.ts +70 -9
- package/src/db/fixedMigratorMongo.ts +10 -10
- package/src/db/index.spec.ts +6 -1
- package/src/db/schema/insightsCollation.ts +21 -0
- package/src/db/schema/sql.ts +8 -5
- package/src/db/schemaGenerators.ts +42 -13
- package/src/db/types.spec.ts +11 -3
- package/src/db/types.ts +13 -7
- package/src/handler-standalone.integration.spec.ts +6 -8
- package/src/handler.ts +12 -12
- package/src/index.ts +3 -3
- package/src/insights/domain.ts +106 -0
- package/src/insights/errors.ts +11 -0
- package/src/{analytics → insights}/eventInput.ts +66 -16
- package/src/insights/insights.integration.spec.ts +475 -0
- package/src/insights/provider.spec.ts +396 -0
- package/src/insights/provider.ts +611 -0
- package/src/insights/queryInput.ts +142 -0
- package/src/insights/routes.ts +104 -0
- package/src/insights/types.ts +55 -0
- package/src/schema/dsl-all-versions.spec.ts +1 -1
- package/src/schema/v1_0_0.spec.ts +77 -3
- package/src/schema/v1_0_0.ts +83 -37
- package/dist/analytics/bounded/activeOverview.cjs +0 -87
- package/dist/analytics/bounded/activeOverview.mjs +0 -85
- package/dist/analytics/bounded/installationSearch.cjs +0 -42
- package/dist/analytics/bounded/installationSearch.mjs +0 -42
- package/dist/analytics/bounded/persistence.cjs +0 -39
- package/dist/analytics/bounded/persistence.mjs +0 -38
- package/dist/analytics/bounded/provider.cjs +0 -170
- package/dist/analytics/bounded/provider.d.cts +0 -7
- package/dist/analytics/bounded/provider.d.mts +0 -7
- package/dist/analytics/bounded/provider.mjs +0 -170
- package/dist/analytics/bounded/scan.cjs +0 -144
- package/dist/analytics/bounded/scan.mjs +0 -138
- package/dist/analytics/domain.d.cts +0 -121
- package/dist/analytics/domain.d.mts +0 -121
- package/dist/analytics/errors.cjs +0 -22
- package/dist/analytics/errors.mjs +0 -20
- package/dist/analytics/persistence.d.cts +0 -6
- package/dist/analytics/persistence.d.mts +0 -6
- package/dist/analytics/queryInput.cjs +0 -58
- package/dist/analytics/queryInput.mjs +0 -55
- package/dist/analytics/routes.cjs +0 -63
- package/dist/analytics/routes.mjs +0 -61
- package/dist/analytics/types.d.cts +0 -17
- package/dist/analytics/types.d.mts +0 -17
- package/src/analytics/analytics.integration.spec.ts +0 -144
- package/src/analytics/bounded/activeOverview.spec.ts +0 -189
- package/src/analytics/bounded/activeOverview.ts +0 -148
- package/src/analytics/bounded/installationSearch.spec.ts +0 -130
- package/src/analytics/bounded/installationSearch.ts +0 -69
- package/src/analytics/bounded/persistence.ts +0 -43
- package/src/analytics/bounded/provider.spec.ts +0 -219
- package/src/analytics/bounded/provider.ts +0 -229
- package/src/analytics/bounded/scan.ts +0 -235
- package/src/analytics/domain.ts +0 -139
- package/src/analytics/errors.ts +0 -18
- package/src/analytics/persistence.ts +0 -10
- package/src/analytics/queryInput.ts +0 -102
- package/src/analytics/routes.ts +0 -123
- package/src/analytics/types.ts +0 -44
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
1
|
const require_databaseConstraintErrors = require("./databaseConstraintErrors.cjs");
|
|
3
2
|
const require_databasePluginUtils = require("./databasePluginUtils.cjs");
|
|
4
3
|
const require_kyselyQuery = require("./kyselyQuery.cjs");
|
|
5
4
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
5
|
+
let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/internal");
|
|
6
6
|
let kysely = require("kysely");
|
|
7
7
|
//#region src/adapters/kyselyCrud.ts
|
|
8
8
|
var KyselyAdapterInvariantError = class extends Error {
|
|
9
|
+
reason;
|
|
9
10
|
name = "KyselyAdapterInvariantError";
|
|
10
11
|
constructor(reason) {
|
|
11
12
|
super(`Kysely plugin invariant failed: ${reason}`);
|
|
@@ -20,7 +21,10 @@ const orderClause = (input) => {
|
|
|
20
21
|
if (clauses === void 0 || clauses.length === 0) return empty;
|
|
21
22
|
return kysely.sql` order by ${kysely.sql.join(clauses.map((clause) => {
|
|
22
23
|
const field = kysely.sql.ref(clause.field);
|
|
23
|
-
|
|
24
|
+
if (input?.model === "bundle_events") return clause.direction === "asc" ? kysely.sql`${field} asc` : kysely.sql`${field} desc`;
|
|
25
|
+
const nullOrder = (clause.nulls ?? (clause.direction === "asc" ? "last" : "first")) === "first" ? kysely.sql`${field} is null desc` : kysely.sql`${field} is null asc`;
|
|
26
|
+
const valueOrder = clause.direction === "asc" ? kysely.sql`${field} asc` : kysely.sql`${field} desc`;
|
|
27
|
+
return kysely.sql`${nullOrder}, ${valueOrder}`;
|
|
24
28
|
}), kysely.sql`, `)}`;
|
|
25
29
|
};
|
|
26
30
|
const insertRow = async (executor, table, row, provider, onConflict = void 0) => {
|
|
@@ -30,6 +34,30 @@ const insertRow = async (executor, table, row, provider, onConflict = void 0) =>
|
|
|
30
34
|
const result = onConflict === void 0 ? await kysely.sql`insert into ${kysely.sql.table(table)} (${columns}) values (${values})`.execute(executor) : provider === "mysql" ? await kysely.sql`insert ignore into ${kysely.sql.table(table)} (${columns}) values (${values})`.execute(executor) : provider === "sqlite" ? await kysely.sql`insert or ignore into ${kysely.sql.table(table)} (${columns}) values (${values})`.execute(executor) : await kysely.sql`insert into ${kysely.sql.table(table)} (${columns}) values (${values}) on conflict do nothing`.execute(executor);
|
|
31
35
|
return Number(result.numAffectedRows ?? 0) > 0;
|
|
32
36
|
};
|
|
37
|
+
const recordKyselyInsights = async (executor, provider, { event }) => {
|
|
38
|
+
const entries = Object.entries(require_databasePluginUtils.toStoredBundleEventRow(event, provider));
|
|
39
|
+
const insert = kysely.sql`insert into bundle_events (${kysely.sql.join(entries.map(([field]) => kysely.sql.ref(field)))}) values (${kysely.sql.join(entries.map(([, value]) => value))})`;
|
|
40
|
+
await (provider === "mysql" ? kysely.sql`${insert} on duplicate key update id = id` : kysely.sql`${insert} on conflict (id) do nothing`).execute(executor);
|
|
41
|
+
const fields = [
|
|
42
|
+
"install_id",
|
|
43
|
+
"user_id",
|
|
44
|
+
"platform",
|
|
45
|
+
"channel",
|
|
46
|
+
"type",
|
|
47
|
+
"from_bundle_id",
|
|
48
|
+
"to_bundle_id",
|
|
49
|
+
"id",
|
|
50
|
+
"received_at_ms"
|
|
51
|
+
];
|
|
52
|
+
const columns = kysely.sql.join(fields.map((field) => kysely.sql.ref(field)));
|
|
53
|
+
const headInsert = kysely.sql`insert into bundle_event_heads (${columns}) select ${columns} from bundle_events where id = ${event.id}`;
|
|
54
|
+
const newer = provider === "mysql" ? kysely.sql`(values(received_at_ms) > bundle_event_heads.received_at_ms or (values(received_at_ms) = bundle_event_heads.received_at_ms and values(id) > bundle_event_heads.id))` : kysely.sql`(excluded.received_at_ms > bundle_event_heads.received_at_ms or (excluded.received_at_ms = bundle_event_heads.received_at_ms and excluded.id > bundle_event_heads.id))`;
|
|
55
|
+
const assignments = kysely.sql.join(fields.filter((field) => field !== "install_id").map((field) => {
|
|
56
|
+
const column = kysely.sql.ref(field);
|
|
57
|
+
return provider === "mysql" ? kysely.sql`${column} = if(${newer}, values(${column}), ${kysely.sql.ref(`bundle_event_heads.${field}`)})` : kysely.sql`${column} = ${kysely.sql.ref(`excluded.${field}`)}`;
|
|
58
|
+
}));
|
|
59
|
+
await (provider === "mysql" ? kysely.sql`${headInsert} on duplicate key update ${assignments}` : kysely.sql`${headInsert} on conflict (install_id) do update set ${assignments} where ${newer}`).execute(executor);
|
|
60
|
+
};
|
|
33
61
|
const updateBundle = async (executor, id, update) => {
|
|
34
62
|
const assignments = Object.entries(update).filter(([, value]) => value !== void 0).map(([field, value]) => kysely.sql`${kysely.sql.ref(field)} = ${value}`);
|
|
35
63
|
if (assignments.length === 0) return;
|
|
@@ -44,7 +72,7 @@ const updateRow = async (executor, table, keyField, key, update) => {
|
|
|
44
72
|
await kysely.sql`update ${kysely.sql.table(table)} set ${kysely.sql.join(assignments)} where ${kysely.sql.ref(keyField)} = ${key}`.execute(executor);
|
|
45
73
|
};
|
|
46
74
|
const assertBundleReferences = async (executor, provider, relationMode, bundleId, baseBundleId) => {
|
|
47
|
-
const ids = [
|
|
75
|
+
const ids = [.../* @__PURE__ */ new Set([bundleId, baseBundleId])].sort((left, right) => left.localeCompare(right));
|
|
48
76
|
const result = await kysely.sql`select ${kysely.sql.ref("id")} from ${kysely.sql.table("bundles")} where ${kysely.sql.ref("id")} in (${kysely.sql.join(ids)}) order by ${kysely.sql.ref("id")}${lockClause(provider, relationMode)}`.execute(executor);
|
|
49
77
|
const storedIds = new Set(result.rows.map(({ id }) => id));
|
|
50
78
|
if (!storedIds.has(bundleId)) throw new KyselyAdapterInvariantError("bundle_patches.bundle_id.foreign-key");
|
|
@@ -55,6 +83,15 @@ const countRows = async (executor, table, where) => {
|
|
|
55
83
|
return Number(result.rows[0]?.total ?? 0);
|
|
56
84
|
};
|
|
57
85
|
const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") => ({
|
|
86
|
+
async findLatestInsightsEvents(input) {
|
|
87
|
+
const where = require_kyselyQuery.buildKyselyWhere(provider, (0, _hot_updater_plugin_core_internal.latestInsightsWhere)(input));
|
|
88
|
+
return (await kysely.sql`SELECT canonical.* 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 canonical ON canonical.id = head.id ORDER BY head.install_id ASC`.execute(executor)).rows.map(require_databasePluginUtils.fromStoredBundleEventRow);
|
|
89
|
+
},
|
|
90
|
+
async countLatestInsightsEvents(input) {
|
|
91
|
+
const groups = (0, _hot_updater_plugin_core_internal.latestInsightsCountGroups)(input).map((where) => kysely.sql`(${require_kyselyQuery.buildKyselyWhere(provider, where)})`);
|
|
92
|
+
const result = await (provider === "mysql" && groups.length === 2 ? kysely.sql`SELECT (SELECT COUNT(*) FROM bundle_event_heads WHERE ${groups[0]}) + (SELECT COUNT(*) FROM bundle_event_heads WHERE ${groups[1]} AND ${groups[0]} IS NOT TRUE) AS count` : kysely.sql`SELECT COUNT(*) AS count FROM bundle_event_heads WHERE (${kysely.sql.join(groups, kysely.sql` OR `)})`).execute(executor);
|
|
93
|
+
return Number(result.rows[0]?.count ?? 0);
|
|
94
|
+
},
|
|
58
95
|
async deleteChannel({ id }) {
|
|
59
96
|
if ((await kysely.sql`select ${kysely.sql.ref("id")}, ${kysely.sql.ref("name")} from ${kysely.sql.table("channels")} where ${kysely.sql.ref("id")} = ${id} limit 1${lockClause(provider, relationMode)}`.execute(executor)).rows[0] === void 0) return {
|
|
60
97
|
deleted: false,
|
|
@@ -94,7 +131,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
94
131
|
await insertRow(executor, "bundle_patches", input.data, provider);
|
|
95
132
|
return input.data;
|
|
96
133
|
case "bundle_events":
|
|
97
|
-
await insertRow(executor, "bundle_events", input.data, provider);
|
|
134
|
+
await insertRow(executor, "bundle_events", require_databasePluginUtils.toStoredBundleEventRow(input.data, provider), provider);
|
|
98
135
|
return input.data;
|
|
99
136
|
case "releases":
|
|
100
137
|
await insertRow(executor, "releases", require_databasePluginUtils.toStoredReleaseRow(input.data, provider), provider);
|
|
@@ -172,6 +209,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
172
209
|
async count(input) {
|
|
173
210
|
if (input.distinct !== void 0) throw new _hot_updater_plugin_core.DatabasePluginInputError("invalid-operation");
|
|
174
211
|
switch (input.model) {
|
|
212
|
+
case "bundle_events": return countRows(executor, "bundle_events", require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
175
213
|
case "bundles": return countRows(executor, "bundles", require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
176
214
|
case "bundle_patches": return countRows(executor, "bundle_patches", require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
177
215
|
case "releases": return countRows(executor, "releases", require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
@@ -225,7 +263,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
225
263
|
case "bundle_events": {
|
|
226
264
|
const where = whereClause(require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
227
265
|
const order = orderClause(input);
|
|
228
|
-
return
|
|
266
|
+
return (await kysely.sql`select * from ${kysely.sql.table("bundle_events")}${where}${order}${pagination}`.execute(executor)).rows.map(require_databasePluginUtils.fromStoredBundleEventRow);
|
|
229
267
|
}
|
|
230
268
|
case "api_keys": {
|
|
231
269
|
const where = whereClause(require_kyselyQuery.buildKyselyWhere(provider, input.where));
|
|
@@ -252,3 +290,4 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
252
290
|
});
|
|
253
291
|
//#endregion
|
|
254
292
|
exports.createKyselyCrud = createKyselyCrud;
|
|
293
|
+
exports.recordKyselyInsights = recordKyselyInsights;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { isChannelDeleteReferencedError, translateChannelDeleteError } from "./databaseConstraintErrors.mjs";
|
|
2
|
-
import { fromStoredBundleRow, fromStoredReleaseCatalogRow, fromStoredReleaseRow, toStoredBundleRow, toStoredBundleUpdate, toStoredReleaseRow, toStoredReleaseUpdate } from "./databasePluginUtils.mjs";
|
|
2
|
+
import { fromStoredBundleEventRow, fromStoredBundleRow, fromStoredReleaseCatalogRow, fromStoredReleaseRow, toStoredBundleEventRow, toStoredBundleRow, toStoredBundleUpdate, toStoredReleaseRow, toStoredReleaseUpdate } from "./databasePluginUtils.mjs";
|
|
3
3
|
import { buildKyselyWhere } from "./kyselyQuery.mjs";
|
|
4
4
|
import { DatabasePluginInputError } from "@hot-updater/plugin-core";
|
|
5
|
+
import { latestInsightsCountGroups, latestInsightsWhere } from "@hot-updater/plugin-core/internal";
|
|
5
6
|
import { sql } from "kysely";
|
|
6
7
|
//#region src/adapters/kyselyCrud.ts
|
|
7
8
|
var KyselyAdapterInvariantError = class extends Error {
|
|
9
|
+
reason;
|
|
8
10
|
name = "KyselyAdapterInvariantError";
|
|
9
11
|
constructor(reason) {
|
|
10
12
|
super(`Kysely plugin invariant failed: ${reason}`);
|
|
@@ -19,7 +21,10 @@ const orderClause = (input) => {
|
|
|
19
21
|
if (clauses === void 0 || clauses.length === 0) return empty;
|
|
20
22
|
return sql` order by ${sql.join(clauses.map((clause) => {
|
|
21
23
|
const field = sql.ref(clause.field);
|
|
22
|
-
|
|
24
|
+
if (input?.model === "bundle_events") return clause.direction === "asc" ? sql`${field} asc` : sql`${field} desc`;
|
|
25
|
+
const nullOrder = (clause.nulls ?? (clause.direction === "asc" ? "last" : "first")) === "first" ? sql`${field} is null desc` : sql`${field} is null asc`;
|
|
26
|
+
const valueOrder = clause.direction === "asc" ? sql`${field} asc` : sql`${field} desc`;
|
|
27
|
+
return sql`${nullOrder}, ${valueOrder}`;
|
|
23
28
|
}), sql`, `)}`;
|
|
24
29
|
};
|
|
25
30
|
const insertRow = async (executor, table, row, provider, onConflict = void 0) => {
|
|
@@ -29,6 +34,30 @@ const insertRow = async (executor, table, row, provider, onConflict = void 0) =>
|
|
|
29
34
|
const result = onConflict === void 0 ? await sql`insert into ${sql.table(table)} (${columns}) values (${values})`.execute(executor) : provider === "mysql" ? await sql`insert ignore into ${sql.table(table)} (${columns}) values (${values})`.execute(executor) : provider === "sqlite" ? await sql`insert or ignore into ${sql.table(table)} (${columns}) values (${values})`.execute(executor) : await sql`insert into ${sql.table(table)} (${columns}) values (${values}) on conflict do nothing`.execute(executor);
|
|
30
35
|
return Number(result.numAffectedRows ?? 0) > 0;
|
|
31
36
|
};
|
|
37
|
+
const recordKyselyInsights = async (executor, provider, { event }) => {
|
|
38
|
+
const entries = Object.entries(toStoredBundleEventRow(event, provider));
|
|
39
|
+
const insert = sql`insert into bundle_events (${sql.join(entries.map(([field]) => sql.ref(field)))}) values (${sql.join(entries.map(([, value]) => value))})`;
|
|
40
|
+
await (provider === "mysql" ? sql`${insert} on duplicate key update id = id` : sql`${insert} on conflict (id) do nothing`).execute(executor);
|
|
41
|
+
const fields = [
|
|
42
|
+
"install_id",
|
|
43
|
+
"user_id",
|
|
44
|
+
"platform",
|
|
45
|
+
"channel",
|
|
46
|
+
"type",
|
|
47
|
+
"from_bundle_id",
|
|
48
|
+
"to_bundle_id",
|
|
49
|
+
"id",
|
|
50
|
+
"received_at_ms"
|
|
51
|
+
];
|
|
52
|
+
const columns = sql.join(fields.map((field) => sql.ref(field)));
|
|
53
|
+
const headInsert = sql`insert into bundle_event_heads (${columns}) select ${columns} from bundle_events where id = ${event.id}`;
|
|
54
|
+
const newer = provider === "mysql" ? sql`(values(received_at_ms) > bundle_event_heads.received_at_ms or (values(received_at_ms) = bundle_event_heads.received_at_ms and values(id) > bundle_event_heads.id))` : sql`(excluded.received_at_ms > bundle_event_heads.received_at_ms or (excluded.received_at_ms = bundle_event_heads.received_at_ms and excluded.id > bundle_event_heads.id))`;
|
|
55
|
+
const assignments = sql.join(fields.filter((field) => field !== "install_id").map((field) => {
|
|
56
|
+
const column = sql.ref(field);
|
|
57
|
+
return provider === "mysql" ? sql`${column} = if(${newer}, values(${column}), ${sql.ref(`bundle_event_heads.${field}`)})` : sql`${column} = ${sql.ref(`excluded.${field}`)}`;
|
|
58
|
+
}));
|
|
59
|
+
await (provider === "mysql" ? sql`${headInsert} on duplicate key update ${assignments}` : sql`${headInsert} on conflict (install_id) do update set ${assignments} where ${newer}`).execute(executor);
|
|
60
|
+
};
|
|
32
61
|
const updateBundle = async (executor, id, update) => {
|
|
33
62
|
const assignments = Object.entries(update).filter(([, value]) => value !== void 0).map(([field, value]) => sql`${sql.ref(field)} = ${value}`);
|
|
34
63
|
if (assignments.length === 0) return;
|
|
@@ -43,7 +72,7 @@ const updateRow = async (executor, table, keyField, key, update) => {
|
|
|
43
72
|
await sql`update ${sql.table(table)} set ${sql.join(assignments)} where ${sql.ref(keyField)} = ${key}`.execute(executor);
|
|
44
73
|
};
|
|
45
74
|
const assertBundleReferences = async (executor, provider, relationMode, bundleId, baseBundleId) => {
|
|
46
|
-
const ids = [
|
|
75
|
+
const ids = [.../* @__PURE__ */ new Set([bundleId, baseBundleId])].sort((left, right) => left.localeCompare(right));
|
|
47
76
|
const result = await sql`select ${sql.ref("id")} from ${sql.table("bundles")} where ${sql.ref("id")} in (${sql.join(ids)}) order by ${sql.ref("id")}${lockClause(provider, relationMode)}`.execute(executor);
|
|
48
77
|
const storedIds = new Set(result.rows.map(({ id }) => id));
|
|
49
78
|
if (!storedIds.has(bundleId)) throw new KyselyAdapterInvariantError("bundle_patches.bundle_id.foreign-key");
|
|
@@ -54,6 +83,15 @@ const countRows = async (executor, table, where) => {
|
|
|
54
83
|
return Number(result.rows[0]?.total ?? 0);
|
|
55
84
|
};
|
|
56
85
|
const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") => ({
|
|
86
|
+
async findLatestInsightsEvents(input) {
|
|
87
|
+
const where = buildKyselyWhere(provider, latestInsightsWhere(input));
|
|
88
|
+
return (await sql`SELECT canonical.* 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 canonical ON canonical.id = head.id ORDER BY head.install_id ASC`.execute(executor)).rows.map(fromStoredBundleEventRow);
|
|
89
|
+
},
|
|
90
|
+
async countLatestInsightsEvents(input) {
|
|
91
|
+
const groups = latestInsightsCountGroups(input).map((where) => sql`(${buildKyselyWhere(provider, where)})`);
|
|
92
|
+
const result = await (provider === "mysql" && groups.length === 2 ? sql`SELECT (SELECT COUNT(*) FROM bundle_event_heads WHERE ${groups[0]}) + (SELECT COUNT(*) FROM bundle_event_heads WHERE ${groups[1]} AND ${groups[0]} IS NOT TRUE) AS count` : sql`SELECT COUNT(*) AS count FROM bundle_event_heads WHERE (${sql.join(groups, sql` OR `)})`).execute(executor);
|
|
93
|
+
return Number(result.rows[0]?.count ?? 0);
|
|
94
|
+
},
|
|
57
95
|
async deleteChannel({ id }) {
|
|
58
96
|
if ((await sql`select ${sql.ref("id")}, ${sql.ref("name")} from ${sql.table("channels")} where ${sql.ref("id")} = ${id} limit 1${lockClause(provider, relationMode)}`.execute(executor)).rows[0] === void 0) return {
|
|
59
97
|
deleted: false,
|
|
@@ -93,7 +131,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
93
131
|
await insertRow(executor, "bundle_patches", input.data, provider);
|
|
94
132
|
return input.data;
|
|
95
133
|
case "bundle_events":
|
|
96
|
-
await insertRow(executor, "bundle_events", input.data, provider);
|
|
134
|
+
await insertRow(executor, "bundle_events", toStoredBundleEventRow(input.data, provider), provider);
|
|
97
135
|
return input.data;
|
|
98
136
|
case "releases":
|
|
99
137
|
await insertRow(executor, "releases", toStoredReleaseRow(input.data, provider), provider);
|
|
@@ -171,6 +209,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
171
209
|
async count(input) {
|
|
172
210
|
if (input.distinct !== void 0) throw new DatabasePluginInputError("invalid-operation");
|
|
173
211
|
switch (input.model) {
|
|
212
|
+
case "bundle_events": return countRows(executor, "bundle_events", buildKyselyWhere(provider, input.where));
|
|
174
213
|
case "bundles": return countRows(executor, "bundles", buildKyselyWhere(provider, input.where));
|
|
175
214
|
case "bundle_patches": return countRows(executor, "bundle_patches", buildKyselyWhere(provider, input.where));
|
|
176
215
|
case "releases": return countRows(executor, "releases", buildKyselyWhere(provider, input.where));
|
|
@@ -224,7 +263,7 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
224
263
|
case "bundle_events": {
|
|
225
264
|
const where = whereClause(buildKyselyWhere(provider, input.where));
|
|
226
265
|
const order = orderClause(input);
|
|
227
|
-
return
|
|
266
|
+
return (await sql`select * from ${sql.table("bundle_events")}${where}${order}${pagination}`.execute(executor)).rows.map(fromStoredBundleEventRow);
|
|
228
267
|
}
|
|
229
268
|
case "api_keys": {
|
|
230
269
|
const where = whereClause(buildKyselyWhere(provider, input.where));
|
|
@@ -250,4 +289,4 @@ const createKyselyCrud = (executor, provider, relationMode = "foreign-keys") =>
|
|
|
250
289
|
}
|
|
251
290
|
});
|
|
252
291
|
//#endregion
|
|
253
|
-
export { createKyselyCrud };
|
|
292
|
+
export { createKyselyCrud, recordKyselyInsights };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
1
|
const require_databasePluginUtils = require("./databasePluginUtils.cjs");
|
|
3
2
|
let kysely = require("kysely");
|
|
4
3
|
//#region src/adapters/kyselyQuery.ts
|
|
@@ -9,7 +8,8 @@ const stringPredicate = (provider, field, operator, value, insensitive) => {
|
|
|
9
8
|
const column = kysely.sql.ref(field);
|
|
10
9
|
if (provider === "sqlite" && !insensitive) {
|
|
11
10
|
const literal = require_databasePluginUtils.escapeGlobPattern(value);
|
|
12
|
-
|
|
11
|
+
const pattern = operator === "contains" ? `*${literal}*` : operator === "starts_with" ? `${literal}*` : `*${literal}`;
|
|
12
|
+
return kysely.sql`${column} glob ${pattern}`;
|
|
13
13
|
}
|
|
14
14
|
const literal = require_databasePluginUtils.escapeLikePattern(value);
|
|
15
15
|
const pattern = operator === "contains" ? `%${literal}%` : operator === "starts_with" ? `${literal}%` : `%${literal}`;
|
|
@@ -8,7 +8,8 @@ const stringPredicate = (provider, field, operator, value, insensitive) => {
|
|
|
8
8
|
const column = sql.ref(field);
|
|
9
9
|
if (provider === "sqlite" && !insensitive) {
|
|
10
10
|
const literal = escapeGlobPattern(value);
|
|
11
|
-
|
|
11
|
+
const pattern = operator === "contains" ? `*${literal}*` : operator === "starts_with" ? `${literal}*` : `*${literal}`;
|
|
12
|
+
return sql`${column} glob ${pattern}`;
|
|
12
13
|
}
|
|
13
14
|
const literal = escapeLikePattern(value);
|
|
14
15
|
const pattern = operator === "contains" ? `%${literal}%` : operator === "starts_with" ? `${literal}%` : `%${literal}`;
|
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
require("../_virtual/_rolldown/runtime.cjs");
|
|
3
2
|
const require_fixedMigratorMongo = require("../db/fixedMigratorMongo.cjs");
|
|
4
3
|
const require_mongodbCollections = require("./mongodbCollections.cjs");
|
|
5
4
|
const require_mongodbReads = require("./mongodbReads.cjs");
|
|
6
5
|
const require_mongodbWrites = require("./mongodbWrites.cjs");
|
|
7
6
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
8
7
|
let _hot_updater_plugin_core_internal = require("@hot-updater/plugin-core/internal");
|
|
8
|
+
let mongodb = require("mongodb");
|
|
9
9
|
//#region src/adapters/mongodb.ts
|
|
10
10
|
const createMongoImplementation = (client, session) => {
|
|
11
11
|
const collections = require_mongodbCollections.createMongoCollections(client);
|
|
12
12
|
return {
|
|
13
|
+
recordInsights: async ({ event }) => {
|
|
14
|
+
const record = () => client.withSession((insightsSession) => insightsSession.withTransaction(async () => {
|
|
15
|
+
const insights = require_mongodbCollections.createMongoCollections(client);
|
|
16
|
+
const options = {
|
|
17
|
+
session: insightsSession,
|
|
18
|
+
collation: { locale: "simple" }
|
|
19
|
+
};
|
|
20
|
+
if ((await insights.bundleEvents.updateOne({ id: event.id }, { $setOnInsert: event }, {
|
|
21
|
+
...options,
|
|
22
|
+
upsert: true
|
|
23
|
+
})).upsertedCount === 0) return;
|
|
24
|
+
const current = await insights.bundleEventHeads.findOne({ install_id: event.install_id }, options);
|
|
25
|
+
if (current !== null && (event.received_at_ms < current.received_at_ms || event.received_at_ms === current.received_at_ms && event.id <= current.id)) return;
|
|
26
|
+
await insights.bundleEventHeads.updateOne({ install_id: event.install_id }, { $set: {
|
|
27
|
+
install_id: event.install_id,
|
|
28
|
+
id: event.id,
|
|
29
|
+
received_at_ms: event.received_at_ms,
|
|
30
|
+
user_id: event.user_id,
|
|
31
|
+
platform: event.platform,
|
|
32
|
+
channel: event.channel,
|
|
33
|
+
type: event.type,
|
|
34
|
+
from_bundle_id: event.from_bundle_id,
|
|
35
|
+
to_bundle_id: event.to_bundle_id
|
|
36
|
+
} }, {
|
|
37
|
+
...options,
|
|
38
|
+
upsert: true
|
|
39
|
+
});
|
|
40
|
+
}));
|
|
41
|
+
try {
|
|
42
|
+
await record();
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (!(error instanceof mongodb.MongoServerError) || error.code !== 11e3) throw error;
|
|
45
|
+
await record();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
13
48
|
...require_mongodbWrites.createMongoWrites(collections, session),
|
|
14
49
|
...require_mongodbReads.createMongoReads(collections, session)
|
|
15
50
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DatabaseAdapterWithCapabilities } from "../db/types.cjs";
|
|
2
2
|
import { MongoClient } from "mongodb";
|
|
3
|
-
|
|
4
3
|
//#region src/adapters/mongodb.d.ts
|
|
5
4
|
interface MongoDBConfig {
|
|
6
5
|
readonly client: MongoClient;
|
|
6
|
+
/** Enables atomic catalog commits. Insights always requires MongoDB 5+ on a replica set or sharded cluster. */
|
|
7
7
|
readonly transactions?: boolean;
|
|
8
8
|
}
|
|
9
9
|
declare const mongoAdapter: (config: MongoDBConfig) => DatabaseAdapterWithCapabilities;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DatabaseAdapterWithCapabilities } from "../db/types.mjs";
|
|
2
2
|
import { MongoClient } from "mongodb";
|
|
3
|
-
|
|
4
3
|
//#region src/adapters/mongodb.d.ts
|
|
5
4
|
interface MongoDBConfig {
|
|
6
5
|
readonly client: MongoClient;
|
|
6
|
+
/** Enables atomic catalog commits. Insights always requires MongoDB 5+ on a replica set or sharded cluster. */
|
|
7
7
|
readonly transactions?: boolean;
|
|
8
8
|
}
|
|
9
9
|
declare const mongoAdapter: (config: MongoDBConfig) => DatabaseAdapterWithCapabilities;
|
|
@@ -4,10 +4,46 @@ import { createMongoReads } from "./mongodbReads.mjs";
|
|
|
4
4
|
import { createMongoWrites } from "./mongodbWrites.mjs";
|
|
5
5
|
import { createDatabasePlugin } from "@hot-updater/plugin-core";
|
|
6
6
|
import { createDatabasePluginAdapter } from "@hot-updater/plugin-core/internal";
|
|
7
|
+
import { MongoServerError } from "mongodb";
|
|
7
8
|
//#region src/adapters/mongodb.ts
|
|
8
9
|
const createMongoImplementation = (client, session) => {
|
|
9
10
|
const collections = createMongoCollections(client);
|
|
10
11
|
return {
|
|
12
|
+
recordInsights: async ({ event }) => {
|
|
13
|
+
const record = () => client.withSession((insightsSession) => insightsSession.withTransaction(async () => {
|
|
14
|
+
const insights = createMongoCollections(client);
|
|
15
|
+
const options = {
|
|
16
|
+
session: insightsSession,
|
|
17
|
+
collation: { locale: "simple" }
|
|
18
|
+
};
|
|
19
|
+
if ((await insights.bundleEvents.updateOne({ id: event.id }, { $setOnInsert: event }, {
|
|
20
|
+
...options,
|
|
21
|
+
upsert: true
|
|
22
|
+
})).upsertedCount === 0) return;
|
|
23
|
+
const current = await insights.bundleEventHeads.findOne({ install_id: event.install_id }, options);
|
|
24
|
+
if (current !== null && (event.received_at_ms < current.received_at_ms || event.received_at_ms === current.received_at_ms && event.id <= current.id)) return;
|
|
25
|
+
await insights.bundleEventHeads.updateOne({ install_id: event.install_id }, { $set: {
|
|
26
|
+
install_id: event.install_id,
|
|
27
|
+
id: event.id,
|
|
28
|
+
received_at_ms: event.received_at_ms,
|
|
29
|
+
user_id: event.user_id,
|
|
30
|
+
platform: event.platform,
|
|
31
|
+
channel: event.channel,
|
|
32
|
+
type: event.type,
|
|
33
|
+
from_bundle_id: event.from_bundle_id,
|
|
34
|
+
to_bundle_id: event.to_bundle_id
|
|
35
|
+
} }, {
|
|
36
|
+
...options,
|
|
37
|
+
upsert: true
|
|
38
|
+
});
|
|
39
|
+
}));
|
|
40
|
+
try {
|
|
41
|
+
await record();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (!(error instanceof MongoServerError) || error.code !== 11e3) throw error;
|
|
44
|
+
await record();
|
|
45
|
+
}
|
|
46
|
+
},
|
|
11
47
|
...createMongoWrites(collections, session),
|
|
12
48
|
...createMongoReads(collections, session)
|
|
13
49
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//#region src/adapters/mongodbCollections.ts
|
|
2
2
|
var MongoAdapterConstraintError = class extends Error {
|
|
3
|
+
reason;
|
|
3
4
|
name = "MongoAdapterConstraintError";
|
|
4
5
|
constructor(reason) {
|
|
5
6
|
super(`MongoDB adapter constraint failed: ${reason}`);
|
|
@@ -19,6 +20,7 @@ const createMongoCollections = (client) => {
|
|
|
19
20
|
bundles: database.collection("bundles"),
|
|
20
21
|
bundlePatches: database.collection("bundle_patches"),
|
|
21
22
|
bundleEvents: database.collection("bundle_events"),
|
|
23
|
+
bundleEventHeads: database.collection("bundle_event_heads"),
|
|
22
24
|
channels: database.collection("channels"),
|
|
23
25
|
apiKeys: database.collection("api_keys"),
|
|
24
26
|
releases: database.collection("releases"),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//#region src/adapters/mongodbCollections.ts
|
|
2
2
|
var MongoAdapterConstraintError = class extends Error {
|
|
3
|
+
reason;
|
|
3
4
|
name = "MongoAdapterConstraintError";
|
|
4
5
|
constructor(reason) {
|
|
5
6
|
super(`MongoDB adapter constraint failed: ${reason}`);
|
|
@@ -19,6 +20,7 @@ const createMongoCollections = (client) => {
|
|
|
19
20
|
bundles: database.collection("bundles"),
|
|
20
21
|
bundlePatches: database.collection("bundle_patches"),
|
|
21
22
|
bundleEvents: database.collection("bundle_events"),
|
|
23
|
+
bundleEventHeads: database.collection("bundle_event_heads"),
|
|
22
24
|
channels: database.collection("channels"),
|
|
23
25
|
apiKeys: database.collection("api_keys"),
|
|
24
26
|
releases: database.collection("releases"),
|
|
@@ -32,14 +32,27 @@ const predicate = (where) => {
|
|
|
32
32
|
case "ends_with": return { $expr: stringExpression(where.field, where.operator, where.value, where.mode) };
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
-
const createMongoWhereDocument = (where) => {
|
|
35
|
+
const createMongoWhereDocument = (where, toPredicate = predicate) => {
|
|
36
36
|
const items = Array.isArray(where) ? where : [];
|
|
37
37
|
const first = items[0];
|
|
38
38
|
if (first === void 0) return {};
|
|
39
|
-
let result =
|
|
40
|
-
for (const item of items.slice(1)) result = { [item.connector === "OR" ? "$or" : "$and"]: [result,
|
|
39
|
+
let result = toPredicate(first);
|
|
40
|
+
for (const item of items.slice(1)) result = { [item.connector === "OR" ? "$or" : "$and"]: [result, toPredicate(item)] };
|
|
41
41
|
return result;
|
|
42
42
|
};
|
|
43
|
+
const insightsPredicate = (where) => {
|
|
44
|
+
if ("mode" in where && where.mode === "insensitive") return predicate(where);
|
|
45
|
+
switch (where.operator) {
|
|
46
|
+
case void 0:
|
|
47
|
+
case "eq": return { [where.field]: { $eq: where.value } };
|
|
48
|
+
case "gt":
|
|
49
|
+
case "gte":
|
|
50
|
+
case "lt":
|
|
51
|
+
case "lte":
|
|
52
|
+
case "in": return { [where.field]: { [`$${where.operator}`]: where.value } };
|
|
53
|
+
default: return predicate(where);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
43
56
|
function createMongoBundleWhere(where) {
|
|
44
57
|
return createMongoWhereDocument(where);
|
|
45
58
|
}
|
|
@@ -47,7 +60,7 @@ function createMongoPatchWhere(where) {
|
|
|
47
60
|
return createMongoWhereDocument(where);
|
|
48
61
|
}
|
|
49
62
|
function createMongoEventWhere(where) {
|
|
50
|
-
return createMongoWhereDocument(where);
|
|
63
|
+
return createMongoWhereDocument(where, insightsPredicate);
|
|
51
64
|
}
|
|
52
65
|
function createMongoApiKeyWhere(where) {
|
|
53
66
|
return createMongoWhereDocument(where);
|
|
@@ -32,14 +32,27 @@ const predicate = (where) => {
|
|
|
32
32
|
case "ends_with": return { $expr: stringExpression(where.field, where.operator, where.value, where.mode) };
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
-
const createMongoWhereDocument = (where) => {
|
|
35
|
+
const createMongoWhereDocument = (where, toPredicate = predicate) => {
|
|
36
36
|
const items = Array.isArray(where) ? where : [];
|
|
37
37
|
const first = items[0];
|
|
38
38
|
if (first === void 0) return {};
|
|
39
|
-
let result =
|
|
40
|
-
for (const item of items.slice(1)) result = { [item.connector === "OR" ? "$or" : "$and"]: [result,
|
|
39
|
+
let result = toPredicate(first);
|
|
40
|
+
for (const item of items.slice(1)) result = { [item.connector === "OR" ? "$or" : "$and"]: [result, toPredicate(item)] };
|
|
41
41
|
return result;
|
|
42
42
|
};
|
|
43
|
+
const insightsPredicate = (where) => {
|
|
44
|
+
if ("mode" in where && where.mode === "insensitive") return predicate(where);
|
|
45
|
+
switch (where.operator) {
|
|
46
|
+
case void 0:
|
|
47
|
+
case "eq": return { [where.field]: { $eq: where.value } };
|
|
48
|
+
case "gt":
|
|
49
|
+
case "gte":
|
|
50
|
+
case "lt":
|
|
51
|
+
case "lte":
|
|
52
|
+
case "in": return { [where.field]: { [`$${where.operator}`]: where.value } };
|
|
53
|
+
default: return predicate(where);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
43
56
|
function createMongoBundleWhere(where) {
|
|
44
57
|
return createMongoWhereDocument(where);
|
|
45
58
|
}
|
|
@@ -47,7 +60,7 @@ function createMongoPatchWhere(where) {
|
|
|
47
60
|
return createMongoWhereDocument(where);
|
|
48
61
|
}
|
|
49
62
|
function createMongoEventWhere(where) {
|
|
50
|
-
return createMongoWhereDocument(where);
|
|
63
|
+
return createMongoWhereDocument(where, insightsPredicate);
|
|
51
64
|
}
|
|
52
65
|
function createMongoApiKeyWhere(where) {
|
|
53
66
|
return createMongoWhereDocument(where);
|