Skip to content

Commit

Permalink
feat: first version
Browse files Browse the repository at this point in the history
  • Loading branch information
Thiago Santos committed Nov 17, 2023
1 parent 658888c commit f9e5b72
Show file tree
Hide file tree
Showing 22 changed files with 10,821 additions and 6,113 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
name: build
on:
pull_request:
branches: [master]
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
node-version: [20.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
name: lint
on:
pull_request:
branches: [master]
branches: [main]

jobs:
lint:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/semantic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: semantic-release

on:
push:
branches: [masterIgnore]
branches: [main]

jobs:
semantic:
Expand All @@ -18,7 +18,7 @@ jobs:
token: ${{ secrets.GH_TOKEN }}
- uses: actions/setup-node@v3
with:
node-version: "14.x"
node-version: "20.x"
- run: printf "//`node -p \"require('url').parse('https://registry.npmjs.org').host\"`/:_authToken=${NPM_TOKEN}\n" >> ~/.npmrc
- run: npm ci
- run: npm run build --if-present
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
name: test
on:
pull_request:
branches: [master, develop]
branches: [main, develop]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
node-version: [20.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
14
20
2 changes: 1 addition & 1 deletion .releaserc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"branches": [
"master"
"main"
],
"plugins": [
"@semantic-release/commit-analyzer",
Expand Down
99 changes: 90 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,100 @@
[![Actions Status](https://github.com/Codibre/boilerplate-base/workflows/build/badge.svg)](https://github.com/Codibre/boilerplate-base/actions)
[![Actions Status](https://github.com/Codibre/boilerplate-base/workflows/test/badge.svg)](https://github.com/Codibre/boilerplate-base/actions)
[![Actions Status](https://github.com/Codibre/boilerplate-base/workflows/lint/badge.svg)](https://github.com/Codibre/boilerplate-base/actions)
[![Test Coverage](https://api.codeclimate.com/v1/badges/65e41e3018643f28168e/test_coverage)](https://codeclimate.com/github/Codibre/boilerplate-base/test_coverage)
[![Maintainability](https://api.codeclimate.com/v1/badges/65e41e3018643f28168e/maintainability)](https://codeclimate.com/github/Codibre/boilerplate-base/maintainability)
[![Packages](https://david-dm.org/Codibre/boilerplate-base.svg)](https://david-dm.org/Codibre/boilerplate-base)
[![npm version](https://badge.fury.io/js/%40codibre%2Fboilerplate-base.svg)](https://badge.fury.io/js/%40codibre%2Fboilerplate-base)
[![Actions Status](https://github.com/Codibre/generic-memoizer/workflows/build/badge.svg)](https://github.com/Codibre/generic-memoizer/actions)
[![Actions Status](https://github.com/Codibre/generic-memoizer/workflows/test/badge.svg)](https://github.com/Codibre/generic-memoizer/actions)
[![Actions Status](https://github.com/Codibre/generic-memoizer/workflows/lint/badge.svg)](https://github.com/Codibre/generic-memoizer/actions)
[![Test Coverage](https://api.codeclimate.com/v1/badges/a6790604f4031ea02e4f/test_coverage)](https://codeclimate.com/github/codibre/nodejs-generic-memoizer/test_coverage)
[![Maintainability](https://api.codeclimate.com/v1/badges/a6790604f4031ea02e4f/maintainability)](https://codeclimate.com/github/codibre/nodejs-generic-memoizer/maintainability)
[![Packages](https://david-dm.org/Codibre/generic-memoizer.svg)](https://david-dm.org/Codibre/generic-memoizer)
[![npm version](https://badge.fury.io/js/generic-memoizer.svg)](https://badge.fury.io/js/generic-memoizer)

Never forget to write your readme! Also, don't forget to add codeclimate key to your github environment variables (as **CC_TEST_REPORTER_ID**) and to update the url here with the one provided by them!
A flexible library for function memoization

## How to Install

```
npm i boilerplate-base
npm i generic-memoizer
```

## How to use it

generic-memoizer is meant to use with dependency injection, but you can do whatever you feel fit. The first way
is the most recommended one, using a **AsyncLocalStoreGetter**. This one uses async-hooks to create a context that will have access to the object in a safe scope, no matter how many concurrent requests you have in your api, for example. To do it, first, inject a singleton instance of your store:

```ts
injectItWithYourInjectionFramework(InjectionSymbol1, new AsyncLocalStoreGetter())
```

If you want to have two separate store for the same request, you do it by specifying a discrimination symbol:

```ts
injectItWithYourInjectionFramework(InjectionSymbol2, new AsyncLocalStoreGetter(Symbol('MySeparateStore')))
```

Now, you must inject your singleton **GenericMemoizer** instance:

```ts
injectItWithYourInjectionFramework(InjectionSymbol3, new GenericMemoizer(getInjected(InjectionSymbol1)));
```

See that, for this instance of GenericMemoizer, we used the first store getter we created. You need to have different GenericMemoizer instances if you want to have separate stores.

Now, with all set, you just need to call your function through the get method:

```ts
const result = await memoizer.get('memoization key', async () => {
... some processing ...
return myResult;
});
```
This way, if any value is already memoized in the given context, it is returned.

## Particularities for AsyncLocalStoreGetter

AsyncLocalStoreGetter will not work under the hoods, as we described above. But afraid not, it's just a little detail that worth telling: The async context does not exist if not created. So, you need to create it so the memoizer using it work. You have to ways to do it:

* Run

```ts
storeGetter.run(async () => {
... Everything inside this callback can access the memoization context ...
})
```

* Start
```ts
storeGetter.start();
... Everything after the above call and into the same Promise chain, will have access to the context
```

We recommend to use run every time possible, but start can be use when, for example, integrating this library with an Express middleware, as you can't put all the following middlewares inside run's callback. Any situation like that, start is a better fit


## RecordLocalStoreGetter

This built-in LocalStorage uses a plain Javascript object with no context control to work. We only recommend the use of it if you have total control over the scope execution. We do not recommend to use, for example, as a Singleton instance of an API, because it will lead to a memory leak. You, however, use it with an API if you can inject is as "in request scope", with the injection framework you're using. For general purpose, it's hard to make it wrong using **AsyncLocalStoreGetter**, so, prefer it, if possible;

## ApmStoreGetter

Apm StoreGetter uses the current instance of **elastic-apm-node**'s transaction to control the memoization scope. If you have your API monitored by it, this is a good way to have under the hood memoization scope in your route, as you don't need to initialize the scope manually.

## Other ways to memoize a method

Aside from **get**, you can also generate memoized version of a function with **wrap**:

```ts
const memoizedMyFunction = memoizer.wrap(myFunction, (param1, param2) => `${param1}:${param2}`);
```

The second params will receive the same parameters as myFunction, and must be used to defined te memoization key based on them. You can wrap functions even when no context is initialized on the store getter, so it is a valid approach to do it during the application bootstrap


Another way you have to do it is by the **replace** method, where you can memoize a instance method, like this:

```ts
memoizer.replace(myInstance, 'myMethod', (param1, param2) => `${param1}:${param2}`);
```

Here, **myInstance.myMethod** is replaced by a memoized version of it. This strategy is also good to use during bootstrap.

## License

Licensed under [MIT](https://en.wikipedia.org/wiki/MIT_License).
2 changes: 1 addition & 1 deletion bitbucket-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pipelines:
- step: *scan-code

branches:
master:
main:
- step: *install-packages
- parallel:
- step: *build-application
Expand Down

0 comments on commit f9e5b72

Please sign in to comment.