breaking: rework how links database migrations are managed (#8162)

This commit is contained in:
Adrien de Peretti authored and GitHub committed 2024-07-22 13:12:23 +05:30
1 parent f435c6c7f6
commit f74fdcb644
24 files changed
+1090 -264

No files matched your search

@@ -40,8 +40,25 @@ export async function initDb({
try {
const {
runMedusaAppMigrations,
getLinksExecutionPlanner,
} = require("@medusajs/medusa/dist/loaders/medusa-app")
await runMedusaAppMigrations({ configModule, container })
const planner = await getLinksExecutionPlanner({
configModule,
container,
})
const actionPlan = await planner.createPlan()
await planner.executePlan(actionPlan)
/**
* cleanup temporary created resources for the migrations
* @internal I didnt find a god place to put that, should we eventually add a close function
* to the planner to handle that part? so that you would do planner.close() and it will handle the cleanup
* automatically just like we usually do for the classic migrations actions
*/
const { MedusaModule } = require("@medusajs/modules-sdk")
MedusaModule.clearInstances()
} catch (err) {
console.error("Something went wrong while running the migrations")
throw err
+49 -58
View File
@@ -1,9 +1,10 @@
import { mergeTypeDefs } from "@graphql-tools/merge"
import { makeExecutableSchema } from "@graphql-tools/schema"
import { RemoteFetchDataCallback } from "@medusajs/orchestration"
import type {
import {
ConfigModule,
ExternalModuleDeclaration,
ILinkMigrationsPlanner,
InternalModuleDeclaration,
LoadedModule,
Logger,
@@ -38,8 +39,8 @@ import {
} from "./medusa-module"
import { RemoteLink } from "./remote-link"
import { RemoteQuery } from "./remote-query"
import { MODULE_RESOURCE_TYPE, MODULE_SCOPE } from "./types"
import { cleanGraphQLSchema } from "./utils"
import { MODULE_RESOURCE_TYPE, MODULE_SCOPE } from "./types"
const LinkModulePackage = MODULE_PACKAGE_NAMES[Modules.LINK]
@@ -56,6 +57,7 @@ declare module "@medusajs/types" {
export type RunMigrationFn = () => Promise<void>
export type RevertMigrationFn = (moduleNames: string[]) => Promise<void>
export type GenerateMigrations = (moduleNames: string[]) => Promise<void>
export type GetLinkExecutionPlanner = () => ILinkMigrationsPlanner
export type MedusaModuleConfig = {
[key: string | Modules]:
@@ -164,7 +166,7 @@ async function initializeLinks({
moduleExports,
}) {
try {
const { initialize, runMigrations, revertMigrations } =
const { initialize, getMigrationPlanner } =
moduleExports ?? (await import(LinkModulePackage))
const linkResolution = await initialize(
@@ -176,16 +178,14 @@ async function initializeLinks({
return {
remoteLink: new RemoteLink(),
linkResolution,
runMigrations,
revertMigrations,
getMigrationPlanner,
}
} catch (err) {
console.warn("Error initializing link modules.", err)
return {
remoteLink: undefined,
linkResolution: undefined,
runMigrations: () => void 0,
revertMigrations: () => void 0,
getMigrationPlanner: () => void 0,
}
}
}
@@ -231,6 +231,7 @@ export type MedusaAppOutput = {
runMigrations: RunMigrationFn
revertMigrations: RevertMigrationFn
generateMigrations: GenerateMigrations
linkMigrationExecutionPlanner: GetLinkExecutionPlanner
onApplicationShutdown: () => Promise<void>
onApplicationPrepareShutdown: () => Promise<void>
onApplicationStart: () => Promise<void>
@@ -369,6 +370,11 @@ async function MedusaApp_({
generateMigrations: async () => {
throw new Error("Generate migrations not allowed in loaderOnly mode")
},
linkMigrationExecutionPlanner: () => {
throw new Error(
"Migrations planner is not avaibable in loaderOnly mode"
)
},
}
}
@@ -392,11 +398,7 @@ async function MedusaApp_({
}
}
const {
remoteLink,
runMigrations: linkModuleMigration,
revertMigrations: revertLinkModuleMigration,
} = await initializeLinks({
const { remoteLink, getMigrationPlanner } = await initializeLinks({
config: linkModuleOrOptions,
linkModules,
injectedDependencies,
@@ -479,7 +481,27 @@ async function MedusaApp_({
await applyMigration({
modulesNames: Object.keys(allModules),
})
}
const revertMigrations: RevertMigrationFn = async (
modulesNames
): Promise<void> => {
await applyMigration({
modulesNames,
action: "revert",
})
}
const generateMigrations: GenerateMigrations = async (
modulesNames
): Promise<void> => {
await applyMigration({
modulesNames,
action: "generate",
})
}
const getMigrationPlannerFn = () => {
const options: Partial<ModuleServiceInitializeOptions> =
"scope" in linkModuleOrOptions
? { ...linkModuleOrOptions.options }
@@ -491,52 +513,7 @@ async function MedusaApp_({
...sharedResourcesConfig?.database,
}
await linkModuleMigration(
{
options,
injectedDependencies,
},
linkModules
)
}
const revertMigrations: RevertMigrationFn = async (
modulesNames
): Promise<void> => {
await applyMigration({
modulesNames,
action: "revert",
})
// TODO: Temporarely disabling this part until we discussed a more appropriate approach to sync the link
// Currently it would revert all link as soon as the revert is run
/*const options: Partial<ModuleServiceInitializeOptions> =
"scope" in linkModuleOrOptions
? { ...linkModuleOrOptions.options }
: {
...(linkModuleOrOptions as Partial<ModuleServiceInitializeOptions>),
}
options.database ??= {
...sharedResourcesConfig?.database,
}
await revertLinkModuleMigration(
{
options,
injectedDependencies,
},
linkModules
)*/
}
const generateMigrations: GenerateMigrations = async (
modulesNames
): Promise<void> => {
await applyMigration({
modulesNames,
action: "generate",
})
return getMigrationPlanner(options, linkModules)
}
return {
@@ -551,6 +528,7 @@ async function MedusaApp_({
runMigrations,
revertMigrations,
generateMigrations,
linkMigrationExecutionPlanner: getMigrationPlannerFn,
sharedContainer: sharedContainer_,
}
}
@@ -601,3 +579,16 @@ export async function MedusaAppMigrateGenerate(
await generateMigrations(moduleNames).finally(MedusaModule.clearInstances)
}
export async function MedusaAppGetLinksExecutionPlanner(
options: MedusaAppOptions = {}
): Promise<ILinkMigrationsPlanner> {
const migrationOnly = true
const { linkMigrationExecutionPlanner } = await MedusaApp_({
...options,
migrationOnly,
})
return linkMigrationExecutionPlanner()
}
@@ -170,6 +170,7 @@ class MedusaModule {
MedusaModule.modules_.clear()
MedusaModule.joinerConfig_.clear()
MedusaModule.moduleResolutions_.clear()
MedusaModule.customLinks_.length = 0
}
public static isInstalled(moduleKey: string, alias?: string): boolean {
+2 -47
View File
@@ -1,47 +1,2 @@
import { FindConfig } from "../common"
import { RestoreReturn, SoftDeleteReturn } from "../dal"
import { IModuleService } from "../modules-sdk"
import { Context } from "../shared-context"
export interface ILinkModule extends IModuleService {
list(
filters?: Record<string, unknown>,
config?: FindConfig<unknown>,
sharedContext?: Context
): Promise<unknown[]>
listAndCount(
filters?: Record<string, unknown>,
config?: FindConfig<unknown>,
sharedContext?: Context
): Promise<[unknown[], number]>
create(
primaryKeyOrBulkData:
| string
| string[]
| [string | string[], string, Record<string, unknown>?][],
foreignKeyData?: string,
sharedContext?: Context
): Promise<unknown[]>
dismiss(
primaryKeyOrBulkData: string | string[] | [string | string[], string][],
foreignKeyData?: string,
sharedContext?: Context
): Promise<unknown[]>
delete(data: unknown | unknown[], sharedContext?: Context): Promise<void>
softDelete(
data: unknown | unknown[],
config?: SoftDeleteReturn,
sharedContext?: Context
): Promise<Record<string, unknown[]> | void>
restore(
data: unknown | unknown[],
config?: RestoreReturn,
sharedContext?: Context
): Promise<Record<string, unknown[]> | void>
}
export * from "./service"
export * from "./migrations"
@@ -0,0 +1,37 @@
/**
* Link descriptor containing metadata about the link's
* modules and models.
*/
export type PlannerActionLinkDescriptor = {
fromModule: string
toModule: string
fromModel: string
toModel: string
}
/**
* A list of actions prepared and executed by
* the "ILinkMigrationsPlanner".
*/
export type LinkMigrationsPlannerAction =
| {
action: "create" | "update" | "notify"
linkDescriptor: PlannerActionLinkDescriptor
sql: string
tableName: string
}
| {
action: "noop"
tableName: string
linkDescriptor: PlannerActionLinkDescriptor
}
| {
action: "delete"
linkDescriptor: PlannerActionLinkDescriptor
tableName: string
}
export interface ILinkMigrationsPlanner {
createPlan(): Promise<LinkMigrationsPlannerAction[]>
executePlan(actions: LinkMigrationsPlannerAction[]): Promise<void>
}
@@ -0,0 +1,47 @@
import { FindConfig } from "../common"
import { RestoreReturn, SoftDeleteReturn } from "../dal"
import { IModuleService } from "../modules-sdk"
import { Context } from "../shared-context"
export interface ILinkModule extends IModuleService {
list(
filters?: Record<string, unknown>,
config?: FindConfig<unknown>,
sharedContext?: Context
): Promise<unknown[]>
listAndCount(
filters?: Record<string, unknown>,
config?: FindConfig<unknown>,
sharedContext?: Context
): Promise<[unknown[], number]>
create(
primaryKeyOrBulkData:
| string
| string[]
| [string | string[], string, Record<string, unknown>?][],
foreignKeyData?: string,
sharedContext?: Context
): Promise<unknown[]>
dismiss(
primaryKeyOrBulkData: string | string[] | [string | string[], string][],
foreignKeyData?: string,
sharedContext?: Context
): Promise<unknown[]>
delete(data: unknown | unknown[], sharedContext?: Context): Promise<void>
softDelete(
data: unknown | unknown[],
config?: SoftDeleteReturn,
sharedContext?: Context
): Promise<Record<string, unknown[]> | void>
restore(
data: unknown | unknown[],
config?: RestoreReturn,
sharedContext?: Context
): Promise<Record<string, unknown[]> | void>
}
@@ -34,7 +34,7 @@ type ExtraOptions = {
[key: string]: string
}
database?: {
table: string
table?: string
idPrefix?: string
extraColumns?: LinkModulesExtraFields
}
@@ -41,7 +41,7 @@ export type ModelsConfigTemplate = { [key: string]: ModelDTOConfig }
export type ModelConfigurationsToConfigTemplate<T extends ModelEntries> = {
[Key in keyof T]: {
dto: T[Key] extends IDmlEntity<any, any>
dto: T[Key] extends DmlEntity<any, any>
? InferEntityType<T[Key]>
: T[Key] extends Constructor<any>
? InstanceType<T[Key]>
@@ -261,7 +261,8 @@ type InferModelFromConfig<T> = {
: never
}
export type MedusaServiceReturnType<ModelsConfig extends Record<any, any>> = {
new (...args: any[]): AbstractModuleService<ModelsConfig>
$modelObjects: InferModelFromConfig<ModelsConfig>
}
export type MedusaServiceReturnType<ModelsConfig extends Record<string, any>> =
{
new (...args: any[]): AbstractModuleService<ModelsConfig>
$modelObjects: InferModelFromConfig<ModelsConfig>
}