@adminjs/mikroorm
Version:
MikroORM adapter for AdminJS
162 lines • 5.61 kB
JavaScript
/* eslint-disable no-param-reassign */
import { BaseResource, BaseRecord, ValidationError, flat, } from 'adminjs';
import { wrap, ReferenceKind, } from '@mikro-orm/core';
import { Property } from './Property.js';
import { convertFilter } from './utils/convert-filter.js';
export class Resource extends BaseResource {
static validate;
orm;
metadata;
model;
propertiesObject;
constructor(args) {
super(args);
const { model, orm } = args;
this.orm = orm;
this.model = model;
this.metadata = this.orm.getMetadata().find(model.name);
this.propertiesObject = this.prepareProperties();
}
databaseName() {
const { database } = this.orm.config
.getDriver()
.getConnection()
.getConnectionOptions();
return database || 'mikroorm';
}
databaseType() {
return this.databaseName();
}
name() {
return this.metadata?.name ?? this.metadata?.className ?? '';
}
id() {
return this.name();
}
properties() {
return [...Object.values(this.propertiesObject)];
}
property(path) {
return this.propertiesObject[path];
}
build(params) {
return new BaseRecord(flat.unflatten(params), this);
}
async count(filter) {
return this.orm.em
.fork()
.getRepository(this.model)
.count(convertFilter(filter));
}
async find(filter, params = {}) {
const { limit = 10, offset = 0, sort = {} } = params;
const { direction, sortBy } = sort;
const results = await this.orm.em
.fork()
.getRepository(this.model)
.find(convertFilter(filter), {
orderBy: {
[sortBy]: direction,
},
limit,
offset,
});
return results.map((result) => new BaseRecord(wrap(result).toObject(), this));
}
async findOne(id) {
const result = await this.orm.em
.fork()
.getRepository(this.model)
.findOne(id); // mikroorm has incorrect types for `findOne`
if (!result)
return null;
return new BaseRecord(wrap(result).toObject(), this);
}
async findMany(ids) {
const pk = this.metadata?.primaryKeys[0];
if (!pk)
return [];
const results = await this.orm.em
.fork()
.getRepository(this.model)
.find({ [pk]: { $in: ids } });
return results.map((result) => new BaseRecord(wrap(result).toObject(), this));
}
async create(params) {
const em = this.orm.em.fork();
const instance = em
.getRepository(this.model)
.create(flat.unflatten(params));
await this.validateAndSave(instance, em);
const returnedParams = flat.flatten(wrap(instance).toObject());
return returnedParams;
}
async update(pk, params = {}) {
const em = this.orm.em.fork();
const instance = await em.getRepository(this.model).findOne(pk);
if (!instance)
throw new Error('Record to update not found');
const updatedInstance = wrap(instance).assign(flat.unflatten(params));
await this.validateAndSave(updatedInstance, em);
const returnedParams = flat.flatten(wrap(updatedInstance).toObject());
return returnedParams;
}
async delete(id) {
await this.orm.em
.fork()
.getRepository(this.model)
.nativeDelete(id); // mikroorm has incorrect types for nativeDelete
}
static isAdapterFor(args) {
const { model, orm } = args ?? {};
return !!model?.name && !!orm?.getMetadata?.().find?.(model.name);
}
async validateAndSave(instance, em) {
if (Resource.validate) {
const errors = await Resource.validate(instance);
if (errors && errors.length) {
const validationErrors = errors.reduce((memo, error) => ({
...memo,
[error.property]: {
type: Object.keys(error.constraints)[0],
message: Object.values(error.constraints)[0],
},
}), {});
throw new ValidationError(validationErrors);
}
}
try {
await em.persistAndFlush(instance);
}
catch (error) {
// TODO: figure out how to get column name from MikroORM's error metadata
// It currently seems to return only whole Entity
console.log(error);
if (error.name === 'QueryFailedError'
|| error.name === 'ValidationError') {
throw new ValidationError({
[error.column]: {
type: 'QueryFailedError',
message: error.message,
},
});
}
}
}
prepareProperties() {
const { hydrateProps = [] } = this.metadata ?? {};
return hydrateProps.reduce((memo, prop, index) => {
if (![
ReferenceKind.SCALAR,
ReferenceKind.MANY_TO_ONE,
ReferenceKind.ONE_TO_ONE,
ReferenceKind.MANY_TO_MANY,
].includes(prop.kind))
return memo;
const property = new Property(prop, index);
memo[property.path()] = property;
return memo;
}, {});
}
}
//# sourceMappingURL=Resource.js.map