This document provides some discussion of design decisions and contains rather informal notes. dstore is distinct from other data modelling frameworks in large part due to its goals. This document is intended to describe those goals and design rationales. A few of the key goals of dstore: * The ultimate goal of dstore is facilitate applications with an amazing user experience. One of the most important ingredients to this experience is high performance components that can quickly and smoothly respond to the user. Consequently, dstore places a high priority on ensuring that data can be accessed as quickly as possible with as little overhead as possible. * dstore aims to provide a clean separation of concerns, helping to define a distinction between the data model and presentation (viewer and controller). * dstore aims to encapsulate data entities to minimize the interface between data models and presentation, and ensure that the presentation code can fully access and interact with data with this interface. * dstore aims to provide a consistent, predictable interface for accessing data. Unlike dojo object stores, dstore handles querying by providing several different query methods that each handle the different parts of a query, including filter and sort. Each of these returns a new collection, which can then be further queried. This purpose of this approach is: * Better encapsulation of a query result. A resulting collection can be passed to a grid without any extra coordination in regards to what query was used * This encapsulation also helps provide more legible querying * query metadata - All queries add query-related metadata to the collection they create. At first, we logged query metadata to separate `filtered`, `sorted`, and `ranged` properties, but doing so lost important information about the order of the queries. We migrated to a unified query log called `queryLog` which has the following benefits: * Retains the order of query operations * Allows easy examination and iteration of the query operations together * Stores querier functions separately rather than composed so a single querier can be invoked without invoking the others * queriers - Each query may have an associated querier function created based on the query arguments that takes an array of input data and returns an array of result data. For example, based on the filter arguments, a filter query may create a querier that takes an array of input data and returns an array of items that pass the filter. Client-side stores such as `dstore/Memory` completely rely on queriers to perform query operations, and the result-tracking mixin `Trackable` relies on queriers to determine a new or updated item's membership and location in a collection. Server-based collections such as `dstore/Rest` do not require queriers to operate, but queriers are required to properly maintain a server-based collection with `Trackable`. * querier factory methods - A collection may provide a querier factory method for each query type. Querier factory methods use the naming convention `'_createQuerier'`, take normalized arguments for their query type, and return a querier function based on those arguments. For example, a querier factory method for a sort query is named `'_createSortQuerier'`, takes normalized sort arguments, and returns a function that takes an array and sorts it according to the query's sort arguments. We explored using a single `queryEngine` property that could contain querier factories for supported query types, but when we started researching custom trackers for individual query types, it became clear the `queryEngine` approach was not sufficiently extensible. Instance methods make such functionality easy to extend through inheritance while objects on the prototype such as `queryEngine` are more difficult to extend. * sort - We had considered making sort modify the order of the current collection, or return a new sorted collection. Doing modification in-place had the advantage of avoiding any cloning of arrays to create a distinct sorted array, and being consistent with Array#sort. Returning a new sorted collection had the advantage of being more functional and consistent with the rest of the dstore collection API. With our initial delegation-based approach to creating new collections, creating new collections for sorts could lead to memory being retained in intermediate steps in querying, but we switched to a copy-based approach which allows intermediate steps in a multi-step query to be garbage collected. Sorting now returns a new sorted collection (not in-place). * Model constructor usage - One of the goals of the persisted objects is to allow an object to exist across numerous instantiations of an application. Consequently, there is a clear distinction between an existing object that is being restored into memory from storage, versus the creation of the a new object. The restoration of existing objects into memory is designed to be as fast as possible to facilitate optimal access to data (and potentially large sets of objects can be returned from stores), regardless of models used, and avoid any performance regressions from older versions of object stores, consequently this restoration typically uses a __proto__ assignment, rather than a constructor (see http://jsperf.com/setting-the-prototype for comparison of different approaches to recreating an object's prototype). On the otherhand, the model constructor is reserved for the actual creation of new objects. This helps to achieve both the clear distinction in the object lifecycle, as well as maintaining optimum speed for the object stores.