0.2.7 • Published 8 months ago

@necrobits/aggregator v0.2.7

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

Aggregator.js

An flexible aggregator component for your backend (or even frontend).

An implementation for entity source with cache (CachedEntitySource) is also shipped in the library.

You can freely define how to gather your data by implementing your own lookup function.

Install

Using npm

npm install @necrobits/aggregator

or using yarn

yarn add @necrobits/aggregator

Quick start

Given the following data and getters

const users = [
    { id: 'A', name: 'Andy' },
    { id: 'B', name: 'Hai' }
];
const findUsers = ids => users.filter(user => ids.includes(user.id));

const todos = [
    { id: 'T1', task: 'Study' },
    { id: 'T2', task: 'Code' }
];
const findTodos = ids => todos.filter(todo => ids.includes(todo.id));

// You want aggregation for this data
const data = [
    {
        date: '22-02-2022',
        tasks: [
            {assigneeId: 'A', taskId: 'T1'}
            {assigneeId: 'B', taskId: 'T2'}
        ],
    },
// {...},
]

The code for the aggregation looks like this:

const userSource = new SimpleEntitySource('user', {
  lookupUsing: findUsers,
  entityIdBy: 'id',
});

const todoSource = new SimpleEntitySource('todo', {
  lookupUsing: findTodos,
  entityIdBy: 'id',
});
const aggregator = new Aggregator({
  user: userSource,
  todo: todoSource,
});
// or
const aggregator = new Aggregator();
aggregator.register('user', userSource).register('todo', todoSource);

Use the aggregator

const opts = {
  'tasks.*.assigneeId': {
    source: 'user',
    to: {
      key: 'assignee',
    },
    removeIdKey: true,
  },
  'tasks.*.taskId': {
    source: 'todo',
    removeIdKey: true,
  },
};
const aggregatedData = await aggregator.aggregate(data, opts);

console.log(aggregatedData);

Output:

[{
    date: '22-02-2022',
    tasks: [
        {
            id: 'T1',
            name: 'Study'
            assignee: {
                id: 'A',
                name: 'Andy'
            }
        },
        {
            id: 'T2',
            name: 'Code',
            assignee: {
                id: 'B',
                name: 'Hai'
            }
        }
    ]
},
{...}]

Syntax

The syntax to define a aggregation process is as follows:

{
    "<path to the object's ID>": {
        //<Aggregation Options>
    }
}

While declare a path to the object's ID, sometimes you have to access to an array. You can simply use * to tell the aggregator to process every element in that array (see example above).

However, if the data itself is an array, you don't need to use the asterik * at the beginning. The aggregator can recognize that automatically. Meaning, don't write *.userId if you have an array of multiple objects that contains userId,

[{ userId: '1' }, { userId: '2' }];

you can simply use userId directly.

{
    "userId":{
        // options
    }
}

Aggregation Options

NameTypeDescriptionRequiredDefault
sourcestringName of the entity source to gather the dataYes
to-If specified, the result is put into another key
to.keystringThe name of the new field to inject the data intoIf to is specified
to.omitNullbooleanIf the lookuped object is null, remove the keyNofalse
removeIdKeybooleanRemove the id field after injecting the dataNofalse
transform(any) => (any)A function to transform the data before the injectionNoIdentity function(v) => v

Using cache with CachedEntitySource

You can implement an adapter that implements the EntityCache interface to use cache in CachedEntitySource.

Example

This is an example for node-cache. You can also use Typescript if you want to.

export class NodeCacheAdapter<T> implements EntityCache<T> {
  constructor(private nodeCache: NodeCache) {}

  async invalidate(keys: string[]): Promise<void> {
    this.nodeCache.del(keys);
    return;
  }

  async get(key: string): Promise<T> {
    return this.nodeCache.get(key);
  }

  async setBatch(batch: { key: string; value: any }[]): Promise<void> {
    this.nodeCache.mset(
      batch.map((b) => ({
        key: b.key,
        val: b.value,
      }))
    );
  }
}
const cache = new NodeCache();
const userSource = new CachedEntitySource<User>("user",{
    cache: new NodeCacheAdapter<User>(cache);
    lookupUsing: findUsers,
    entityIdBy: "id"
});

CachedEntitySource Options

NameTypeDescription
cacheEntityCacheThe cache instance that implements the EntityCache interface
lookupUsingEntityLookupFunction(string[]) => (T[] | Promise<T[]>)A function that receives an array of IDs and returns an array of entities(or an Promise)
entityIdBystring | (T) => stringThe name of the ID field in the entity, or a function that receives an entityand returns its ID.

License

MIT

0.2.7

8 months ago

0.2.6

8 months ago

0.2.5

1 year ago

0.2.1

2 years ago

0.2.0

2 years ago

0.2.3

1 year ago

0.2.2

2 years ago

0.2.4

1 year ago

0.1.5

2 years ago

0.1.4

2 years ago

0.1.3

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago