@avonjs/avonjs
Version:
A fluent Node.js API generator.
201 lines (200 loc) • 6.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const joi_1 = __importDefault(require("joi"));
const FieldCollection_1 = __importDefault(require("../Collections/FieldCollection"));
const Contracts_1 = require("../Contracts");
const BelongsToFilter_1 = __importDefault(require("./Filters/BelongsToFilter"));
const Relation_1 = __importDefault(require("./Relation"));
class BelongsTo extends Relation_1.default {
/**
* Indicates trashed items have to be included in the related resource.
*/
withTrashed = true;
/**
* Prevent the trashed item from being included in the query.
*/
withoutTrashed() {
this.withTrashed = false;
return this;
}
/**
* Mutate the field value for response.
*/
getMutatedValue(request, value) {
return this.isLoaded() ? super.getMutatedValue(request, value)[0] : value;
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fillForAction(request, model) {
if (request.exists(this.attribute)) {
model.setAttribute(this.attribute, this.relatedResource
.resolveRepository(request)
.find(request.input(this.attribute)));
}
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fillAttributeFromRequest(request, requestAttribute, model, attribute) {
if (!request.exists(requestAttribute)) {
this.fillAttributeFromDefault(request, model, this.foreignKeyName(request));
return;
}
const value = request.get(requestAttribute);
model.setAttribute(this.foreignKeyName(request), this.isValidNullValue(value) ? this.nullValue() : value);
return async (request, model) => {
await request
.newResource(model)
.authorizeTo(request, Contracts_1.Ability.add, [
await this.getRelatedResource(request, value),
]);
};
}
/**
* Get related models for given resources.
*/
async searchRelatables(request, resources) {
const repository = this.relatedResource.resolveRepository(request).where({
key: this.ownerKeyName(request),
value: resources
.map((resource) => resource.getAttribute(this.foreignKeyName(request)))
.filter((value) => value),
operator: Contracts_1.Operator.in,
});
const query = this.relatableQueryCallback.apply(repository, [request, repository]) ??
repository;
return this.softDeletes() //@ts-ignore
? query.withTrashed().all()
: query.all();
}
/**
* Format the given related resource.
*/
formatRelatedResource(request, resource) {
const repository = this.relatedResource.resolveRepository(request);
const softDeleted = this.softDeletes() && repository.isSoftDeleted(resource);
return {
...new FieldCollection_1.default(this.relatableFields(request))
.resolve(resource)
.fieldValues(request),
softDeleted,
};
}
/**
* Indicates related resource soft deletes applied.
*/
softDeletes() {
return this.withTrashed && this.relatedResource.softDeletes();
}
/**
* Make the field filter.
*/
makeFilter(request) {
return new BelongsToFilter_1.default(this);
}
/**
* Determine field is resolvable or not.
*/
resolvable() {
return true;
}
/**
* Determine if the underlying file should be pruned when the resource is deleted.
*/
isPrunable() {
return false;
}
/**
* Determine field is orderable or not.
*/
isOrderable() {
return true;
}
/**
* Define orderable attribute.
*/
orderableAttribute(request) {
return this.foreignKeyName(request);
}
/**
* Get the validation rules for this field.
*/
getRules(request) {
const rules = this.isNullable()
? joi_1.default.any().allow(null)
: joi_1.default.any().required();
return {
[this.attribute]: rules.external(async (value, { error }) => {
if (this.isValidNullValue(value)) {
return this.nullValue();
}
if ((await this.getRelatedResource(request, value)) === undefined) {
return error('any.custom', {
error: new Error(`Related resource with ID:'${value}' not found`),
});
}
return value;
}),
};
}
async getRelatedResource(request, id) {
const repository = this.relatedResource.resolveRepository(request).where({
key: this.ownerKeyName(request),
operator: Contracts_1.Operator.eq,
value: id,
});
// to ensure only valid data attached
const query = this.relatableQueryCallback.apply(repository, [request, repository]) ??
repository;
return query.first();
}
/**
* Get the base swagger-ui schema.
*/
baseSchema(request) {
return {
...super.baseSchema(request),
default: this.isNullable() ? null : this.resolveDefaultValue(request),
type: 'number',
oneOf: [{ type: 'string' }, { type: 'number' }],
};
}
payloadSchema(request) {
return {
...this.baseSchema(request),
default: this.isNullable() ? null : this.resolveDefaultValue(request),
description: [
this.helpText,
`use the "associable/${this.attribute}" to retrieve data`,
].join('</br>'),
};
}
/**
* Get the swagger-ui schema.
*/
responseSchema(request) {
if (!this.isLoaded()) {
return this.baseSchema(request);
}
return {
...super.responseSchema(request),
type: 'object',
properties: {
...new FieldCollection_1.default(this.schemaFields(request)).responseSchemas(request),
softDeleted: {
type: 'boolean',
default: false,
description: 'Indicates whether the related resource is soft-deleted or not',
},
},
default: null,
nullable: true,
oneOf: undefined,
};
}
}
exports.default = BelongsTo;