Skip to content

Commit 9dbe390

Browse files
committed
feat: update Resource class so that it no longer requires static orm attribute
1 parent 03ae01b commit 9dbe390

File tree

7 files changed

+41
-77
lines changed

7 files changed

+41
-77
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,13 @@ const setupAdminJs = async () => {
3131
clientUrl: process.env.DATABASE_URL,
3232
});
3333

34-
// MikroORM exposes it's entity manager through created ORM instance (`orm.em`) and it's required for
35-
// the adapter to run database queries. The static method `Resource.setORM` extracts required properties from your
36-
// ORM instance.
37-
Resource.setORM(orm);
3834
// If your entities use `class-validator` to validate data, you can inject it's validate method into the resource.
3935
Resource.validate = validate;
4036
AdminJS.registerAdapter({ Database, Resource });
4137

4238
// You can instantiate AdminJS either by specifying all resources separately:
4339
const adminJs = new AdminJS({
44-
resources: [{ resource: User, options: {} }],
40+
resources: [{ resource: { model: User, orm }, options: {} }],
4541
});
4642

4743
// Or by passing your ORM instance into `databases` property.

example-app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"dependencies": {
2222
"@adminjs/express": "^4.0.0",
23+
"@adminjs/mikroorm": "^1.0.0",
2324
"@mikro-orm/core": "^4.5.0",
2425
"@mikro-orm/postgresql": "^4.5.0",
2526
"adminjs": "^5.2.2",

example-app/src/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ const run = async () => {
2424
debug: true,
2525
});
2626

27-
Resource.setORM(orm as any);
2827
AdminJS.registerAdapter({ Database, Resource });
2928

3029
const app = express();
3130

3231
const resources = [
3332
{
34-
resource: User,
33+
resource: { model: User, orm },
3534
options: {
3635
properties: {
3736
firstName: {
@@ -41,7 +40,7 @@ const run = async () => {
4140
},
4241
},
4342
{
44-
resource: Car,
43+
resource: { model: Car, orm },
4544
options: {
4645
properties: {
4746
meta: { type: 'mixed' },
@@ -54,7 +53,7 @@ const run = async () => {
5453
},
5554
},
5655
},
57-
Seller,
56+
{ model: Seller, orm },
5857
];
5958

6059
const admin = new AdminJS({

spec/Property.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ describe('Property', () => {
1717

1818
beforeAll(async () => {
1919
orm = await initORM();
20-
Resource.setORM(orm);
21-
resource = new Resource(Car);
20+
resource = new Resource({ model: Car, orm });
2221
properties = resource.properties();
2322
});
2423

spec/Resource.spec.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('Resource', () => {
2525
});
2626

2727
beforeEach(async () => {
28-
resource = new Resource(Car);
28+
resource = new Resource({ model: Car, orm });
2929

3030
await orm.em.getRepository(Car).nativeDelete({});
3131
await orm.em.getRepository(User).nativeDelete({});
@@ -38,16 +38,14 @@ describe('Resource', () => {
3838

3939
describe('.isAdapterFor', () => {
4040
it('returns false if `orm` is not set before', () => {
41-
expect(Resource.isAdapterFor(Car)).toEqual(false);
41+
expect(Resource.isAdapterFor(Car as any)).toEqual(false);
4242
});
4343

44-
it('returns true when Entity is given and `orm` is set', () => {
45-
Resource.setORM(orm);
46-
expect(Resource.isAdapterFor(Car)).toEqual(true);
44+
it('returns true when correct args are given', () => {
45+
expect(Resource.isAdapterFor({ model: Car, orm })).toEqual(true);
4746
});
4847

4948
it('returns false for any other kind of resources', () => {
50-
Resource.setORM(orm);
5149
expect(Resource.isAdapterFor({ Car: true } as any)).toEqual(false);
5250
});
5351
});

src/Database.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ export class Database extends BaseDatabase {
1414
if (!metadata) return [];
1515
metadata.decorate(this.orm.em);
1616

17-
Resource.setORM(this.orm);
1817
return Object.values(metadata.getAll()).reduce((memo: Resource[], meta) => {
19-
const resource = new Resource(meta.class);
18+
const resource = new Resource({
19+
model: meta.class,
20+
orm: this.orm,
21+
});
2022
memo.push(resource);
2123

2224
return memo;
2325
}, []);
2426
}
2527

2628
public static isAdapterFor(orm: MikroORM): boolean {
27-
return !!orm.isConnected && orm.isConnected() && !!orm.getMetadata();
29+
return !!orm.isConnected?.() && !!orm.getMetadata?.();
2830
}
2931
}

src/Resource.ts

Lines changed: 26 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,36 @@ export type AdapterORM = {
2121
metadata: MetadataStorage;
2222
};
2323

24-
// eslint-disable-next-line max-len
25-
const OrmNotFoundError = 'ORM is not set. Make sure to set it before registering the adapter: AdminJS.setORM(mikroOrmInstance)';
26-
2724
export class Resource extends BaseResource {
28-
public static orm: AdapterORM;
29-
3025
public static validate: any;
3126

32-
private metadata: EntityMetadata | undefined;
27+
private orm: MikroORM;
28+
29+
private metadata?: EntityMetadata;
3330

3431
private model: EntityClass<AnyEntity>;
3532

3633
private propertiesObject: Record<string, Property>;
3734

38-
constructor(model: EntityClass<AnyEntity>) {
39-
super(model);
35+
constructor(args: { model: EntityClass<AnyEntity>, orm: MikroORM }) {
36+
super(args);
37+
38+
const { model, orm } = args;
39+
this.orm = orm;
4040
this.model = model;
41-
this.metadata = Resource.orm?.metadata?.find(model.name);
41+
this.metadata = this.orm.getMetadata().find(model.name);
4242
this.propertiesObject = this.prepareProperties();
4343
}
4444

45-
public static setORM(orm: MikroORM) {
46-
orm.getMetadata().decorate(orm.em);
47-
Resource.orm = Resource.stripOrmConfig(orm);
48-
}
49-
5045
public databaseName(): string {
51-
return Resource.orm?.database || 'mikroorm';
46+
const {
47+
database,
48+
} = this.orm.config.getDriver().getConnection().getConnectionOptions();
49+
return database || 'mikroorm';
5250
}
5351

5452
public databaseType(): string {
55-
return Resource.orm?.databaseType || this.databaseName();
53+
return this.orm.config.getAll().type || this.databaseName();
5654
}
5755

5856
public name(): string {
@@ -76,20 +74,16 @@ export class Resource extends BaseResource {
7674
}
7775

7876
public async count(filter: Filter): Promise<number> {
79-
if (!Resource.orm) throw new Error(OrmNotFoundError);
80-
81-
return Resource.orm.entityManager.getRepository(this.model).count(
77+
return this.orm.em.getRepository(this.model).count(
8278
convertFilter(filter),
8379
);
8480
}
8581

8682
public async find(filter: Filter, params: Record<string, any> = {}): Promise<Array<BaseRecord>> {
87-
if (!Resource.orm) throw new Error(OrmNotFoundError);
88-
8983
const { limit = 10, offset = 0, sort = {} } = params;
9084
const { direction, sortBy } = sort as { direction: 'asc' | 'desc', sortBy: string };
9185

92-
const results = await Resource.orm.entityManager
86+
const results = await this.orm.em
9387
.getRepository(this.model)
9488
.find(
9589
convertFilter(filter), {
@@ -105,11 +99,9 @@ export class Resource extends BaseResource {
10599
}
106100

107101
public async findOne(id: string | number): Promise<BaseRecord | null> {
108-
if (!Resource.orm) throw new Error(OrmNotFoundError);
109-
110-
const result = await Resource.orm.entityManager
102+
const result = await this.orm.em
111103
.getRepository(this.model)
112-
.findOne(id as any); // mikroorm has incorrect types for findOne
104+
.findOne(id as any); // mikroorm has incorrect types for `findOne`
113105

114106
if (!result) return null;
115107

@@ -119,22 +111,18 @@ export class Resource extends BaseResource {
119111
public async findMany(
120112
ids: Array<string | number>,
121113
): Promise<Array<BaseRecord>> {
122-
if (!Resource.orm) throw new Error(OrmNotFoundError);
123-
124114
const pk = this.metadata?.primaryKeys[0];
125115
if (!pk) return [];
126116

127-
const results = await Resource.orm.entityManager
117+
const results = await this.orm.em
128118
.getRepository(this.model)
129119
.find({ [pk]: { $in: ids } });
130120

131121
return results.map((result) => new BaseRecord(wrap(result).toJSON(), this));
132122
}
133123

134124
public async create(params: Record<string, any>): Promise<Record<string, any>> {
135-
if (!Resource.orm) throw new Error(OrmNotFoundError);
136-
137-
const instance = Resource.orm?.entityManager
125+
const instance = this.orm.em
138126
.getRepository(this.model)
139127
.create(flat.unflatten(params));
140128

@@ -146,9 +134,7 @@ export class Resource extends BaseResource {
146134
}
147135

148136
public async update(pk: string | number, params: Record<string, any> = {}): Promise<Record<string, any>> {
149-
if (!Resource.orm) throw new Error(OrmNotFoundError);
150-
151-
const instance = await Resource.orm?.entityManager
137+
const instance = await this.orm.em
152138
.getRepository(this.model)
153139
.findOne(pk as any); // mikroorm has incorrect types for findOneOrFail
154140

@@ -164,32 +150,15 @@ export class Resource extends BaseResource {
164150
}
165151

166152
public async delete(id: string | number): Promise<void> {
167-
if (!Resource.orm) return;
168-
169-
await Resource.orm?.entityManager
153+
await this.orm.em
170154
.getRepository(this.model)
171155
.nativeDelete(id as any); // mikroorm has incorrect types for nativeDelete
172156
}
173157

174-
public static isAdapterFor(rawResource: EntityClass<AnyEntity>): boolean {
175-
try {
176-
if (Resource.orm === null) return false;
177-
const metadata = Resource.orm?.metadata?.find(rawResource.name);
178-
return !!metadata;
179-
} catch (e) {
180-
return false;
181-
}
182-
}
183-
184-
public static stripOrmConfig(orm: MikroORM) {
185-
const {
186-
database,
187-
} = orm.config.getDriver().getConnection().getConnectionOptions();
188-
const databaseType = orm.config.getAll().type;
189-
const entityManager = orm.em;
190-
const metadata = orm.getMetadata();
158+
public static isAdapterFor(args?: { model?: EntityClass<AnyEntity>, orm?: MikroORM }): boolean {
159+
const { model, orm } = args ?? {};
191160

192-
return { database, databaseType, entityManager, metadata };
161+
return !!model?.name && !!orm?.getMetadata?.().find?.(model.name);
193162
}
194163

195164
async validateAndSave(instance: Loaded<AnyEntity>): Promise<void> {
@@ -210,7 +179,7 @@ export class Resource extends BaseResource {
210179
}
211180
}
212181
try {
213-
await Resource.orm?.entityManager.persistAndFlush(instance);
182+
await this.orm.em.persistAndFlush(instance);
214183
} catch (error) {
215184
if (error.name === 'QueryFailedError') {
216185
throw new ValidationError({

0 commit comments

Comments
 (0)