Skip to content

Commit

Permalink
feat: Add key value store plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed May 17, 2023
1 parent 0d0575e commit 95244fa
Show file tree
Hide file tree
Showing 157 changed files with 990 additions and 8,479 deletions.
Empty file added packages/kv-store/CHANGELOG.md
Empty file.
File renamed without changes.
File renamed without changes.
18 changes: 18 additions & 0 deletions packages/kv-store/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"apiReport": {
"enabled": true,
"reportFolder": "./api",
"reportTempFolder": "./api"
},

"docModel": {
"enabled": true,
"apiJsonFilePath": "./api/<unscopedPackageName>.api.json"
},

"dtsRollup": {
"enabled": false
},
"mainEntryPointFilePath": "<projectFolder>/build/index.d.ts"
}
49 changes: 49 additions & 0 deletions packages/kv-store/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@sphereon/ssi-sdk.kv-store-temp",
"description": "Key Value Store plugin",
"version": "0.11.0",
"source": "src/index.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc"
},
"dependencies": {
"@veramo/utils": "4.2.0",
"events": "^3.3.0",
"debug": "^4.3.4",
"json-buffer": "^3.0.1",
"typeorm": "^0.3.10",
"uint8arrays": "^3.1.1"
},
"devDependencies": {
"@veramo/cli": "4.2.0",
"@types/json-buffer": "^3.0.0",
"@types/debug": "^4.1.7",
"keyv": "^4.5.2",
"@keyv/test-suite": "^1.9.2",
"@keyv/sqlite": "^3.6.5",
"@keyv/compress-brotli": "^1.1.3",
"@keyv/compress-gzip": "^1.2.3",
"eslint": "^8.33.0",
"eslint-plugin-promise": "^6.1.1",
"timekeeper": "^2.2.0",
"typescript": "^4.9.5"
},
"files": [
"dist/**/*",
"src/**/*",
"README.md",
"LICENSE"
],
"publishConfig": {
"access": "public"
},
"repository": "[email protected]:uport-project/veramo.git",
"author": "Niels Klomp <[email protected]>",
"license": "Apache-2.0",
"keywords": [
"Key Value Store",
"keyv"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import KeyvSqlite from '@keyv/sqlite'
import timekeeper from 'timekeeper'
import { Keyv } from '../keyv/keyv'
import { DataSource } from 'typeorm'
import { KeyValueStoreEntity } from '../store-adapters/typeorm/entities/keyValueStoreEntity'
import { KeyValueStoreEntity } from '../store-adapters'
import { KeyValueTieredStoreAdapter, KeyValueTypeORMStoreAdapter } from '../store-adapters'
import { KeyvOptions } from '../keyv/keyv-types'
import { kvStoreMigrations } from '../store-adapters/typeorm/migrations'
import { kvStoreMigrations } from '../store-adapters'

let dbConnection: DataSource
beforeEach(async () => {
Expand Down Expand Up @@ -61,29 +61,6 @@ describe('keyv sqlite store', () => {
})

describe('keyv TypeORM store', () => {
/*let dbConnection: DataSource
beforeEach(async () => {
dbConnection = await new DataSource({
type: 'sqlite',
database: ':memory:',
logging: 'all',
migrationsRun: true,
synchronize: false,
migrations: [...kvStoreMigrations],
entities: [KeyValueStoreEntity],
}).initialize()
})
afterEach(async () => {
try {
(await dbConnection).destroy()
} catch (error) {
// the disconnect test will close the DB anyway
}
})
*/
it('should respect ttl', async () => {
const store = new KeyValueTypeORMStoreAdapter({ dbConnection, namespace: 'test' })
const keyv = new Keyv<string>(store)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Provides a {@link @veramo/kv-store#KeyValueStore} for the
* {@link @veramo/core#Agent} plugin that implements {@link @veramo/kv-store#IKeyValueStore} interface
* Provides a {@link @sphereon/ssi-sdk.kv-store-temp#KeyValueStore} for the
* {@link @veramo/core#Agent} plugin that implements {@link @sphereon/ssi-sdk.kv-store-temp#IKeyValueStore} interface
*
* @packageDocumentation
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { IKeyValueStore, IKeyValueStoreOnArgs, IKeyValueStoreOptions, IValueData } from './key-value-types'
import { IKeyValueStore, IKeyValueStoreOnArgs, IKeyValueStoreOptions, IValueData, ValueStoreType } from './key-value-types'
import { Keyv } from './keyv/keyv'
import { KeyvDeserializedData, KeyvOptions, KeyvStoredData } from './keyv/keyv-types'

/**
* Agent plugin that implements {@link @veramo/kv-store#IKeyValueStore} interface
* Agent plugin that implements {@link @sphereon/ssi-sdk.kv-store-temp#IKeyValueStore} interface
* @public
*/
export class KeyValueStore<ValueType> implements IKeyValueStore<ValueType> {
export class KeyValueStore<ValueType extends ValueStoreType> implements IKeyValueStore<ValueType> {
/**
* The main keyv typescript port which delegates to the storage adapters and takes care of some common functionality
*
* @private
* @internal
*/
private readonly keyv: Keyv<ValueType>

Expand Down Expand Up @@ -58,7 +58,7 @@ export class KeyValueStore<ValueType> implements IKeyValueStore<ValueType> {
// Making sure we return the same array length as the amount of key(s) passed in
if (result === null || result === undefined || result.length === 0) {
result = new Array<KeyvStoredData<ValueType>>()
keys.forEach(() => result.push({ value: undefined, expires: undefined } as KeyvDeserializedData<ValueType>))
keys.forEach(() => result.push({ value: undefined, expires: undefined } as unknown as KeyvDeserializedData<ValueType>))
}
return result.map((v) => (!!v ? this.toDeserializedValueData(v) : { value: undefined, expires: undefined }))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,29 @@
/**
* This is how the store will actually store the value.
* It contains an optional `expires` property, which indicates when the value would expire
*
* @beta
*/
export interface IValueData<ValueType> {
value: ValueType | undefined
expires: number | undefined
}

/**
* Event listener arguments
*
* @beta
*/
export interface IKeyValueStoreOnArgs {
eventName: string | symbol
listener: (...args: any[]) => void
}

/*export interface IKeyValueStoreGetArgs {
key: string
}
export interface IKeyValueStoreGetManyArgs {
keys: string[]
}
export interface IKeyValueStoreHasArgs {
key: string
}
export interface IKeyValueStoreDeleteArgs {
key: string
}
export interface IKeyValueStoreDeleteManyArgs {
keys: string[]
}
export interface IKeyValueStoreSetArgs<ValueType> {
key: string
value: ValueType
ttl?: number
}*/

/**
* Options for the Key Value store
*
* @beta
*/
export interface IKeyValueStoreOptions<ValueType> {
[key: string]: any

Expand All @@ -61,37 +47,93 @@ export interface IKeyValueStoreOptions<ValueType> {
emitErrors?: boolean
}

/**
* A store adapter implementation needs to provide namespace support
*
* @beta
*/
export interface IKeyValueStoreAdapter<ValueType> {
namespace?: string | undefined
}

export interface IKeyValueStore<ValueType> {
/**
* The types that can be stored by a store adapter
*
* @public
*/
export type ValueStoreType = object | string | number | boolean

/**
* A Key Value store is responsible for managing Values identified by keys.
*
* @beta
*/
export interface IKeyValueStore<ValueType extends ValueStoreType> {
/**
* Get a single value by key. Can be undefined as the underlying store typically will not throw an error for a non existing key
*
* @param key Contains the key to search for
* @param key - Contains the key to search for
*/
get(key: string): Promise<ValueType | undefined>

/**
* Get a single item as Value Data from the store. Will always return a Value Data Object, but the value in it can be undefined in case the actual store does not contain the value
* @param key Contains the key to search for
*
* @param key - Contains the key to search for
*/
getAsValueData(key: string): Promise<IValueData<ValueType>>

/**
* Get multiple values from the store. Will always return an array with values, but the values can be undefined in case the actual store does not contain the value for the respective key
*
* @param keys - Contains the keys to search for
*/
getMany(keys: string[]): Promise<Array<ValueType | undefined>>

/**
* Get multiple items as Value Data from the store. Will always return an array with Value Data Object, but the value in it can be undefined in case the actual store does not contain the value
*
* @param keys - Contains the keys to search for
*/
getManyAsValueData(keys: string[]): Promise<Array<IValueData<ValueType>>>

/**
* Store a single value
*
* @param key - The key
* @param value - The value
* @param ttl - An optional number how long to store the value in milliseconds. If not provided will be stored indefinitely
*/
set(key: string, value: ValueType, ttl?: number): Promise<IValueData<ValueType>>

/**
* Delete a value from the store by key
*
* @param key - The key to delete the value for
*/
delete(key: string): Promise<boolean>

/**
* Delete multiple values by provided keys
*
* @param keys - The keys to delete the values for
*/
deleteMany(keys: string[]): Promise<boolean[]>

/**
* Clear the whole store (delete all values)
*/
clear(): Promise<IKeyValueStore<ValueType>>

/**
* Determine whether the store has the value belonging to the provided key
*
* @param key The key to search for
*/
has(key: string): Promise<boolean>

/**
* Disconnect the backing store. After this operation the store typically cannot be reused, unless the store object is re-instantiated
*/
disconnect(): Promise<void>
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { IKeyValueStoreAdapter } from '../../key-value-types'

type KeyvTieredIndex = 'local' | 'remote'

/**
* Tiered keyv store adapter, combining 2 adapters/stores into one
* @alpha
*/
export class KeyValueTieredStoreAdapter<Value> extends EventEmitter implements KeyvStore<Value>, IKeyValueStoreAdapter<Value> {
opts: Options_
remote: KeyvStore<Value>
Expand Down
Loading

0 comments on commit 95244fa

Please sign in to comment.