Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/Builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,19 @@ export class Builder<M extends Model = Model, GET_RESPONSE extends RetrievalResp
constructor(
modelType: typeof Model,
queriedRelationName: string | undefined = undefined,
baseModelJsonApiType: string | undefined = undefined,
rootEndpoint: string | undefined = undefined,
baseModelJsonApiId: string | undefined = undefined,
forceSingular: boolean = false
) {
this.modelType = modelType;
this.baseUrl = modelType.effectiveJsonApiBaseUrl;
baseModelJsonApiType = baseModelJsonApiType
? baseModelJsonApiType
: modelType.effectiveJsonApiType;
this.query = new Query(baseModelJsonApiType, queriedRelationName, baseModelJsonApiId);
this.query = new Query(
rootEndpoint
? rootEndpoint
: modelType.effectiveEndpoint,
queriedRelationName,
baseModelJsonApiId
);
this.initPaginationSpec();
this.httpClient = modelType.effectiveHttpClient;
this.forceSingular = forceSingular;
Expand Down Expand Up @@ -183,7 +186,7 @@ export class Builder<M extends Model = Model, GET_RESPONSE extends RetrievalResp
private clone(): Builder<M, GET_RESPONSE>
{
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));
Expand Down
2 changes: 1 addition & 1 deletion src/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(/^\/+/, '');
}

Expand Down
39 changes: 16 additions & 23 deletions src/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {QueryParam} from "./QueryParam";

export class Query
{
protected jsonApiType: string;
public readonly rootEndpoint: string;

protected jsonApiId: string | undefined;

Expand All @@ -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 = [];
Expand Down Expand Up @@ -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);
Expand All @@ -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()
Expand Down
58 changes: 29 additions & 29 deletions src/relation/Relation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,40 @@ import {Model} from "../Model";
import {Reflection} from "../util/Reflection";
export class Relation<R extends Model = Model>
{
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
Expand All @@ -38,23 +50,11 @@ export class Relation<R extends Model = Model>

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;
}
}
31 changes: 17 additions & 14 deletions src/relation/ToManyRelation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,40 @@ import {Model} from "../Model";
export class ToManyRelation<M extends Model = Model, R extends Model = Model> extends Relation<R> implements QueryMethods<M, PluralResponse<M>>
{
get(page?: number): Promise<PluralResponse<M>> {
return <Promise<PluralResponse<M>>> new Builder(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId())
.get(page);
return this.builder.get(page);
}

first(): Promise<SingularResponse<M>> {
return new Builder<M>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId())
.first();
return this.builder.first();
}

find(id: string | number): Promise<SingularResponse<M>> {
return new Builder<M>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId())
.find(id);
return this.builder.find(id);
}

where(attribute: string, value: string): Builder<M> {
return new Builder<M>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId())
.where(attribute, value);
return this.builder.where(attribute, value);
}

with(value: any): Builder<M> {
return new Builder<M>(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<M> {
return new Builder<M>(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<M> {
return new Builder<M>(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<M>(
this.relatedType,
this.name,
this.getReferringType().effectiveEndpoint,
this.referringObject.getApiId()
);
}
}
32 changes: 18 additions & 14 deletions src/relation/ToOneRelation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,41 @@ import {Model} from "../Model";
export class ToOneRelation<M extends Model = Model, R extends Model = Model> extends Relation<R> implements QueryMethods<M, SingularResponse<M>>
{
get(page?: number): Promise<SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true)
.get(page);
return this.builder.get(page);
}

first(): Promise<SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true)
.first();
return this.builder.first();
}

find(id: string | number): Promise<SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true)
.find(id);
return this.builder.find(id);
}

where(attribute: string, value: string): Builder<M, SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(this.getType(), this.getName(), this.getReferringType().effectiveJsonApiType, this.getReferringObject().getApiId(), true)
.where(attribute, value);
return this.builder.where(attribute, value);
}

with(value: any): Builder<M, SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(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<M, SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(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<M, SingularResponse<M>> {
return new Builder<M, SingularResponse<M>>(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<M, SingularResponse<M>>(
this.relatedType,
this.name,
this.getReferringType().effectiveEndpoint,
this.referringObject.getApiId(),
true
);
}
}