diff --git a/src/Builder.ts b/src/Builder.ts index 97c152f..d1834fb 100644 --- a/src/Builder.ts +++ b/src/Builder.ts @@ -34,16 +34,19 @@ export class Builder { let clone = Object.create(this); - let query = new Query(this.query.getJsonApiType(), this.query.getQueriedRelationName(), this.query.getJsonApiId()); + let query = new Query(this.query.rootEndpoint, this.query.getQueriedRelationName(), this.query.getJsonApiId()); this.query.getFilters().forEach(filter => query.addFilter(filter)); this.query.getOptions().forEach(option => query.addOption(option)); diff --git a/src/Model.ts b/src/Model.ts index 8311382..a34a8cf 100644 --- a/src/Model.ts +++ b/src/Model.ts @@ -348,7 +348,7 @@ export abstract class Model return this._effectiveJsonApiType; } - private static get effectiveEndpoint(): string { + public static get effectiveEndpoint(): string { return (this.endpoint ?? this.effectiveJsonApiType).replace(/^\/+/, ''); } diff --git a/src/Query.ts b/src/Query.ts index e960177..9f9d35d 100644 --- a/src/Query.ts +++ b/src/Query.ts @@ -7,7 +7,7 @@ import {QueryParam} from "./QueryParam"; export class Query { - protected jsonApiType: string; + public readonly rootEndpoint: string; protected jsonApiId: string | undefined; @@ -27,9 +27,9 @@ export class Query protected limit: number | undefined; - constructor(jsonApiType: string, queriedRelationName: string | undefined = undefined, jsonApiId: string | undefined = undefined) + constructor(rootEndpoint: string, queriedRelationName: string | undefined = undefined, jsonApiId: string | undefined = undefined) { - this.jsonApiType = jsonApiType; + this.rootEndpoint = rootEndpoint; this.jsonApiId = jsonApiId; this.queriedRelationName = queriedRelationName; this.include = []; @@ -97,23 +97,21 @@ export class Query public toString(): string { - let relationToFind = ''; - - if (!this.jsonApiId) { - relationToFind = this.queriedRelationName - ? '/' + this.queriedRelationName - : ''; - } else { - relationToFind = this.queriedRelationName - ? '/' + this.jsonApiId + '/' + this.queriedRelationName - : ''; - } - - let idToFind: string = this.idToFind + const relationToFind = this.queriedRelationName + ? + ( + !this.jsonApiId + ? '/' + this.queriedRelationName + : '/' + this.jsonApiId + '/' + this.queriedRelationName + ) + : + ''; + + const idToFind: string = this.idToFind ? '/' + this.idToFind : ''; - let searchParams: QueryParam[] = []; + const searchParams: QueryParam[] = []; this.addFilterParameters(searchParams); this.addIncludeParameters(searchParams); this.addOptionsParameters(searchParams); @@ -129,12 +127,7 @@ export class Query paramString += encodeURIComponent(searchParam.name) + '=' + encodeURIComponent(searchParam.value); } - return this.jsonApiType + relationToFind + idToFind + paramString; - } - - public getJsonApiType() - { - return this.jsonApiType; + return this.rootEndpoint + relationToFind + idToFind + paramString; } public getJsonApiId() diff --git a/src/relation/Relation.ts b/src/relation/Relation.ts index 279df5a..66eee40 100644 --- a/src/relation/Relation.ts +++ b/src/relation/Relation.ts @@ -2,28 +2,40 @@ import {Model} from "../Model"; import {Reflection} from "../util/Reflection"; export class Relation { - private relatedType; + protected readonly relatedType; + protected readonly referringObject: R; + protected readonly name: string; - private referringObject: R | undefined; - - private name: string; - - constructor(relatedType, referringObject: R | undefined = undefined, name: string | undefined = undefined) + constructor( + relatedType, + referringObject?: R, + name?: string + ) { this.relatedType = relatedType; - this.referringObject = referringObject; - if (name !== undefined) { - this.name = name; - } else { - const calculatedName = Reflection.getNameOfNthMethodOffStackTrace(new Error(), 2); - if (calculatedName === undefined) { + this.referringObject = (() => { + if (referringObject === undefined) { throw new Error( - 'Relationship name could not be automatically determined. ' - + 'It is recommended to provide the relationship name explicitly in the relationship definition.' - ); + "Referring type not set on this relation. You should define the relation on your model with e.g." + + " 'this.hasMany(...)' instead of with 'new ToManyRelation(...)'" + ) + } + return referringObject; + })(); + this.name = (() => { + if (name !== undefined) { + return name; + } else { + const calculatedName = Reflection.getNameOfNthMethodOffStackTrace(new Error(), 2); + if (calculatedName === undefined) { + throw new Error( + 'Relationship name could not be automatically determined. ' + + 'It is recommended to provide the relationship name explicitly in the relationship definition.' + ); + } + return calculatedName; } - this.name = calculatedName; - } + })(); } public getType(): any @@ -38,23 +50,11 @@ export class Relation public getReferringObject(): Model { - if (!this.referringObject) { - throw new Error( - "Referring type not set on this relation. You should define the relation on your model with e.g." + - " 'this.hasMany(...)' instead of with 'new ToManyRelation(...)'" - ) - } return this.referringObject; } public getName(): string { - if (!this.name) { - throw new Error( - "Cannot deduce name of relation. You should define the relation on your model with e.g." + - " 'this.hasMany(...)' instead of with 'new ToManyRelation(...)'" - ); - } return this.name; } } diff --git a/src/relation/ToManyRelation.ts b/src/relation/ToManyRelation.ts index f8ea246..b60e03d 100644 --- a/src/relation/ToManyRelation.ts +++ b/src/relation/ToManyRelation.ts @@ -9,37 +9,40 @@ import {Model} from "../Model"; export class ToManyRelation extends Relation implements QueryMethods> { get(page?: number): Promise> { - return >> new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .get(page); + return this.builder.get(page); } first(): Promise> { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .first(); + return this.builder.first(); } find(id: string | number): Promise> { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .find(id); + return this.builder.find(id); } where(attribute: string, value: string): Builder { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .where(attribute, value); + return this.builder.where(attribute, value); } with(value: any): Builder { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .with(value); + return this.builder.with(value); } public orderBy(attribute: string, direction?: SortDirection|string): Builder { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .orderBy(attribute, direction); + return this.builder.orderBy(attribute, direction); } option(queryParameter: string, value: string): Builder { - return new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId()) - .option(queryParameter, value); + return this.builder.option(queryParameter, value); + } + + private get builder() + { + return new Builder( + this.relatedType, + this.name, + this.getReferringType().effectiveEndpoint, + this.referringObject.getApiId() + ); } } diff --git a/src/relation/ToOneRelation.ts b/src/relation/ToOneRelation.ts index 42018f0..d9f1a3e 100644 --- a/src/relation/ToOneRelation.ts +++ b/src/relation/ToOneRelation.ts @@ -8,37 +8,41 @@ import {Model} from "../Model"; export class ToOneRelation extends Relation implements QueryMethods> { get(page?: number): Promise> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .get(page); + return this.builder.get(page); } first(): Promise> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .first(); + return this.builder.first(); } find(id: string | number): Promise> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .find(id); + return this.builder.find(id); } where(attribute: string, value: string): Builder> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .where(attribute, value); + return this.builder.where(attribute, value); } with(value: any): Builder> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .with(value); + return this.builder.with(value); } orderBy(attribute: string, direction?: SortDirection|string): Builder> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .orderBy(attribute, direction); + return this.builder.orderBy(attribute, direction); } option(queryParameter: string, value: string): Builder> { - return new Builder>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true) - .option(queryParameter, value); + return this.builder.option(queryParameter, value); + } + + private get builder() + { + return new Builder>( + this.relatedType, + this.name, + this.getReferringType().effectiveEndpoint, + this.referringObject.getApiId(), + true + ); } }