|
import Adapter from 'ember-data/adapters/json-api'; |
|
import { Promise, resolve, all } from 'rsvp'; |
|
import Ember from 'ember'; |
|
|
|
const { run } = Ember; |
|
|
|
const PETS = { |
|
'1': { name: 'Shen', owner: '1' }, |
|
'2': { name: 'Pirate', owner: '1' }, |
|
'3': { name: 'Rebel', owner: '2' }, |
|
'4': { name: 'Messi', owner: '2' }, |
|
'5': { name: 'Lion', owner: '3' }, |
|
'6': { name: 'Beast', owner: '3' }, |
|
}; |
|
function getPet(id) { |
|
return { |
|
type: 'pet', |
|
id, |
|
attributes: { |
|
name: PETS[id].name |
|
}, |
|
relationships: { |
|
owner: { |
|
data: { type: 'person', id: PETS[id].owner } |
|
} |
|
} |
|
} |
|
} |
|
|
|
function getPets(ids) { |
|
alert(`Coalesced Request For ${ids.join(', ')}`); |
|
return resolve({ |
|
data: ids.map(getPet) |
|
}); |
|
} |
|
|
|
export default class ApplicationAdapter extends Adapter { |
|
constructor() { |
|
super(...arguments); |
|
this.coalescedResourceFinds = new Map(); |
|
} |
|
|
|
_flushCoalescedFind(type) { |
|
let map = this.coalescedResourceFinds; |
|
let finds = map.get(type); |
|
map.delete(type); |
|
let ids = Object.keys(finds); |
|
|
|
getPets(ids).then(doc => { |
|
// in real life we would normalize here first |
|
// but since we are already json-api we are good |
|
let { data } = doc; |
|
|
|
if (!Array.isArray(data)) { |
|
throw new Error('wrong stuff bud'); |
|
} |
|
|
|
let lookupDict = Object.create(null); |
|
data.forEach(resource => { |
|
if (resource.type === type) { |
|
lookupDict[resource.id] = resource; |
|
} |
|
}); |
|
|
|
ids.forEach(id => { |
|
let resource = lookupDict[id]; |
|
|
|
if (!resource) { |
|
// probably actually reject |
|
throw new Error('missing stuff'); |
|
} |
|
|
|
// resolve the original request |
|
finds[id]({ data: resource }); |
|
}); |
|
|
|
// make sure all returned records are pushed, |
|
// not just the specifically requested ones |
|
this.store.push(doc); |
|
}); |
|
} |
|
|
|
findResource({ type, id }) { |
|
let map = this.coalescedResourceFinds; |
|
let finds = map.get(type); |
|
|
|
if (!finds) { |
|
finds = Object.create(null); |
|
map.set(type, finds); |
|
run.next(() => { |
|
this._flushCoalescedFind(type); |
|
}); |
|
|
|
// de-dupe duplicate finds |
|
} else if (finds[id]) { |
|
return finds[id]; |
|
} |
|
|
|
return new Promise(resolveFind => { |
|
finds[id] = resolveFind; |
|
}); |
|
} |
|
|
|
findHasMany(store, snapshot, link, relationshipMeta) { |
|
let promises = snapshot.hasMany(relationshipMeta.key) |
|
.map(i => { |
|
return this.findResource({ |
|
type: relationshipMeta.type, |
|
id: i.id |
|
}); |
|
}); |
|
|
|
return all(promises).then(results => { |
|
return { |
|
data: results.map(result => result.data) |
|
}; |
|
}); |
|
} |
|
} |