@flumens/utils 0.4.0 → 0.5.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/MigrationManager.d.ts +100 -0
- package/dist/MigrationManager.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** ****************************************************************************
|
|
2
|
+
* Internal state migration functionality.
|
|
3
|
+
*
|
|
4
|
+
* Cases:
|
|
5
|
+
* - First run - no migrations needed, just set the version.
|
|
6
|
+
* - Versions match - no migrations needed, the state was already migrated.
|
|
7
|
+
* - Versions differ - run all migrations in sequence, starting from the first
|
|
8
|
+
* one that is greater than the current version.
|
|
9
|
+
* - If no migrations are found for the current version, just set the version.
|
|
10
|
+
*
|
|
11
|
+
* Each migration should be idempotent if possible, as it may be interrupted
|
|
12
|
+
* and re-run multiple times.
|
|
13
|
+
**************************************************************************** */
|
|
14
|
+
export type Migration = {
|
|
15
|
+
/** Semver version when this migration becomes relevant (inclusive). */
|
|
16
|
+
version: string;
|
|
17
|
+
/** Optional descriptive name for logging. */
|
|
18
|
+
name?: string;
|
|
19
|
+
/** The migration script. Keep it idempotent if possible. */
|
|
20
|
+
up: () => void | Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export default class MigrationsManager {
|
|
23
|
+
private migrations;
|
|
24
|
+
private newVersion;
|
|
25
|
+
private currentVersion;
|
|
26
|
+
private updateVersion;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new MigrationsManager instance.
|
|
29
|
+
*
|
|
30
|
+
* @param migrations - Array of migration objects to be applied
|
|
31
|
+
* @param newVersion - A function that returns the target version we want to migrate to
|
|
32
|
+
* @param currentVersion - A function that returns the last migrated version
|
|
33
|
+
* @param updateVersion - A function to persist the version after each migration
|
|
34
|
+
*/
|
|
35
|
+
constructor(migrations: Migration[], newVersion: () => string | Promise<string>, currentVersion: () => (string | null) | Promise<string | null>, updateVersion: (version: string) => Promise<void>);
|
|
36
|
+
/**
|
|
37
|
+
* Main update function.
|
|
38
|
+
*
|
|
39
|
+
* Flow:
|
|
40
|
+
* 1. If currentVersion === newVersion -> No migrations needed
|
|
41
|
+
* 2. If currentVersion is null -> First run, just set version
|
|
42
|
+
* 3. If currentVersion < newVersion -> Find and run applicable migrations
|
|
43
|
+
* 4. Each migration updates the version individually for interruption safety
|
|
44
|
+
*/
|
|
45
|
+
run(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Returns the index of the first found update in sequence.
|
|
48
|
+
*
|
|
49
|
+
* Finds the first migration whose version is greater than currentVersion.
|
|
50
|
+
* Since migrations are sorted, this is the starting point for running updates.
|
|
51
|
+
*
|
|
52
|
+
* Example:
|
|
53
|
+
* - currentVersion: "3.5.0"
|
|
54
|
+
* - migrations: ["2.0.0", "3.0.0", "4.0.0", "5.0.0"]
|
|
55
|
+
* - returns: index 2 (migration "4.0.0")
|
|
56
|
+
*
|
|
57
|
+
* @returns Index of first migration to run, or -1 if none found
|
|
58
|
+
*/
|
|
59
|
+
private findFirstMigrationIndex;
|
|
60
|
+
/**
|
|
61
|
+
* Recursively apply all updates.
|
|
62
|
+
*
|
|
63
|
+
* Runs migrations sequentially starting from migrationIndex.
|
|
64
|
+
* After each successful migration, the version is persisted immediately.
|
|
65
|
+
*
|
|
66
|
+
* Why persist after each migration?
|
|
67
|
+
* - If the app crashes or migration is interrupted, we don't re-run
|
|
68
|
+
* already completed migrations on next startup
|
|
69
|
+
* - Each migration should be idempotent to handle this scenario
|
|
70
|
+
*
|
|
71
|
+
* @param migrationIndex - Index in migrations array to start from
|
|
72
|
+
* @throws Rethrows any error from migration.up() to halt the process
|
|
73
|
+
*/
|
|
74
|
+
private applyUpdates;
|
|
75
|
+
/**
|
|
76
|
+
* https://gist.github.com/alexey-bass/1115557
|
|
77
|
+
* Simply compares left version to right one.
|
|
78
|
+
*
|
|
79
|
+
* Compares semantic version strings numerically, part by part.
|
|
80
|
+
* Handles versions with different segment counts (e.g., "1.2" vs "1.2.3").
|
|
81
|
+
*
|
|
82
|
+
* Examples:
|
|
83
|
+
* versionCompare('1.1', '1.2') => -1 (1.1 is lower)
|
|
84
|
+
* versionCompare('1.1', '1.1') => 0 (equal)
|
|
85
|
+
* versionCompare('1.2', '1.1') => 1 (1.2 is higher)
|
|
86
|
+
* versionCompare('2.23.3', '2.22.3') => 1
|
|
87
|
+
* versionCompare('1.0', '1.0.1') => -1 (missing segments treated as 0)
|
|
88
|
+
*
|
|
89
|
+
* Returns:
|
|
90
|
+
* -1 = left is LOWER than right
|
|
91
|
+
* 0 = they are equal (or invalid input)
|
|
92
|
+
* 1 = left is GREATER than right
|
|
93
|
+
*
|
|
94
|
+
* Note: Returns 0 for invalid input instead of throwing
|
|
95
|
+
*
|
|
96
|
+
* @param left - First version string (e.g., "1.2.3")
|
|
97
|
+
* @param right - Second version string (e.g., "1.2.4")
|
|
98
|
+
*/
|
|
99
|
+
private static versionCompare;
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const t=require("tslib");class i{constructor(t,e,r,s){this.migrations=t,this.newVersion=e,this.currentVersion=r,this.updateVersion=s;this.migrations.sort(((t,e)=>{const r=i.versionCompare(t.version,e.version);return 1===r?1:-1===r?-1:0}))}run(){return t.__awaiter(this,void 0,void 0,(function*(){const t=yield this.currentVersion(),i=yield this.newVersion();if(t!==i){if(!this.currentVersion)return console.log(`First run - setting version to ${i}`),void(yield this.updateVersion(i));const e=this.findFirstMigrationIndex(t);if(e<0)return;yield this.applyUpdates(e)}}))}findFirstMigrationIndex(t){if(!this.migrations.length)return-1;let e=-1;return this.migrations.some(((r,s)=>1===i.versionCompare(r.version,t)&&(e=s,!0))),e}applyUpdates(i){return t.__awaiter(this,void 0,void 0,(function*(){const t=this.migrations[i];try{console.log(`Update: ${t.version} ${t.name||""}`),yield t.up(),yield this.updateVersion(t.version)}catch(t){throw console.error(t),t}this.migrations.length-1<=i||(yield this.applyUpdates(i+1))}))}static versionCompare(t,i){if(typeof t+typeof i!="stringstring")return 0;const e=t.split("."),r=i.split("."),s=Math.max(e.length,r.length);for(let t=0;t<s;t++){if(e[t]&&!r[t]&&parseInt(e[t],10)>0||parseInt(e[t],10)>parseInt(r[t],10))return 1;if(r[t]&&!e[t]&&parseInt(r[t],10)>0||parseInt(e[t],10)<parseInt(r[t],10))return-1}return 0}}exports.default=i;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.device=exports.string=void 0;const e=require("tslib");var r=require("./string.js");Object.defineProperty(exports,"string",{enumerable:!0,get:function(){return e.__importDefault(r).default}});var t=require("./device.js");Object.defineProperty(exports,"device",{enumerable:!0,get:function(){return e.__importDefault(t).default}}),e.__exportStar(require("./deferred.js"),exports),e.__exportStar(require("./date.js"),exports),e.__exportStar(require("./image.js"),exports),e.__exportStar(require("./location.js"),exports),e.__exportStar(require("./type.js"),exports),e.__exportStar(require("./sentry.js"),exports),e.__exportStar(require("./errors.js"),exports),e.__exportStar(require("./platform.js"),exports),e.__exportStar(require("./uuid.js"),exports);
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.device=exports.string=void 0;const e=require("tslib");var r=require("./string.js");Object.defineProperty(exports,"string",{enumerable:!0,get:function(){return e.__importDefault(r).default}});var t=require("./device.js");Object.defineProperty(exports,"device",{enumerable:!0,get:function(){return e.__importDefault(t).default}}),e.__exportStar(require("./deferred.js"),exports),e.__exportStar(require("./date.js"),exports),e.__exportStar(require("./image.js"),exports),e.__exportStar(require("./location.js"),exports),e.__exportStar(require("./type.js"),exports),e.__exportStar(require("./sentry.js"),exports),e.__exportStar(require("./errors.js"),exports),e.__exportStar(require("./platform.js"),exports),e.__exportStar(require("./uuid.js"),exports),e.__exportStar(require("./MigrationManager.js"),exports);
|