Skip to content

Commit

Permalink
feat: allow loading predefined migrations from proper exports (#9872)
Browse files Browse the repository at this point in the history
Currently, predefined migrations can only be loaded if they are part of
one of our db adapters.

With this PR, plugins will be able to export their own predefined
migrations that can be created like this:

`pnpm payload migrate:create --file
@payloadcms/plugin-someplugin/someMigration`

with the plugin exporting it in their package.json:

```json
  "exports": {
    "./someMigration": {
      "import": "./someMigration.mjs",
      "types": "./someMigration.mjs",
      "default": "./someMigration.mjs"
    }
  },
```
  • Loading branch information
AlessioGr authored Dec 12, 2024
1 parent 9d324ff commit d4d79c1
Showing 1 changed file with 25 additions and 5 deletions.
30 changes: 25 additions & 5 deletions packages/payload/src/database/migrations/getPredefinedMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ export const getPredefinedMigration = async ({
}): Promise<MigrationTemplateArgs> => {
// Check for predefined migration.
// Either passed in via --file or prefixed with '@payloadcms/db-mongodb/' for example
if (file || migrationNameArg?.startsWith('@payloadcms/')) {
const importPath = file ?? migrationNameArg

if (importPath?.startsWith('@payloadcms/db-')) {
// removes the package name from the migrationName.
const migrationName = (file || migrationNameArg).split('/').slice(2).join('/')
const migrationName = importPath.split('/').slice(2).join('/')
let cleanPath = path.join(dirname, `./predefinedMigrations/${migrationName}`)

if (fs.existsSync(`${cleanPath}.mjs`)) {
cleanPath = `${cleanPath}.mjs`
} else if (fs.existsSync(`${cleanPath}.js`)) {
Expand All @@ -36,19 +37,38 @@ export const getPredefinedMigration = async ({
})
process.exit(1)
}

cleanPath = cleanPath.replaceAll('\\', '/')
const moduleURL = pathToFileURL(cleanPath)
try {
const { downSQL, imports, upSQL } = await eval(`import('${moduleURL.href}')`)
return { downSQL, imports, upSQL }
return {
downSQL,
imports,
upSQL,
}
} catch (err) {
payload.logger.error({
err,
msg: `Error loading predefined migration ${migrationName}`,
})
process.exit(1)
}
} else if (importPath) {
try {
const { downSQL, imports, upSQL } = await eval(`import('${importPath}')`)
return {
downSQL,
imports,
upSQL,
}
} catch (_err) {
if (importPath?.includes('/')) {
// We can assume that the intent was to import a file, thus we throw an error.
throw new Error(`Error importing migration file from ${importPath}`)
}
// Silently fail. If the migration cannot be imported, it will be created as a blank migration and the import path will be used as the migration name.
return {}
}
}
return {}
}

0 comments on commit d4d79c1

Please sign in to comment.