@herlinus/coloquent
Version:
Library for retrieving model objects from a JSON-API, with a fluent syntax inspired by Laravel Eloquent.
116 lines • 4.9 kB
JavaScript
import { ToManyRelation } from "../relation/ToManyRelation";
import { ToOneRelation } from "../relation/ToOneRelation";
import { Map } from "../util/Map";
import { Response } from "./Response";
export class RetrievalResponse extends Response {
constructor(query, httpClientResponse, modelType, responseBody) {
super(query, httpClientResponse);
this.modelType = modelType;
this.resourceIndex = new Map();
this.modelIndex = new Map();
// Index the JsonApiDocs
this.indexIncludedDocs(responseBody.included);
this.indexRequestedResources(responseBody.data);
// Build Models from the JsonApiDocs, for which the previously built indexes come in handy
this.makeModelIndex(responseBody.data);
// Prepare arrays for immediate access through this.getData() and this.getIncluded()
this.makeDataArray(responseBody.data);
this.makeIncludedArray(responseBody.included);
}
getIncluded() {
return this.included;
}
indexIncludedDocs(includedDocs = []) {
for (let doc of includedDocs) {
this.indexDoc(doc);
}
}
indexDoc(doc) {
let type = doc.type;
let id = doc.id;
if (!this.resourceIndex.get(type)) {
this.resourceIndex.set(type, new Map());
}
this.resourceIndex.get(type).set(id, doc);
}
indexAsModel(doc, modelType, includeTree) {
let type = doc.type;
let id = doc.id;
if (!this.modelIndex.get(type)) {
this.modelIndex.set(type, new Map());
}
if (modelType.polymorphicOn) {
modelType = modelType.getClass(doc) || modelType;
}
let model = new modelType();
model.populateFromResource(doc, true);
this.modelIndex.get(type).set(id, model);
for (let resourceRelationName in Object.assign(Object.assign({}, includeTree), doc.relationships)) {
const modelRelationName = this.convertRelationNameToCamelCase(resourceRelationName);
if (model[modelRelationName] === undefined) {
continue;
}
const includeSubtree = includeTree ? includeTree[resourceRelationName] : {};
let relation = model[modelRelationName];
if (relation instanceof Function) {
relation = relation.call(model);
}
if (relation instanceof ToManyRelation) {
let relatedStubs = (doc.relationships !== undefined && doc.relationships[resourceRelationName] !== undefined)
?
doc.relationships[resourceRelationName].data
:
undefined;
let r = [];
if (relatedStubs) {
for (let stub of relatedStubs) {
let relatedDoc = this.resourceIndex.get(stub.type).get(stub.id);
let relatedModel = this.indexAsModel(relatedDoc, relation.getType(), includeSubtree);
r.push(relatedModel);
}
}
model.setRelation(modelRelationName, r, true);
}
else if (relation instanceof ToOneRelation) {
let stub = (doc.relationships !== undefined && doc.relationships[resourceRelationName] !== undefined)
?
doc.relationships[resourceRelationName].data
:
undefined;
let relatedModel = null;
if (stub) {
let typeMap = this.resourceIndex.get(stub.type);
if (typeMap) {
let relatedDoc = typeMap.get(stub.id);
relatedModel = this.indexAsModel(relatedDoc, relation.getType(), includeSubtree);
}
}
model.setRelation(modelRelationName, relatedModel, true);
}
else {
throw new Error('Unknown type of Relation encountered: ' + typeof relation);
}
}
return model;
}
makeIncludedArray(includedDocs = []) {
this.included = [];
for (let doc of includedDocs) {
const models = this.modelIndex.get(doc.type);
if (models !== undefined) {
this.included.push(models.get(doc.id));
}
}
}
convertRelationNameToCamelCase(relationName) {
return relationName.replace(/-\w/g, (m) => m[1].toUpperCase());
}
static coalesceUndefinedIntoNull(value) {
return value !== undefined
?
value
:
null;
}
}
//# sourceMappingURL=RetrievalResponse.js.map