Introduce method to make store migrations injectable

- Use it for ClusterStore

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton committed 2022-12-06 09:18:58 -05:00
1 parent 3dce6f916e
commit ad814ebdf6
23 files changed
+395 -280

No files matched your search

+2 -2
View File
@@ -4,8 +4,8 @@
*/
import mockFs from "mock-fs";
import type { BaseStoreDependencies } from "../base-store";
import { BaseStore } from "../base-store";
import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store";
import { action, comparer, makeObservable, observable, toJS } from "mobx";
import { readFileSync } from "fs";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
@@ -5,19 +5,19 @@
import path from "path";
import type Config from "conf";
import type { Options as ConfOptions } from "conf/dist/source/types";
import type { Migrations, Options as ConfOptions } from "conf/dist/source/types";
import { ipcMain, ipcRenderer } from "electron";
import type { IEqualsComparer } from "mobx";
import { makeObservable, reaction, runInAction } from "mobx";
import type { Disposer } from "./utils";
import { isPromiseLike, toJS } from "./utils";
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "./ipc";
import type { Disposer } from "../utils";
import { isPromiseLike, toJS } from "../utils";
import { broadcastMessage, ipcMainOn, ipcRendererOn } from "../ipc";
import isEqual from "lodash/isEqual";
import { kebabCase } from "lodash";
import type { GetConfigurationFileModel } from "./get-configuration-file-model/get-configuration-file-model.injectable";
import type { Logger } from "./logger";
import type { GetConfigurationFileModel } from "../get-configuration-file-model/get-configuration-file-model.injectable";
import type { Logger } from "../logger";
export interface BaseStoreParams<T> extends ConfOptions<T> {
export interface BaseStoreParams<T> extends Omit<ConfOptions<T>, "migrations"> {
syncOptions?: {
fireImmediately?: boolean;
equals?: IEqualsComparer<T>;
@@ -29,6 +29,7 @@ export interface BaseStoreDependencies {
readonly logger: Logger;
readonly storeMigrationVersion: string;
readonly directoryForUserData: string;
readonly migrations: Migrations<Record<string, unknown>>;
getConfigurationFileModel: GetConfigurationFileModel;
}
@@ -39,7 +40,7 @@ export abstract class BaseStore<T extends object> {
protected storeConfig?: Config<T>;
protected syncDisposers: Disposer[] = [];
readonly displayName: string;
readonly displayName = this.params.configName;
protected constructor(
protected readonly dependencies: BaseStoreDependencies,
@@ -48,10 +49,6 @@ export abstract class BaseStore<T extends object> {
makeObservable(this);
this.displayName = this.params.configName;
if (ipcRenderer) {
this.params.migrations = undefined; // don't run migrations on renderer
}
}
/**
@@ -64,6 +61,7 @@ export abstract class BaseStore<T extends object> {
projectVersion: this.dependencies.storeMigrationVersion,
cwd: this.cwd(),
...this.params,
migrations: this.dependencies.migrations as Migrations<T>,
});
const res = this.fromStore(this.storeConfig.store);
@@ -0,0 +1,46 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { InjectionToken } from "@ogre-tools/injectable";
import { lifecycleEnum, getInjectable } from "@ogre-tools/injectable";
import type Conf from "conf/dist/source";
import type { Migrations } from "conf/dist/source/types";
import loggerInjectable from "../logger.injectable";
import { getOrInsert, iter } from "../utils";
export interface MigrationDeclaration {
version: string;
run(store: Conf<Partial<Record<string, unknown>>>): void;
}
const storeMigrationsInjectable = getInjectable({
id: "store-migrations",
instantiate: (di, token): Migrations<Record<string, unknown>> => {
const logger = di.inject(loggerInjectable);
const declarations = di.injectMany(token);
const migrations = new Map<string, MigrationDeclaration["run"][]>();
for (const decl of declarations) {
getOrInsert(migrations, decl.version, []).push(decl.run);
}
return Object.fromEntries(
iter.map(
migrations,
([v, fns]) => [v, (store) => {
logger.info(`Running ${v} migration for ${store.path}`);
for (const fn of fns) {
fn(store);
}
}],
),
);
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, token: InjectionToken<MigrationDeclaration, void>) => token.id,
}),
});
export default storeMigrationsInjectable;
@@ -11,6 +11,8 @@ import directoryForUserDataInjectable from "../app-paths/directory-for-user-data
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import loggerInjectable from "../logger.injectable";
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
import storeMigrationsInjectable from "../base-store/migrations.injectable";
import { clusterStoreMigrationInjectionToken } from "./migration-token";
const clusterStoreInjectable = getInjectable({
id: "cluster-store",
@@ -23,6 +25,7 @@ const clusterStoreInjectable = getInjectable({
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
logger: di.inject(loggerInjectable),
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
migrations: di.inject(storeMigrationsInjectable, clusterStoreMigrationInjectionToken),
}),
});
+3 -5
View File
@@ -6,10 +6,9 @@
import { ipcMain, ipcRenderer, webFrame } from "electron";
import { action, comparer, computed, makeObservable, observable, reaction } from "mobx";
import type { BaseStoreDependencies } from "../base-store";
import { BaseStore } from "../base-store";
import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store";
import { Cluster } from "../cluster/cluster";
import migrations from "../../migrations/cluster-store";
import { disposer, toJS } from "../utils";
import type { ClusterModel, ClusterId, ClusterState } from "../cluster-types";
import { requestInitialClusterStates } from "../../renderer/ipc";
@@ -31,7 +30,7 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
readonly displayName = "ClusterStore";
readonly clusters = observable.map<ClusterId, Cluster>();
protected disposer = disposer();
protected readonly disposer = disposer();
constructor(protected readonly dependencies: Dependencies) {
super(dependencies, {
@@ -40,7 +39,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
syncOptions: {
equals: comparer.structural,
},
migrations,
});
makeObservable(this);
@@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { MigrationDeclaration } from "../../migrations/helpers";
export const clusterStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
id: "cluster-store-migration",
});
@@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import fsInjectable from "./fs.injectable";
export type ReadFileBufferSync = (filePath: string) => Buffer;
const readFileBufferSyncInjectable = getInjectable({
id: "read-file-buffer-sync",
instantiate: (di): ReadFileBufferSync => {
const { readFileSync } = di.inject(fsInjectable);
return (filePath) => readFileSync(filePath);
},
});
export default readFileBufferSyncInjectable;
@@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import fsInjectable from "./fs.injectable";
const readJsonSyncInjectable = getInjectable({
id: "read-json-sync",
instantiate: (di) => di.inject(fsInjectable).readJsonSync,
});
export default readJsonSyncInjectable;
+2 -2
View File
@@ -4,8 +4,8 @@
*/
import { action, comparer, observable, makeObservable, computed } from "mobx";
import type { BaseStoreDependencies } from "../base-store";
import { BaseStore } from "../base-store";
import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store";
import migrations from "../../migrations/hotbar-store";
import { toJS } from "../utils";
import type { CatalogEntity } from "../catalog";
+2 -2
View File
@@ -5,8 +5,8 @@
import { app } from "electron";
import { action, observable, reaction, makeObservable, isObservableArray, isObservableSet, isObservableMap } from "mobx";
import type { BaseStoreDependencies } from "../base-store";
import { BaseStore } from "../base-store";
import type { BaseStoreDependencies } from "../base-store/base-store";
import { BaseStore } from "../base-store/base-store";
import migrations from "../../migrations/user-store";
import { getOrInsertSet, toggle, toJS, object } from "../../renderer/utils";
import { DESCRIPTORS } from "./preferences-helpers";
+2 -2
View File
@@ -4,8 +4,8 @@
*/
import { action, comparer, observable, makeObservable } from "mobx";
import type { BaseStoreDependencies } from "./base-store";
import { BaseStore } from "./base-store";
import type { BaseStoreDependencies } from "./base-store/base-store";
import { BaseStore } from "./base-store/base-store";
import migrations from "../migrations/weblinks-store";
import * as uuid from "uuid";
import { toJS } from "./utils";