1.0.7 • Published 3 months ago

@tcn/resource-store v1.0.7

Weekly downloads
-
License
Apache-2.0
Repository
-
Last release
3 months ago

Resource Stores


Table of Contents

Overview

This package defines some useful interfaces for working with AIP resources, and some concrete implementations that you can use with the Table and other components.

Core Concepts

ResourceStore

The ResourceStore fills the role of "API Adapter". It is not an interface or implementation, but rather a name we give to a class that has a specific role (similar to Domain or Presenter).

The job of the ResourceStore is to represent a resource, which could be local or remote. This concept is driven by the resource-oriented API design influenced by AIP, similar to the "repository pattern". The ResourceStore insulates the application from where the data comes from.

Key responsibilities:

  • Representing a resource (local or remote)
  • Abstracting data source from application logic
  • Managing caching when needed
  • Providing a 1:1 mapping between API actions and methods

A ResourceStore will typically extend a DataSource implementation, which handles list features according to AIP standards, adding to it actions corresponding to those provided by the REST API. We expect there will generally be a 1:1 relationship between actions surfaced by the API and methods on the ResourceStore.

The ResourceStore instances will be injected into your domain, which may use it directly, and will expose them as properties on itself so the stores are available to presenters. By this pattern, the Domain will often become a "bag of resources", and may contain very little else.

If your application needs to cache entities, the ResourceStore is an appropriate place to manage that caching. In cases where coordination between resources is necessary, each store should stay "pure" to the entity it is intended to represent (unaware of other resources), and the Domain should handle cross-store interactions, surfacing additional methods to the presenters as necessary.

DataSource

The DataSource handles AIP-160 compliant list features, including filtering, sorting, and paging. There are two implementations provided (perhaps more to follow): the AIPDataSource and the StaticDataSource. In each case, you configure the source with the list of fields you wish to work with on the represented entity, and then can page through results, apply a filter, and sort by field.

Important: the DataSource is not aware of or directely attached to a UI view. It might be thought of as a "view" only in database terms (a "view" of a set of data), but since "view" is overloaded, we'll avoid using it in this document. The DataSource does not format, localize, or otherwise prepare data for user consumption.

See the DataSource interface for more details.

Usage Examples

AIPDataSource Example

The AIPDataSource takes two type parameters: AIPDataSource<TLocal, TRemote>. The first represents what the DataSource will present on the table. The second is the incoming type, or the type of the resource as provided from the service. In the field definitions, the getValue function will give you a TRemote, and you should return a field that belongs to TLocal.

const fields = [
  {
    fieldName: 'name',
    sourceFieldName: 'name',
    getValue: (i: AIPOrganization) => i.name,
  },
  {
    fieldName: 'displayName',
    sourceFieldName: 'display_name',
    getValue: (i: AIPOrganization) => i.displayName,
  },
  {
    fieldName: 'billingId',
    sourceFieldName: 'billing_id',
    getValue: (i: AIPOrganization) => i.billingId,
  },
  {
    fieldName: 'clientSid',
    sourceFieldName: 'client_sid',
    getValue: (i: AIPOrganization) => i.clientSid,
  },
  {
    fieldName: 'timeZone',
    sourceFieldName: 'time_zone',
    getValue: (i: AIPOrganization) => i.timeZone,
  },
  {
    fieldName: 'createTime',
    sourceFieldName: 'create_time',
    getValue: (i: AIPOrganization) => new Date(i.createTime),
  },
  {
    fieldName: 'updateTime',
    sourceFieldName: 'update_time',
    getValue: (i: AIPOrganization) => new Date(i.updateTime),
  },
];

return new AIPDataSource<Organization, AIPOrganization>({
  resourceUrl: "https://api.dev.tcn.com/tcn/org/organizations/v1alpha1/organizations",
  resourceName: "organizations",
  fields,
  authToken,
});

For each field, the fieldName will become the property name on the entity, the sourceFieldName corresponds to the property name as defined in the proto (annoying, yes -- we're looking a options to automate that), and getValue allows you to extract the value for the field (including converting timestamps to Dates, etc.).

Because the returned JSON data is untyped, you may wish to define a type for the JSON data, or you may treat the argument to the getValue handler as an explicit any.

StaticDataSource Example

This class presents a local, static array of data as a DataSource, permitting filtering, sorting, and paging.

type DataItem = {
  id: string;
  name: string;
  age: number;
};

const items: DataItem[] = [
  { id: 'one', name: 'Sam Spade', age: 22 },
  { id: 'two', name: 'Kelsior', age: 166 },
  { id: 'three', name: 'Tress', age: 17 },
  { id: 'four', name: 'Breeze', age: 45 },
  { id: 'five', name: 'Spook', age: 17 },
  { id: 'six', name: 'Anne', age: 32 },
  { id: 'seven', name: 'Hoid', age: 1934 },
  { id: 'eight', name: 'Vasher', age: 320 },
];

return new StaticDataSource<DataItem>(items, [
  new StringField('name', i => i.name),
  new NumberField('age', i => i.age),
]);

Note the difference in how field definitions are supplied to the StaticDataSource. In an AIP source, filtering and sorting is handled by the service, but for static data, it is handled in the fields themselves. These fields implement StaticDataSourceField, and are fairly trivial to implement for whatever data type you need to work with.

1.0.7

3 months ago