Final Class: BufferingDataProvider

Oracle® JavaScript Extension Toolkit (JET)
9.0.0

F24343-01

Signature:

final class BufferingDataProvider<K, D> implements DataProvider<K, D>

QuickNav

BufferingDataProvider

Version:
  • 9.0.0
Since:
  • 9.0.0
Module:
  • ojbufferingdataprovider

Module usage

See JET Module Loading for an overview of module usage within JET.

Javascript Import Format
define(['ojs/ojbufferingdataprovider'], function(BufferingDataProvider) {
 // Application should call API on BufferingDataProvider 
})
Typescript Import Format
//This class is exported directly as module. To import it
import BufferingDataProvider= require("ojs/ojbufferingdataprovider");

Generic Parameters
ParameterDescription
KType of key
DType of data

JET In Typescript

A detailed description of working with JET elements and classes in your typescript project can be found at: JET Typescript Usage.

Final classes in JET

Classes in JET are generally final and do not support subclassing. At the moment, final is not enforced. However, this will likely change in an upcoming JET release.

Description

BufferingDataProvider is a wrapping DataProvider that provides edit buffering for an underlying DataProvider, so that the edits can be committed to the data source later on. The underlying DataProvider is responsible for fetchting data, and BufferingDataProvider will merge any buffered edits with the underlying data so that they appear as an unified set of data.

Because all edits are tracked by keys, the underlying DataProvider must return unique keys in the metadata. If new rows are added, unique keys must be specified for the new rows.

In addition to the methods in the DataProvider interface, BufferingDataProvider implements a set of methods for managing edits:

  • addItem
  • removeItem
  • updateItem
  • getSubmittableItems
  • resetAllUnsubmittedItems
  • resetUnsubmittedItem
  • setItemStatus

In a typical usage scenario, an application will:

  1. Create an instance of the underlying DataProvider that provides the actual data.
  2. Create an instance of BufferingDataProvider, passing the underlying DataProvider instance and any options.
  3. Call "addItem", "removeItem", and "updateItem" on the BufferingDataProvider instance to create edit items, usually in response to user interactions. These methods correspond to the basic data operations. Buffer entries will be created for the edit items with a status of "unsubmitted".
  4. When ready to submit the edits, call "getSubmittableItems" to get the list of submittable edit items.
  5. Call "setItemStatus" to set the edit items' status to "submitting".
  6. Submit the actual data to the data source and wait for its completion. How this is done is up to the application and dependent on the data source.
  7. If the submission is successful, call "setItemStatus" to set the edit items' status to "submitted". If the submission is unsuccessful, call "setItemStatus" to set the edit items' status to "unsubmitted" and pass error messages if available.
  8. Show the error messages to the user if needed.

In general, the edit item data should have the same shape as the data in the underlying DataProvider.

If sorting and filtering is used in the underlying DataProvider, the application should ensure that all attributes referenced in the sort criterion and filter criterion are included in the item data. If there is a sortCriteria, added items are merged with the underlying data based on the sortCriteria. If there is no sortCriteria, added items are inserted at the beginning of the underlying data. Furthermore, iterators obtained by fetchFirst must all use the same sortCriteria if the application is using those iterators at the same time.

BufferingDataProvider does not validate the item key and data. It is up to the application to perform any validation prior to creating edit items in the buffer.

Events

Consumers can add event listeners to listen for the following event types and respond to data change.

mutate

This event is fired when items have been added or removed from the data.

Event payload is found under event.detail, which implements the DataProviderMutationEventDetail interface.

refresh

This event is fired when the data has been refreshed and components need to re-fetch the data.

This event contains no additional event payload.

submittableChange

This event is fired when the number of submittable edit items has changed. An edit item is submittable if it is in "unsubmitted" status and there is no other edit item with the same key in "submitting" status.

Event payload is found under event.detail, which is array of objects that implement the EditItem interface.

Example of consumer listening for the "submittableChange" event type:
var listener = function(event) {
  var editItems = event.detail;
  console.log("Number of submittable edit items: " + editItems.length);
};
dataProvider.addEventListener("submittableChange", listener);

Constructor

new BufferingDataProvider(dataProvider, options)

Parameters:
Name Type Argument Description
dataProvider DataProvider.<K, D> The underlying DataProvider that provides the original data.
options Object <optional>
Options for the underlying DataProvider.

Methods

addEventListener(eventType: string, listener: EventListener): void

Add a callback function to listen for a specific event type.
Parameters:
Name Type Description
eventType string The event type to listen for.
listener EventListener The callback function that receives the event notification.

addItem(item: Item<K, D>): void

Create a buffer entry for adding a row. The entry initially has a status of 'unsubmitted'.

If a "remove" entry already exists:

  1. If the "remove" entry does not have data, it will be changed to an "update" entry with the new data.
  2. If the "remove" entry has data, it will be compared to the new data passed to this method.
    If the data are the same, the "remove" entry will be removed and no new entry will be created.
    If the data are different, the "remove" entry will be changed to an "update" entry with the new data.

Application can call setItemStatus to change the status of the entry to 'submitting' or 'submitted'. There can be at most one entry in 'unsubmitted' status and one entry in 'submitting' status with the same key. This allows application to keep track of additional changes to a row while submitting previous changes.

Parameters:
Name Type Description
item Item.<K, D> an Item object that represents the row.
Since:
  • 9.0.0
Throws:
if an "add" or "update" entry already exists for the same key.
Type
Error

containsKeys(parameters : FetchByKeysParameters<K>) : Promise<ContainsKeysResults<K>>

Check if there are rows containing the specified keys. The resulting key map will only contain keys which were actually found.
Parameters:
Name Type Description
parameters FetchByKeysParameters contains by key parameters
Since:
  • 4.2.0
Returns:
Returns Promise which resolves to ContainsKeysResults.
Type
Promise.<ContainsKeysResults>
Example

Check if keys 1001 and 556 are contained

let containsKeys = [1001, 556];
let value = await dataprovider.containsKeys({keys: containsKeys});
let results = value['results'];
if (results.has(1001)) {
  console.log('Has key 1001');
} else if (results.has(556){
  console.log('Has key 556');
}

createOptimizedKeyMap(initialMap?: Map<K, D>): Map<K, D>

Return an empty Map which is optimized to store key value pairs

Optionally provided by certain DataProvider implementations for storing key/value pairs from the DataProvider in a performant fashion. Sometimes components will need to temporarily store a Map of keys provided by the DataProvider, for example, in the case of maintaining a Map of selected keys. Only the DataProvider is aware of the internal structure of keys such as whether they are primitives, Strings, or objects and how to do identity comparisons. Therefore, the DataProvider can optionally provide a Map implementation which can performantly store key/value pairs surfaced by the DataProvider.

Parameters:
Name Type Argument Description
initialMap Map.<any> <optional>
Optionally specify an initial map of key/values for the Map. If not specified, then return an empty Map.
Since:
  • 6.2.0
Returns:
Returns a Map optimized for handling keys from the DataProvider.
Type
Map.<any>
Example

create empty key Map

let keyMap = dataprovider.createOptimizedKeyMap();

createOptimizedKeySet(initialSet?: Set<K>): Set<K>

Return an empty Set which is optimized to store keys

Optionally provided by certain DataProvider implementations for storing keys from the DataProvider in a performant fashion. Sometimes components will need to temporarily store a Set of keys provided by the DataProvider, for example, in the case of maintaining a Set of selected keys. Only the DataProvider is aware of the internal structure of keys such as whether they are primitives, Strings, or objects and how to do identity comparisons. Therefore, the DataProvider can optionally provide a Set implementation which can performantly store keys surfaced by the DataProvider.

Parameters:
Name Type Argument Description
initialSet Set.<any> <optional>
Optionally specify an initial set of keys for the Set. If not specified, then return an empty Set.
Since:
  • 6.2.0
Returns:
Returns a Set optimized for handling keys from the DataProvider.
Type
Set.<any>
Example

create empty key Set

let keySet = dataprovider.createOptimizedKeySet();

dispatchEvent(evt: Event): boolean

Dispatch an event and invoke any registered listeners.
Parameters:
Name Type Description
event Event The event object to dispatch.
Returns:
Return false if a registered listener has cancelled the event. Return true otherwise.
Type
boolean

fetchByKeys(parameters : FetchByKeysParameters<K>) : Promise<FetchByKeysResults<K, D>>

Fetch rows by keys. The resulting key map will only contain keys which were actually found.
Parameters:
Name Type Description
parameters FetchByKeysParameters fetch by key parameters
Since:
  • 4.2.0
Returns:
Returns Promise which resolves to FetchByKeysResults.
Type
Promise.<FetchByKeysResults>
Example

Fetch for keys 1001 and 556

let fetchKeys = [1001, 556];
let value = await dataprovider.fetchByKeys({keys: fetchKeys});
// get the data for key 1001
console.log(value.results.get(1001).data);

fetchByOffset(parameters: FetchByOffsetParameters<D>): Promise<FetchByOffsetResults<K, D>>

Fetch rows by offset

A generic implementation of this method is available from FetchByOffsetMixin. It is for convenience and may not provide the most efficient implementation for your data provider. Classes that implement the DataProvider interface are encouraged to provide a more efficient implementation.

Parameters:
Name Type Description
parameters FetchByOffsetParameters fetch by offset parameters
Since:
  • 4.2.0
Returns:
Returns Promise which resolves to FetchByOffsetResults.
Type
Promise.<FetchByOffsetResults>
Example

Fetch by offset 5 rows starting at index 2

let result = await dataprovider.fetchByOffset({size: 5, offset: 2});
let results = result['results'];
let data = results.map(function(value) {
  return value['data'];
});
let keys = results.map(function(value) {
  return value['metadata']['key'];
});

fetchFirst(parameters?: FetchListParameters<D>): AsyncIterable<FetchListResult<K, D>>

Get an asyncIterator which can be used to fetch a block of data.
Parameters:
Name Type Argument Description
params FetchListParameters <optional>
fetch parameters
Since:
  • 4.2.0
See:
Returns:
AsyncIterable with FetchListResult
Type
AsyncIterable.<FetchListResult>
Example

Get an asyncIterator and then fetch first block of data by executing next() on the iterator. Subsequent blocks can be fetched by executing next() again.

let asyncIterator = dataprovider.fetchFirst(options)[Symbol.asyncIterator]();
let result = await asyncIterator.next();
let value = result.value;
let data = value.data;
let keys = value.metadata.map(function(val) {
  return val.key;
});
// true or false for done
let done = result.done;

getCapability(capabilityName: string): any

Determines whether this DataProvider defines a certain feature.
Parameters:
Name Type Description
capabilityName string capability name. Defined capability names are: "fetchByKeys", "fetchByOffset", "sort", "fetchCapability" and "filter".
Since:
  • 4.2.0
Returns:
capability information or null if undefined
Type
Object
Example

Check what kind of fetchByKeys is defined.

let capabilityInfo = dataprovider.getCapability('fetchByKeys');
if (capabilityInfo.implementation == 'iteration') {
  // the DataProvider supports iteration for fetchByKeys
  ...

getSubmittableItems(): Array<BufferingDataProvider.EditItem<K, D>>

Get the list of all submittable edit items.

Caller should call setItemStatus to change the status to "submitting" when ready to submit. Once the edit item for a key is moved to 'submitting', new edit for the same key will be tracked separately. There can be at most one "submitting" edit item and one "unsubmitted" edit item for the same key.

Since:
  • 9.0.0
Returns:
an array of all submittable edit items. Each edit item implements the EditItem interface.
Type
Array.<BufferingDataProvider.EditItem.<K, D>>

getTotalSize() : {Promise.<number>}

Return the total number of rows in this dataprovider
Returns:
Returns a Promise which resolves to the total number of rows. -1 is unknown row count.
Type
Promise.<number>
Example

Get the total rows

let value = await dataprovider.getTotalSize();
if (value == -1) {
  // we don't know the total row count
} else {
  // the total count
  console.log(value);

isEmpty(): 'yes' | 'no' | 'unknown'

Returns a string that indicates if this data provider is empty. Valid values are:
  • "yes": this data provider is empty.
  • "no": this data provider is not empty.
  • "unknown": it is not known if this data provider is empty until a fetch is made.
Since:
  • 4.2.0
Returns:
string that indicates if this data provider is empty
Type
"yes" | "no" | "unknown"
Example

Check if empty

let isEmpty = dataprovider.isEmpty();
console.log('DataProvider is empty: ' + isEmpty);

removeEventListener(eventType: string, listener: EventListener): void

Remove a listener previously registered with addEventListener.
Parameters:
Name Type Description
eventType string The event type that the listener was registered for.
listener EventListener The callback function that was registered.

removeItem(item: ItemWithOptionalData<K, D>): void

Create a buffer entry for removing a row. The entry initially has a status of 'unsubmitted'.

If an "add" entry already exists, it will be deleted.
If an "update" entry already exists, it will be changed to a "remove" entry.

Application can call setItemStatus to change the status of the entry to 'submitting' or 'submitted'. There can be at most one entry in 'unsubmitted' status and one entry in 'submitting' status with the same key. This allows application to keep track of additional changes to a row while submitting previous changes.

Parameters:
Name Type Description
item ItemWithOptionalData an ItemWithOptionalData object that represents the row.
Since:
  • 9.0.0
Throws:
if a "remove" entry already exists for the same key.
Type
Error

resetAllUnsubmittedItems()

Reset all rows by discarding all 'unsubmitted' edit items, so that the data from the underlying DataProvider will be used.
Since:
  • 9.0.0

resetUnsubmittedItem(key: K): void

Reset a row by discarding any 'unsubmitted' edit item for the row, so that the data from the underlying DataProvider will be used.
Parameters:
Name Type Description
key K The key of the row to reset.
Since:
  • 9.0.0

setItemStatus(editItem: BufferingDataProvider.EditItem<K, D>, newStatus: 'unsubmitted' | 'submitting' | 'submitted', error?: ItemMessage): void

Set the status of an edit item.

Application should set an edit item to 'submitting' before committing its change to the data source. This will prevent any new edit item with the same key from being changed to 'submitting'.

When setting an edit item from 'submitting' back to 'unsubmitted' (usually upon submission error), and there is another 'unsubmitted' entry for the same key (this happens when edit is allowed while an edit item is submitting), the error will be set on the new 'unsubmitted' entry and the current 'submitting' entry will be disposed.

when setting an edit item to 'submitted', the edit item will be removed from the buffer.

Parameters:
Name Type Argument Description
editItem BufferingDataProvider.EditItem.<K, D> The edit item to set status on. This should implement the EditItem interface and is usually one of the items returned by the getSubmittableItems method.
newStatus 'unsubmitted' | 'submitting' | 'submitted' the new status of the edit item. If an edit item is marked as "submitted", it will be removed at the DataProvider's discretion.
error ItemMessage <nullable>
an optional error message.
Since:
  • 9.0.0

updateItem(item: Item<K, D>): void

Create a buffer entry for updating a row. The entry initially has a status of 'unsubmitted'.

If an "add" or "update" entry already exists, the data of the entry will be changed.

Application can call setItemStatus to change the status of the entry to 'submitting' or 'submitted'. There can be at most one entry in 'unsubmitted' status and one entry in 'submitting' status with the same key. This allows application to keep track of additional changes to a row while submitting previous changes.

Parameters:
Name Type Description
item Item.<K, D> an Item object that represents the row.
Since:
  • 9.0.0
Throws:
if a "remove" entry already exists for the same key.
Type
Error