UNPKG

@avonjs/avonjs

Version:

A fluent Node.js API generator.

236 lines (235 loc) 7.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const change_case_all_1 = require("change-case-all"); const collect_js_1 = __importDefault(require("collect.js")); const Avon_1 = __importDefault(require("../Avon")); const FieldCollection_1 = __importDefault(require("../Collections/FieldCollection")); const Contracts_1 = require("../Contracts"); const Exceptions_1 = require("../Exceptions"); const Filters_1 = require("../Filters"); const Orderings_1 = require("../Orderings"); const Lazy_1 = __importDefault(require("./Lazy")); const ResourceRelationshipGuesser_1 = require("./ResourceRelationshipGuesser"); class Relation extends Lazy_1.default { /** * Name of the relationship. */ relation; /** * The related resource instance */ relatedResource; /** * The foreign key of the parent model. * The attribute name that holds the parent model key. */ foreignKey; /** * The associated key on the child model. * Defaults to primary key of parent model. */ ownerKey; /** * The callback that should be run to associate relations. */ relatableQueryCallback = (request, repository) => this.relatedResource.relatableQuery(request, repository) ?? repository; constructor(resource, relation) { const relatedResource = Avon_1.default.resourceForKey(resource); Exceptions_1.RuntimeException.when(relatedResource === undefined, `Resource '${resource}' not found for relationship ${relation ?? resource}`); super(relation ?? (0, ResourceRelationshipGuesser_1.guessRelation)(relatedResource)); this.relation = this.attribute; this.relatedResource = relatedResource; this.ownerKey = this.relatedResource.repository().model().getKeyName(); this.foreignKey = (0, change_case_all_1.snakeCase)(`${this.relation}_${this.ownerKey}`); } /** * Indicates fields uses to display in relation request. */ relatableFields = (request) => { const fields = this.relatedResource.fieldsForAssociation(request); return new FieldCollection_1.default(fields) .filterForAssociation(request) .withoutUnresolvableFields() .withoutRelatableFields() .all(); }; /** * Get all of the possibly available filters for the request. */ availableFilters(request) { return new FieldCollection_1.default(this.relatableFields(request)) .withOnlyFilterableFields() .authorized(request) .map((field) => field.resolveFilter(request)) .filter((filter) => filter instanceof Filters_1.Filter) .merge(this.relatedResourceFilters(request)) .unique((filter) => filter.key()) .all(); } /** * Resolve the related resource filters. */ relatedResourceFilters(request) { return this.relatedResource .resolveFilters(request) .filter((filter) => filter.authorizedToSee(request)); } /** * Get all of the possibly available filters for the request. */ availableOrderings(request) { return new FieldCollection_1.default(this.relatableFields(request)) .withOnlyOrderableFields() .authorized(request) .map((field) => field.resolveOrdering(request)) .filter((ordering) => ordering instanceof Orderings_1.Ordering) .merge(this.relatedResourceOrderings(request)) .unique((ordering) => ordering.key()) .all(); } /** * Resolve the related resource orderings. */ relatedResourceOrderings(request) { return this.relatedResource .resolveOrderings(request) .filter((ordering) => ordering.authorizedToSee(request)); } /** * Mutate the field value for response. */ getMutatedValue(request, value) { return (0, collect_js_1.default)(value) .map((relatable) => this.formatRelatedResource(request, relatable)) .values() .all(); } /** * Format the given related resource. */ formatRelatedResource(request, resource) { return new FieldCollection_1.default(this.relatableFields(request)) .resolve(resource) .fieldValues(request); } /** * Set related model foreign key. */ withForeignKey(foreignKey) { this.foreignKey = foreignKey; return this; } /** * Get attribute that hold the related model key. */ foreignKeyName(request) { return this.foreignKey; } /** * Set related model owner key. */ withOwnerKey(ownerKey) { this.ownerKey = ownerKey; return this; } /** * Get attribute that hold the related model key. */ ownerKeyName(request) { return this.ownerKey; } /** * Determine display fields. */ fields(callback) { this.relatableFields = callback; return this; } /** * Resolve value for given resources. */ async resolveForResources(request, resources) { return this.resolveRelatables(request, resources); } /** * Resolve related value for given resources. */ async resolveRelatables(request, resources) { const relatables = await this.searchRelatables(request, resources); resources.forEach((resource) => { resource.setAttribute(this.attribute, relatables.filter((relatable) => { return ( // biome-ignore lint/suspicious/noDoubleEquals: relatable.getAttribute(this.ownerKeyName(request)) == resource.getAttribute(this.foreignKeyName(request))); })); }); } /** * Search associable resources. */ async searchAssociable(request, withTrashed = false) { const repository = await this.relatedResource.search(request, request.filters(), request.orderings(), withTrashed ? Contracts_1.TrashedStatus.WITH : Contracts_1.TrashedStatus.DEFAULT); const query = this.relatableQueryCallback.apply(repository, [ request, repository, ]); return query ?? repository; } /** * Determine the associate relations query. */ relatableQueryUsing(relatableQueryCallback) { this.relatableQueryCallback = relatableQueryCallback; return this; } /** * Define filterable attribute. */ filterableAttribute(request) { return this.foreignKeyName(request); } /** * Resolve the field's value. */ resolve(resource, attribute) { super.resolve(resource, this.isLoaded() || this.foreignKey === '' ? attribute : this.foreignKey); } /** * Determine field is filterable or not. */ isFilterable() { return true; } /** * Determine field is orderable or not. */ isOrderable() { return false; } responseSchema(request) { const fields = this.schemaFields(request); return { ...super.responseSchema(request), type: 'array', default: fields.fieldValues(request), items: { type: 'object', properties: fields.responseSchemas(request) }, }; } payloadSchema(request) { const fields = this.schemaFields(request); return { ...super.payloadSchema(request), type: 'array', default: fields.fieldValues(request), items: { type: 'object', properties: fields.payloadSchemas(request) }, }; } schemaFields(request) { return new FieldCollection_1.default(this.relatableFields(request)); } } exports.default = Relation;