@adocasts.com/dto
Version:
Easily make and generate DTOs from Lucid Models
113 lines (112 loc) • 3.81 kB
JavaScript
import { generators } from '@adonisjs/core/app';
import string from '@adonisjs/core/helpers/string';
export default class DtoService {
app;
constructor(app) {
this.app = app;
}
/**
* Get DTO file, class, and property info
* @param name
* @param model
*/
getDtoInfo(name, model) {
const entity = generators.createEntity(this.#getDtoName(name));
const fileName = generators.modelFileName(entity.name).replace('_dto', '').replace('.ts', '');
const data = {
entity,
fileName,
className: generators.modelName(entity.name),
variable: string.camelCase(name),
exportPath: this.app.makePath('app/dtos', entity.path, fileName + '.ts'),
properties: [],
};
if (!model.isReadable)
return data;
data.properties = this.#getDtoProperties(model);
return data;
}
/**
* Normalize name of the DTO
* @param name
* @private
*/
#getDtoName(name) {
return name.toLowerCase().endsWith('dto') ? name : name + '_dto';
}
/**
* Get DTO's property, type, and constructor value setting info
* @param model
* @private
*/
#getDtoProperties(model) {
return model.properties.map((property) => {
const typeRaw = this.#getDtoType(property);
const type = typeRaw.map((item) => item.dtoType || item.type).join(' | ');
return {
name: property.name,
type,
typeRaw: typeRaw,
declaration: this.#getPropertyDeclaration(property, type),
valueSetter: this.#getValueSetter(property, model),
};
});
}
/**
* Get normalized DTO types
* @param property
* @private
*/
#getDtoType(property) {
if (property.relation?.dtoType) {
const types = [property.relation];
// plural relationships will be normalized to empty array
// however, singular relationships may be null if not loaded/preloaded regardless of type
if (!property.relation.isPlural) {
types.push({ type: 'null' });
}
return types;
}
return property.types.map(({ ...item }) => {
if (item.type === 'DateTime') {
item.type = 'string';
}
return item;
});
}
/**
* get class declaration string for property
* @param property
* @param type
* @private
*/
#getPropertyDeclaration(property, type) {
if (!property.defaultValue) {
return `declare ${property.name}${property.isOptionallyModified ? '?' : ''}: ${type}`;
}
return `${property.name}: ${type} = ${property.defaultValue}`;
}
/**
* Get value setter for use in the constructor for the property
* @param property
* @param model
* @private
*/
#getValueSetter(property, model) {
const nullable = property.types.find((item) => item.type === 'null');
const optional = property.types.find((item) => item.type === 'optional');
const accessor = `${model.variable}.${property.name}`;
if (property.relation?.model) {
return property.relation.isPlural
? `${property.relation.dto}.fromArray(${accessor})`
: `${accessor} && new ${property.relation.dto}(${accessor})`;
}
const dateTimeType = property.types.find((item) => item.type === 'DateTime');
if (dateTimeType) {
return optional || nullable
? accessor + `?.toISO()${optional ? '' : '!'}`
: accessor + `.toISO()!`;
}
return accessor;
}
}