Skip to content

Commit

Permalink
feat: elasticsearch storage
Browse files Browse the repository at this point in the history
  • Loading branch information
boredland committed Oct 3, 2022
1 parent 779bdc7 commit caa733f
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ _Note: The underlying storage layer must be installed separately._
| [node-fs](https://www.npmjs.com/package/@boredland/node-ts-cache-storage-node-fs)| ```yarn add @boredland/node-ts-cache-storage-node-fs```|
| [ioredis](https://www.npmjs.com/package/@boredland/node-ts-cache-storage-ioredis)| ```yarn add @boredland/node-ts-cache-storage-ioredis```|
| [postgres](https://www.npmjs.com/package/@boredland/node-ts-cache-storage-pg)| ```yarn add @boredland/node-ts-cache-storage-pg```|
| [elasticsearch](https://www.npmjs.com/package/@boredland/node-ts-cache-storage-elasticsearch)| ```yarn add @boredland/node-ts-cache-storage-elasticsearch```|

## Usage

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/storage/storageTestFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ export const storageTestFactory = (storage: Storage) => {
});

describe("direct usage", () => {
it("should initialize the pg storage correctly", () => {
it("should initialize the storage correctly", () => {
expect(cache).not.toBeNull();
expect(cache).not.toBeUndefined();
});

it("should add and retrieve string values from the pg storage", async () => {
it("should add and retrieve string values from the storage", async () => {
await cache.setItem("k1", "test1");
const k1 = await cache.getItem("k1");
expect(k1?.content).toBe("test1");
Expand All @@ -41,7 +41,7 @@ export const storageTestFactory = (storage: Storage) => {
expect(k2?.content).toBe("test2");
});

it("should add and retrieve nested values from the pg storage", async () => {
it("should add and retrieve nested values from the storage", async () => {
const v1 = { data: { name: "deep1" } };
await cache.setItem("k1", v1);
const k1 = await cache.getItem("k1");
Expand Down
31 changes: 31 additions & 0 deletions packages/storage-elasticsearch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# node-ts-cache-storage-elasticsearch

ElasticSearch storage module for [node-ts-cache](https://www.npmjs.com/package/node-ts-cache).

This module expects you to bring your own instance of ElasticSearch.

```bash
yarn add @boredland/node-ts-cache @boredland/node-ts-cache-storage-elasticsearch
```

```ts
import { ElasticSearchStorage } from "@boredland/node-ts-cache-storage-elasticsearch"
import { Cache, CacheContainer } from "@boredland/node-ts-cache"
import { Client } from "@elastic/elasticsearch";

const client = new Client({
node: "http://localhost:9200",
Connection: mock.getConnection(),
});

const storage = new ElasticSearchStorage(indexName, client);

const userCache = new CacheContainer(storage)

class MyService {
@Cache(userCache, { ttl: 60 })
public async getUsers(): Promise<string[]> {
return ["Max", "User"]
}
}
```
42 changes: 42 additions & 0 deletions packages/storage-elasticsearch/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@boredland/node-ts-cache-storage-elasticsearch",
"description": "ElasticSearch storage module for node-ts-cache",
"version": "5.0.0",
"private": false,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig-build.json"
},
"repository": {
"type": "git",
"url": "git+https://github.com/boredland/node-ts-cache.git"
},
"keywords": [
"node",
"nodejs",
"cache",
"typescript",
"ts",
"caching",
"cache",
"elastic",
"elasticsearch",
"node-cache",
"ts-cache"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/boredland/node-ts-cache/issues"
},
"homepage": "https://github.com/boredland/node-ts-cache#readme",
"peerDependencies": {
"@boredland/node-ts-cache": "^6.0.0",
"@elastic/elasticsearch": "^8.4.0"
},
"devDependencies": {
"@boredland/node-ts-cache": "^6.0.0",
"@elastic/elasticsearch": "^8.4.0",
"@elastic/elasticsearch-mock": "^2.0.0"
}
}
80 changes: 80 additions & 0 deletions packages/storage-elasticsearch/src/elastic-storage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { ElasticSearchStorage } from ".";
import { storageTestFactory } from "../../core/src/storage/storageTestFactory";
import { decoratorTestFactory } from "../../core/src/decorator/decoratorTestFactory";
import { Client } from "@elastic/elasticsearch";
import Mock from "@elastic/elasticsearch-mock";
import type { CachedItem } from "@boredland/node-ts-cache";

const mock = new Mock();
const indexName = "123abcTest";

const lastItemFromPath = (path: string) =>
decodeURIComponent(path.substring(path.lastIndexOf("/") + 1));

let memCache: Record<string, CachedItem> = {};

mock.add(
{
method: "GET",
path: `/${indexName}/_doc/:id`,
},
(params) => {
const key = lastItemFromPath(params.path as string);
const item = memCache[key];
return {
_index: "my-index-000001",
_id: "0",
_version: 1,
_seq_no: 0,
_primary_term: 1,
found: !!item,
_source: item,
};
}
);

mock.add(
{
method: "PUT",
path: `/${indexName}/_doc/:id`,
},
(params) => {
const key = lastItemFromPath(params.path as string);
memCache[key] = params.body as CachedItem;
return "ok";
}
);

mock.add(
{
method: "DELETE",
path: `/${indexName}/_doc/:id`,
},
async (params) => {
const key = lastItemFromPath(params.path as string);
delete memCache[key];
return "ok";
}
);

mock.add(
{
method: "DELETE",
path: `/${indexName}`,
},
async () => {
memCache = {};
return "ok";
}
);

describe("elasticsearch-storage", () => {
const client = new Client({
node: "http://localhost:9200",
Connection: mock.getConnection(),
});
const storage = new ElasticSearchStorage(indexName, client);

storageTestFactory(storage);
decoratorTestFactory(storage);
});
54 changes: 54 additions & 0 deletions packages/storage-elasticsearch/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { Client } from "@elastic/elasticsearch";
import type { CachedItem, Storage } from "@boredland/node-ts-cache";
import type { GetResponse } from "@elastic/elasticsearch/lib/api/types";

export class ElasticSearchStorage implements Storage {
constructor(
private indexName: string,
private elasticsearchInstance: Client
) {}

async clear(): Promise<void> {
try {
await this.elasticsearchInstance.indices.delete({
index: this.indexName,
ignore_unavailable: true,
});
} catch (e) {
return;
}
}

async removeItem(key: string): Promise<void> {
await this.elasticsearchInstance.delete({
index: this.indexName,
id: encodeURIComponent(key),
refresh: "wait_for",
});
}

async getItem(key: string): Promise<CachedItem | undefined> {
let item: GetResponse<CachedItem | undefined>;

try {
item = await this.elasticsearchInstance.get<CachedItem>({
index: this.indexName,
id: encodeURIComponent(key),
});
} catch (e) {
return undefined;
}

if (!item.found) return undefined;
return item._source;
}

async setItem(key: string, content: CachedItem): Promise<void> {
await this.elasticsearchInstance.index({
index: this.indexName,
id: encodeURIComponent(key),
refresh: "wait_for",
body: content,
});
}
}
8 changes: 8 additions & 0 deletions packages/storage-elasticsearch/tsconfig-build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": ["./src"],
"exclude": ["**/*.test.ts"],
"compilerOptions": {
"sourceMap": false
}
}
7 changes: 7 additions & 0 deletions packages/storage-elasticsearch/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"include": ["./src"],
"compilerOptions": {
"outDir": "./dist"
}
}
4 changes: 2 additions & 2 deletions packages/storage-ioredis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
"devDependencies": {
"ioredis": "^5.2.3",
"ioredis-mock": "^8",
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"peerDependencies": {
"ioredis": "^5",
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"dependencies": {
"superjson": "1.10.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/storage-memory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
},
"homepage": "https://github.com/boredland/node-ts-cache#readme",
"peerDependencies": {
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"devDependencies": {
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
}
}
4 changes: 2 additions & 2 deletions packages/storage-node-fs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
},
"homepage": "https://github.com/boredland/node-ts-cache#readme",
"peerDependencies": {
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"devDependencies": {
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"dependencies": {
"superjson": "1.10.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/storage-pg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
},
"homepage": "https://github.com/boredland/node-ts-cache#readme",
"peerDependencies": {
"@boredland/node-ts-cache": "^5.1.0"
"@boredland/node-ts-cache": "^6.0.0"
},
"devDependencies": {
"@boredland/node-ts-cache": "^5.1.0",
"@boredland/node-ts-cache": "^6.0.0",
"pg": "^8.8.0",
"pg-mem": "^2.6.3"
}
Expand Down
Loading

0 comments on commit caa733f

Please sign in to comment.