Skip to content

Commit

Permalink
Merge pull request #1 from naveendurgasap/randomiseKey
Browse files Browse the repository at this point in the history
feat: support json keys
  • Loading branch information
gabel authored Jan 16, 2024
2 parents 415cede + ab5e27c commit cfdf95b
Show file tree
Hide file tree
Showing 5 changed files with 2,822 additions and 4,241 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ await keyv.set(key, value)

await keyv.get(key)

keyv.disconnect();
keyvNats.disconnect();
```

## Tests
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"typescript": "^5.0.4"
},
"dependencies": {
"keyv": "^4.5.2",
"nats": "^2.14.0"
"@types/seedrandom": "^3.0.8",
"keyv": "^4.5.4",
"nats": "^2.14.0",
"seedrandom": "^3.0.5"
}
}
20 changes: 15 additions & 5 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Keyv from 'keyv'
import KeyvNats from "./index";
import { NatsConnectionOptions, NatsContainer, StartedNatsContainer } from "testcontainers";
import { NatsConnectionImpl } from "nats/lib/nats-base-client/nats";
import {JetStreamClientImpl} from "nats/lib/jetstream/jsclient";
import {Bucket} from "nats/lib/jetstream/kv";

let options: NatsConnectionOptions
let container: StartedNatsContainer
Expand All @@ -23,13 +25,15 @@ afterAll(async () => {
await container.stop()
})

describe('Nats Keyv storage apapter', () => {
describe('Nats Keyv storage adapter', () => {
test('Basic initialization of NATS keyv adapter connection to NATS (using testcontainers)', async () => {
const keyvNats = new KeyvNats(options);
expect(keyvNats).toBeInstanceOf(KeyvNats);

await keyvNats.connect();
expect(keyvNats.client).toBeInstanceOf(NatsConnectionImpl);
expect(keyvNats.jetStream).toBeInstanceOf(JetStreamClientImpl);
expect(keyvNats.keyValueBucket).toBeInstanceOf(Bucket);
await keyvNats.disconnect();
})

Expand Down Expand Up @@ -116,11 +120,17 @@ describe('Nats Keyv storage apapter', () => {
await keyvNats.connect();
const keyv = new Keyv({ store: keyvNats })

const key = 'foo'
const value = 'bar'
const jsonKey = {
url : '/organization/S123456789'
}
const key = JSON.stringify(jsonKey)
const value = {
"id": "123456789",
"businessPartnerType": "organization",
}
await keyv.set(key, value)

expect(await keyv.get(key)).toBe(value)
await keyv.disconnect();
expect(await keyv.get(key)).toEqual(value)
await keyvNats.disconnect();
})
})
19 changes: 14 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EventEmitter } from 'events';
import type { Store } from 'keyv';
import { connect, NatsConnection, ConnectionOptions, JetStreamClient, KV, StringCodec } from "nats";
import seedrandom from "seedrandom";

type KeyvNatsOptions = ConnectionOptions & {
ttl?: number,
Expand All @@ -11,14 +12,14 @@ class KeyvNats<Value = any> extends EventEmitter implements Store<Value> {
public ttlSupport = true;
public client: NatsConnection | undefined = undefined
public opts: KeyvNatsOptions = {servers: 'localhost:4222'}
private jetStream: JetStreamClient | undefined = undefined
public jetStream: JetStreamClient | undefined = undefined
private namespace: string = 'keyv'
/**
* Time to live in milliseconds
* @private ttl
*/
private ttl: number = 0
private keyValueBucket: KV | undefined
public keyValueBucket: KV | undefined

constructor(options?: KeyvNatsOptions) {
super();
Expand Down Expand Up @@ -63,7 +64,7 @@ class KeyvNats<Value = any> extends EventEmitter implements Store<Value> {

delete(key: string): boolean | Promise<boolean> {
if (this.keyValueBucket)
return this.keyValueBucket.delete(key).then(() => {
return this.keyValueBucket.delete(getRandomisedKey(key)).then(() => {
return true
})

Expand All @@ -73,7 +74,7 @@ class KeyvNats<Value = any> extends EventEmitter implements Store<Value> {
get(key: string): Promise<Value | undefined> | Value | undefined {
if (this.keyValueBucket)
// @ts-expect-error - Value needs to be number, string or buffer
return this.keyValueBucket.get(key.replace(":","_")).then((kvValue) => {
return this.keyValueBucket.get(getRandomisedKey(key)).then((kvValue) => {
if (kvValue) {
const value = StringCodec().decode(kvValue.value)
return value ? value : undefined
Expand All @@ -88,10 +89,18 @@ class KeyvNats<Value = any> extends EventEmitter implements Store<Value> {
set(key: string, value: Value): any {
if (this.keyValueBucket)
// @ts-expect-error - Value needs to be number, string or buffer
return this.keyValueBucket.put(key.replace(":","_"), StringCodec().encode(value))
return this.keyValueBucket.put(getRandomisedKey(key), StringCodec().encode(value))

return undefined
}
}

/**
* Key's can be complex jsons. This function generates a random but unique int 32 value for the given json.
* This makes the key valid to store in the NATS's kv bucket.
*/
const getRandomisedKey = (key: string) => {
return seedrandom(key.replace(":","_")).int32().toString()
}

export = KeyvNats
Loading

0 comments on commit cfdf95b

Please sign in to comment.