Skip to content

Commit

Permalink
feat(core): remove static require calls (#3814)
Browse files Browse the repository at this point in the history
There were some places where we did a static `require()` call, e.g. when
loading the driver implementation based on the `type` option. Those
places were problematic for bundlers like webpack, as well as new school
build systems like vite.

Instead of specifying the `type` we now have several options:

1. use `defineConfig()` helper imported from the driver package to
create your ORM config:
   ```ts title='mikro-orm.config.ts'
   import { defineConfig } from '@mikro-orm/mysql';

   export default defineConfig({ ... });
   ```
3. use `MikroORM.init()` on class imported from the driver package:
   ```ts title='app.ts'
   import { MikroORM } from '@mikro-orm/mysql';

   const orm = await MikroORM.init({ ... });
   ```
5. specify the `driver` option:
   ```ts title='mikro-orm.config.ts'
   import { MySqlDriver } from '@mikro-orm/mysql';

   export default { driver: MySqlDriver, ... };
   ```

> The `MIKRO_ORM_TYPE` is still supported, but no longer does a static
require of the driver class. Its usage is rather discouraged and it
might be removed in future versions too.

Similarly, we had to get rid of the `require()` calls for extensions
like `Migrator`, `EntityGenerator` and `Seeder`. Those need to be
registered as extensions in your ORM config. `SchemaGenerator` extension
is registered automatically.

> This is required only for the shortcuts available on `MikroORM`
object, e.g. `orm.migrator.up()`, alternatively you can instantiate the
`Migrator` yourself explicitly.

```ts title='mikro-orm.config.ts'
import { defineConfig } from '@mikro-orm/mysql';
import { Migrator } from '@mikro-orm/migrations';
import { EntityGenerator } from '@mikro-orm/entity-generator';
import { SeedManager } from '@mikro-orm/seeder';

export default defineConfig({
  dbName: 'test',
  extensions: [Migrator, EntityGenerator, SeedManager], // those would have a static `register` method
});
```

Closes #3743
  • Loading branch information
B4nan committed Apr 12, 2023
1 parent 5c69b66 commit a82b930
Show file tree
Hide file tree
Showing 48 changed files with 194 additions and 587 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Expand Up @@ -186,7 +186,7 @@ jobs:
name: Publish
if: github.ref == 'refs/heads/v6' && !contains(github.event.head_commit.message, '[skip ci]')
runs-on: ubuntu-latest
# needs: [ test, build, lint ]
needs: [ test, build, lint ]
steps:
- name: Checkout Source code
uses: actions/checkout@v3
Expand Down
61 changes: 61 additions & 0 deletions docs/docs/upgrading-v5-to-v6.md
Expand Up @@ -11,3 +11,64 @@ Support for older node versions was dropped.
## TypeScript 4.9+ required

Support for older TypeScript versions was dropped.

## Removal of static require calls

There were some places where we did a static `require()` call, e.g. when loading the driver implementation based on the `type` option. Those places were problematic for bundlers like webpack, as well as new school build systems like vite.

### The `type` option is removed in favour of driver exports

Instead of specifying the `type` we now have several options:

1. use `defineConfig()` helper imported from the driver package to create your ORM config:
```ts title='mikro-orm.config.ts'
import { defineConfig } from '@mikro-orm/mysql';

export default defineConfig({ ... });
```
2. use `MikroORM.init()` on class imported from the driver package:
```ts title='app.ts'
import { MikroORM } from '@mikro-orm/mysql';

const orm = await MikroORM.init({ ... });
```
3. specify the `driver` option:
```ts title='mikro-orm.config.ts'
import { MySqlDriver } from '@mikro-orm/mysql';

export default {
driver: MySqlDriver,
...
};
```

> The `MIKRO_ORM_TYPE` is still supported, but no longer does a static require of the driver class. Its usage is rather discouraged and it might be removed in future versions too.
### ORM extensions

Similarly, we had to get rid of the `require()` calls for extensions like `Migrator`, `EntityGenerator` and `Seeder`. Those need to be registered as extensions in your ORM config. `SchemaGenerator` extension is registered automatically.

> This is required only for the shortcuts available on `MikroORM` object, e.g. `orm.migrator.up()`, alternatively you can instantiate the `Migrator` yourself explicitly.
```ts title='mikro-orm.config.ts'
import { defineConfig } from '@mikro-orm/mysql';
import { Migrator } from '@mikro-orm/migrations';
import { EntityGenerator } from '@mikro-orm/entity-generator';
import { SeedManager } from '@mikro-orm/seeder';

export default defineConfig({
dbName: 'test',
extensions: [Migrator, EntityGenerator, SeedManager], // those would have a static `register` method
});
```

## `MikroORM.init()` no longer accepts a `Configuration` instance

The options always needs to be plain JS object now. This was always only an internal way, partially useful in tests, never meant to be a user API (while many people since the infamous Ben Awad video mistakenly complicated their typings with it).

## Removed `MongoDriver` methods

- `createCollections` in favour of `orm.schema.createSchema()`
- `dropCollections` in favour of `orm.schema.dropSchema()`
- `refreshCollections` in favour of `orm.schema.refreshDatabase()`
- `ensureIndexes` in favour of `orm.schema.ensureIndexes()`
1 change: 0 additions & 1 deletion lerna.json
Expand Up @@ -14,7 +14,6 @@
"**/tests/**",
"**/*.md"
],
"useNx": false,
"npmClient": "yarn",
"useWorkspaces": true
}
16 changes: 1 addition & 15 deletions packages/better-sqlite/package.json
Expand Up @@ -67,20 +67,6 @@
"@mikro-orm/core": "^5.6.16"
},
"peerDependencies": {
"@mikro-orm/core": "^5.0.0",
"@mikro-orm/entity-generator": "^5.0.0",
"@mikro-orm/migrations": "^5.0.0",
"@mikro-orm/seeder": "^5.0.0"
},
"peerDependenciesMeta": {
"@mikro-orm/entity-generator": {
"optional": true
},
"@mikro-orm/migrations": {
"optional": true
},
"@mikro-orm/seeder": {
"optional": true
}
"@mikro-orm/core": "^5.0.0"
}
}
49 changes: 0 additions & 49 deletions packages/cli/package.json
Expand Up @@ -68,54 +68,5 @@
"fs-extra": "11.1.1",
"tsconfig-paths": "4.2.0",
"yargs": "15.4.1"
},
"devDependencies": {
"@mikro-orm/entity-generator": "^5.6.16",
"@mikro-orm/migrations": "^5.6.16",
"@mikro-orm/seeder": "^5.6.16"
},
"peerDependencies": {
"@mikro-orm/better-sqlite": "^5.0.0",
"@mikro-orm/entity-generator": "^5.0.0",
"@mikro-orm/mariadb": "^5.0.0",
"@mikro-orm/migrations": "^5.0.0",
"@mikro-orm/migrations-mongodb": "^5.0.0",
"@mikro-orm/mongodb": "^5.0.0",
"@mikro-orm/mysql": "^5.0.0",
"@mikro-orm/postgresql": "^5.0.0",
"@mikro-orm/seeder": "^5.0.0",
"@mikro-orm/sqlite": "^5.0.0"
},
"peerDependenciesMeta": {
"@mikro-orm/better-sqlite": {
"optional": true
},
"@mikro-orm/entity-generator": {
"optional": true
},
"@mikro-orm/mariadb": {
"optional": true
},
"@mikro-orm/migrations": {
"optional": true
},
"@mikro-orm/migrations-mongodb": {
"optional": true
},
"@mikro-orm/mongodb": {
"optional": true
},
"@mikro-orm/mysql": {
"optional": true
},
"@mikro-orm/postgresql": {
"optional": true
},
"@mikro-orm/seeder": {
"optional": true
},
"@mikro-orm/sqlite": {
"optional": true
}
}
}
4 changes: 1 addition & 3 deletions packages/cli/src/CLIHelper.ts
@@ -1,7 +1,5 @@
import { pathExists } from 'fs-extra';
import yargs from 'yargs';
import { platform } from 'os';
import { fileURLToPath } from 'url';
import type { Configuration, IDatabaseDriver, Options } from '@mikro-orm/core';
import { colors, ConfigurationLoader, MikroORM, Utils } from '@mikro-orm/core';

Expand Down Expand Up @@ -35,7 +33,7 @@ export class CLIHelper {
options.get('discovery').warnWhenNoEntities = warnWhenNoEntities;
}

return MikroORM.init(options);
return MikroORM.init(options.getAll());
}

static async isDBConnected(): Promise<boolean> {
Expand Down
10 changes: 5 additions & 5 deletions packages/cli/src/commands/GenerateEntitiesCommand.ts
@@ -1,6 +1,4 @@
import type { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
import { Utils } from '@mikro-orm/core';
import type { EntityManager } from '@mikro-orm/knex';
import { CLIHelper } from '../CLIHelper';

export type Options = { dump: boolean; save: boolean; path: string; schema: string };
Expand Down Expand Up @@ -46,9 +44,11 @@ export class GenerateEntitiesCommand<U extends Options = Options> implements Com
}

const orm = await CLIHelper.getORM(false);
const { EntityGenerator } = await Utils.dynamicImport('@mikro-orm/entity-generator');
const generator = new EntityGenerator(orm.em as EntityManager);
const dump = await generator.generate({ save: args.save, baseDir: args.path, schema: args.schema });
const dump = await orm.entityGenerator.generate({
save: args.save,
baseDir: args.path,
schema: args.schema,
});

if (args.dump) {
CLIHelper.dump(dump.join('\n\n'));
Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/commands/MigrationCommandFactory.ts
@@ -1,7 +1,6 @@
import type { ArgumentsCamelCase, Argv, CommandModule } from 'yargs';
import type { Configuration, MikroORM, MikroORMOptions, IMigrator } from '@mikro-orm/core';
import type { Configuration, MikroORM, MikroORMOptions, IMigrator, MigrateOptions } from '@mikro-orm/core';
import { Utils, colors } from '@mikro-orm/core';
import type { MigrateOptions } from '@mikro-orm/migrations';
import { CLIHelper } from '../CLIHelper';

export class MigrationCommandFactory {
Expand Down
44 changes: 0 additions & 44 deletions packages/core/package.json
Expand Up @@ -65,49 +65,5 @@
"globby": "11.1.0",
"mikro-orm": "~5.6.16",
"reflect-metadata": "0.1.13"
},
"peerDependencies": {
"@mikro-orm/better-sqlite": "^5.0.0",
"@mikro-orm/entity-generator": "^5.0.0",
"@mikro-orm/mariadb": "^5.0.0",
"@mikro-orm/migrations": "^5.0.0",
"@mikro-orm/migrations-mongodb": "^5.0.0",
"@mikro-orm/mongodb": "^5.0.0",
"@mikro-orm/mysql": "^5.0.0",
"@mikro-orm/postgresql": "^5.0.0",
"@mikro-orm/seeder": "^5.0.0",
"@mikro-orm/sqlite": "^5.0.0"
},
"peerDependenciesMeta": {
"@mikro-orm/better-sqlite": {
"optional": true
},
"@mikro-orm/entity-generator": {
"optional": true
},
"@mikro-orm/mariadb": {
"optional": true
},
"@mikro-orm/migrations": {
"optional": true
},
"@mikro-orm/migrations-mongodb": {
"optional": true
},
"@mikro-orm/mongodb": {
"optional": true
},
"@mikro-orm/mysql": {
"optional": true
},
"@mikro-orm/postgresql": {
"optional": true
},
"@mikro-orm/seeder": {
"optional": true
},
"@mikro-orm/sqlite": {
"optional": true
}
}
}
29 changes: 11 additions & 18 deletions packages/core/src/MikroORM.ts
Expand Up @@ -25,24 +25,23 @@ export class MikroORM<D extends IDatabaseDriver = IDatabaseDriver> {
* Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
* If you omit the `options` parameter, your CLI config will be used.
*/
static async init<D extends IDatabaseDriver = IDatabaseDriver>(options?: Options<D> | Configuration<D>, connect = true): Promise<MikroORM<D>> {
static async init<D extends IDatabaseDriver = IDatabaseDriver>(options?: Options<D>, connect = true): Promise<MikroORM<D>> {
ConfigurationLoader.registerDotenv(options);
const coreVersion = await ConfigurationLoader.checkPackageVersion();
const env = ConfigurationLoader.loadEnvironmentVars<D>();

if (!options) {
options = await ConfigurationLoader.getConfiguration<D>();
options = (await ConfigurationLoader.getConfiguration<D>()).getAll();
}

let opts = options instanceof Configuration ? options.getAll() : options;
opts = Utils.merge(opts, env);
await ConfigurationLoader.commonJSCompat(opts as object);
options = Utils.merge(options, env);
await ConfigurationLoader.commonJSCompat(options!);

if ('DRIVER' in this && !opts.driver && !opts.type) {
(opts as Options).driver = (this as unknown as { DRIVER: Constructor<IDatabaseDriver> }).DRIVER;
if ('DRIVER' in this && !options!.driver) {
(options as Options).driver = (this as unknown as { DRIVER: Constructor<IDatabaseDriver> }).DRIVER;
}

const orm = new MikroORM(opts);
const orm = new MikroORM(options!);
orm.logger.log('info', `MikroORM version: ${colors.green(coreVersion)}`);

// we need to allow global context here as we are not in a scope of requests yet
Expand Down Expand Up @@ -177,9 +176,8 @@ export class MikroORM<D extends IDatabaseDriver = IDatabaseDriver> {
return extension;
}

// TODO remove in v6 (https://github.com/mikro-orm/mikro-orm/issues/3743)
/* istanbul ignore next */
return this.driver.getPlatform().getSchemaGenerator(this.driver, this.em) as any;
throw new Error(`SchemaGenerator extension not registered.`);
}

/**
Expand All @@ -192,8 +190,7 @@ export class MikroORM<D extends IDatabaseDriver = IDatabaseDriver> {
return extension;
}

// TODO remove in v6 (https://github.com/mikro-orm/mikro-orm/issues/3743)
return this.driver.getPlatform().getEntityGenerator(this.em) as T;
throw new Error(`EntityGenerator extension not registered.`);
}

/**
Expand All @@ -206,8 +203,7 @@ export class MikroORM<D extends IDatabaseDriver = IDatabaseDriver> {
return extension;
}

// TODO remove in v6 (https://github.com/mikro-orm/mikro-orm/issues/3743)
return this.driver.getPlatform().getMigrator(this.em) as T;
throw new Error(`Migrator extension not registered.`);
}

/**
Expand All @@ -220,10 +216,7 @@ export class MikroORM<D extends IDatabaseDriver = IDatabaseDriver> {
return extension;
}

// TODO remove in v6 (https://github.com/mikro-orm/mikro-orm/issues/3743)
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { SeedManager } = require('@mikro-orm/seeder');
return this.config.getCachedService(SeedManager, this.em);
throw new Error(`SeedManager extension not registered.`);
}

/**
Expand Down
4 changes: 0 additions & 4 deletions packages/core/src/drivers/DatabaseDriver.ts
Expand Up @@ -147,10 +147,6 @@ export abstract class DatabaseDriver<C extends Connection> implements IDatabaseD
return this.dependencies;
}

async ensureIndexes(): Promise<void> {
throw new Error(`${this.constructor.name} does not use ensureIndexes`);
}

protected inlineEmbeddables<T>(meta: EntityMetadata<T>, data: T, where?: boolean): void {
Object.keys(data as Dictionary).forEach(k => {
if (Utils.isOperator(k)) {
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/drivers/IDatabaseDriver.ts
Expand Up @@ -71,8 +71,6 @@ export interface IDatabaseDriver<C extends Connection = Connection> {

getMetadata(): MetadataStorage;

ensureIndexes(): Promise<void>;

/**
* Returns name of the underlying database dependencies (e.g. `mongodb` or `mysql2`)
* for SQL drivers it also returns `knex` in the array as connectors are not used directly there
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Expand Up @@ -7,7 +7,8 @@ export {
Constructor, ConnectionType, Dictionary, PrimaryKeyType, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter,
AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator,
GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff,
IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref,
IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref, ISchemaGenerator,
UmzugMigration, MigrateOptions, MigrationResult, MigrationRow,
} from './typings';
export * from './enums';
export * from './errors';
Expand Down
9 changes: 1 addition & 8 deletions packages/core/src/platforms/Platform.ts
Expand Up @@ -353,18 +353,11 @@ export abstract class Platform {
// no extensions by default
}

/* istanbul ignore next: kept for type inference only */
getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): ISchemaGenerator {
throw new Error(`${driver.constructor.name} does not support SchemaGenerator`);
}

getEntityGenerator(em: EntityManager): IEntityGenerator {
throw new Error(`${this.constructor.name} does not support EntityGenerator`);
}

getMigrator(em: EntityManager): IMigrator {
throw new Error(`${this.constructor.name} does not support Migrator`);
}

processDateProperty(value: unknown): string | number | Date {
return value as string;
}
Expand Down

0 comments on commit a82b930

Please sign in to comment.