2.0.3 • Published 2 years ago

@elastic.io/oih-standard-library v2.0.3

Weekly downloads
75
License
Apache-2.0
Repository
github
Last release
2 years ago

CircleCI

OIH Standard Library

Table of Contents

  • lookupObject(criteria: any, objectType: any, cfg?: any, msg?: any)
  • createObject(object, cfg, msg)
  • updateObject(criteria: any, objectType: any, object: any, cfg?: any, msg?: any) If you need completely custom behaviour you can extend from Upsert class and override process, in this case following OIH standard is your responsibility.

Note:

  • Its your responsibility to ensure that lookupObject returns only 1 object.
  • lookupObject method must return null to indicate that object hasn't been found.

    Upsert Object By Id

  1. Create Action
  2. Create class that extends UpsertObjectById class
  3. Implement lookupObject(),createObject(),updateObject() methods. Example below.
  4. Optional override methods:
  • getType - default implementation expects objectType to be present in input configuration,
  • getCriteria - by default, returns id value from body in input message or null,
  • getObjectFromMessage- by default, returns body object from input message.
  1. Create instance of your class and pass logger to constructor. const myUpsertObjectByIDImpl = new MyUpsertObjectByIdImpl(logger);
  2. Export myUpsertObjectByIDImpl.process(msg, cfg, snapshot) as process method. Example below.
    Example of Usage
    Works in sailor > 2.4.2 Upsert Object Action
    const { UpsertObjectById } = require('@elastic.io/oih-standard-library/lib/actions/upsert');

class MyUpsertObjectByIdImpl extends UpsertObjectById { async lookupObject(criteria, objectType, cfg, msg) { const existObject = await getObjectInAPI(criteria, objectType, cfg, msg); if (existObject) { return existObject; } return null; }

async createObject(object, cfg, msg) { return await createObjectInAPI(object, cfg, msg); }

async updateObject(criteria, objectType, object, cfg, msg) { return await updateObjectInAPI(criteria, objectType, object, cfg, msg); } // You can also override getType, getCriteria and getObjectFromMessage methods if needed }

async function process(msg, cfg, snapshot = {}) { const upsertAction = new MyUpsertObjectByIdImpl(this.logger); // Sailor version > 2.4.2 return upsertAction.process(msg, cfg, snapshot); } module.exports.process = process;

 #### Upsert By Unique Criteria

The same as [Upsert Object By Id](#upsert-object-by-id) but `getCriteria` method by default returns value of field `uniqueCriteria` that is defined in input configuration, from the body in the input message.

### Create Object
Similar to upsert object but needed for the following cases:

- Objects that can be created but can not be updated after creation (e.g. Invoices)
- Cases where you want to create an object and its children
- Cases where the id of the object includes information in the object (e.g. The ID of a sales line is the sales order ID + SKU).

##### Example Use Case
See above.

### Lookup Object (at most 1)
 For implementing LookupObject action in most cases you need to extend from `LookupObjectById` or `LookupObjectByUniqueCriteria` classes.
 If you need completely custom behaviour you can extend from `LookupObject` class and override process and lookupObject method,
 in this case following OIH standard is your responsibility.
#### Lookup Object By Id
 Note:
 * Its your responsibility to ensure that `lookupObject` returns only 1 object. This implementation assume that `id` is unique for `objectType`.
 * `lookupObject` method must return `null` to indicate that object hasn't been found.
 1. Create Action
 2. Create class that extends LookupObjectById class
 3. Override `lookupObject()` methods. Example below.
 4. Optional override `getType` and `getId` methods. Default implementation expects `objectType` to be present in input configuration and `id` in input message.
 5. Create instance of your class and pass `logger` to constructor. `const myLookupByIDImpl = new MyLookupByIdImpl(logger);`
 6. Export `myLookupByIDImpl.process(msg, cfg, snapshot)` as process method. Example below.
 ##### Example of Usage
 Works in sailor > 2.4.2
 Lookup Action
```js
const { LookupById } = require('@elastic.io/oih-standard-library/lib/actions/lookupObject');

class MyLookupByIDImpl extends LookupById {


  async lookupObject(id, objectType, cfg, msg) { // In most cases you need just id, type and cfg
    const result = await lookupObjectInAPI(id,  objectType, cfg, msg); // Lookup object
    return result; // Return found object. If you return null, it will indicate no object found.
  }
  // You can also override getType and getId methods if needed
}


async function process(msg, cfg, snapshot = {}) {
  const lookupAction = new MyLookupByIDImpl(this.logger); // Sailor version > 2.4.2
  return lookupAction.process(msg, cfg, snapshot);
}

module.exports.process = process;

Lookup Object By Unique Criteria

Note:

  • In case when lookupObject method has found more than 1 object it must return an array or throw error.
  • lookupObject method must return null to indicate that object hasn't been found.
  1. Create Action
  2. Create class that extends LookupObjectByUniqueCriteria class
  3. Override lookupObject() methods. Example below.
  4. Optional override getType and getCriteria methods. Default implementation expects objectType to be present in input configuration and id in input message.
  5. Create instance of your class and pass logger to constructor. const myLookupObjectByUniqueCriteriaImpl = new MyLookupObjectByUniqueCriteriaImpl(logger);
  6. Export myLookupObjectByUniqueCriteriaImpl.process(msg, cfg, snapshot) as process method. Example below.

    Example of Usage

    Works in sailor > 2.4.2 Lookup Action

    const { LookupByUniqueCriteria } = require('@elastic.io/oih-standard-library/lib/actions/lookupObject');
    
    class  MyLookupObjectByUniqueCriteriaImpl extends  LookupByUniqueCriteria {
async lookupObject(criteria, objectType, cfg, msg) { // In most cases you need just criteria, type and cfg
  const result = await lookupObjectInAPI(id,  objectType, cfg, msg); // Lookup object
  if (result instanceof Array) {
    // return it or throw error. If result.length > 1 error will be thrown by action
}
return result; // Return found object. If you return null, it will indicate no object found.
}
// You can also override getType and getCriteria methods if needed

}

async function process(msg, cfg, snapshot = {}) { const lookupAction = new MyLookupObjectByUniqueCriteriaImpl(this.logger); // Sailor version > 2.4.2 return lookupAction.process(msg, cfg, snapshot); }

module.exports.process = process;

### Lookup Objects (Plural)
For implementing Lookup Objects (plural), you will have to extend from `LookupObjects` class.
You must provide the functions `getObjectsByCriteria(objectType, criteria: Array, msg?, cfg?, pageSize?, firstPage?, orderBy?):` and `getMetaModel(cfg)`

#### Steps for implementation
1. Create Action
2. Create class that extends `LookupObjects (plural)`
3. Override `getObjectsByCriteria()` and `getMetaModel()`
4. Optionally override methods like `getCriteria()`. Default implementation assumes a specific format to the metadata fields as provided by `getInMetadata()`, so you may wish to also override this function
5. Create instance of your class and pass the `logger` method to the constructor.
6. Export `myLookupObjects.process(msg, cfg, snapshot)` as process method. Example below:


#### Example
```Javascript
const { LookupObjects } = require('@elastic.io/oih-standard-library/lib/actions/lookupObjects');

class MyLookupObjects extends LookupObjects {

async getObjectsByCriteria(objectType, criteria, msg, cfg) { // In most cases you need objectType, criteria
  const results = await lookupObjects(objectType, criteria); // Perform lookup
  return results; // Return lookup results
}

async getMetaModel(cfg) {
  const metaModel = {};
  const properties = {
    fields: ['field1', 'field2'],
    conditions: ['=', 'in'],
    orderEnum: ['asc', 'desc'],
    includeOrder: false,
    additionalFields: 'additionalField',
    criteriaLinkEnum: ['and', 'or'],
    disableCriteriaLink: false
  };
  metaModel.in = this.getInMetadata(cfg, properties);
  metaModel.out = {
    type: object,
    ...
  };
  return metaModel;
}
}


async function process(msg, cfg, snapshot = {}) {
const deleteAction = new MyLookupObjects(this.logger, this.emit); // Sailor version > 2.4.2
return deleteAction.process(msg, cfg, snapshot);
}

module.exports.process = process;

Delete Object

For implementing Delete action in most cases you need to extend from DeleteById or DeleteByUniqueCriteria classes. If you need completely custom behaviour you can extend from Delete class and override process and deleteObject method, in this case following OIH standard is your responsibility.

Delete By ID

Note:

  • Its your responsibility to ensure that deleteObject deletes only 1 object. This implementation assume that id is unique for objectType.
  • If deleteObject method is returning null empty object would be emitted. You can indicate with null that object hasn`t been deleted or found.
  1. Create Action
  2. Create class that extends DeleteById class
  3. Override deleteObject() methods. Example below.
  4. Optional override getType and getId methods. Default implementation expects objectType to be present in input configuration. For unique criteria: uniqueCriteria field name in input configuration and value in input message.
  5. Create instance of your class and pass logger to constructor. const myDeleteByIDImpl = new MyDeleteByIdImpl(logger);
  6. Export myDeleteByIDImpl.process(msg, cfg, snapshot) as process method. Example below.
    Example of Usage
    Works in sailor > 2.4.2 Delete Action
const { DeleteById } = require('@elastic.io/oih-standard-library/lib/actions/delete');

class MyDeleteByIDImpl extends DeleteById {


  async deleteObject(id, cfg, msg) { // In most cases you need just id, type and cfg
    const deletedID = await deleteObjectInAPI(id, cfg, msg); // Delete object
    return deletedID; // Return deleted object ID. If you return null, empty object would be emitted.
  }
  // You can also override getType and getId methods if needed
}


async function process(msg, cfg, snapshot = {}) {
  const deleteAction = new MyDeleteByIDImpl(this.logger); // Sailor version > 2.4.2
  return deleteAction.process(msg, cfg, snapshot);
}

module.exports.process = process;

Delete By Unique Criteria

Note:

  • If more than 1 object was found with same uniqueCriteria, error would be thrown by this implementation
  • If deleteObject method is returning null empty object would be emitted. You can indicate with null that object hasn`t been deleted or found.
  1. Create Action
  2. Create class that extends DeleteById class
  3. Override findObjectByCriteria and deleteObject() methods. Example below.
  4. Optional override getType and getCriteria methods. Default implementation expects objectType to be present in input configuration. For unique criteria: uniqueCriteria field name in input configuration and value in input message.
  5. Create instance of your class and pass logger to constructor. const myDeleteByCriteriaImpl = new MyDeleteByCriteriaImpl(logger);
  6. Export myDeleteByCriteriaImpl.process(msg, cfg, snapshot) as process method. Example below.

    Example of Usage

    Works in sailor > 2.4.2 Delete Action

    const { DeleteByUniqueCriteria } = require('@elastic.io/oih-standard-library/lib/actions/delete');
    
    class MyDeleteByCriteriaImpl extends DeleteByUniqueCriteria {
    
      async findObjectByUniqueCriteria(criteria, type, cfg, msg) { // In most cases you need just criteria, type and cfg
         // criteria sructure {
         //  uniqueCriteria: 'fieldName',
         //  value: 'fieldValue',
         // }
         const object =  await findObjectInAPI(criteria, type, cfg, msg); // objects that match this criteria
         const numberOfObjects =  object.count; // You do not need to check or throw error in this case, action implementation will do this
         return { // return structure must contain object and numberOfObjects found
           object,
           numberOfObjects
         }
      }
      async deleteObject(object, cfg, msg) { // In most cases you need just object, type and cfg
        const deletedID = await deleteObjectInAPI(object, cfg, msg); // Delete object
        return deletedID; // Return deleted object ID if you return null, empty object would be emitted.
      }
      // You can also override getType and getId methods if needed
    }

async function process(msg, cfg, snapshot = {}) { const deleteAction = new MyDeleteByCriteriaImpl(this.logger); // Sailor version > 2.4.2 return deleteAction.process(msg, cfg, snapshot); }

module.exports.process = process;

### Lookup Set Of Objects
  For implementing LookupObject action in most cases you need to extend from `LookupSetOfObjectsSingleField` class or  wait for `LookupSetOfObjectsMultipleField` class to be implemented.
  If you need completely custom behaviour you can extend from `LookupSetOfObjects` class and override process and lookupSetOfObjects method,
  in this case following OIH standard is your responsibility.

  **Notes:**
  * Lookup Set will handle the case when the set of items to lookup is empty.
  * Lookup Set will handle casting the result into an array.
  * Lookup Set will de-duplicate the incoming array and check size contraints.
  * Lookup Set will make sure all the items in the set that should be there are there and then rebound or error as appropreate.

  **Methods that must be overridden:**
  * `async lookupSetOfObjects(criteriaFieldName, objectType, itemsToLookup, cfg, msg)` - Given an field name, object type and array of ids, find the objects in that set and return as an array

  **Methods that can be overridden (if the underlying functionality doesn't work):**
  * `async process(msg, cfg, snapshot)` - Overwrite the entire process function
  * `getType(cfg: any, msg: any)` - Identify type from config
  * `getItemsToLookup(msg: any, cfg: any)` - Extract item info from the body
  * `getMaxItemsToLookup(msg:any, cfg: any)` - Provide max size of set: defaults to 100
  * `getCriteriaFieldName(msg: any, cfg: any): string` - Extract the criteria field from config
  * `doesItemMatch(lookupCriteriaValue: any, item:any, msg:any, cfg:any): boolean` - Check if a given object has the id value described in `lookupCriteriaValue`

## Triggers
### Get New And Updated Objects Polling
For implementing et New And Updated Objects Polling(Polling Trigger) extend from class `PollingTrigger` and override: `getObjects`, `getObjectsFromPage` methods.
Note:
1. `getObjectsFromPage(options)` - `options: { objectType, startTime, endTime, page, cfg, snapshot }`, where `page` is structure with fields: `pageNumber`, `pageSize`.
2. `getObjectsFromPage` - must return following structure: `{ 'objects': 'result of polling' 'nextPage' : 'number or object, represents next page to poll' }`.
3. `emitIndividually` behaviour expects array to be returned by method: `getObjects`.
#### How to implement:
1. Create Trigger
2. Create class that extends `PollingTrigger`
3. Override `getObjects()` and `getObjectsFromPage()` methods
4. Optionally override methods any other methods, see class `PollingTrigger`
5. Create instance of your class and pass the `logger` nad `emitter` to the constructor.
6. Export `myPollingTrigger.process(cfg, snapshot)` as process method. Example below:
#### Example of Usage
```js
const PollingTrigger  = require('@elastic.io/oih-standard-library/lib/triggers/getNewAndUpdated');

class MyPollingTriggerImpl extends PollingTrigger {

  async getObjects(options) {
     // options: { objectType, startTime, endTime, cfg }
     return api.poll(options); // Poll object from API, Note: emitIndividually expects array to be returned by this method
  }
  async getObjectsFromPage(options) {
     // options: { objectType, startTime, endTime, page, cfg, snapshot }
     // page.pageNumber - current page,
     // page.pageSize - size of page to poll,
     const result = await api.pollPage(objectType, page, startTime, endTime, cfg, snapshot);
     return { nextPage: result.nextPage, objects: result.objects } // Must return structure like this
  }
}


async function process(cfg, snapshot) {
  const trigger = new MyPollingTriggerImpl(this.logger, this.emit); // Sailor version > 2.4.2
  return trigger.process(cfg, snapshot);
}

module.exports.process = process;

Webhooks

Firstly, Webhook subscription handling strategy should be implemented. For this purpose HandleWebhookSubscriptionByIdAbstractStrategy must be extended and createWebhooks & deleteWebhooks methods must be implemented. Also can be defined absolutely new strategy. For this purpose, just implement interface HandleSWebhookSubscriptionAbstractStrategy.

Example of Usage

const { HandleWebhookSubscriptionByIdAbstractStrategy, Webhook, defaultProcessWebhook } = require('@elastic.io/oih-standard-library/lib/triggers/webhook');

// implementation of subscription create strategy
// in this class we must implement create/delete WebhookSubscription methods
class HandleWebhookSubscriptionByIdStrategy extends HandleWebhookSubscriptionByIdAbstractStrategy {
 constructor(client, logger) {
   super(logger);
   this.client = client;
 }

// According to superclass definition should return object with array of ids; Example: {ids: ['webhook1', 'webhook2']}
 async createWebhooks(objectType, eventTypes) {
   const webhooks = await Promise.all(eventTypes.map(eventType => this.client.create({
     topic: eventType,
     address: process.env.ELASTICIO_FLOW_WEBHOOK_URI,
     format: 'json',
   }, WEBHOOK_OBJECT_TYPE)));
   return { ids: webhooks.map(webhook => webhook.id) };
 }

 async deleteWebhooks(input) {
     await Promise.all(input.ids.map(id => this.client.delete({ id }, WEBHOOK_OBJECT_TYPE)));
 }
}

// construct Webhook object using HandleWebhookSubscriptionByIdStrategy strategy
function configuredWebhook(cfg, logger) {
 const credentials = {
   apiKey: cfg.apiKey,
   shopName: cfg.shopName,
   password: cfg.password,
 };
 const client = new Client(credentials);
 const handleWebhookSubscriptionByIdStrategy = new HandleWebhookSubscriptionByIdStrategy(client, logger);
 const webhook = new Webhook(logger, handleWebhookSubscriptionByIdStrategy);
 return webhook;
}

// Export startup and shutdown functions
async function startup(cfg) {
 const webhook = await configuredWebhook(cfg, this.logger);
 return webhook.startup(cfg);
}

async function shutdown(cfg, data) {
 const webhook = await configuredWebhook(cfg, this.logger);
 await webhook.shutdown(cfg, data);
}

// Export static process function
module.exports.process = defaultProcessWebhook;
module.exports.startup = startup;
module.exports.shutdown = shutdown;
2.0.3

2 years ago

2.0.3-dev.2

2 years ago

2.0.3-dev.1

2 years ago

2.0.2

2 years ago

2.0.1

2 years ago

2.0.1-dev.2

2 years ago

2.0.1-dev.1

2 years ago

2.0.0

3 years ago

2.0.0-dev.2

3 years ago

1.2.0-dev.1

3 years ago

1.1.5

3 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.2-pre1

4 years ago

1.1.1

4 years ago

1.1.1-pre1

4 years ago

1.1.0

4 years ago

1.1.0-pre3

4 years ago

1.1.0-pre2

4 years ago

1.1.0-pre

4 years ago

1.0.4-beta1

4 years ago

1.0.3

4 years ago

1.0.3-beta2

4 years ago

1.0.3-beta1

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.1-dev.5

4 years ago

1.0.1-dev.4

4 years ago

1.0.1-dev.3

4 years ago

1.0.1-dev.2

4 years ago

1.0.1-dev.1

4 years ago

1.0.0

4 years ago

0.0.10-dev.22

4 years ago

0.0.10-dev.23

4 years ago

0.0.10-dev.21

4 years ago

0.0.10-dev.20

4 years ago

0.0.10-dev.19

4 years ago

0.0.10-dev.18

4 years ago

0.0.10-dev.17

4 years ago

0.0.10-dev.16

4 years ago

0.0.10-dev.15

4 years ago

0.0.10-dev.14

4 years ago

0.0.10-dev.13

4 years ago

0.0.10-dev.12

4 years ago

0.0.10-dev.11

4 years ago

0.0.10-dev.10

4 years ago

0.0.10-dev.9

4 years ago

0.0.10-dev.8

4 years ago

0.0.10-dev.7

4 years ago

0.0.10

4 years ago

0.0.10-dev.6

4 years ago

0.0.10-dev.5

4 years ago

0.0.10-dev.4

4 years ago

0.0.10-dev.3

4 years ago

0.0.10-dev.2

4 years ago

0.0.10-dev.1

5 years ago

0.0.10-rc1

5 years ago

0.0.9

5 years ago

1.0.0-rc9

5 years ago

1.0.0-rc8

5 years ago

1.0.0-rc7

5 years ago

1.0.0-rc6

5 years ago

1.0.0-rc5

5 years ago

1.0.0-rc4

5 years ago

1.0.0-rc3

5 years ago

1.0.0-rc2

5 years ago

1.0.0-rc1

5 years ago