@avonjs/avonjs
Version:
A fluent Node.js API generator.
482 lines (481 loc) • 13.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 Contracts_1 = require("../Contracts");
const AuthorizedToSee_1 = __importDefault(require("../Mixins/AuthorizedToSee"));
const Filterable_1 = __importDefault(require("../Mixins/Filterable"));
const Lookupable_1 = __importDefault(require("../Mixins/Lookupable"));
const Nullable_1 = __importDefault(require("../Mixins/Nullable"));
const Orderable_1 = __importDefault(require("../Mixins/Orderable"));
const Presentable_1 = __importDefault(require("../Mixins/Presentable"));
const mixin_1 = require("../support/mixin");
const TextFilter_1 = __importDefault(require("./Filters/TextFilter"));
const Ordering_1 = __importDefault(require("./Orderings/Ordering"));
class Field extends (0, mixin_1.mixin)(class {
}, Lookupable_1.default, Nullable_1.default, Filterable_1.default, Orderable_1.default, Presentable_1.default, AuthorizedToSee_1.default) {
/**
* The attribute / column name of the field.
*/
attribute;
/**
* The validation attribute for the field.
*/
validationAttribute;
/**
* The field's resolved value.
*/
value;
/**
* The callback to be used to hydrate the model attribute.
*/
fillCallback;
/**
* The callback to be used to resolve the field's display value.
*/
displayCallback = (value, resource, attribute) => value;
/**
* The callback to be used to resolve the field's value.
*/
resolveCallback = (value, resource, attribute) => value;
/**
* The callback to be used for the field's default value.
*/
defaultCallback;
/**
* The validation rules callback for creation and updates.
*/
rulesSchema = joi_1.default.any();
/**
* The validation rules callback for creation.
*/
creationRulesSchema = joi_1.default.any();
/**
* The validation rules callback for updates.
*/
updateRulesSchema = joi_1.default.any();
/**
* The help text for the field.
*/
helpText;
/**
* Custom label for the field.
*/
name;
/**
* Define the default orderable callback.
*/
defaultOrderingCallback() {
return (request, repository, direction) => {
repository.order({
key: this.orderableAttribute(request),
direction: Contracts_1.Direction.ASC === direction ? Contracts_1.Direction.ASC : Contracts_1.Direction.DESC,
});
};
}
constructor(attribute, resolveCallback) {
super();
this.attribute = attribute;
if (resolveCallback !== undefined) {
this.resolveCallback = resolveCallback;
}
}
/**
* Resolve the field's value for display.
*/
resolveForDisplay(resource, attribute) {
this.resolve(resource, attribute);
}
/**
* Resolve the field's value.
*/
resolve(resource, attribute) {
const resolveAttribute = attribute ?? this.attribute;
this.setValue(this.resolveCallback(this.resolveAttribute(resource, resolveAttribute), resource, resolveAttribute));
}
/**
* Resolve the given attribute from the given resource.
*/
resolveAttribute(resource, attribute) {
return resource.getAttribute(attribute);
}
/**
* Set the callback to be used for determining the field's default value.
*/
default(callback) {
this.defaultCallback = callback;
return this;
}
/**
* Resolve the default value for the field.
*/
resolveDefaultValue(request) {
if (request.isCreateOrAttachRequest() ||
request.isActionRequest() ||
request.isSchemaRequest()) {
return this.defaultCallback?.apply(this, [request]);
}
}
/**
* Define the callback that should be used to display the field's value.
*/
displayUsing(displayCallback) {
this.displayCallback = displayCallback;
return this;
}
/**
* Define the callback that should be used to resolve the field's value.
*/
resolveUsing(resolveCallback) {
this.resolveCallback = resolveCallback;
return this;
}
/**
* Specify a callback that should be used to hydrate the model attribute for the field.
*/
fillUsing(fillCallback) {
this.fillCallback = fillCallback;
return this;
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fill(request, model) {
return this.fillInto(request, model, this.attribute);
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fillForAction(request, model) {
return this.fill(request, model);
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fillInto(request, model, attribute, requestAttribute) {
return this.fillAttribute(request, requestAttribute ?? this.attribute, model, attribute);
}
/**
* Hydrate the given attribute on the model based on the incoming request.
*/
fillAttribute(request, requestAttribute, model, attribute) {
return this.fillCallback !== undefined
? this.fillCallback(request, model, attribute, requestAttribute)
: this.fillAttributeFromRequest(request, requestAttribute, model, 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, attribute);
return;
}
const value = request.get(requestAttribute);
model.setAttribute(attribute, this.isValidNullValue(value) ? this.nullValue() : value);
}
/**
* Hydrate the given attribute on the model based on the default callback.
*/
fillAttributeFromDefault(request, model, attribute) {
const value = this.resolveDefaultValue(request);
if (value !== undefined) {
model.setAttribute(attribute, this.isValidNullValue(value) ? this.nullValue() : value);
}
}
/**
* Get the value considered as null.
*/
nullValue() {
return null;
}
/**
* Set the value for the field.
*/
setValue(value) {
this.value = value;
return this;
}
/**
* Set the validation rules for the field.
*/
rules(rules) {
this.rulesSchema = this.rulesSchema.concat(rules);
return this;
}
/**
* Get the validation rules for this field.
*/
getRules(request) {
return { [this.attribute]: this.rulesSchema };
}
/**
* Get the creation rules for this field.
*/
getCreationRules(request) {
const rules = this.getRules(request);
return {
...rules,
[this.attribute]: rules[this.attribute].concat(this.creationRulesSchema),
};
}
/**
* Set the creation validation rules for the field.
*/
creationRules(rules) {
this.creationRulesSchema = this.creationRulesSchema.concat(rules);
return this;
}
/**
* Get the update rules for this field.
*/
getUpdateRules(request) {
const rules = this.getRules(request);
return {
...rules,
[this.attribute]: rules[this.attribute].concat(this.updateRulesSchema),
};
}
/**
* Set the creation validation rules for the field.
*/
updateRules(rules) {
this.updateRulesSchema = this.updateRulesSchema.concat(rules);
return this;
}
/**
* Get the validation attribute for the field.
*/
getValidationAttribute(request) {
return this.validationAttribute;
}
/**
* Get field validator.
*/
validator() {
return joi_1.default;
}
/**
* Determine if the field is required.
*/
isRequired(request) {
if (request.isResourceIndexRequest() ||
request.isActionRequest() ||
request.isCreateOrAttachRequest()) {
return this.isRequiredForCreation(request);
}
if (request.isUpdateOrUpdateAttachedRequest()) {
return this.isRequiredForUpdate(request);
}
return false;
}
/**
* Determine if the field is required for creation.
*/
isRequiredForCreation(request) {
const rules = this.getCreationRules(request)[this.attribute];
return rules.$_getFlag('presence') === 'required';
}
/**
* Determine if the field is required for update.
*/
isRequiredForUpdate(request) {
const rules = this.getUpdateRules(request)[this.attribute];
return rules.$_getFlag('presence') === 'required';
}
/**
* Define filterable attribute.
*/
filterableAttribute(request) {
return this.attribute;
}
/**
* Define orderable attribute.
*/
orderableAttribute(request) {
return this.attribute;
}
/**
* Determine field is fillable or not.
*/
fillable() {
return true;
}
/**
* Determine field is resolvable or not.
*/
resolvable() {
return true;
}
/**
* Specify the field help text.
*/
help(helpText) {
this.helpText = helpText;
return this;
}
/**
* Specify the field label.
*/
withName(name) {
this.name = name;
return this;
}
/**
* Determine if the element should be displayed for the given request.
*/
authorize(request) {
return this.authorizedToSee(request);
}
/**
* Make the field filter.
*/
makeFilter(request) {
return new TextFilter_1.default(this);
}
/**
* Make the field filter.
*/
makeOrdering(request) {
return new Ordering_1.default(this);
}
/**
* Determine that the field should be nullable.
*/
nullable(nullable = true, validator) {
super.nullable(nullable, validator);
if (nullable) {
this.rules(this.rulesSchema.allow(null));
}
else {
this.required();
}
return this;
}
/**
* Determine that the field should be filled in the request.
*/
required(required = true) {
if (required) {
this.rules(this.rulesSchema.required());
}
return this;
}
/**
* Determines that the field can be omitted from the request.
*/
optional(optional = true) {
if (optional) {
this.rules(this.rulesSchema.optional());
}
return this;
}
/**
* Get the value for the field.
*/
getValue(request) {
if (this.value === undefined) {
this.value = this.resolveDefaultValue(request);
}
const value = this.value !== undefined && !this.isValidNullValue(this.value) // ![undefined, this.nullValue()].includes(this.value)
? this.getMutatedValue(request, this.value)
: this.nullValue();
return value ?? this.nullValue();
}
/**
* Get the swagger-ui schema.
*/
schema(request) {
return {
payload: this.payloadSchema(request),
response: this.responseSchema(request),
};
}
/**
* Get the swagger-ui schema.
*/
payloadSchema(request) {
return this.baseSchema(request);
}
/**
* Get the swagger-ui schema.
*/
responseSchema(request) {
return this.baseSchema(request);
}
/**
* Get the base swagger-ui schema.
*/
baseSchema(request) {
return {
type: 'string',
nullable: this.isNullable(),
description: this.helpText,
title: this.name ?? this.attribute,
default: this.resolveDefaultValue(request),
};
}
/**
* Serialize parameters for schema.
*/
serializeParameters(request) {
return [
{
name: this.attribute,
in: 'body',
schema: this.schema(request).payload,
},
];
}
lookupable(callback) {
return super.lookupable(callback);
}
filterable(callback) {
return super.filterable(callback);
}
orderable(callback) {
return super.orderable(callback);
}
canSee(callback) {
return super.canSee(callback);
}
hideFromIndex(callback) {
return super.hideFromIndex(callback);
}
hideFromDetail(callback) {
return super.hideFromDetail(callback);
}
hideWhenCreating(callback) {
return super.hideWhenCreating(callback);
}
hideWhenUpdating(callback) {
return super.hideWhenUpdating(callback);
}
showOnIndex(callback) {
return super.showOnIndex(callback);
}
showOnDetail(callback) {
return super.showOnDetail(callback);
}
showOnCreating(callback) {
return super.showOnCreating(callback);
}
showOnUpdating(callback) {
return super.showOnUpdating(callback);
}
onlyOnIndex() {
return super.onlyOnIndex();
}
onlyOnDetail() {
return super.onlyOnDetail();
}
onlyOnForms() {
return super.onlyOnForms();
}
exceptOnForms() {
return super.exceptOnForms();
}
}
exports.default = Field;