Skip to content

Instantly share code, notes, and snippets.

@2468ben
Created September 10, 2015 01:48
Show Gist options
  • Save 2468ben/dde2d551a93509b99deb to your computer and use it in GitHub Desktop.
Save 2468ben/dde2d551a93509b99deb to your computer and use it in GitHub Desktop.
Active Model Sideload-only Serializer code
//mirage/config.js
import Em from 'ember';
import utils from 'ember-cli-mirage/shorthands/utils';
import serializerDefs from 'crowdly-pa/tests/helpers/serializer-defs';
import SerializerMachine from 'crowdly-pa/tests/helpers/serializer-machine';
import { pluralize } from 'ember-inflector';
export default function() {
this.timing = 50; // delay for each request, automatically set to 0 during testing
}
// You can optionally export a config that is only loaded during tests
export function testConfig() {
this.logging = true;
//Custom Serializer Machine
const sM = new SerializerMachine(server.db, serializerDefs);
server.sM = sM;
this.get('/me', (db, request) => {
const _me = db.users.find(1);
return sM.serializeRecords('user', _me, request);
});
}
//tests/helpers/mock-serializer.js
import extend from 'ember-cli-mirage/utils/extend';
class MockSerializer {
constructor() {
this.relationships.forEach((rel) => {
if(!rel.key) { rel.key = rel.type; }
if(!rel.inverseOf) { rel.inverseOf = this.type; }
const idSuffix = rel.assoc === 'belongsTo' ? '_id' : '_ids';
rel.fk = `${rel.key}${idSuffix}`;
});
}
serialize(record, request) {
return record;
}
relationshipsFor(record, request) {
return [];
}
relsByKey(keys = []) {
return keys.map((key) => this.relationships.findBy('key', key));
}
}
MockSerializer.prototype.relationships = [];
MockSerializer.prototype.type = null;
MockSerializer.extend = extend;
export default MockSerializer;
//tests/helpers/serializer-defs.js
import Em from 'ember';
import utils from 'ember-cli-mirage/shorthands/utils';
const serializerDefs = [
{
type: 'user',
relationships: [{
assoc: 'belongsTo',
type: 'partner'
},{
assoc: 'hasMany',
type: 'bucket_membership'
},{
assoc: 'hasMany',
type: 'topic'
},{
assoc: 'hasMany',
type: 'comment'
}],
relationshipsFor: function(record, request) {
const _qps = request.queryParams;
const _keys = ['bucket_membership'];
if(_qps.include_partner) { _keys.addObject('partner'); }
return this.relsByKey(_keys);
},
serialize: function(record, request) {
const _qps = request.queryParams;
const attrs = Em.copy(record);
if(!_qps.include_interaction_counts) {
delete attrs.likes_count;
delete attrs.comments_count;
delete attrs.shares_count;
} else if(_qps.is_reviewer) {
delete attrs.shares_count;
}
return attrs;
}
},{
type: 'partner',
relationships: [{
assoc: 'hasMany',
type: 'bucket'
},{
assoc: 'hasMany',
type: 'landing_page'
},{
assoc: 'hasMany',
type: 'external_link'
}],
relationshipsFor: function(record, request) {
return this.relsByKey(['bucket','landing_page','external_link']);
}
},{
type: 'landing_page',
relationships: [{
assoc: 'belongsTo',
type: 'partner'
},{
assoc: 'belongsTo',
type: 'bucket'
}]
},
{
type: 'external_link',
relationships: [{
assoc: 'belongsTo',
type: 'partner'
}],
serialize: function(record, request) {
const attrs = Em.copy(record);
if(!attrs.exclude_details) {
delete attrs.global_clicks;
delete attrs.shortened_clink_url;
}
return attrs;
}
},{
type: 'keyword',
relationships: [{
assoc: 'belongsTo',
type: 'user'
}]
},{
type: 'bucket',
relationships: [{
assoc: 'belongsTo',
type: 'partner'
},{
assoc: 'hasMany',
type: 'bucket_memberships'
},{
assoc: 'belongsTo',
type: 'landing_page'
}]
},{
type: 'bucket_membership',
relationships: [{
assoc: 'belongsTo',
type: 'partner'
},{
assoc: 'belongsTo',
type: 'bucket'
},{
assoc: 'belongsTo',
type: 'user'
},{
assoc: 'belongsTo',
type: null,
key: 'external',
polymorphic: true
}]
},{
type: 'like',
relationships: [{
assoc: 'belongsTo',
type: null,
key: 'subject',
inverseOf: 'partner_like',
polymorphic: true
}]
},{
type: 'topic',
relationships: [{
assoc: 'belongsTo',
type: 'user'
},{
assoc: 'belongsTo',
type: 'like',
key: 'partner_like',
inverseOf: 'subject'
},{
assoc: 'hasMany',
type: 'comment',
key: 'response',
inverseOf: 'subject'
},{
assoc: 'hasMany',
type: 'bucket_membership'
}],
serialize: function(record, request) {
const _qps = request.queryParams;
const attrs = Em.copy(record);
if(_qps.exclude_response_ids) {
delete attrs.response_ids;
} else if(attrs.response_ids) {
attrs.responses_count = attrs.response_ids.length;
}
return attrs;
},
relationshipsFor: function(record, request) {
return this.relsByKey(['user','partner_like','response']);
},
},{
type: 'comment',
relationships: [{
assoc: 'belongsTo',
type: 'user'
},{
assoc: 'belongsTo',
type: 'like',
key: 'partner_like'
},{
assoc: 'belongsTo',
type: 'topic',
key: 'subject',
inverseOf: 'response'
},{
assoc: 'belongsTo',
type: 'comment',
key: 'parent',
inverseOf: 'response'
},{
assoc: 'hasMany',
type: 'comment',
key: 'response',
inverseOf: 'parent'
},{
assoc: 'hasMany',
type: 'bucket_membership'
}],
relationshipsFor: function(record, request) {
return this.relsByKey(['user','partner_like','response']);
},
serialize: function(record, request) {
const _qps = request.queryParams;
const attrs = Em.copy(record);
if(_qps.exclude_response_ids) {
delete attrs.response_ids;
} else if(attrs.response_ids) {
attrs.responses_count = attrs.response_ids.length;
}
attrs.replyable = attrs.subject_id || attrs.parent_id;
return attrs;
}
}
];
export default serializerDefs;
//tests/helpers/serializer-machine.js
import Em from 'ember';
import { pluralize } from 'ember-inflector';
import MockSerializer from './mock-serializer';
class SerializerMachine {
constructor(db, defs) {
this.db = db;
this.setupSerializers(defs);
}
setupSerializers(defs) {
this.mockSerializers = {};
defs.forEach((def) => {
const _serializer = new (MockSerializer.extend(def))();
this.mockSerializers[_serializer.type] = _serializer;
});
}
addCollectionToResponse(response, collection) {
collection.forEach((recordsHash) => {
Object.keys(recordsHash).forEach((key) => {
recordsHash[key].forEach((record) => {
let listForKey = response[key] = Em.makeArray(response[key]);
const existingRecord = listForKey.findBy('id', record.id);
if(existingRecord) {
Em.merge(existingRecord, record);
} else {
listForKey.pushObject(record);
}
});
});
});
return response;
}
serializeRecords(type, records, request, response, key) {
const _collection = Em.makeArray(records).map((record) => this.serializeRecord(type, record, request, key));
return this.addCollectionToResponse(response || {}, _collection);
}
serializeRecord(type, record, request, key) {
const _model = this.mockSerializers[type];
const _response = {};
const _serializedRecord = _model.serialize(record, request);
_response[pluralize(key || _model.type)] = [_serializedRecord];
_model.relationshipsFor(record, request).forEach((relationship) => {
this.serializeRelationship(relationship, type, record, request, _response);
});
return _response;
}
serializeRelationship(relationship, type, record, request, response) {
let _fk, _fkid;
if(relationship.assoc === 'belongsTo') {
_fk = 'id';
_fkid = record[relationship.fk];
} else {
const inverseRel = this.getRelationship(relationship.type, relationship.inverseOf);
_fk = `${inverseRel.key}_id`;
_fkid = record.id;
}
const _collection = this.collectionFor(relationship.type);
if(!_fkid) { return; }
const _assocRecords = _collection.filterBy(_fk, _fkid);
if(!_assocRecords.length) { return; }
this.serializeRecords(relationship.type, _assocRecords, request, response, relationship.key);
}
getRelationship(recordType, relationshipKey) {
return this.mockSerializers[recordType].relsByKey([relationshipKey])[0];
}
collectionFor(type) {
return this.db[pluralize(type)];
}
}
export default SerializerMachine;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment