Store

A Store object is the main tool to exchange data with the APS controller.

Purpose

A Store is often used as a data source for multi-entry widgets, for example grid or select.

It is important to remember that a Store object, in contrast with a Model object, does not create a live connection between a widget and data. That is, to reflect data changes in widgets, you need to send an update command explicitly.

In the following example, a grid uses the vpsStore as the data source:

var grid = new Grid({
   id: "srv-grid",
   store: vpsStore,
   ...
});

Once the vpsStore store is updated, you can sync it with the grid using the following command:

grid.refresh();

The SDK provides the following kinds of Store:

  • Resource Store, or simply Store - is actually an interface with the remote data source, that is with the APS controller.

  • Memory - is the local synchronous store of data. It is not connected to a remote data source.

Resource Store

Store based on the aps/ResourceStore module is used to interact with a remote APS repository asynchronously. It can receive, send, remove, and modify data on a remote server through the APS REST API. The methods of an asynchronous store return promises. The store completely encapsulates the process of data transfer from and to the remote server. For the complete list of properties and methods, refer to APS JS API document.

Properties

PROPERTY

TYPE

DEFAULT

DESCRIPTION

target

String presenting the URL of the target data source, that is APS controller

“”

Since custom JavaScript files and APS controller are functioning on the same node, its usual value is “/aps/2/resources/” that allows access to all APS resources in the system. This is the only mandatory property.

apsType

String presenting APS type

“”

Defines the type of APS resources that this store should work with, for example, “”http://aps-standard.org/samples/basic/vps/1.0”.

idProperty

String

“aps.type”

Usually, there is no need to make it different from the default value. It specifies the property used as object identifier. This property is used to reference objects in multi-entry widgets.

baseQuery

RQL statement

“”

The statement is added to each query request to limit the list of resources or to add data about linked resources.

The apsType property specifies a filter based on the implementing() function and added to the base URL containing the target property.

Example:

require(["aps/ResourceStore"],
   function(Store){
      var vpsStore = new Store({
         apsType:   "http://aps-standard.org/samples/basic/vps/1.0",
         target:    "/aps/2/resources/"
      });
});

Basing on this definition, you can request a list of objects:

var servers = [];
vpsStore.query().then(function(data) {
   servers = data;
});

The above query() method will generate the following REST request:

GET /aps/2/resources?implementing(http://aps-standard.org/samples/basic/vps/1.0)

Warning

Following this example, it is not allowed to use the apsType filter, when the target is a custom method, for example, target: “/aps/2/resources/” + id + “/myMethod”.

It is possible to add an RQL filter to the store declaration using the baseQuery property. For example, to extract the links with other resources, you can assign the select filter to the baseQuery property. In the following code, the linked offer will be available for each requested VPS:

var store = new Store({
   apsType: "http://aps-standard.org/samples/basic/vps/2.0",
   target: "/aps/2/resources/",
   baseQuery: "select(offer)"
});

If the store declared above is used in a grid, the following column will represent offers linked to VPSes:

{ field: "offer.name", name: "Offer" }

Methods

To get and modify the store data, you can use the following store methods:

METHOD

ARGUMENTS

DESCRIPTION

add(object,directives)

object - JSON representation
directives - additional directives of the “dojo/store/api/Store.PutDirectives” type

Creates an object or throws an error if the object already exists.

put(object,directives)

object - JSON representation
directives - additional directives of the “dojo/store/api/Store.PutDirectives” type

Configures an object.

remove(ID)

ID - APS ID of the resource

Deletes an object by its APS ID.

query(query,options)

query - a filter containing a list of properties or an RQL string
options - optional arguments used to arrange the result set

Queries a store for a set of objects. Both arguments are optional.

Query

The query(query,options) method is used to retrieve a list of objects (resources) through the store. The method returns an object of the dojo/store/api/Store.QueryResults type.

Note

A server response must contain a Content-Range header with the total number of records. See HTTP specification for details .

The most convenient way of processing the returned data is to use array processing methods built into the object.

The query argument is intended to filter the received data by applying a list of properties with required values or by applying an RQL string.

  • Filtering by a list of properties. You can use any properties declared in resource types. In the following example, the method is used to get a list of VPSes where the number of CPU cores is 4.

    var store = new Store({
        target:    "/aps/2/resources/"
    });
    
    store.query({ aps:
        { type: "http://aps-standard.org/samples/async1pn/vps/1.0" },
        hardware:{ CPU:{ number:4 }}
    });
    
  • Filtering by means of an RQL request. The following query retrieves a list of VPSes that have not less than 4 CPU cores and whose status is aps:ready:

    var vpsStore = new Store({
        apsType: "http://aps-standard.org/samples/async1pn/vps/1.0",
        target:  "/aps/2/resources/"
    });
    
    vpsStore.query("hardware.CPU.number=ge=4,aps.status=eq=aps:ready");
    

The options argument is an object containing up to three properties:

  • start[number] - the number of the first line in the list of queried objects that the method must return.

  • count[number] - the number of lines in the returned data block.

  • sort[array] - an array of sorting objects. Each object must contain two properties: attribute and descending. The first property contains the name of the property to be used for sorting, and the second property is a boolean that requires the sorting direction, for example:

    sort[{ attribute:"name", descending:false }]
    

mapQuery

The mapQuery(row) method is a custom method that is called from the query method. It is used to process a row before the query method returns it. The method receives a row, processes it, and then returns it back.

In a Store definition, you can define the custom mapQuery(row) method if you need to process each row before the query method returns it.

Memory

Memory based on the aps/Memory module is a local store not connected to any remote data source.

This is the simplest way to create a store. You can simply provide an array to the constructor and work with it using properties and methods similar to those used in the Store.

For the complete list of properties and methods, refer to APS JS API document.

As an example, let us get records filtered by the “prime” property:

require(["aps/Memory", "aps/ready!"],
  function(Memory){
     var employees = [
         { name: "Jim",  department: "accounting",     prime: true  },
         { name: "Bill", department: "engineering",    prime: false },
         { name: "Mike", department: "sales",          prime: false },
         { name: "John", department: "sales",          prime: true  }
     ];

     var store = new Memory({ data: employees, idProperty: "name" });

     store.query({ prime: true }).forEach(function(object, i){
         console.log("Value of row number " + i, object);
});

In addition, as an argument of the query method, you can use a string request based on Resource Query Language. A simple aps/Grid that allows entering RQL statements in the input field and then implementing them:

RUN DEMO

load(["aps/PageContainer", [
    ["aps/Grid", {
        id:     "grid",
        columns:  layoutSimpleGrid,
        showPaging: false,
        store:    store
    }, [
        ["aps/Toolbar", [
            ["aps/TextBox", {
                id: "input",
                placeHolder: 'RQL query',
                // ...
}],
            ["aps/ToolbarButton", {
                id:         "button",
                label:      "Search",
                iconClass:  "sb-search",
                // ...
}],
            ["aps/ToolbarButton", {
                label:    "Reset",
                iconClass:  "sb-show-all",
                // ...
}]
        ]]
    ]]
]])

You can create new objects in a store, as well as delete existing ones:

employeeStore.add({name:"George", department:"accounting"});
employeeStore.remove("Bill");

You can also change objects located in the store. The main thing is to not forget to save changes using the put method.

var jim = employeeStore.get("Jim");
jim.department = "engineering";
employeeStore.put(jim);

Synchronization of Data Transfer

Operations with a store can be either synchronous or asynchronous. If you work with a store synchronously, the code must handle the received data immediately after a query is processed. If you work with a store asynchronously, its methods return a promise, and you should use callback functions to handle it.

Method then

You can add such a handler function using the callback then method. The method returns a promise that is fulfilled when the callback completes.

.then(callback, errback, progback);

Parameter

Type

Description

callback

Function

Callback handler of the resolved promise. The request result will be passed to it as an argument.

errback

Function

Callback to be invoked when a promise is rejected.

progback

Function

Callback to be invoked when a promise provides a progress update.

Example:

store.add({ name: "Tim", department: "R&D", prime: true }).then(function(object) {
   // handle created object
});

Method when

The more universal is the dojo/when module, because the when method provided by the module can handle both synchronous and asynchronous requests. The syntax looks as follows:

when(valueOrPromise, callback, errback, progback);

The parameters of the method are described in the table:

Parameter

Type

Description

valueOrPromise

Undefined

Method or result of calling the method that makes a request.

callback

Function

Callback handler of the request result. The request result will be passed to it as an argument.

errback

Function

Callback to be invoked when a promise is rejected.

progback

Function

Callback to be invoked when a promise provides a progress update.

The errback and progback arguments are optional.

Examples

The following example illustrates the usage of the handler and errback callback functions:

require(["aps/ResourceStore", "dojo/when", "aps/ready!"],
   function(Store, when){
      var store = new Store({
         apsType:   "http://aps-standard.org/samples/basic/vps/1.0",
         target:    "/aps/2/resources/"
      });

      when(store.query(), function(data) {
         console.log("success!", data);
      }, function(e){
         console.log("error!", e);
      });
});

If you send several requests concurrently, the order in which the responses from the server are received will not necessarily match the order in which the requests have been sent. To synchronize processing of the data received as a result of all completed requests, you can use the dojo/promise/all module. With the all method provided by the module, you can combine all requests into a unified call of the when method. In this case, an array with elements representing data from the corresponding requests will be passed to the handler of the request results.

require(["aps/ResourceStore", "dojo/when", "dojo/promise/all", "aps/ready!"],
   function(Store, when, all) {
      var offerStore = new Store({
         apsType:   "http://aps-standard.org/samples/offer-mgmt/offer/1.0",
         target:    "/aps/2/resources/"
      });

      var vpsStore = new Store({
         apsType:   "http://aps-standard.org/samples/offer-mgmt/vps/1.0",
         target:    "/aps/2/resources/"
      });

      when(all([offerStore.query(), vpsStore.query()]), function(data) {
         console.log("success!");
         console.log("Offer List", data[0]);
         console.log("VPS List", data[1]);
      }, function(e) {
         console.log("error!", e);
      });
});