@hot-updater/server 0.36.6 → 1.0.0-rc.0
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/adapters/databaseConstraintErrors.cjs +23 -0
- package/dist/adapters/databaseConstraintErrors.mjs +21 -0
- package/dist/adapters/databasePluginUtils.cjs +117 -0
- package/dist/adapters/databasePluginUtils.mjs +106 -0
- package/dist/adapters/drizzle.cjs +53 -176
- package/dist/adapters/drizzle.d.cts +6 -4
- package/dist/adapters/drizzle.d.mts +6 -4
- package/dist/adapters/drizzle.mjs +54 -177
- package/dist/adapters/drizzleCrud.cjs +250 -0
- package/dist/adapters/drizzleCrud.mjs +249 -0
- package/dist/adapters/drizzleLazyDB.cjs +84 -36
- package/dist/adapters/drizzleLazyDB.mjs +84 -36
- package/dist/adapters/drizzleQuery.cjs +68 -0
- package/dist/adapters/drizzleQuery.mjs +67 -0
- package/dist/adapters/kysely.cjs +18 -138
- package/dist/adapters/kysely.d.cts +3 -12
- package/dist/adapters/kysely.d.mts +3 -12
- package/dist/adapters/kysely.mjs +19 -139
- package/dist/adapters/kyselyCrud.cjs +254 -0
- package/dist/adapters/kyselyCrud.mjs +253 -0
- package/dist/adapters/kyselyQuery.cjs +56 -0
- package/dist/adapters/kyselyQuery.mjs +55 -0
- package/dist/adapters/mongodb.cjs +21 -174
- package/dist/adapters/mongodb.d.cts +3 -2
- package/dist/adapters/mongodb.d.mts +3 -2
- package/dist/adapters/mongodb.mjs +21 -174
- package/dist/adapters/mongodbCollections.cjs +36 -0
- package/dist/adapters/mongodbCollections.mjs +30 -0
- package/dist/adapters/mongodbQuery.cjs +77 -0
- package/dist/adapters/mongodbQuery.mjs +70 -0
- package/dist/adapters/mongodbReads.cjs +148 -0
- package/dist/adapters/mongodbReads.mjs +147 -0
- package/dist/adapters/mongodbWrites.cjs +134 -0
- package/dist/adapters/mongodbWrites.mjs +133 -0
- package/dist/adapters/prisma.cjs +205 -180
- package/dist/adapters/prisma.d.cts +3 -3
- package/dist/adapters/prisma.d.mts +3 -3
- package/dist/adapters/prisma.mjs +206 -181
- package/dist/adapters/prismaQuery.cjs +58 -0
- package/dist/adapters/prismaQuery.mjs +56 -0
- package/dist/adapters/prismaRows.cjs +198 -0
- package/dist/adapters/prismaRows.mjs +188 -0
- package/dist/analytics/bounded/activeOverview.cjs +87 -0
- package/dist/analytics/bounded/activeOverview.mjs +85 -0
- package/dist/analytics/bounded/installationSearch.cjs +42 -0
- package/dist/analytics/bounded/installationSearch.mjs +42 -0
- package/dist/analytics/bounded/persistence.cjs +39 -0
- package/dist/analytics/bounded/persistence.mjs +38 -0
- package/dist/analytics/bounded/provider.cjs +170 -0
- package/dist/analytics/bounded/provider.d.cts +7 -0
- package/dist/analytics/bounded/provider.d.mts +7 -0
- package/dist/analytics/bounded/provider.mjs +170 -0
- package/dist/analytics/bounded/scan.cjs +144 -0
- package/dist/analytics/bounded/scan.mjs +138 -0
- package/dist/analytics/domain.d.cts +121 -0
- package/dist/analytics/domain.d.mts +121 -0
- package/dist/analytics/errors.cjs +22 -0
- package/dist/analytics/errors.mjs +20 -0
- package/dist/analytics/eventInput.cjs +111 -0
- package/dist/analytics/eventInput.mjs +111 -0
- package/dist/analytics/persistence.d.cts +6 -0
- package/dist/analytics/persistence.d.mts +6 -0
- package/dist/analytics/queryInput.cjs +58 -0
- package/dist/analytics/queryInput.mjs +55 -0
- package/dist/analytics/routes.cjs +63 -0
- package/dist/analytics/routes.mjs +61 -0
- package/dist/analytics/types.d.cts +17 -0
- package/dist/analytics/types.d.mts +17 -0
- package/dist/apiKeys.cjs +139 -0
- package/dist/apiKeys.d.cts +50 -0
- package/dist/apiKeys.d.mts +50 -0
- package/dist/apiKeys.mjs +133 -0
- package/dist/createHotUpdaterCore.cjs +48 -26
- package/dist/createHotUpdaterCore.d.cts +49 -17
- package/dist/createHotUpdaterCore.d.mts +49 -17
- package/dist/createHotUpdaterCore.mjs +51 -29
- package/dist/db/createBundleDiff.cjs +45 -68
- package/dist/db/createBundleDiff.d.cts +3 -3
- package/dist/db/createBundleDiff.d.mts +3 -3
- package/dist/db/createBundleDiff.mjs +47 -68
- package/dist/db/databasePluginCore.cjs +138 -0
- package/dist/db/databasePluginCore.mjs +137 -0
- package/dist/db/fixedMigrator.cjs +36 -93
- package/dist/db/fixedMigrator.mjs +36 -93
- package/dist/db/fixedMigratorMongo.cjs +319 -0
- package/dist/db/fixedMigratorMongo.mjs +319 -0
- package/dist/db/fixedMigratorShared.cjs +23 -0
- package/dist/db/fixedMigratorShared.mjs +18 -0
- package/dist/db/mongoMigrationExecution.cjs +11 -0
- package/dist/db/mongoMigrationExecution.mjs +11 -0
- package/dist/db/releaseCatalog.cjs +66 -0
- package/dist/db/releaseCatalog.d.cts +17 -0
- package/dist/db/releaseCatalog.d.mts +17 -0
- package/dist/db/releaseCatalog.mjs +64 -0
- package/dist/db/schema/mongodb.cjs +14 -6
- package/dist/db/schema/mongodb.mjs +14 -6
- package/dist/db/schema/registry.cjs +0 -2
- package/dist/db/schema/registry.mjs +1 -2
- package/dist/db/schema/sql.cjs +31 -14
- package/dist/db/schema/sql.mjs +32 -13
- package/dist/db/schema/sqlOperations.cjs +4 -4
- package/dist/db/schema/sqlOperations.mjs +5 -5
- package/dist/db/schemaGenerators.cjs +52 -18
- package/dist/db/schemaGenerators.mjs +52 -18
- package/dist/db/schemaReadiness.cjs +4 -3
- package/dist/db/schemaReadiness.mjs +4 -3
- package/dist/db/sqlMigrationExecution.cjs +67 -0
- package/dist/db/sqlMigrationExecution.mjs +66 -0
- package/dist/db/types.cjs +2 -6
- package/dist/db/types.d.cts +60 -16
- package/dist/db/types.d.mts +60 -16
- package/dist/db/types.mjs +3 -6
- package/dist/db/updateArtifacts.cjs +114 -60
- package/dist/db/updateArtifacts.mjs +117 -62
- package/dist/handler.cjs +108 -282
- package/dist/handler.d.cts +3 -46
- package/dist/handler.d.mts +3 -46
- package/dist/handler.mjs +107 -281
- package/dist/handlerBundleRoutes.cjs +155 -0
- package/dist/handlerBundleRoutes.mjs +155 -0
- package/dist/handlerErrors.cjs +9 -0
- package/dist/handlerErrors.mjs +9 -0
- package/dist/handlerParameters.cjs +39 -0
- package/dist/handlerParameters.mjs +34 -0
- package/dist/handlerReleaseCatalogRoutes.cjs +111 -0
- package/dist/handlerReleaseCatalogRoutes.mjs +110 -0
- package/dist/handlerReleaseManagementRoutes.cjs +125 -0
- package/dist/handlerReleaseManagementRoutes.mjs +124 -0
- package/dist/handlerTypes.d.cts +63 -0
- package/dist/handlerTypes.d.mts +63 -0
- package/dist/handlerVersionRoutes.cjs +10 -0
- package/dist/handlerVersionRoutes.d.cts +4 -0
- package/dist/handlerVersionRoutes.d.mts +4 -0
- package/dist/handlerVersionRoutes.mjs +9 -0
- package/dist/index.cjs +10 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.mts +9 -3
- package/dist/index.mjs +5 -2
- package/dist/node.cjs +19 -12
- package/dist/node.d.cts +15 -10
- package/dist/node.d.mts +15 -10
- package/dist/node.mjs +19 -13
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/schema/dsl.cjs +19 -2
- package/dist/schema/dsl.mjs +17 -3
- package/dist/schema/index.cjs +1 -8
- package/dist/schema/index.mjs +2 -8
- package/dist/schema/types.cjs +3 -1
- package/dist/schema/types.mjs +3 -2
- package/dist/schema/v1_0_0.cjs +364 -0
- package/dist/schema/v1_0_0.mjs +357 -0
- package/dist/storageAccess.cjs +69 -25
- package/dist/storageAccess.mjs +68 -25
- package/dist/types/index.d.cts +4 -3
- package/dist/types/index.d.mts +5 -4
- package/package.json +8 -7
- package/src/adapters/databaseConstraintErrors.ts +25 -0
- package/src/adapters/databasePluginTestDatabase.ts +106 -0
- package/src/adapters/databasePluginUtils.spec.ts +29 -0
- package/src/adapters/databasePluginUtils.ts +214 -0
- package/src/adapters/drizzle.spec.ts +208 -47
- package/src/adapters/drizzle.ts +106 -293
- package/src/adapters/drizzleCrud.ts +419 -0
- package/src/adapters/drizzleLazyDB.ts +206 -100
- package/src/adapters/drizzleQuery.ts +164 -0
- package/src/adapters/kysely.spec.ts +126 -88
- package/src/adapters/kysely.ts +76 -334
- package/src/adapters/kyselyCrud.ts +588 -0
- package/src/adapters/kyselyQuery.ts +128 -0
- package/src/adapters/mongodb.spec.ts +141 -0
- package/src/adapters/mongodb.ts +60 -288
- package/src/adapters/mongodbCollections.ts +62 -0
- package/src/adapters/mongodbQuery.ts +226 -0
- package/src/adapters/mongodbReads.ts +311 -0
- package/src/adapters/mongodbRows.spec.ts +64 -0
- package/src/adapters/mongodbRows.ts +118 -0
- package/src/adapters/mongodbTestClient.ts +342 -0
- package/src/adapters/mongodbTestFilter.ts +166 -0
- package/src/adapters/mongodbWrites.ts +260 -0
- package/src/adapters/prisma.spec.ts +196 -0
- package/src/adapters/prisma.ts +417 -292
- package/src/adapters/prismaQuery.ts +129 -0
- package/src/adapters/prismaRows.spec.ts +98 -0
- package/src/adapters/prismaRows.ts +301 -0
- package/src/adapters/prismaTestClient.ts +396 -0
- package/src/analytics/analytics.integration.spec.ts +144 -0
- package/src/analytics/bounded/activeOverview.spec.ts +189 -0
- package/src/analytics/bounded/activeOverview.ts +148 -0
- package/src/analytics/bounded/installationSearch.spec.ts +130 -0
- package/src/analytics/bounded/installationSearch.ts +69 -0
- package/src/analytics/bounded/persistence.ts +43 -0
- package/src/analytics/bounded/provider.spec.ts +219 -0
- package/src/analytics/bounded/provider.ts +229 -0
- package/src/analytics/bounded/scan.ts +235 -0
- package/src/analytics/domain.ts +139 -0
- package/src/analytics/errors.ts +18 -0
- package/src/analytics/eventInput.ts +168 -0
- package/src/analytics/persistence.ts +10 -0
- package/src/analytics/queryInput.ts +102 -0
- package/src/analytics/routes.ts +123 -0
- package/src/analytics/types.ts +44 -0
- package/src/apiKeys.integration.spec.ts +192 -0
- package/src/apiKeys.spec.ts +162 -0
- package/src/apiKeys.ts +220 -0
- package/src/createHotUpdaterCore.ts +164 -100
- package/src/db/bundleRows.spec.ts +164 -0
- package/src/db/bundleRows.ts +10 -140
- package/src/db/createBundleDiff.spec.ts +172 -127
- package/src/db/createBundleDiff.ts +91 -110
- package/src/db/databasePluginCore.spec.ts +62 -0
- package/src/db/databasePluginCore.testFixtures.ts +76 -0
- package/src/db/databasePluginCore.ts +185 -0
- package/src/db/databasePluginUpdateCheck.bench.ts +107 -0
- package/src/db/fixedMigrator.spec.ts +184 -42
- package/src/db/fixedMigrator.ts +64 -205
- package/src/db/fixedMigratorMongo.spec.ts +192 -0
- package/src/db/fixedMigratorMongo.ts +425 -0
- package/src/db/fixedMigratorShared.ts +36 -0
- package/src/db/hotUpdaterSchema.ts +0 -1
- package/src/db/index.spec.ts +333 -1025
- package/src/db/mongoMigrationExecution.ts +23 -0
- package/src/db/node-sqlite.d.ts +25 -0
- package/src/db/releaseCatalog.ts +148 -0
- package/src/db/schema/mongodb.ts +20 -6
- package/src/db/schema/sql.ts +52 -11
- package/src/db/schema/sqlOperations.ts +5 -4
- package/src/db/schemaGenerators.ts +107 -23
- package/src/db/schemaReadiness.ts +2 -1
- package/src/db/sqlMigrationExecution.spec.ts +65 -0
- package/src/db/sqlMigrationExecution.ts +108 -0
- package/src/db/types.spec.ts +55 -0
- package/src/db/types.ts +129 -65
- package/src/db/updateArtifacts.spec.ts +359 -0
- package/src/db/updateArtifacts.ts +290 -126
- package/src/handler-standalone.integration.spec.ts +401 -364
- package/src/handler.spec.ts +137 -582
- package/src/handler.testFixtures.ts +30 -0
- package/src/handler.ts +218 -616
- package/src/handlerAuth.integration.spec.ts +33 -0
- package/src/handlerBundleRoutes.ts +259 -0
- package/src/handlerErrors.ts +7 -0
- package/src/handlerManagement.spec.ts +262 -0
- package/src/handlerParameters.ts +105 -0
- package/src/handlerReleaseCatalogRoutes.ts +154 -0
- package/src/handlerReleaseManagementRoutes.ts +213 -0
- package/src/handlerTypes.ts +96 -0
- package/src/handlerVersionRoutes.ts +12 -0
- package/src/index.ts +22 -2
- package/src/node.spec.ts +79 -10
- package/src/node.ts +20 -17
- package/src/releaseCatalogRoutes.integration.spec.ts +238 -0
- package/src/runtime.spec.ts +126 -959
- package/src/runtime.testFixtures.ts +71 -0
- package/src/schema/dsl-all-versions.spec.ts +26 -17
- package/src/schema/dsl.ts +41 -2
- package/src/schema/index.ts +3 -9
- package/src/schema/types.ts +9 -3
- package/src/schema/v1_0_0.spec.ts +146 -0
- package/src/schema/v1_0_0.ts +465 -0
- package/src/storageAccess.spec.ts +127 -32
- package/src/storageAccess.ts +106 -55
- package/src/types/index.ts +2 -1
- package/dist/db/bundleRows.cjs +0 -82
- package/dist/db/bundleRows.d.cts +0 -33
- package/dist/db/bundleRows.d.mts +0 -33
- package/dist/db/bundleRows.mjs +0 -79
- package/dist/db/pluginCore.cjs +0 -242
- package/dist/db/pluginCore.mjs +0 -241
- package/dist/db/schema/sqlMigrations.cjs +0 -74
- package/dist/db/schema/sqlMigrations.mjs +0 -73
- package/dist/db/schemaEnhancements.cjs +0 -20
- package/dist/db/schemaEnhancements.mjs +0 -19
- package/dist/route.cjs +0 -7
- package/dist/route.mjs +0 -7
- package/dist/schema/v0_21_0.cjs +0 -38
- package/dist/schema/v0_21_0.mjs +0 -37
- package/dist/schema/v0_29_0.cjs +0 -45
- package/dist/schema/v0_29_0.mjs +0 -44
- package/dist/schema/v0_31_0.cjs +0 -82
- package/dist/schema/v0_31_0.mjs +0 -80
- package/src/db/pluginCore.spec.ts +0 -1095
- package/src/db/pluginCore.ts +0 -475
- package/src/db/pluginUpdateCheck.bench.ts +0 -254
- package/src/db/schema/sqlMigrations.ts +0 -219
- package/src/db/schemaEnhancements.ts +0 -55
- package/src/route.ts +0 -7
- package/src/schema/v0_21_0.ts +0 -52
- package/src/schema/v0_29_0.ts +0 -62
- package/src/schema/v0_31_0.spec.ts +0 -73
- package/src/schema/v0_31_0.ts +0 -120
package/src/db/fixedMigrator.ts
CHANGED
|
@@ -1,49 +1,31 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type { MongoClient } from "mongodb";
|
|
1
|
+
import { sql, type QueryExecutorProvider } from "kysely";
|
|
3
2
|
|
|
4
3
|
import {
|
|
4
|
+
HOT_UPDATER_CORE_SCHEMA_KEY,
|
|
5
5
|
HOT_UPDATER_SCHEMA_VERSION,
|
|
6
6
|
HOT_UPDATER_SETTINGS_TABLE,
|
|
7
7
|
} from "../schema/types";
|
|
8
|
-
import { createMongoMigrationOperations } from "./schema/mongodb";
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
assertCurrentOrEmptySchemaVersion,
|
|
10
|
+
assertSupportedMigrationMode,
|
|
11
|
+
getEmptyMigrationResult,
|
|
12
|
+
inferLegacyCoreSchemaVersion,
|
|
13
|
+
isCurrentSchemaVersion,
|
|
14
|
+
} from "./fixedMigratorShared";
|
|
13
15
|
import { createTableSql } from "./schema/sql";
|
|
14
|
-
import { createV029AlterSql, createV031AlterSql } from "./schema/sqlMigrations";
|
|
15
16
|
import {
|
|
16
17
|
createSqlCreateOperations,
|
|
17
18
|
getSettingsInsertSql,
|
|
18
19
|
} from "./schema/sqlOperations";
|
|
20
|
+
import { executeMigrationStatements } from "./sqlMigrationExecution";
|
|
19
21
|
import type {
|
|
20
22
|
MigrateOptions,
|
|
21
|
-
MigrationOperation,
|
|
22
23
|
MigrationResult,
|
|
23
24
|
Migrator,
|
|
24
25
|
ORMSQLProvider,
|
|
25
26
|
RelationMode,
|
|
26
27
|
} from "./types";
|
|
27
28
|
|
|
28
|
-
interface SettingsDatabase {
|
|
29
|
-
readonly private_hot_updater_settings: {
|
|
30
|
-
readonly key: string;
|
|
31
|
-
readonly value: string;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const getEmptyResult = (): MigrationResult => ({
|
|
36
|
-
operations: [],
|
|
37
|
-
execute: async () => {},
|
|
38
|
-
getSQL: () => "",
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const assertSupportedMigrationMode = (options: MigrateOptions): void => {
|
|
42
|
-
if (options.mode === "from-database") {
|
|
43
|
-
throw new Error("Hot Updater migrations support only mode: 'from-schema'.");
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
29
|
const isMissingSettingsTableError = (error: unknown): boolean => {
|
|
48
30
|
if (!(error instanceof Error)) return false;
|
|
49
31
|
const message = error.message.toLowerCase();
|
|
@@ -56,222 +38,97 @@ const isMissingSettingsTableError = (error: unknown): boolean => {
|
|
|
56
38
|
);
|
|
57
39
|
};
|
|
58
40
|
|
|
59
|
-
const isMongoNamespaceExistsError = (error: unknown): boolean => {
|
|
60
|
-
if (!(error instanceof Error)) return false;
|
|
61
|
-
const mongoError = error as { code?: unknown; codeName?: unknown };
|
|
62
|
-
return mongoError.code === 48 || mongoError.codeName === "NamespaceExists";
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const ignoreExistingCollection = (error: unknown): undefined => {
|
|
66
|
-
if (isMongoNamespaceExistsError(error)) {
|
|
67
|
-
return undefined;
|
|
68
|
-
}
|
|
69
|
-
throw error;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const toCustomOperations = (
|
|
73
|
-
statements: readonly string[],
|
|
74
|
-
settingsOperation?: MigrationOperation,
|
|
75
|
-
): MigrationOperation[] => [
|
|
76
|
-
...statements.map(
|
|
77
|
-
(statement): MigrationOperation => ({
|
|
78
|
-
type: "custom",
|
|
79
|
-
sql: statement,
|
|
80
|
-
}),
|
|
81
|
-
),
|
|
82
|
-
...(settingsOperation ? [settingsOperation] : []),
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
const assertSupportedSchemaVersion = (
|
|
86
|
-
currentVersion: string | undefined,
|
|
87
|
-
): void => {
|
|
88
|
-
if (
|
|
89
|
-
currentVersion !== undefined &&
|
|
90
|
-
currentVersion !== "0.21.0" &&
|
|
91
|
-
currentVersion !== "0.29.0"
|
|
92
|
-
) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`Unsupported Hot Updater schema version: ${currentVersion}`,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
41
|
export const createKyselyMigrator = ({
|
|
100
42
|
db,
|
|
101
43
|
provider,
|
|
102
44
|
relationMode = "foreign-keys",
|
|
103
45
|
}: {
|
|
104
|
-
db:
|
|
46
|
+
db: QueryExecutorProvider;
|
|
105
47
|
provider: ORMSQLProvider;
|
|
106
48
|
relationMode?: RelationMode;
|
|
107
49
|
}): Migrator => {
|
|
108
|
-
const
|
|
50
|
+
const getSetting = async (key: string): Promise<string | undefined> => {
|
|
109
51
|
try {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
52
|
+
const result = await sql<{ readonly value: unknown }>`select ${sql.ref(
|
|
53
|
+
"value",
|
|
54
|
+
)} from ${sql.table(HOT_UPDATER_SETTINGS_TABLE)} where ${sql.ref(
|
|
55
|
+
"key",
|
|
56
|
+
)} = ${key} limit 1`.execute(db);
|
|
57
|
+
const row = result.rows[0];
|
|
58
|
+
if (!row) return undefined;
|
|
59
|
+
if (typeof row.value !== "string") {
|
|
60
|
+
throw new Error(`Invalid Hot Updater schema setting: ${key}`);
|
|
61
|
+
}
|
|
62
|
+
return row.value;
|
|
116
63
|
} catch (error) {
|
|
117
64
|
if (!isMissingSettingsTableError(error)) throw error;
|
|
118
65
|
return undefined;
|
|
119
66
|
}
|
|
120
67
|
};
|
|
121
68
|
|
|
69
|
+
const getCoreVersion = (): Promise<string | undefined> =>
|
|
70
|
+
getSetting(HOT_UPDATER_CORE_SCHEMA_KEY);
|
|
71
|
+
|
|
72
|
+
const getSchemaVersions = async (): Promise<{
|
|
73
|
+
readonly coreVersion: string | undefined;
|
|
74
|
+
readonly legacyCoreVersion: string | undefined;
|
|
75
|
+
}> => {
|
|
76
|
+
const coreVersion = await getCoreVersion();
|
|
77
|
+
const legacyCoreVersion = inferLegacyCoreSchemaVersion(
|
|
78
|
+
await getSetting("version"),
|
|
79
|
+
);
|
|
80
|
+
return { coreVersion, legacyCoreVersion };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const getVersion = async (): Promise<string | undefined> => {
|
|
84
|
+
const { coreVersion, legacyCoreVersion } = await getSchemaVersions();
|
|
85
|
+
return coreVersion ?? legacyCoreVersion;
|
|
86
|
+
};
|
|
87
|
+
|
|
122
88
|
const makeResult = async (
|
|
123
89
|
options: MigrateOptions = {},
|
|
124
90
|
): Promise<MigrationResult> => {
|
|
125
91
|
assertSupportedMigrationMode(options);
|
|
126
92
|
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
return
|
|
93
|
+
const { coreVersion, legacyCoreVersion } = await getSchemaVersions();
|
|
94
|
+
if (isCurrentSchemaVersion(coreVersion)) {
|
|
95
|
+
return getEmptyMigrationResult();
|
|
130
96
|
}
|
|
131
|
-
|
|
97
|
+
assertCurrentOrEmptySchemaVersion(coreVersion ?? legacyCoreVersion);
|
|
132
98
|
|
|
133
99
|
const settingsStatement = getSettingsInsertSql(provider);
|
|
134
100
|
const settingsOperation =
|
|
135
101
|
options.updateSettings === false
|
|
136
102
|
? undefined
|
|
137
|
-
:
|
|
138
|
-
type: "custom",
|
|
103
|
+
: {
|
|
104
|
+
type: "custom" as const,
|
|
139
105
|
sql: settingsStatement,
|
|
140
|
-
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
? [...createTableSql(provider, relationMode), settingsStatement]
|
|
146
|
-
: [
|
|
147
|
-
...(currentVersion === "0.21.0"
|
|
148
|
-
? createV029AlterSql(provider)
|
|
149
|
-
: []),
|
|
150
|
-
...(currentVersion === "0.21.0" || currentVersion === "0.29.0"
|
|
151
|
-
? createV031AlterSql(provider, relationMode)
|
|
152
|
-
: []),
|
|
153
|
-
...executableSettingsStatements,
|
|
154
|
-
];
|
|
155
|
-
const operations =
|
|
156
|
-
currentVersion === undefined
|
|
157
|
-
? createSqlCreateOperations(provider, relationMode, settingsOperation)
|
|
158
|
-
: toCustomOperations(
|
|
159
|
-
[
|
|
160
|
-
...(currentVersion === "0.21.0"
|
|
161
|
-
? createV029AlterSql(provider)
|
|
162
|
-
: []),
|
|
163
|
-
...(currentVersion === "0.21.0" || currentVersion === "0.29.0"
|
|
164
|
-
? createV031AlterSql(provider, relationMode)
|
|
165
|
-
: []),
|
|
166
|
-
],
|
|
167
|
-
settingsOperation,
|
|
168
|
-
);
|
|
106
|
+
};
|
|
107
|
+
const statements = [
|
|
108
|
+
...createTableSql(provider, relationMode),
|
|
109
|
+
settingsStatement,
|
|
110
|
+
];
|
|
169
111
|
|
|
170
112
|
return {
|
|
171
|
-
operations
|
|
113
|
+
operations: createSqlCreateOperations(
|
|
114
|
+
provider,
|
|
115
|
+
relationMode,
|
|
116
|
+
settingsOperation,
|
|
117
|
+
),
|
|
172
118
|
getSQL: () => statements.map((statement) => `${statement};`).join("\n\n"),
|
|
173
|
-
execute:
|
|
174
|
-
const { sql } = await import("kysely");
|
|
175
|
-
for (const statement of statements) {
|
|
176
|
-
await sql.raw(statement).execute(db);
|
|
177
|
-
}
|
|
178
|
-
},
|
|
119
|
+
execute: () => executeMigrationStatements({ db, provider, statements }),
|
|
179
120
|
};
|
|
180
121
|
};
|
|
181
122
|
|
|
182
123
|
return {
|
|
183
124
|
getVersion,
|
|
184
125
|
getNameVariants: async () => undefined,
|
|
185
|
-
next: async () =>
|
|
186
|
-
|
|
126
|
+
next: async () => {
|
|
127
|
+
const { coreVersion } = await getSchemaVersions();
|
|
128
|
+
return isCurrentSchemaVersion(coreVersion)
|
|
187
129
|
? undefined
|
|
188
|
-
: { version: HOT_UPDATER_SCHEMA_VERSION }
|
|
189
|
-
previous: async () => undefined,
|
|
190
|
-
up: makeResult,
|
|
191
|
-
down: async () => {
|
|
192
|
-
throw new Error("No previous schema to migrate to.");
|
|
130
|
+
: { version: HOT_UPDATER_SCHEMA_VERSION };
|
|
193
131
|
},
|
|
194
|
-
migrateTo: async (version, options) => {
|
|
195
|
-
if (version !== HOT_UPDATER_SCHEMA_VERSION) {
|
|
196
|
-
throw new Error(`Invalid version ${version}`);
|
|
197
|
-
}
|
|
198
|
-
return makeResult(options);
|
|
199
|
-
},
|
|
200
|
-
migrateToLatest: makeResult,
|
|
201
|
-
};
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export const createMongoMigrator = (client: MongoClient): Migrator => {
|
|
205
|
-
const settings = client
|
|
206
|
-
.db()
|
|
207
|
-
.collection<{ key: string; value: unknown }>(HOT_UPDATER_SETTINGS_TABLE);
|
|
208
|
-
const getVersion = async (): Promise<string | undefined> => {
|
|
209
|
-
const row = await settings.findOne({ key: "version" });
|
|
210
|
-
return typeof row?.value === "string" ? row.value : undefined;
|
|
211
|
-
};
|
|
212
|
-
const makeResult = async (
|
|
213
|
-
options: MigrateOptions = {},
|
|
214
|
-
): Promise<MigrationResult> => {
|
|
215
|
-
assertSupportedMigrationMode(options);
|
|
216
|
-
|
|
217
|
-
if ((await getVersion()) === HOT_UPDATER_SCHEMA_VERSION) {
|
|
218
|
-
return getEmptyResult();
|
|
219
|
-
}
|
|
220
|
-
const settingsOperation =
|
|
221
|
-
options.updateSettings === false
|
|
222
|
-
? undefined
|
|
223
|
-
: ({
|
|
224
|
-
type: "custom",
|
|
225
|
-
key: "version",
|
|
226
|
-
value: HOT_UPDATER_SCHEMA_VERSION,
|
|
227
|
-
} satisfies MigrationOperation);
|
|
228
|
-
return {
|
|
229
|
-
operations: createMongoMigrationOperations(settingsOperation),
|
|
230
|
-
execute: async () => {
|
|
231
|
-
const db = client.db();
|
|
232
|
-
for (const table of hotUpdaterSchema.tables) {
|
|
233
|
-
if (table.internal) continue;
|
|
234
|
-
await db
|
|
235
|
-
.createCollection(table.ormName)
|
|
236
|
-
.catch(ignoreExistingCollection);
|
|
237
|
-
}
|
|
238
|
-
await db.collection("bundles").createIndex(
|
|
239
|
-
{ id: 1 },
|
|
240
|
-
{
|
|
241
|
-
name: "bundles_id_idx",
|
|
242
|
-
},
|
|
243
|
-
);
|
|
244
|
-
for (const table of hotUpdaterSchema.tables) {
|
|
245
|
-
if (table.internal) continue;
|
|
246
|
-
for (const index of (table.indexes ?? []).filter((item) =>
|
|
247
|
-
schemaIndexAppliesToProvider(item, "mongodb"),
|
|
248
|
-
)) {
|
|
249
|
-
await db
|
|
250
|
-
.collection(table.ormName)
|
|
251
|
-
.createIndex(
|
|
252
|
-
Object.fromEntries(index.columns.map((column) => [column, 1])),
|
|
253
|
-
{ name: index.name },
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (options.updateSettings !== false) {
|
|
258
|
-
await settings.updateOne(
|
|
259
|
-
{ key: "version" },
|
|
260
|
-
{ $set: { value: HOT_UPDATER_SCHEMA_VERSION } },
|
|
261
|
-
{ upsert: true },
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
};
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
return {
|
|
269
|
-
getVersion,
|
|
270
|
-
getNameVariants: async () => undefined,
|
|
271
|
-
next: async () =>
|
|
272
|
-
(await getVersion()) === HOT_UPDATER_SCHEMA_VERSION
|
|
273
|
-
? undefined
|
|
274
|
-
: { version: HOT_UPDATER_SCHEMA_VERSION },
|
|
275
132
|
previous: async () => undefined,
|
|
276
133
|
up: makeResult,
|
|
277
134
|
down: async () => {
|
|
@@ -286,3 +143,5 @@ export const createMongoMigrator = (client: MongoClient): Migrator => {
|
|
|
286
143
|
migrateToLatest: makeResult,
|
|
287
144
|
};
|
|
288
145
|
};
|
|
146
|
+
|
|
147
|
+
export { createMongoMigrator } from "./fixedMigratorMongo";
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { MongoClient } from "mongodb";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { createInMemoryDatabasePlugin } from "../../../test-utils/test/inMemoryDatabasePlugin";
|
|
5
|
+
import { createDatabasePluginCore } from "./databasePluginCore";
|
|
6
|
+
import { createMongoMigrator } from "./fixedMigrator";
|
|
7
|
+
import { createSchemaReadinessChecker } from "./schemaReadiness";
|
|
8
|
+
|
|
9
|
+
function createSettingsMongoClient(
|
|
10
|
+
values: Readonly<Record<string, unknown>>,
|
|
11
|
+
): MongoClient {
|
|
12
|
+
return {
|
|
13
|
+
db: () => ({
|
|
14
|
+
collection: () => ({
|
|
15
|
+
find: ({ key }: { readonly key: string }) => ({
|
|
16
|
+
limit: () => ({
|
|
17
|
+
toArray: async () => {
|
|
18
|
+
const value = values[key];
|
|
19
|
+
return value === undefined ? [] : [{ key, value }];
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
}),
|
|
23
|
+
listIndexes: () => ({
|
|
24
|
+
toArray: async () => [{ key: { key: 1 }, unique: true }],
|
|
25
|
+
}),
|
|
26
|
+
}),
|
|
27
|
+
}),
|
|
28
|
+
} as unknown as MongoClient;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("MongoDB migration", () => {
|
|
32
|
+
it("creates schema 1.0.0 from an empty database", async () => {
|
|
33
|
+
const settings = new Map<string, unknown>();
|
|
34
|
+
const settingsCollection = {
|
|
35
|
+
find: ({ key }: { readonly key: string }) => ({
|
|
36
|
+
limit: () => ({
|
|
37
|
+
toArray: async () => {
|
|
38
|
+
const value = settings.get(key);
|
|
39
|
+
return value === undefined ? [] : [{ key, value }];
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
}),
|
|
43
|
+
createIndex: vi.fn(async (): Promise<string> => "key_1"),
|
|
44
|
+
listIndexes: () => ({ toArray: async () => [] }),
|
|
45
|
+
updateOne: async (
|
|
46
|
+
{ key }: { readonly key: string },
|
|
47
|
+
update: { readonly $set: { readonly value: unknown } },
|
|
48
|
+
) => void settings.set(key, update.$set.value),
|
|
49
|
+
};
|
|
50
|
+
const modelCollection = {
|
|
51
|
+
find: () => ({ toArray: async () => [] }),
|
|
52
|
+
listIndexes: () => ({ toArray: async () => [] }),
|
|
53
|
+
createIndex: async () => "created",
|
|
54
|
+
};
|
|
55
|
+
const command = vi.fn(
|
|
56
|
+
async (_input: Record<string, unknown>): Promise<void> => undefined,
|
|
57
|
+
);
|
|
58
|
+
const database = {
|
|
59
|
+
command,
|
|
60
|
+
createCollection: async () => undefined,
|
|
61
|
+
collection: (name: string) =>
|
|
62
|
+
name === "private_hot_updater_settings"
|
|
63
|
+
? settingsCollection
|
|
64
|
+
: modelCollection,
|
|
65
|
+
};
|
|
66
|
+
const client = { db: () => database } as unknown as MongoClient;
|
|
67
|
+
|
|
68
|
+
await (
|
|
69
|
+
await createMongoMigrator(client).migrateToLatest({
|
|
70
|
+
mode: "from-schema",
|
|
71
|
+
updateSettings: true,
|
|
72
|
+
})
|
|
73
|
+
).execute();
|
|
74
|
+
|
|
75
|
+
expect(settingsCollection.createIndex).toHaveBeenCalledWith(
|
|
76
|
+
{ key: 1 },
|
|
77
|
+
{ unique: true },
|
|
78
|
+
);
|
|
79
|
+
expect(settings.get("schema.core")).toBe("1.0.0");
|
|
80
|
+
const commands = command.mock.calls.map(([input]) => input);
|
|
81
|
+
expect(commands.find(({ collMod }) => collMod === "bundles")).toMatchObject(
|
|
82
|
+
{
|
|
83
|
+
validationAction: "error",
|
|
84
|
+
validationLevel: "strict",
|
|
85
|
+
validator: {
|
|
86
|
+
$and: [
|
|
87
|
+
{
|
|
88
|
+
$jsonSchema: {
|
|
89
|
+
properties: {
|
|
90
|
+
archive_byte_size: {
|
|
91
|
+
bsonType: ["double", "int", "long"],
|
|
92
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
93
|
+
minimum: 0,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: expect.arrayContaining(["archive_byte_size"]),
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
$expr: {
|
|
101
|
+
$eq: [{ $trunc: "$archive_byte_size" }, "$archive_byte_size"],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
expect(
|
|
109
|
+
commands.find(({ collMod }) => collMod === "bundle_patches"),
|
|
110
|
+
).toMatchObject({
|
|
111
|
+
validationAction: "error",
|
|
112
|
+
validationLevel: "strict",
|
|
113
|
+
validator: {
|
|
114
|
+
$and: [
|
|
115
|
+
{
|
|
116
|
+
$jsonSchema: {
|
|
117
|
+
properties: {
|
|
118
|
+
byte_size: {
|
|
119
|
+
bsonType: ["double", "int", "long"],
|
|
120
|
+
maximum: Number.MAX_SAFE_INTEGER,
|
|
121
|
+
minimum: 0,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
required: expect.arrayContaining(["byte_size"]),
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
$expr: {
|
|
129
|
+
$and: expect.arrayContaining([
|
|
130
|
+
{
|
|
131
|
+
$eq: [{ $trunc: "$byte_size" }, "$byte_size"],
|
|
132
|
+
},
|
|
133
|
+
]),
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("is a no-op when schema.core is already 1.0.0", async () => {
|
|
142
|
+
const client = createSettingsMongoClient({ "schema.core": "1.0.0" });
|
|
143
|
+
const migrator = createMongoMigrator(client);
|
|
144
|
+
|
|
145
|
+
await expect(migrator.getVersion()).resolves.toBe("1.0.0");
|
|
146
|
+
await expect(
|
|
147
|
+
migrator.migrateToLatest({ mode: "from-schema" }),
|
|
148
|
+
).resolves.toMatchObject({ operations: [] });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("ignores a leftover version marker when schema.core is 1.0.0", async () => {
|
|
152
|
+
const client = createSettingsMongoClient({
|
|
153
|
+
"schema.core": "1.0.0",
|
|
154
|
+
version: "0.36.0",
|
|
155
|
+
});
|
|
156
|
+
const migrator = createMongoMigrator(client);
|
|
157
|
+
|
|
158
|
+
await expect(migrator.getVersion()).resolves.toBe("1.0.0");
|
|
159
|
+
await expect(
|
|
160
|
+
migrator.migrateToLatest({ mode: "from-schema" }),
|
|
161
|
+
).resolves.toMatchObject({ operations: [] });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("rejects in-place upgrade from a v0 schema marker", async () => {
|
|
165
|
+
const client = createSettingsMongoClient({ "schema.core": "0.38.0" });
|
|
166
|
+
const migrator = createMongoMigrator(client);
|
|
167
|
+
|
|
168
|
+
await expect(
|
|
169
|
+
migrator.migrateToLatest({ mode: "from-schema" }),
|
|
170
|
+
).rejects.toThrow("Hot Updater v1 cannot migrate schema 0.38.0");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("blocks v0 schema readiness before reading bundle data", async () => {
|
|
174
|
+
const client = createSettingsMongoClient({ version: "0.36.0" });
|
|
175
|
+
const migrator = createMongoMigrator(client);
|
|
176
|
+
const plugin = createInMemoryDatabasePlugin();
|
|
177
|
+
const count = vi.spyOn(plugin.models.bundles, "count");
|
|
178
|
+
const findMany = vi.spyOn(plugin.models.bundles, "findMany");
|
|
179
|
+
const core = createDatabasePluginCore(plugin, async () => null, {
|
|
180
|
+
beforeOperation: createSchemaReadinessChecker(
|
|
181
|
+
"v0-mongodb",
|
|
182
|
+
() => migrator,
|
|
183
|
+
),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await expect(core.api.getBundles({ limit: 1 })).rejects.toThrow(
|
|
187
|
+
"Hot Updater v1 cannot migrate schema 0.36.0",
|
|
188
|
+
);
|
|
189
|
+
expect(count).not.toHaveBeenCalled();
|
|
190
|
+
expect(findMany).not.toHaveBeenCalled();
|
|
191
|
+
});
|
|
192
|
+
});
|