Created
April 12, 2018 18:16
-
-
Save bgentry/25630f9549231656a3a90853945e9e3d to your computer and use it in GitHub Desktop.
Ember identity map for ember-apollo-client models
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this is an example model | |
import ObjectProxy from "@ember/object/proxy"; | |
function objectEqual(a, b) { | |
if (typeOf(a) === "instance" || typeOf(b) === "instance") { | |
return isEqual(a, b); | |
} else if (typeOf(a) === "object" && typeOf(b) === "object") { | |
return Object.entries(a).every(([propname, value]) => { | |
return b[propname] === value; | |
}); | |
} | |
return a === b; | |
} | |
export default ObjectProxy.extend({ | |
isEqual(other) { | |
if (other instanceof ObjectProxy) { | |
let otherContent = get(other, "content"); | |
return objectEqual(get(this, "content"), otherContent); | |
} | |
return false; | |
}, | |
// go nuts with computed properties, service injections, etc | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A route where we immediately wrap the EmberObject from ember-apollo-client in our model type: | |
import Route from "@ember/route"; | |
import query from "myapp/gql/queries/batch-show"; | |
import { Promise as RSVPPromise } from "rsvp"; | |
import { inject as service } from "@ember/service"; | |
export default ProtectedRoute.extend({ | |
store: service(), | |
model({ id }) { | |
return this.get("apollo") | |
.watchQuery( | |
{ | |
query, | |
variables: { id }, | |
fetchPolicy: "cache-and-network", | |
}, | |
"batch" | |
) | |
.then(result => { | |
return RSVPPromise.resolve( | |
result | |
? this.get("store").createRecord("batch", { content: result }) | |
: result | |
); | |
}); | |
}, | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An identity map service that performs the functions often handled by the "store" service of other Ember data-related addons. | |
import Service from "@ember/service"; | |
import { A } from "@ember/array"; | |
import EmberObject from "@ember/object"; | |
import { assert } from "@ember/debug"; | |
import { getOwner } from "@ember/application"; | |
function buildRecord(type, data, store) { | |
return createRecord(type, data, store); | |
} | |
function createRecord(type, data, store) { | |
let factory = factoryForType(type, store); | |
let primaryKey = primaryKeyForType(type, store); | |
assert(`No model was found for type: ${type}`, factory); | |
let record = factory.create(data); | |
let id = data[primaryKey]; | |
identityMapForType(type, store)[id] = record; | |
return record; | |
} | |
function factoryForType(type, store) { | |
return getOwner(store).factoryFor(`model:${type}`); | |
} | |
function primaryKeyForType(type, store) { | |
const factory = factoryForType(type, store) || {}; | |
// http://emberjs.com/deprecations/v2.x/#toc_migrating-from-_lookupfactory-to-factoryfor | |
return factory.class && (factory.class.primaryKey || "id"); | |
} | |
function identityMapForType(type, store) { | |
let typeIdentityMap = store.get("identityMap"); | |
let idIdentityMap = typeIdentityMap[type] || {}; | |
typeIdentityMap[type] = idIdentityMap; | |
return idIdentityMap; | |
} | |
const ServiceType = Service || EmberObject; | |
let Store = ServiceType.extend({ | |
init() { | |
this._super(...arguments); | |
this.reset(); | |
}, | |
reset() { | |
this.set("recompute", A()); | |
this.set("filtersMap", {}); | |
this.set("identityMap", {}); | |
}, | |
willDestroy() { | |
this.setProperties({ | |
identityMap: null, | |
filtersMap: null, | |
recompute: null, | |
}); | |
}, | |
clear(type) { | |
if (type === undefined) { | |
this.reset(); | |
} | |
delete this.get("identityMap")[type]; | |
this.scheduleUpdate(type); | |
}, | |
createRecord(type, data) { | |
return buildRecord(type, data, this); | |
}, | |
}); | |
export default Store; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A component where we take the plain EmberObject as input, and use a computed to wrap it in our model object: | |
import Component from "@ember/component"; | |
import { computed } from "@ember/object"; | |
import { inject as service } from "@ember/service"; | |
export default Component.extend({ | |
batch: null, // the raw EmberObject returned by ember-apollo-client | |
store: service(), | |
// the model-ized version: | |
batch: computed("rawBatch", function() { | |
return this.get("store").createRecord("batch", { | |
content: this.get("rawBatch") || {}, | |
}); | |
}), | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment