-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(repository): add KVRepository impl using legacy juggler #1539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| // Copyright IBM Corp. 2017,2018. All Rights Reserved. | ||
| // Node module: @loopback/repository | ||
| // This file is licensed under the MIT License. | ||
| // License text available at https://opensource.org/licenses/MIT | ||
|
|
||
| import * as legacy from 'loopback-datasource-juggler'; | ||
|
|
||
| import {Options, DataObject} from '../common-types'; | ||
| import {Entity} from '../model'; | ||
|
|
||
| import {KeyValueRepository, KeyValueFilter} from './kv.repository'; | ||
|
|
||
| import {juggler, ensurePromise} from './legacy-juggler-bridge'; | ||
|
|
||
| /** | ||
| * Polyfill for Symbol.asyncIterator | ||
| * See https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html | ||
| */ | ||
| // tslint:disable-next-line:no-any | ||
| if (!(Symbol as any).asyncIterator) { | ||
| // tslint:disable-next-line:no-any | ||
| (Symbol as any).asyncIterator = Symbol.for('Symbol.asyncIterator'); | ||
| } | ||
|
|
||
| /** | ||
| * An implementation of KeyValueRepository based on loopback-datasource-juggler | ||
| */ | ||
| export class DefaultKeyValueRepository<T extends Entity> | ||
| implements KeyValueRepository<T> { | ||
| /** | ||
| * A legacy KeyValueModel class | ||
| */ | ||
| kvModelClass: typeof juggler.KeyValueModel; | ||
|
|
||
| /** | ||
| * Construct a KeyValueRepository with a legacy DataSource | ||
| * @param ds Legacy DataSource | ||
| */ | ||
| constructor( | ||
| private entityClass: typeof Entity & {prototype: T}, | ||
| ds: juggler.DataSource, | ||
| ) { | ||
| // KVModel class is placeholder to receive methods from KeyValueAccessObject | ||
| // through mixin | ||
| this.kvModelClass = ds.createModel<typeof juggler.KeyValueModel>( | ||
| '_kvModel', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wrote a comment on this line that was somehow lost :( Consider the following scenario: an app has two key-value models called Creating a new model class on every request has negative performance impact too. Another problem I see here is that we are not defining any properties on the backing model class. As a result, legacy juggler is not going to verify that the input data are valid model properties. AFAIK, KVAO does not implement validations yet (see lib/kvao/set.js), thus I guess this second point is not a blocker for this pull request. Ideally, I'd like our
|
||
| ); | ||
| } | ||
|
|
||
| delete(key: string, options?: Options): Promise<void> { | ||
| return ensurePromise(this.kvModelClass.delete(key, options)); | ||
| } | ||
|
|
||
| deleteAll(options?: Options): Promise<void> { | ||
| return ensurePromise(this.kvModelClass.deleteAll(options)); | ||
| } | ||
|
|
||
| protected toEntity(modelData: legacy.ModelData): T { | ||
| if (modelData == null) return modelData; | ||
| let data = modelData; | ||
| if (typeof modelData.toObject === 'function') { | ||
| data = modelData.toObject(); | ||
| } | ||
| return new this.entityClass(data) as T; | ||
| } | ||
|
|
||
| async get(key: string, options?: Options): Promise<T> { | ||
| const val = this.kvModelClass.get(key, options) as legacy.PromiseOrVoid< | ||
| legacy.ModelData | ||
| >; | ||
| const result = await ensurePromise(val); | ||
| return this.toEntity(result); | ||
| } | ||
|
|
||
| set(key: string, value: DataObject<T>, options?: Options): Promise<void> { | ||
| return ensurePromise<void>(this.kvModelClass.set(key, value, options)); | ||
| } | ||
|
|
||
| expire(key: string, ttl: number, options?: Options): Promise<void> { | ||
| return ensurePromise<void>(this.kvModelClass.expire(key, ttl, options)); | ||
| } | ||
|
|
||
| ttl(key: string, options?: Options): Promise<number> { | ||
| return ensurePromise<number>(this.kvModelClass.ttl(key, options)); | ||
| } | ||
|
|
||
| keys(filter?: KeyValueFilter, options?: Options): AsyncIterable<string> { | ||
| const kvModelClass = this.kvModelClass; | ||
| const iterator = { | ||
| [Symbol.asyncIterator]() { | ||
| return new AsyncKeyIteratorImpl( | ||
| kvModelClass.iterateKeys(filter, options), | ||
| ); | ||
| }, | ||
| }; | ||
| return iterator; | ||
| } | ||
| } | ||
|
|
||
| class AsyncKeyIteratorImpl implements AsyncIterator<string> { | ||
| constructor(private keys: legacy.AsyncKeyIterator) {} | ||
| next() { | ||
| const key = ensurePromise<string | undefined>(this.keys.next()); | ||
| return key.then(k => { | ||
| return {done: k === undefined, value: k || ''}; | ||
| }); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍