dstore

repository·master·Indexed 43 days ago

https://github.com/dojo/dojo1-dstore

A data collection infrastructure framework (version 1.2.2-pre) providing a consistent interface for interacting with various storage mediums such as Memory, REST, and LocalDB. It utilizes Collections for querying, filtering, and sorting data, and Stores for managing data operations. dstore features a Promise-based asynchronous API, integration with dmodel for data modelling, and adapters for legacy Dojo object store compatibility.

Tokens
10.4K
Snippets
27
Records
51
Agent score
54%

What's inside dstore

  1. What is a Store in dstore

    master

    A Store is an extension of a Collection. While a collection contains a set of objects, a Store provides a full interface for managing the lifecycle of that data, including identifying, adding, modifying, removing, and querying objects.

    Key characteristics:

    • Asynchronous by default: Most methods return a Promise.
    • Optional implementation: Not all methods are required; full implementations like Rest and Memory provide most of the API.
    • Identity-based: Uses an identity property (defaulting to id) to manage objects.
  2. What is a Collection in dstore

    master

    A Collection is an interface for a set of items that can be filtered or sorted to produce new collections.

    Key characteristics:

    • Optional Implementation: When implementing the interface, methods and properties are optional; only include what is required.
    • Lazy Retrieval: Objects in a collection might not be retrieved from the underlying storage until they are accessed via forEach(), fetch(), or fetchRange().
    • Snapshots: The fetch() methods return a snapshot of the data. If the underlying data changes, calling these methods again will retrieve the latest data.
  3. Use Adapters for legacy Dojo compatibility

    master
    If you are working with legacy Dojo object stores or widgets that expect the Dojo object store interface, dstore provides Adapters to bridge the gap. Additionally, there is an adapter available for using dstore with charts.
  4. Implement hierarchical data with the Tree mixin

    master

    The Tree mixin provides support for hierarchical (parent-child) data structures, making it compatible with hierarchical UI components like dgrid.

    It uses a parent-based approach where children are found by querying for objects that have a parent property matching the ID of the parent object. Objects may optionally have a hasChildren property; if absent, the mixin assumes they may have children.

    Implemented Methods

    • getChildren(parent): Returns a collection representing the children of the provided parent object (filtered by the parent property).
    • mayHaveChildren(parent): Synchronously returns a boolean indicating if the parent might have children (actual retrieval may be asynchronous).
    • getRootCollection(): Returns the root collection (objects where the parent property is null).

    Note for Custom Implementations: You can override these methods to support different data models, such as using direct object references instead of ID-based parent properties.

  5. Track object index positions with the Trackable mixin

    master

    The Trackable mixin allows you to track the index positions of objects as they are added, updated, or deleted.

    By calling the track() method, you create a new tracked collection. When modification events occur, the tracked collection matches changes against cached data (even if sorted or filtered) and decorates the events with their specific index positions. For detailed information on how tracked collections and events behave, refer to the Collections documentation.

  6. Understand the core entities: Collection and Store

    master

    dstore is a data infrastructure framework for modelling and interacting with data. It revolves around two primary abstractions:

    • Collection: An interface for a list of objects. Collections can be iterated over, sorted, filtered, and monitored for changes. Data retrieval is often lazy; objects may not be fetched from the underlying storage until methods like forEach(), fetch(), or fetchRange() are called.
    • Store: An extension of a Collection. While a Collection focuses on viewing and querying data, a Store provides the interface for managing data, including identifying, adding, removing, and updating objects.
  7. How dstore handles querying and collections

    master

    Unlike traditional object stores, dstore handles querying by providing multiple query methods (such as filter and sort) that each return a new collection. This approach provides several benefits:

    • Encapsulation: A resulting collection contains all the context of the query used to create it. This allows you to pass a collection directly to a UI component (like a grid) without needing to coordinate the original query parameters.
    • Legibility: Querying follows a chainable, functional pattern that is easier to read.
    • Immutability/Functional Style: Sorting and filtering return new collections rather than modifying the existing one in-place. This allows intermediate steps in a multi-step query to be garbage collected, preventing memory leaks.

    Example workflow:

    1. Start with a base collection.
    2. Apply a filter to get a new filtered collection.
    3. Apply a sort to that filtered collection to get a final sorted collection.
  8. Track collection changes with `track()`

    master

    The track() method creates a new collection that is automatically updated as the parent collection changes. Tracked collections include index and previousIndex in their events to indicate the position of the change.

    Requirements:

    • track() is typically provided by dstore/Trackable.
    • For server-side stores (like Rest), you must mix in SimpleQuery to provide client-side querying capabilities required by Trackable.

    Usage Example:

    // Setup a trackable store
    var TrackableMemory = declare([Memory, Trackable]);
    var store = new TrackableMemory({ data: [...] });
    
    // Track a filtered/sorted subset
    var filteredSorted = store.filter({ inStock: true }).sort('price');
    var tracked = filteredSorted.track();
    
    // Listen for changes with index information
    tracked.on('add, update, delete', function (event) {
        var newIndex = event.index;
        var oldIndex = event.previousIndex;
        var object = event.target;
    });

    Key Behaviors:

    • Indices reported are relative to the entire collection, not just the fetched range.
    • If an object is added/updated outside of currently fetched ranges, index will be undefined.
    • If an object falls between fetched ranges, beforeIndex is provided to indicate the index of the first object the new/updated object comes before.
    // Example of creating a trackable Rest store
    var TrackableRest = declare([Rest, SimpleQuery, Trackable]);
    
    var store = new TrackableRest({ ... });
    var tracked = store.filter({ category: 'books' }).track();
    
    tracked.on('add', function(event) {
        console.log('Added at index:', event.index);
    });
  9. Understanding query metadata and the queryLog

    master

    Every query operation in dstore adds metadata to the collection it creates. Instead of separate properties for different query types, dstore uses a unified queryLog.

    Benefits of queryLog:

    • Order Preservation: It retains the exact order in which query operations were applied.
    • Iteration: It allows for easy examination and iteration of the entire sequence of query operations.
    • Granular Execution: It stores querier functions separately rather than as a single composed function. This means a single querier can be invoked without being forced to run all the others in the chain.
  10. How queriers work in dstore

    master

    A querier is a function created based on query arguments that takes an array of input data and returns an array of result data.

    • Client-side stores (e.g., dstore/Memory): Rely completely on queriers to perform all query operations.
    • Server-based collections (e.g., dstore/Rest): Do not require queriers for basic operations, but they are required to properly maintain a server-based collection when using the Trackable mixin.
    • Result-tracking: The Trackable mixin uses queriers to determine if an item is new or updated and to locate its position within a collection.
  11. Nesting Queries and Joins

    master

    You can perform nested queries (similar to joins) by passing a collection as an argument to the in or contains filter methods. This is often used to filter one store based on the results of another.

    When performing nested queries, it is recommended to use .select() to ensure only the necessary keys (like foreign keys) are returned for the comparison.

    // Find all tasks in high priority projects using a projectId foreign key
    var tasksOfHighPriorityProjects = taskStore.filter(
        new Filter().in('projectId', 
            projectStore.filter({ priority: 'high' }).select('id')
        )
    );
  12. Integrate data modelling with dmodel

    master

    dstore can be integrated with the dmodel package to provide robust data modelling. When you set a model on a store, every object returned by that store (whether via get() or fetch()) becomes an instance of that data model.

    This allows you to use dmodel methods on your data objects for:

    • Saving objects
    • Validating data
    • Monitoring objects for changes