Permalink
Browse files

Merge branch 'relationship-improvements'

  • Loading branch information...
2 parents e846f50 + d870297 commit b5660bdc25bfd03af95e3746696a13db07612d10 @wycats wycats committed Oct 13, 2012
Showing with 15,645 additions and 10,500 deletions.
  1. +3 −1 .jshintrc
  2. +236 −0 ARCHITECTURE.md
  3. +329 −0 BREAKING_CHANGES.md
  4. +2 −0 packages/ember-data/lib/adapters.js
  5. +7 −7 packages/ember-data/lib/adapters/fixture_adapter.js
  6. +40 −17 packages/ember-data/lib/adapters/rest_adapter.js
  7. +80 −0 packages/ember-data/lib/adapters/transforms.js
  8. +1 −1 packages/ember-data/lib/core.js
  9. +3 −3 packages/ember-data/lib/main.js
  10. +276 −0 packages/ember-data/lib/system/adapter.js
  11. +0 −125 packages/ember-data/lib/system/adapters.js
  12. +1 −0 packages/ember-data/lib/system/application_ext.js
  13. +1 −0 packages/ember-data/lib/system/associations.js
  14. +46 −36 packages/ember-data/lib/system/associations/belongs_to.js
  15. +74 −1 packages/ember-data/lib/system/associations/ext.js
  16. +6 −18 packages/ember-data/lib/system/associations/has_many.js
  17. +352 −0 packages/ember-data/lib/system/associations/one_to_many_change.js
  18. +0 −1 packages/ember-data/lib/system/model.js
  19. +19 −115 packages/ember-data/lib/system/model/attributes.js
  20. +0 −140 packages/ember-data/lib/system/model/data_proxy.js
  21. +330 −221 packages/ember-data/lib/system/model/model.js
  22. +168 −284 packages/ember-data/lib/system/model/states.js
  23. +2 −2 packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js
  24. +1 −0 packages/ember-data/lib/system/record_arrays/filtered_record_array.js
  25. +176 −65 packages/ember-data/lib/system/record_arrays/many_array.js
  26. +13 −3 packages/ember-data/lib/system/record_arrays/record_array.js
  27. +395 −0 packages/ember-data/lib/system/serializer.js
  28. +750 −200 packages/ember-data/lib/system/store.js
  29. +76 −189 packages/ember-data/lib/system/transaction.js
  30. +83 −0 packages/ember-data/tests/helpers.js
  31. +0 −50 packages/ember-data/tests/integration/app_test.js
  32. +41 −0 packages/ember-data/tests/integration/application_test.js
  33. +166 −81 packages/ember-data/tests/integration/associations_test.js
  34. +61 −0 packages/ember-data/tests/integration/client_id_generation_test.js
  35. +75 −0 packages/ember-data/tests/integration/find_all_test.js
  36. +82 −0 packages/ember-data/tests/integration/find_test.js
  37. +41 −0 packages/ember-data/tests/integration/mapping_test.js
  38. +197 −0 packages/ember-data/tests/integration/materialization_tests.js
  39. +51 −0 packages/ember-data/tests/integration/queries_test.js
  40. +310 −0 packages/ember-data/tests/integration/record_persistence_test.js
  41. +657 −0 packages/ember-data/tests/integration/rollback_test.js
  42. +172 −0 packages/ember-data/tests/integration/serialization_test.js
  43. +47 −407 packages/ember-data/tests/integration/store_adapter_test.js
  44. +393 −0 packages/ember-data/tests/integration/store_model_filter_test.js
  45. +85 −0 packages/ember-data/tests/integration/transaction_adapter_test.js
  46. +43 −0 packages/ember-data/tests/integration/transform_test.js
  47. +226 −0 packages/ember-data/tests/unit/adapter_test.js
  48. +48 −185 packages/ember-data/tests/unit/associations_test.js
  49. +15 −15 packages/ember-data/tests/unit/fixture_adapter_test.js
  50. +0 −125 packages/ember-data/tests/unit/many_array_test.js
  51. +158 −338 packages/ember-data/tests/unit/model_test.js
  52. +29 −261 packages/ember-data/tests/unit/record_array_test.js
  53. +21 −1 packages/ember-data/tests/unit/rest_adapter_test.js
  54. +260 −0 packages/ember-data/tests/unit/serializer_test.js
  55. +84 −26 packages/ember-data/tests/unit/store_test.js
  56. +0 −298 packages/ember-data/tests/unit/to_json_test.js
  57. +57 −44 packages/ember-data/tests/unit/transaction_test.js
  58. +4,365 −2,969 packages/ember/lib/main.js
  59. +108 −0 tests/ember_configuration.js
  60. +17 −133 tests/index.html
  61. +4,312 −4,138 tests/{jquery-1.7.1.js → jquery-1.8.2.js}
  62. +54 −0 tests/qunit_configuration.js
View
@@ -22,7 +22,9 @@
"strictEqual",
"module",
"expect",
- "minispade"
+ "minispade",
+ "async",
+ "invokeAsync"
],
"node" : false,
View
@@ -0,0 +1,236 @@
+# Ember Data Architecture
+
+## Roles & Responsibilities
+
+### DS.Store
+
+The store is the primary interface between the application developer
+and the data store. It is responsible for managing all available
+records, both materialized and immaterialized. At its core, it is a
+bookkeeping object that indexes loaded hashes, and serves as a
+coordinator between the other objects in the system.
+
+* Indexes data hashes by type and ID
+* Supplies a `clientId` for each requested record, and maps type/ID
+ to `clientId`s and vice versa.
+* Serves as an identity map for records of a given type/ID
+* Creates new records and transactions
+ * By default, `Post.createRecord()` asks the default store to
+ create the record.
+ * Optionally, coordinates with adapter to generate a client-generated
+ ID for new records.
+* Coordinates with the adapter to request records (find, findMany,
+ findAll, findQuery).
+* Sends lifecycle events to records. For example, the store notifies
+ a record when the adapter has saved its pending changes (`didCommit`)
+* Serves as the callback target for the adapter (`didCreateRecord`, et
+ al)
+* Responsible for managing indexes that power live record arrays
+ * Filters: when a new data hash is loaded into the store, it updates
+ any filters registered on that type. Records notify the store
+ (via `hashWasUpdated`) when any properties change, causing the
+ filters to update.
+ * `find()`: `find()` is a special filter that matches all records
+ for a given type.
+
+### DS.Model
+
+A model defines the attributes and relationships for a given type.
+Instances of models, called records, are objects that provide an Ember
+interface to JSON hashes returned by the server. Internally, records
+keep track of their original JSON hash and any unsaved changes (see
+`DataProxy` below for more details).
+
+Records move through states in a state manager throughout their life.
+For example, a newly created record begins its life in the
+`loaded.created` state. A record requested from the server starts in the
+`loading` state, and moves into the `loaded.saved` state once the server
+returns its JSON hash.
+
+When a store materializes a record, it asks the adapter (see below) to
+extract the record's attributes and associations and normalize their
+names. This means that records will always have normalized data hashes.
+
+* Has a series of lifecycle flags (`isLoaded`, etc.)
+* Serializes the record into a persistable JSON hash, accepting
+ adapter-provided options (such as `includeForeignKeys`).
+* Manages an underlying `DataProxy`
+* Manages a `StateManager` and sends any events to its state manager
+* Tracks its current transaction
+* Sends events to the transaction when the record becomes dirty
+* Updates materialized `ManyArrays` if the underlying data changes
+* Aliases store methods that require a type parameter to the `DS.Model`
+ type. For example, instead of requiring you to call
+ `store.find(App.Person, 1)`, you can say `App.Person.find(1)`.
+
+### DataProxy
+
+A record's `DataProxy` wraps its server-returned JSON hash plus any
+unsaved changes in a single object.
+
+It also supports `commit`, which collapses the unsaved changes into
+the saved changes, and `rollback`, which discards any unsaved changes.
+
+### Record State Manager
+
+Manages the current state of a record. Every record has its own instance
+of the `StateManager`.
+
+When events occur to the record (e.g. the data hash changes, the store
+acknowledges its commit), the record sends events to the state manager.
+This allows the record to have context-specific responses to these
+events, and initiate state transitions in response to events.
+
+There is a lot of specific documentation in `system/model/states.js`.
+
+### DS.Transaction
+
+A transaction represents a unit of work that can be atomically committed
+to the adapter. When a transaction is committed, it is responsible for
+providing all of the changes to the adapter to save. A transaction can
+also be rolled back, which reverts any changes that occurred but had not
+yet been saved to the adapter.
+
+Every record must belong to a transaction. By default, records belong
+to the default transaction, which is a transaction that is implicitly
+created with the store.
+
+Transactions are ephemeral objects. Once committed or rolled back, they
+should not be used again.
+
+* Stores references to records, grouped by the current state of the
+ record.
+ * For example, a newly created record is saved in the `created`
+ bucket, while a record that has attributes changed is saved in the
+ `updated` bucket.
+* Stores descriptions of changed relationships. When a relationship
+ changes, information about its old parent, new parent, and new child
+ is saved in the transaction.
+* Raises an exception if changes in relationships are made between
+ records that are in different transactions.
+* Able to move records into itself from another transaction if it is
+ legal.
+* When committed, provides changed records to the adapter and
+ responsible for moving those records into an `inFlight` state.
+* After committing or rolling back, moves clean records into the store's
+ default transaction.
+* When rolled back, the transaction notifies all changed records to
+ discard changes.
+
+### DS.RecordArray
+
+Record arrays represent an ordered list of records. They are backed by
+an array of client IDs. When retrieving a record from the record array,
+it will be materialized lazily if necessary.
+
+`DS.RecordArray` is an abstract base class that provides many of the
+features needed by its concrete implementations, described below.
+
+### DS.ManyArray
+
+Represents a one-to-many relationship. When the association is retrieved
+from a record, a `ManyArray` is created that contains an array of the
+client IDs that belong to that record.
+
+* Notifies the transaction if the relationship is modified
+* Tracks aggregate state of member records via `isLoaded` flag
+* Updates added records to point ther inverse association to the new
+ parent.
+
+### DS.AdapterPopulatedRecordArray
+
+Represents an ordered list of records whose order and membership is
+determined by the adapter. For example, a query sent to the adapter may
+trigger a search on the server, whose results would be loaded into an
+instance of the `AdapterPopulatedRecordArray`.
+
+### DS.FilteredRecordArray
+
+Represents a list of records whose membership is determined by the
+store. As records are created, loaded, or modified, the store evaluates
+them to determine if they should be part of the record array.
+
+### DS.Adapter
+
+The adapter is responsible for translating a store request into the
+appropriate action to take against a persistence layer. For example, a
+REST adapter may translate the request to find a record of type
+`App.Photo` with ID `1` into an HTTP `GET` request to
+`/photos/1`.
+
+The responsibility of the adapter fall into two general categories:
+retrieving records and committing changes to records.
+
+#### Finding Via an Adapter
+
+* Loading records into the store in response to `find()`
+* Loading multiple records into the store in response to `findMany()`
+* Loading the results of a query into an `AdapterPopulatedRecordArray`
+ in response to a `findQuery()`
+* Loading records into the store in response to `findAll()`
+
+#### Saving Changes
+
+The adapter receives a list of all changes from a transaction in
+its `commit()` method. It is responsible for evaluating those changes,
+figuring out what to do in order to persist them, and letting the
+store know when the server acknowledged the save for a given
+record.
+
+As part of this process, the adapter receives a list of all
+created, updated, and deleted records, as well as a list of all
+changes to relationships.
+
+In order to make this easy for an adapter to implement this pattern,
+the `DS.Adapter` abstract class offers some conveniences:
+
+* If a record has no attribute changes, but is involved in a
+ relationship change, the abstract `DS.Adapter` calls the
+ `shouldCommit` method with the ambiguous record and the
+ relationship changes.
+ * In a relational model, for example, the adapter will return
+ true if the record is the child of a relationship change
+ and false if the record is the old or new parent.
+ * If the `shouldCommit` method returns false, the abstract
+ `commit` method will immediately call `didUpdateRecord`
+ on the store.
+* If a record is involved in a relationship change, the abstract
+ `commit` method will call the adapter's `willCommit` method
+ with the record and the list of relationships.
+ * This gives the adapter an opportunity to pend the record.
+ For example, if a child record needs a foreign key, but
+ the parent record's ID does not exist yet, the adapter
+ can wait for the parent ID to become populated.
+* The abstract `commit` method will call `createRecords`,
+ `updateRecords`, and `deleteRecords` to allow the adapter
+ to break up the commits to the server in an appropriate way.
+
+#### Client-Side ID Generation
+
+Adapters can specify a mechanism for new records to generate client-side
+IDs. In general, this method should return a UUID or something with
+extremely low collission possibility.
+
+When a store creates a new record, it first consults the adapter to
+determine whether the ID can be generated on the client. If so, it will
+apply the generated ID to the record immediately.
+
+One major benefit of generating IDs on the client is that records do not
+need to wait for associated records to be saved in order to retrieve
+their foreign keys.
+
+#### Naming Conventions
+
+The adapter is also responsible for normalizing a server-provided data
+hash to the naming expected by Ember.
+
+In general, this means converting underscored names to camelcased names.
+
+It is also responsible for converting dirty records into a data hash
+expected by the server. For example, the adapter may need to add a
+foreign key to the data hash by adding `_id` to its association.
+
+The abstract adapter class provides normalization functions that call
+into the `namingConvention` hash in the concrete classes. For very
+custom logic, the concrete classes may want to override the
+normalization directly, but that should be very rare.
Oops, something went wrong.

0 comments on commit b5660bd

Please sign in to comment.