@bigtest/mirage
Version:
A client-side server to develop, test and prototype your app.
223 lines (175 loc) • 6.03 kB
JavaScript
import Serializer from '../serializer';
import { dasherize, pluralize, camelize } from '@bigtest/mirage';
import _get from 'lodash/get';
import _ from 'lodash';
const JSONAPISerializer = Serializer.extend({
keyForModel(modelName) {
return dasherize(modelName);
},
keyForCollection(modelName) {
return dasherize(modelName);
},
keyForAttribute(attr) {
return dasherize(attr);
},
keyForRelationship(key) {
return dasherize(key);
},
getHashForPrimaryResource(resource) {
let resourceHash = this.getHashForResource(resource);
let hashWithRoot = { data: resourceHash };
let addToIncludes = this.getAddToIncludesForResource(resource);
return [ hashWithRoot, addToIncludes ];
},
getHashForIncludedResource(resource) {
let serializer = this.serializerFor(resource.modelName);
let hash = serializer.getHashForResource(resource);
let hashWithRoot = { included: (this.isModel(resource) ? [ hash ] : hash) };
let addToIncludes = [];
if (!this.hasQueryParamIncludes()) {
addToIncludes = this.getAddToIncludesForResource(resource);
}
return [ hashWithRoot, addToIncludes ];
},
getHashForResource(resource) {
let hash;
if (this.isModel(resource)) {
hash = this._getResourceObjectForModel(resource);
} else {
hash = resource.models.map((m) => this._getResourceObjectForModel(m));
}
return hash;
},
/*
Returns a flat unique list of resources that need to be added to includes
*/
getAddToIncludesForResource(resource) {
let relationshipPaths;
if (_get(this, 'request.queryParams.include')) {
relationshipPaths = this.request.queryParams.include.split(',');
} else {
let serializer = this.serializerFor(resource.modelName);
relationshipPaths = serializer.getKeysForIncluded();
}
return this.getAddToIncludesForResourceAndPaths(resource, relationshipPaths);
},
getAddToIncludesForResourceAndPaths(resource, relationshipPaths) {
let includes = [];
relationshipPaths.forEach((path) => {
let relationshipNames = path.split('.');
let newIncludes = this.getIncludesForResourceAndPath(resource, ...relationshipNames);
includes.push(newIncludes);
});
return _(includes)
.flatten()
.compact()
.uniqBy(m => m.toString())
.value();
},
getIncludesForResourceAndPath(resource, ...names) {
let nameForCurrentResource = camelize(names.shift());
let includes = [];
let modelsToAdd = [];
if (this.isModel(resource)) {
let relationship = resource[nameForCurrentResource];
if (this.isModel(relationship)) {
modelsToAdd = [ relationship ];
} else if (this.isCollection(relationship)) {
modelsToAdd = relationship.models;
}
} else {
resource.models.forEach((model) => {
let relationship = model[nameForCurrentResource];
if (this.isModel(relationship)) {
modelsToAdd.push(relationship);
} else if (this.isCollection(relationship)) {
modelsToAdd = modelsToAdd.concat(relationship.models);
}
});
}
includes = includes.concat(modelsToAdd);
if (names.length) {
modelsToAdd.forEach((model) => {
includes = includes.concat(this.getIncludesForResourceAndPath(model, ...names));
});
}
return includes;
},
_getResourceObjectForModel(model) {
let attrs = this._attrsForModel(model, true);
delete attrs.id;
let hash = {
type: this.typeKeyForModel(model),
id: model.id,
attributes: attrs
};
return this._maybeAddRelationshipsToResourceObjectForModel(hash, model);
},
_maybeAddRelationshipsToResourceObjectForModel(hash, model) {
let relationships = model.associationKeys.reduce((relationships, key) => {
let relationship = model[key];
let relationshipKey = this.keyForRelationship(key);
let relationshipHash = {};
if (this.hasLinksForRelationship(model, key)) {
let serializer = this.serializerFor(model.modelName);
let links = serializer.links(model);
relationshipHash.links = links[key];
}
if (this.alwaysIncludeLinkageData || this._relationshipIsIncluded(key)) {
let data = null;
if (this.isModel(relationship)) {
data = {
type: this.typeKeyForModel(relationship),
id: relationship.id
};
} else if (this.isCollection(relationship)) {
data = relationship.models.map((model) => {
return {
type: this.typeKeyForModel(model),
id: model.id
};
});
}
relationshipHash.data = data;
}
if (!_.isEmpty(relationshipHash)) {
relationships[relationshipKey] = relationshipHash;
}
return relationships;
}, {});
if (!_.isEmpty(relationships)) {
hash.relationships = relationships;
}
return hash;
},
hasLinksForRelationship(model, relationshipKey) {
let serializer = this.serializerFor(model.modelName);
let links;
if (serializer.links) {
links = serializer.links(model);
return links[relationshipKey] != null;
}
},
_relationshipIsIncluded(relationshipKey) {
if (this.request && this.request.queryParams && this.request.queryParams.include) {
let relationshipKeyAsString = this.keyForRelationship(relationshipKey);
return this.request.queryParams
.include
.split(',')
.some(str => str.indexOf(relationshipKeyAsString) > -1);
} else {
return this.include.includes(relationshipKey);
}
},
getQueryParamIncludes() {
return (_get(this, 'request.queryParams.include'));
},
hasQueryParamIncludes() {
return !!this.getQueryParamIncludes();
},
typeKeyForModel(model) {
return dasherize(pluralize(model.modelName));
}
});
JSONAPISerializer.prototype.alwaysIncludeLinkageData = false;
export default JSONAPISerializer;