Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add hook to generate client-side IDs

Previously, the store assumed that record IDs
would always be generated on the server, and
did not update bookkeeping information about
server IDs until the `didCreateRecord` method
was called.

Now, adapters may optionally implement the
`generateIdForRecord` method, which is invoked
each time a new record is created. If this method
exists, its return value will be used as the
record's ID, and internal store bookkeeping will
be updated.

This commit also adds some cursory documentation
to the DS.Adapter file.
  • Loading branch information...
commit b41d355f5440c6ff1796a4d9da967df7f879ad61 1 parent 6fca4fc
tomhuda authored
86 packages/ember-data/lib/system/adapters.js
View
@@ -1,4 +1,90 @@
+/**
+ An adapter is an object that receives requests from a store and
+ translates them into the appropriate action to take against your
+ persistence layer. The persistence layer is usually an HTTP API, but may
+ be anything, such as the browser's local storage.
+
+ ### Creating an Adapter
+
+ First, create a new subclass of `DS.Adapter`:
+
+ App.MyAdapter = DS.Adapter.extend({
+ // ...your code here
+ });
+
+ To tell your store which adapter to use, set its `adapter` property:
+
+ App.store = DS.Store.create({
+ revision: 3,
+ adapter: App.MyAdapter.create()
+ });
+
+ `DS.Adapter` is an abstract base class that you should override in your
+ application to customize it for your backend. The minimum set of methods
+ that you should implement is:
+
+ * `find()`
+ * `createRecord()`
+ * `updateRecord()`
+ * `deleteRecord()`
+
+ To improve the network performance of your application, you can optimize
+ your adapter by overriding these lower-level methods:
+
+ * `findMany()`
+ * `createRecords()`
+ * `updateRecords()`
+ * `deleteRecords()`
+ * `commit()`
+
+ For more information about the adapter API, please see `README.md`.
+*/
+
DS.Adapter = Ember.Object.extend({
+ /**
+ The `find()` method is invoked when the store is asked for a record that
+ has not previously been loaded. In response to `find()` being called, you
+ should query your persistence layer for a record with the given ID. Once
+ found, you can asynchronously call the store's `load()` method to load
+ the record.
+
+ Here is an example `find` implementation:
+
+ find: function(store, type, id) {
+ var url = type.url;
+ url = url.fmt(id);
+
+ jQuery.getJSON(url, function(data) {
+ // data is a Hash of key/value pairs. If your server returns a
+ // root, simply do something like:
+ // store.load(type, id, data.person)
+ store.load(type, id, data);
+ });
+ }
+ */
+ find: null,
+
+ /**
+ If the globally unique IDs for your records should be generated on the client,
+ implement the `generateIdForRecord()` method. This method will be invoked
+ each time you create a new record, and the value returned from it will be
+ assigned to the record's `primaryKey`.
+
+ Most traditional REST-like HTTP APIs will not use this method. Instead, the ID
+ of the record will be set by the server, and your adapter will update the store
+ with the new ID when it calls `didCreateRecord()`. Only implement this method if
+ you intend to generate record IDs on the client-side.
+
+ The `generateIdForRecord()` method will be invoked with the requesting store as
+ the first parameter and the newly created record as the second parameter:
+
+ generateIdForRecord: function(store, record) {
+ var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision();
+ return uuid;
+ }
+ */
+ generateIdForRecord: null,
+
commit: function(store, commitDetails) {
commitDetails.updated.eachType(function(type, array) {
this.updateRecords(store, type, array.slice());
14 packages/ember-data/lib/system/store.js
View
@@ -169,7 +169,19 @@ DS.Store = Ember.Object.extend({
// Extract the primary key from the `properties` hash,
// based on the `primaryKey` for the model type.
- var id = properties[get(record, 'primaryKey')] || null;
+ var primaryKey = get(record, 'primaryKey'),
+ id = properties[primaryKey] || null;
+
+ // If the passed properties do not include a primary key,
+ // give the adapter an opportunity to generate one.
+ var adapter;
+ if (Ember.none(id)) {
+ adapter = get(this, 'adapter');
+ if (adapter && adapter.generateIdForRecord) {
+ id = adapter.generateIdForRecord(this, record);
+ properties.id = id;
+ }
+ }
var hash = {}, clientId;
48 packages/ember-data/tests/integration/store_adapter_test.js
View
@@ -127,6 +127,54 @@ test("when all records for a type are requested, the adapter's findAll method is
equal(get(array, 'length'), 0, "The array is 0 length do far");
});
+test("if an adapter implements the generateIdForRecord method, it gets invoked when new records are created", function() {
+ expect(7);
+
+ var idCount = 0;
+
+ var Comment = DS.Model.extend();
+ var Post = DS.Model.extend({
+ primaryKey: 'fooId',
+ comments: DS.hasMany(Comment)
+ });
+
+ Comment.reopen({
+ primaryKey: '__ID',
+ post: DS.belongsTo(Post)
+ });
+
+ var adapter = DS.Adapter.create({
+ generateIdForRecord: function(passedStore, record) {
+ equal(store, passedStore, "should pass store as first parameter");
+ ok(true, "generateIdForRecord should be called");
+ return "id-" + (++idCount);
+ },
+
+ createRecord: function(store, type, record) {
+ if (type === Comment) {
+ equal(get(record, 'id'), 'id-1', "created record should be assigned correct id");
+ } else {
+ equal(get(record, 'id'), 'id-2', "second record should be assigned the correct id");
+ }
+ }
+ });
+
+ var store = DS.Store.create({
+ adapter: adapter
+ });
+
+ var comment = store.createRecord(Comment);
+ var post = store.createRecord(Post);
+
+ set(comment, 'post', post);
+
+ equal(comment.toJSON().post_id, "id-2", "assigned id is immediately available in JSON form of record");
+
+ Ember.run(function() {
+ store.commit();
+ });
+});
+
test("when a store is committed, the adapter's commit method is called with updates", function() {
expect(2);
Please sign in to comment.
Something went wrong with that request. Please try again.