Comparing version 0.0.7 to 0.0.8
@@ -6,7 +6,7 @@ "use strict"; | ||
active = true; | ||
cache = new Map(); | ||
uniques = new Map(); | ||
callbacks = []; | ||
append(key) { | ||
if (this.cache.has(key)) { | ||
return this.cache.get(key); | ||
if (this.uniques.has(key)) { | ||
return this.uniques.get(key); | ||
} | ||
@@ -16,3 +16,3 @@ const promise = new Promise((resolve, reject) => { | ||
}); | ||
this.cache.set(key, promise); | ||
this.uniques.set(key, promise); | ||
return promise; | ||
@@ -19,0 +19,0 @@ } |
@@ -17,16 +17,21 @@ "use strict"; | ||
} | ||
function getInstanceBatcher(self, property, fn, options) { | ||
const bkey = `${property}_____batcher`; | ||
// check if the instance already has a batcher for this method | ||
if (self[bkey]) | ||
return self[bkey]; | ||
// otherwise, create a new batcher and store it in the instance so it is unique for that instance | ||
self[bkey] = new MethodBatcher(self, fn, options); | ||
return self[bkey]; | ||
// this Symbol is used to store the MethodBatcher instances in the instance of the class that is using the decorator | ||
// this way we can have a unique batcher for each instance and method of the class decorated with @InBatches | ||
const holder = Symbol('__inbatches__'); | ||
function getInstanceBatcher(instance, property, descriptor, options) { | ||
// check if the instance already has a holder for all the batchers in the class | ||
instance[holder] = instance[holder] ?? new Map(); | ||
// check if the instance already has a method matcher for this specific method | ||
if (instance[holder].has(property)) | ||
return instance[holder].get(property); | ||
// otherwise, create a new batcher and store it in the instance batchers holder | ||
const batcher = new MethodBatcher(instance, descriptor, options); | ||
instance[holder].set(property, batcher); | ||
return batcher; | ||
} | ||
function InBatches(options) { | ||
return function (_, property, descriptor) { | ||
const fn = descriptor.value; | ||
const method = descriptor.value; | ||
descriptor.value = function (...args) { | ||
const batcher = getInstanceBatcher(this, property, fn, options); | ||
const batcher = getInstanceBatcher(this, property, method, options); | ||
return batcher.enqueue(args); | ||
@@ -33,0 +38,0 @@ }; |
{ | ||
"name": "inbatches", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"private": false, | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
116
README.md
@@ -12,3 +12,5 @@ # @InBatches(📦,📦,📦,...) | ||
Heavily inspired by [graphql/dataloader](https://github.com/graphql/dataloader) but using classes and decorators 😜 | ||
Heavily inspired by [graphql/dataloader](https://github.com/graphql/dataloader) but simpler using decorators (😜 really | ||
decoupled). Because of that the | ||
rest of your application doesn't event need to know about the batching/dataloader, it just works! | ||
@@ -19,8 +21,6 @@ ## Table of Contents | ||
- [Usage](#usage) | ||
- [Basic Usage](#basic-usage) | ||
- [Using the `@InBatches` Decorator](#using-the-inbatches-decorator) | ||
- [Basic usage with `@InBatches` Decorator](#basic-usage-with-inbatches-decorator) | ||
- [Advanced usage with custom `Batcher` class](#advanced-usage-with-custom-batcher-class) | ||
- [API](#api) | ||
- [`BatcherOptions`](#batcheroptions) | ||
- [`Batcher<K, V>` Class](#batcherk-v-class) | ||
- [`InBatches<K, V>` Decorator](#inbatches-decorator) | ||
- [Contributing](#contributing) | ||
@@ -35,25 +35,41 @@ - [License](#license) | ||
or | ||
```bash | ||
yarn add inbatches | ||
``` | ||
## Usage | ||
### Using the `Batcher` Class | ||
### Basic usage with `@InBatches` Decorator | ||
The simplest way to get the grown running is to use the `@InBatches` decorator. This decorator will wrap your method | ||
and will batch-enable it, like magic! 🧙♂️ | ||
```typescript | ||
import { Batcher } from 'inbatches'; | ||
import { InBatches } from 'inbatches'; | ||
// Define a class that extends Batcher and implements the `run` method | ||
// the `run` method will be called with an array of keys collected from the `enqueue` method | ||
class MyBatcher extends Batcher<number, string> { | ||
async run(ids: number[]): Promise<string[]> { | ||
// Perform asynchronous operations using the keys | ||
// you must return an array of results in the same order as the keys | ||
return this.db.getMany(ids); | ||
class MyService { | ||
// (optional) overloaded method, where you define the keys as `number` and the return type as `User` for typings | ||
async fetch(key: number): Promise<User>; | ||
// This method is now batch-enabled | ||
@InBatches() | ||
async fetch(keys: number | number[]): Promise<User | User[]> { | ||
if (Array.isArray(keys)) return await this.db.getMany(keys); | ||
// in reality the Decorator will wrap this method and it will never be called with a single key :) | ||
throw new Error('It will never be called with a single key 😉'); | ||
} | ||
} | ||
``` | ||
// Create an instance of your batcher | ||
const batcher = new MyBatcher(); | ||
Profit! 🤑 | ||
// Enqueue keys for batched execution | ||
```typescript | ||
const service = new MyService(); | ||
const result = [1, 2, 3, 4, 5].map(async id => { | ||
return await batcher.enqueue(id); | ||
return await service.fetch(id); | ||
}); | ||
@@ -67,30 +83,29 @@ | ||
### Using the `@InBatches` Decorator | ||
### Advanced usage with custom `Batcher` class | ||
The library also provides a decorator called `InBatches` that you can use to batch-enable methods of your class. | ||
Another way to use the library is to create a class that extends the `Batcher` class and implement the `run` method. | ||
This class will provide a `enqueue` method that you can use to enqueue keys for batched execution. | ||
```typescript | ||
import { InBatches } from 'inbatches'; | ||
import { Batcher } from 'inbatches'; | ||
class MyService { | ||
// (optional) overloaded method, where you define the keys as `number` and the return type as `string` for typings | ||
async fetch(keys: number): Promise<string>; | ||
// in reality the Decorator will wrap this method and it will never be called with a single key :) | ||
@InBatches() // This method is now batch-enabled | ||
async fetch(keys: number | number[]): Promise<string | string[]> { | ||
if (Array.isArray(keys)) { | ||
return this.db.getMany(keys); | ||
} | ||
// the Decorator will wrap this method and because of that it will never be called with a single key | ||
throw new Error('It will never be called with a single key 😉'); | ||
// The `run` method will be called with an array of keys collected from the `enqueue` method | ||
class MyBatcher extends Batcher<number, string> { | ||
async run(ids: number[]): Promise<string[]> { | ||
// Perform asynchronous operations using the keys | ||
// you must return an array of results in the same order as the keys | ||
return this.db.getMany(ids); | ||
} | ||
} | ||
``` | ||
const service = new MyService(); | ||
then | ||
```typescript | ||
// Create an instance of your batcher | ||
const batcher = new MyBatcher(); | ||
// Enqueue keys for batched execution | ||
const result = [1, 2, 3, 4, 5].map(async id => { | ||
return await service.fetch(id); | ||
return await batcher.enqueue(id); | ||
}); | ||
@@ -115,29 +130,2 @@ | ||
### `Batcher<K, V>` Class | ||
An abstract class that provides the core functionality for batching and executing asynchronous operations. | ||
- `enqueue(key: K): Promise<V>`: Enqueues a key for batching and returns a promise that resolves to the result when | ||
available. | ||
### `InBatches` Decorator | ||
A decorator function that can be applied to methods to enable batching. | ||
- Usage: `@InBatches(options?: BatcherOptions)` | ||
- Example: | ||
```typescript | ||
class MyService { | ||
// (optional) overloaded method, where you define the keys as `number` and the return type as `string` for typings | ||
async fetchResults(keys: number): Promise<string> | ||
@InBatches({ maxBatchSize: 10 }) | ||
async fetchResults(keys: number | number[]): Promise<string | string[]> { | ||
// Batch-enabled method logic | ||
} | ||
} | ||
``` | ||
## Contributing | ||
@@ -144,0 +132,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
170
12180
133