@travetto/cache 8.0.0-alpha.8 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ npm install @travetto/cache
13
13
  yarn add @travetto/cache
14
14
  ```
15
15
 
16
- Provides a foundational structure for integrating caching at the method level. This allows for easy extension with a variety of providers, and is usable with or without [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."). The code aims to handle use cases surrounding common/basic usage.
16
+ Provides a foundational structure for integrating caching at the method level. This allows for easy extension with a variety of providers, and is usable with or without [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."). The code aims to handle use cases surrounding common/basic usage.
17
17
 
18
18
  The cache module requires an [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10) to provide functionality for reading and writing streams. You can use any existing providers to serve as your [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10), or you can roll your own.
19
19
 
@@ -38,16 +38,16 @@ Currently, the following are packages that provide [Expiry](https://github.com/t
38
38
  * [File Model Support](https://github.com/travetto/travetto/tree/main/module/model-file#readme "File system backing for the travetto model module.") - @travetto/model-file
39
39
 
40
40
  ## Decorators
41
- The caching framework provides method decorators that enables simple use cases. One of the requirements to use the caching decorators is that the method arguments, and return values need to be serializable into [JSON](https://www.json.org). Any other data types are not currently supported and would require either manual usage of the caching services directly, or specification of serialization/deserialization routines in the cache config.
41
+ The caching framework provides method decorators that enables simple use cases. One of the requirements to use the caching decorators is that the method arguments, and return values need to be serializable into [JSON](https://www.json.org). Any other data types are not currently supported and would require either manual usage of the caching services directly, or specification of serialization/deserialization routines in the cache config.
42
42
 
43
- Additionally, to use the decorators you will need to have a [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L32) object accessible on the class instance. This can be dependency injected, or manually constructed. The decorators will detect the field at time of method execution, which decouples construction of your class from the cache construction.
43
+ Additionally, to use the decorators you will need to have a [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L35) object accessible on the class instance. This can be dependency injected, or manually constructed. The decorators will detect the field at time of method execution, which decouples construction of your class from the cache construction.
44
44
 
45
- [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L12) is a decorator that will cache all successful results, keyed by a computation based on the method arguments. Given the desire for supporting remote caches (e.g. [redis](https://redis.io), [memcached](https://memcached.org)), only asynchronous methods are supported.
45
+ [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L12) is a decorator that will cache all successful results, keyed by a computation based on the method arguments. Given the desire for supporting remote caches (e.g. [redis](https://redis.io), [memcached](https://memcached.org)), only asynchronous methods are supported.
46
46
 
47
47
  **Code: Using decorators to cache expensive async call**
48
48
  ```typescript
49
- import { MemoryModelService } from '@travetto/model-memory';
50
49
  import { Cache, CacheService } from '@travetto/cache';
50
+ import { MemoryModelService } from '@travetto/model-memory';
51
51
 
52
52
  async function request(url: string): Promise<string> {
53
53
  let value: string;
@@ -56,10 +56,7 @@ async function request(url: string): Promise<string> {
56
56
  }
57
57
 
58
58
  export class Worker {
59
-
60
- myCache = new CacheService(
61
- new MemoryModelService({ namespace: '' })
62
- );
59
+ myCache = new CacheService(new MemoryModelService({ namespace: '' }));
63
60
 
64
61
  @Cache('myCache', '1s')
65
62
  async calculateExpensiveResult(expression: string): Promise<string> {
@@ -74,26 +71,25 @@ The [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/dec
74
71
  * `name` the field name of the current class which points to the desired cache source.
75
72
  * `config` the additional/optional config options, on a per invocation basis
76
73
 
77
- * `keySpace` the key space within the cache. Defaults to class name plus method name.
78
- * `key` the function will use the inputs to determine the cache key, defaults to all params `JSON.stringify`ied
79
- * `params` the function used to determine the inputs for computing the cache key. This is an easier place to start to define what parameters are important in ,caching. This defaults to all inputs.
80
- * `maxAge` the number of milliseconds will hold the value before considering the cache entry to be invalid. By default values will live infinitely.
81
- * `extendOnAccess` determines if the cache timeout should be extended on access. This only applies to cache values that have specified a `maxAge`.
82
- * `serialize` the function to execute before storing a cacheable value. This allows for any custom data modification needed to persist as a string properly.
83
- * `reinstate` the function to execute on return of a cached value. This allows for any necessary operations to conform to expected output (e.g. re-establishing class instances, etc.). This method should not be used often, as the return values of the methods should naturally serialize to/from `JSON` and the values should be usable either way.
74
+ * `keySpace` the key space within the cache. Defaults to class name plus method name.
75
+ * `key` the function will use the inputs to determine the cache key, defaults to all params `JSON.stringify`ied
76
+ * `params` the function used to determine the inputs for computing the cache key. This is an easier place to start to define what parameters are important in ,caching. This defaults to all inputs.
77
+ * `maxAge` the number of milliseconds will hold the value before considering the cache entry to be invalid. By default values will live infinitely.
78
+ * `extendOnAccess` determines if the cache timeout should be extended on access. This only applies to cache values that have specified a `maxAge`.
79
+ * `serialize` the function to execute before storing a cacheable value. This allows for any custom data modification needed to persist as a string properly.
80
+ * `reinstate` the function to execute on return of a cached value. This allows for any necessary operations to conform to expected output (e.g. re-establishing class instances, etc.). This method should not be used often, as the return values of the methods should naturally serialize to/from `JSON` and the values should be usable either way.
84
81
 
85
82
  ### EvictCache
86
- Additionally, there is support for planned eviction via the [@EvictCache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L44) decorator. On successful execution of a method with this decorator, the matching keySpace/key value will be evicted from the cache. This requires coordination between multiple methods, to use the same `keySpace` and `key` to compute the expected key.
83
+ Additionally, there is support for planned eviction via the [@EvictCache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L55) decorator. On successful execution of a method with this decorator, the matching keySpace/key value will be evicted from the cache. This requires coordination between multiple methods, to use the same `keySpace` and `key` to compute the expected key.
87
84
 
88
85
  **Code: Using decorators to cache/evict user access**
89
86
  ```typescript
87
+ import { Cache, CacheService, EvictCache } from '@travetto/cache';
90
88
  import { MemoryModelService } from '@travetto/model-memory';
91
- import { Cache, EvictCache, CacheService } from '@travetto/cache';
92
89
 
93
- class User { }
90
+ class User {}
94
91
 
95
92
  export class UserService {
96
-
97
93
  myCache = new CacheService(new MemoryModelService({ namespace: '' }));
98
94
  database: {
99
95
  lookupUser(id: string): Promise<User>;
@@ -119,14 +115,14 @@ export class UserService {
119
115
  ```
120
116
 
121
117
  ## Extending the Cache Service
122
- By design, the [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L32) relies solely on the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module. Specifically on the [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10). This combines basic support for CRUD as well as knowledge of how to manage expirable content. Any model service that honors these contracts is a valid candidate to power the [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L32). The [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L32) is expecting the model service to be registered using the @travetto/cache:model:
118
+ By design, the [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L35) relies solely on the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module. Specifically on the [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10). This combines basic support for CRUD as well as knowledge of how to manage content that expires. Any model service that honors these contracts is a valid candidate to power the [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L35). The [CacheService](https://github.com/travetto/travetto/tree/main/module/cache/src/service.ts#L35) is expecting the model service to be registered using the @travetto/cache:model:
123
119
 
124
120
  **Code: Registering a Custom Model Source**
125
121
  ```typescript
122
+ import { CacheModelSymbol } from '@travetto/cache';
126
123
  import { InjectableFactory } from '@travetto/di';
127
124
  import type { ModelExpirySupport } from '@travetto/model';
128
125
  import { MemoryModelService } from '@travetto/model-memory';
129
- import { CacheModelSymbol } from '@travetto/cache';
130
126
 
131
127
  class Config {
132
128
  @InjectableFactory(CacheModelSymbol)
package/__index__.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './src/types.ts';
2
1
  export * from './src/decorator.ts';
3
2
  export * from './src/service.ts';
4
- export * from './src/util.ts';
3
+ export * from './src/types.ts';
4
+ export * from './src/util.ts';
package/package.json CHANGED
@@ -1,37 +1,40 @@
1
1
  {
2
2
  "name": "@travetto/cache",
3
- "version": "8.0.0-alpha.8",
4
- "type": "module",
3
+ "version": "8.0.0",
5
4
  "description": "Caching functionality with decorators for declarative use.",
6
5
  "keywords": [
7
- "typescript",
8
- "travetto",
6
+ "cache",
9
7
  "decorator",
10
- "cache"
8
+ "travetto",
9
+ "typescript"
11
10
  ],
12
11
  "homepage": "https://travetto.io",
13
12
  "license": "MIT",
14
13
  "author": {
15
- "email": "travetto.framework@gmail.com",
16
- "name": "Travetto Framework"
14
+ "name": "Travetto Framework",
15
+ "email": "travetto.framework@gmail.com"
16
+ },
17
+ "repository": {
18
+ "url": "git+https://github.com/travetto/travetto.git",
19
+ "directory": "module/cache"
17
20
  },
18
21
  "files": [
19
22
  "__index__.ts",
20
23
  "src",
21
24
  "support"
22
25
  ],
26
+ "type": "module",
23
27
  "main": "__index__.ts",
24
- "repository": {
25
- "url": "git+https://github.com/travetto/travetto.git",
26
- "directory": "module/cache"
28
+ "publishConfig": {
29
+ "access": "public"
27
30
  },
28
31
  "dependencies": {
29
- "@travetto/di": "^8.0.0-alpha.8",
30
- "@travetto/model": "^8.0.0-alpha.8"
32
+ "@travetto/di": "^8.0.0",
33
+ "@travetto/model": "^8.0.0"
31
34
  },
32
35
  "peerDependencies": {
33
- "@travetto/test": "^8.0.0-alpha.8",
34
- "@travetto/transformer": "^8.0.0-alpha.4"
36
+ "@travetto/test": "^8.0.0",
37
+ "@travetto/transformer": "^8.0.0"
35
38
  },
36
39
  "peerDependenciesMeta": {
37
40
  "@travetto/transformer": {
@@ -43,8 +46,5 @@
43
46
  },
44
47
  "travetto": {
45
48
  "displayName": "Caching"
46
- },
47
- "publishConfig": {
48
- "access": "public"
49
49
  }
50
50
  }
package/src/decorator.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { castTo, type MethodDescriptor, type TimeSpan, TimeUtil } from '@travetto/runtime';
2
2
 
3
3
  import type { CacheService } from './service.ts';
4
- import { type CoreCacheConfig, type CacheConfig, type CacheAware, CacheConfigSymbol, EvictConfigSymbol } from './types.ts';
4
+ import { type CacheAware, type CacheConfig, CacheConfigSymbol, type CoreCacheConfig, EvictConfigSymbol } from './types.ts';
5
5
 
6
6
  /**
7
7
  * Indicates a method is intended to cache. The return type must be properly serializable
@@ -9,10 +9,16 @@ import { type CoreCacheConfig, type CacheConfig, type CacheAware, CacheConfigSym
9
9
  * @param config The additional cache configuration
10
10
  * @kind decorator
11
11
  */
12
- export function Cache<F extends string, U extends Record<F, CacheService>>(field: F, maxAge: number | TimeSpan, config?: Omit<CacheConfig, 'maxAge'>): MethodDecorator;
12
+ export function Cache<F extends string, U extends Record<F, CacheService>>(
13
+ field: F,
14
+ maxAge: number | TimeSpan,
15
+ config?: Omit<CacheConfig, 'maxAge'>
16
+ ): MethodDecorator;
13
17
  export function Cache<F extends string, U extends Record<F, CacheService>>(field: F, input?: CacheConfig): MethodDecorator;
14
18
  export function Cache<F extends string, U extends Record<F, CacheService>>(
15
- field: F, input?: number | TimeSpan | CacheConfig, config: Exclude<CacheConfig, 'maxAge'> = {}
19
+ field: F,
20
+ input?: number | TimeSpan | CacheConfig,
21
+ config: Exclude<CacheConfig, 'maxAge'> = {}
16
22
  ): MethodDecorator {
17
23
  if (input !== undefined) {
18
24
  if (typeof input === 'string' || typeof input === 'number') {
@@ -21,12 +27,17 @@ export function Cache<F extends string, U extends Record<F, CacheService>>(
21
27
  config = input;
22
28
  }
23
29
  }
24
- const decorator = function <R extends Promise<unknown>>(target: U & CacheAware, propertyKey: string, descriptor: MethodDescriptor<R>): void {
30
+ const decorator = function <R extends Promise<unknown>>(
31
+ target: U & CacheAware,
32
+ propertyKey: string,
33
+ descriptor: MethodDescriptor<R>
34
+ ): void {
25
35
  config.keySpace ??= `${target.constructor.name}.${propertyKey}`;
26
36
  (target[CacheConfigSymbol] ??= {})[propertyKey] = config;
27
37
  const handler = descriptor.value!;
28
38
  // Allows for DI to run, as the service will not be bound until after the decorator is run
29
39
  descriptor.value = castTo(function (this: typeof target) {
40
+ // biome-ignore lint/complexity/noArguments: We want to use arguments here
30
41
  return this[field].cache(this, propertyKey, handler, [...arguments]);
31
42
  });
32
43
  Object.defineProperty(descriptor.value, 'name', { value: propertyKey, writable: false });
@@ -48,8 +59,9 @@ export function EvictCache<F extends string, U extends Record<F, CacheService>>(
48
59
  const handler = descriptor.value!;
49
60
  // Allows for DI to run, as the service will not be bound until after the decorator is run
50
61
  descriptor.value = castTo(function (this: typeof target) {
62
+ // biome-ignore lint/complexity/noArguments: We want to use arguments here
51
63
  return this[field].evict(this, propertyKey, handler, [...arguments]);
52
64
  });
53
65
  Object.defineProperty(descriptor.value, 'name', { value: propertyKey, writable: false });
54
66
  };
55
- }
67
+ }
package/src/error.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { RuntimeError } from '@travetto/runtime';
2
2
 
3
3
  /** Cache Error Class */
4
- export class CacheError extends RuntimeError { }
4
+ export class CacheError extends RuntimeError {}
package/src/service.ts CHANGED
@@ -1,36 +1,38 @@
1
- import { ExpiresAt, Index, Model, type ModelExpirySupport, NotFoundError, ModelStorageUtil, ModelIndexedUtil } from '@travetto/model';
2
- import { Text } from '@travetto/schema';
3
1
  import { Inject, Injectable } from '@travetto/di';
4
- import { RuntimeError, JSONUtil, TimeUtil } from '@travetto/runtime';
2
+ import { ExpiresAt, Model, type ModelExpirySupport, ModelStorageUtil, NotFoundError } from '@travetto/model';
3
+ import { ModelIndexedUtil, sortedIndex } from '@travetto/model-indexed';
4
+ import { JSONUtil, RuntimeError, TimeUtil } from '@travetto/runtime';
5
+ import { MaxLength, Text } from '@travetto/schema';
5
6
 
6
7
  import { CacheError } from './error.ts';
7
- import { CacheUtil } from './util.ts';
8
8
  import { type CacheAware, CacheConfigSymbol, CacheModelSymbol, EvictConfigSymbol } from './types.ts';
9
+ import { CacheUtil } from './util.ts';
9
10
 
10
11
  const INFINITE_MAX_AGE = TimeUtil.duration('10y', 'ms');
11
12
 
12
- @Index({
13
- name: 'keySpace',
14
- type: 'unsorted',
15
- fields: [{ keySpace: 1 }]
16
- })
17
13
  @Model({ autoCreate: 'production' })
18
14
  export class CacheRecord {
19
15
  id: string;
20
16
  @Text()
21
17
  entry: string;
18
+ @MaxLength(500)
22
19
  keySpace: string;
23
20
  @ExpiresAt()
24
21
  expiresAt: Date;
25
22
  issuedAt: Date;
26
23
  }
27
24
 
25
+ const keySpaceIndex = sortedIndex(CacheRecord, {
26
+ name: 'keySpace',
27
+ key: { keySpace: true },
28
+ sort: { expiresAt: 1 }
29
+ });
30
+
28
31
  /**
29
32
  * Cache source
30
33
  */
31
34
  @Injectable()
32
35
  export class CacheService {
33
-
34
36
  #modelService: ModelExpirySupport;
35
37
 
36
38
  constructor(@Inject({ qualifier: CacheModelSymbol, resolution: 'loose' }) modelService: ModelExpirySupport) {
@@ -48,7 +50,8 @@ export class CacheService {
48
50
  const delta = expiresAt.getTime() - Date.now();
49
51
  const maxAge = expiresAt.getTime() - issuedAt.getTime();
50
52
 
51
- if (delta < 0) { // Expired
53
+ if (delta < 0) {
54
+ // Expired
52
55
  await this.#modelService.delete(CacheRecord, id);
53
56
  throw new CacheError('Key expired', { category: 'data' });
54
57
  }
@@ -76,14 +79,15 @@ export class CacheService {
76
79
  async set(id: string, keySpace: string, entry: unknown, maxAge?: number): Promise<unknown> {
77
80
  const entryText = JSONUtil.toBase64(entry);
78
81
 
79
- const store = await this.#modelService.upsert(CacheRecord,
82
+ const store = await this.#modelService.upsert(
83
+ CacheRecord,
80
84
  CacheRecord.from({
81
85
  id,
82
86
  entry: entryText!,
83
87
  keySpace,
84
88
  expiresAt: TimeUtil.fromNow(maxAge || INFINITE_MAX_AGE),
85
89
  issuedAt: new Date()
86
- }),
90
+ })
87
91
  );
88
92
 
89
93
  return JSONUtil.fromBase64(store.entry);
@@ -104,8 +108,10 @@ export class CacheService {
104
108
  async deleteAll(keySpace: string): Promise<void> {
105
109
  if (ModelIndexedUtil.isSupported(this.#modelService)) {
106
110
  const removes: Promise<void>[] = [];
107
- for await (const item of this.#modelService.listByIndex(CacheRecord, 'keySpace', { keySpace })) {
108
- removes.push(this.#modelService.delete(CacheRecord, item.id));
111
+ for await (const batch of this.#modelService.listByIndex(CacheRecord, keySpaceIndex, { keySpace })) {
112
+ for (const item of batch) {
113
+ removes.push(this.#modelService.delete(CacheRecord, item.id));
114
+ }
109
115
  }
110
116
  await Promise.all(removes);
111
117
  } else {
@@ -162,7 +168,8 @@ export class CacheService {
162
168
  result = await this.set(id, config.keySpace!, data, config.maxAge);
163
169
  }
164
170
 
165
- if (config.reinstate) { // Reinstate result value if needed
171
+ if (config.reinstate) {
172
+ // Reinstate result value if needed
166
173
  result = config.reinstate(result);
167
174
  }
168
175
 
@@ -190,4 +197,4 @@ export class CacheService {
190
197
  }
191
198
  return result;
192
199
  }
193
- }
200
+ }
package/src/types.ts CHANGED
@@ -48,4 +48,3 @@ export interface CacheAware {
48
48
  [CacheConfigSymbol]?: Record<string, CacheConfig>;
49
49
  [EvictConfigSymbol]?: Record<string, CoreCacheConfig>;
50
50
  }
51
-
package/src/util.ts CHANGED
@@ -6,7 +6,6 @@ import type { CoreCacheConfig } from './types.ts';
6
6
  * Standard cache utilities
7
7
  */
8
8
  export class CacheUtil {
9
-
10
9
  /**
11
10
  * Generate key given config, cache source and input params
12
11
  */
@@ -16,4 +15,4 @@ export class CacheUtil {
16
15
  const key = `${config.keySpace!}_${JSONUtil.toBase64(keyParams)}`;
17
16
  return BinaryMetadataUtil.hash(key, { length: 32 });
18
17
  }
19
- }
18
+ }
@@ -1,11 +1,12 @@
1
1
  import assert from 'node:assert';
2
2
  import timers from 'node:timers/promises';
3
3
 
4
- import { Suite, Test } from '@travetto/test';
5
- import { type ModelExpirySupport, ModelIndexedUtil } from '@travetto/model';
6
4
  import { Inject, Injectable } from '@travetto/di';
7
- import { castTo, type Class } from '@travetto/runtime';
5
+ import type { ModelExpirySupport } from '@travetto/model';
6
+ import { ModelIndexedUtil } from '@travetto/model-indexed';
7
+ import { type Class, castTo } from '@travetto/runtime';
8
8
  import { Schema } from '@travetto/schema';
9
+ import { Suite, Test } from '@travetto/test';
9
10
 
10
11
  import { InjectableSuite } from '@travetto/di/support/test/suite.ts';
11
12
  import { ModelSuite } from '@travetto/model/support/test/suite.ts';
@@ -15,11 +16,10 @@ import type { CacheService } from '../../src/service.ts';
15
16
  import { CacheModelSymbol } from '../../src/types.ts';
16
17
 
17
18
  @Schema()
18
- class User { }
19
+ class User {}
19
20
 
20
21
  @Injectable()
21
22
  class SampleService {
22
-
23
23
  @Inject()
24
24
  source: CacheService;
25
25
 
@@ -85,7 +85,6 @@ class SampleService {
85
85
  @ModelSuite(CacheModelSymbol)
86
86
  @InjectableSuite()
87
87
  export abstract class CacheServiceSuite {
88
-
89
88
  serviceClass: Class<ModelExpirySupport>;
90
89
  configClass: Class;
91
90
 
@@ -106,7 +105,7 @@ export abstract class CacheServiceSuite {
106
105
  start = Date.now();
107
106
  res = await service.basic(10);
108
107
  diff = Date.now() - start;
109
- assert(diff < (100 + this.baseLatency));
108
+ assert(diff < 100 + this.baseLatency);
110
109
  assert(res === 20);
111
110
  }
112
111
 
@@ -145,7 +144,7 @@ export abstract class CacheServiceSuite {
145
144
  start = Date.now();
146
145
  res = await service.ageExtension(10);
147
146
  diff = Date.now() - start;
148
- assert(diff < (100 + this.baseLatency));
147
+ assert(diff < 100 + this.baseLatency);
149
148
  assert(res === 30);
150
149
  }
151
150
 
@@ -202,12 +201,12 @@ export abstract class CacheServiceSuite {
202
201
  await service.getUser('200');
203
202
  const start = Date.now();
204
203
  await service.getUser('200');
205
- assert((Date.now() - start) <= (this.baseLatency + 100));
204
+ assert(Date.now() - start <= this.baseLatency + 100);
206
205
 
207
206
  await service.deleteUser('200');
208
207
  const start2 = Date.now();
209
208
  await service.getUser('200');
210
- assert((Date.now() - start2) >= 100);
209
+ assert(Date.now() - start2 >= 100);
211
210
 
212
211
  // First time is free
213
212
  await service.deleteUser('200');
@@ -224,33 +223,33 @@ export abstract class CacheServiceSuite {
224
223
  const service = this.testService;
225
224
 
226
225
  // Prime cache
227
- for (let i = 0; i < 10; i++) {
226
+ for (let i = 0; i < 10; i += 1) {
228
227
  const start = Date.now();
229
228
  await service.getUser(`${i}`);
230
- assert((Date.now() - start) >= 100);
229
+ assert(Date.now() - start >= 100);
231
230
  }
232
231
 
233
232
  // Read cache
234
- for (let i = 0; i < 10; i++) {
233
+ for (let i = 0; i < 10; i += 1) {
235
234
  const start = Date.now();
236
235
  await service.getUser(`${i}`);
237
- assert((Date.now() - start) <= (this.baseLatency + 100));
236
+ assert(Date.now() - start <= this.baseLatency + 100);
238
237
  }
239
238
 
240
239
  await service.deleteAllUsers();
241
240
 
242
241
  // Prime cache
243
- for (let i = 0; i < 10; i++) {
242
+ for (let i = 0; i < 10; i += 1) {
244
243
  const start = Date.now();
245
244
  await service.getUser(`${i}`);
246
- assert((Date.now() - start) >= 100);
245
+ assert(Date.now() - start >= 100);
247
246
  }
248
247
 
249
248
  // Read cache
250
- for (let i = 0; i < 10; i++) {
249
+ for (let i = 0; i < 10; i += 1) {
251
250
  const start = Date.now();
252
251
  await service.getUser(`${i}`);
253
- assert((Date.now() - start) <= (this.baseLatency + 100));
252
+ assert(Date.now() - start <= this.baseLatency + 100);
254
253
  }
255
254
  }
256
- }
255
+ }