@travetto/cache 6.0.0-rc.0 → 6.0.0-rc.2

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
@@ -15,7 +15,7 @@ yarn add @travetto/cache
15
15
 
16
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
- The cache module requires an [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11) 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/service/expiry.ts#L11), or you can roll your own.
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
 
20
20
  **Install: provider**
21
21
  ```bash
@@ -25,7 +25,7 @@ npm install @travetto/model-{provider}
25
25
 
26
26
  yarn add @travetto/model-{provider}
27
27
  ```
28
- Currently, the following are packages that provide [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/service/expiry.ts#L11):
28
+ Currently, the following are packages that provide [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10):
29
29
  * [DynamoDB Model Support](https://github.com/travetto/travetto/tree/main/module/model-dynamodb#readme "DynamoDB backing for the travetto model module.") - @travetto/model-dynamodb
30
30
  * [Elasticsearch Model Source](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch#readme "Elasticsearch backing for the travetto model module, with real-time modeling support for Elasticsearch mappings.") - @travetto/model-elasticsearch
31
31
  * [MongoDB Model Support](https://github.com/travetto/travetto/tree/main/module/model-mongo#readme "Mongo backing for the travetto model module.") - @travetto/model-mongo
@@ -40,9 +40,9 @@ Currently, the following are packages that provide [Expiry](https://github.com/t
40
40
  ## Decorators
41
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#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.
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.
44
44
 
45
- [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L13) 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
@@ -70,7 +70,7 @@ export class Worker {
70
70
  ```
71
71
 
72
72
  ### Cache
73
- The [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L13) decorator supports configurations on:
73
+ The [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L12) decorator supports configurations on:
74
74
  * `name` the field name of the current class which points to the desired cache source.
75
75
  * `config` the additional/optional config options, on a per invocation basis
76
76
 
@@ -83,7 +83,7 @@ The [@Cache](https://github.com/travetto/travetto/tree/main/module/cache/src/dec
83
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.
84
84
 
85
85
  ### EvictCache
86
- Additionally, there is support for planned eviction via the [@EvictCache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L39) 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.
86
+ Additionally, there is support for planned eviction via the [@EvictCache](https://github.com/travetto/travetto/tree/main/module/cache/src/decorator.ts#L38) 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
87
 
88
88
  **Code: Using decorators to cache/evict user access**
89
89
  ```typescript
@@ -119,7 +119,7 @@ export class UserService {
119
119
  ```
120
120
 
121
121
  ## Extending the Cache Service
122
- 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/service/expiry.ts#L11). 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#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:
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:
123
123
 
124
124
  **Code: Registering a Custom Model Source**
125
125
  ```typescript
package/__index__.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './src/types';
2
- export * from './src/decorator';
3
- export * from './src/service';
4
- export * from './src/util';
1
+ export * from './src/types.ts';
2
+ export * from './src/decorator.ts';
3
+ export * from './src/service.ts';
4
+ export * from './src/util.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cache",
3
- "version": "6.0.0-rc.0",
3
+ "version": "6.0.0-rc.2",
4
4
  "description": "Caching functionality with decorators for declarative use.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -25,12 +25,12 @@
25
25
  "directory": "module/cache"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/di": "^6.0.0-rc.0",
29
- "@travetto/model": "^6.0.0-rc.0"
28
+ "@travetto/di": "^6.0.0-rc.2",
29
+ "@travetto/model": "^6.0.0-rc.2"
30
30
  },
31
31
  "peerDependencies": {
32
- "@travetto/test": "^6.0.0-rc.0",
33
- "@travetto/transformer": "^6.0.0-rc.0"
32
+ "@travetto/test": "^6.0.0-rc.2",
33
+ "@travetto/transformer": "^6.0.0-rc.3"
34
34
  },
35
35
  "peerDependenciesMeta": {
36
36
  "@travetto/transformer": {
package/src/decorator.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { castTo, MethodDescriptor, TimeSpan, TimeUtil } from '@travetto/runtime';
2
2
 
3
- import { CacheService } from './service';
4
- import { CoreCacheConfig, CacheConfig } from './types';
5
- import { CacheAware, CacheConfigSymbol, EvictConfigSymbol } from './internal/types';
3
+ import { CacheService } from './service.ts';
4
+ import { CoreCacheConfig, CacheConfig, CacheAware, CacheConfigSymbol, EvictConfigSymbol } from './types.ts';
6
5
 
7
6
  /**
8
7
  * Indicates a method is intended to cache. The return type must be properly serializable
@@ -22,7 +21,7 @@ export function Cache<F extends string, U extends Record<F, CacheService>>(
22
21
  config = cfg;
23
22
  }
24
23
  }
25
- const dec = function <R extends Promise<unknown>>(target: U & CacheAware, propertyKey: string, descriptor: MethodDescriptor<R>): void {
24
+ const dec = function <R extends Promise<unknown>>(target: U & CacheAware, propertyKey: string, _descriptor: MethodDescriptor<R>): void {
26
25
  config.keySpace ??= `${target.constructor.name}.${propertyKey}`;
27
26
  (target[CacheConfigSymbol] ??= {})[propertyKey] = config;
28
27
  };
@@ -37,7 +36,7 @@ export function Cache<F extends string, U extends Record<F, CacheService>>(
37
36
  * @augments `@travetto/cache:Evict`
38
37
  */
39
38
  export function EvictCache<F extends string, U extends Record<F, CacheService>>(field: F, config: CoreCacheConfig = {}) {
40
- return function <R extends Promise<unknown>>(target: U & CacheAware, propertyKey: string, descriptor: MethodDescriptor<R>): void {
39
+ return function <R extends Promise<unknown>>(target: U & CacheAware, propertyKey: string, _descriptor: MethodDescriptor<R>): void {
41
40
  config.keySpace ??= `${target.constructor.name}.${propertyKey}`;
42
41
  (target[EvictConfigSymbol] ??= {})[propertyKey] = config;
43
42
  };
package/src/service.ts CHANGED
@@ -1,14 +1,11 @@
1
- import { ExpiresAt, Index, Model, ModelExpirySupport, NotFoundError } from '@travetto/model';
1
+ import { ExpiresAt, Index, Model, ModelExpirySupport, NotFoundError, ModelStorageUtil, ModelIndexedUtil } from '@travetto/model';
2
2
  import { Text } from '@travetto/schema';
3
3
  import { Inject, Injectable } from '@travetto/di';
4
4
  import { AppError, Runtime, TimeUtil, Util } from '@travetto/runtime';
5
- import { isIndexedSupported, isStorageSupported } from '@travetto/model/src/internal/service/common';
6
5
 
7
- import { CacheError } from './error';
8
- import { CacheUtil } from './util';
9
- import { CacheAware, CacheConfigSymbol, EvictConfigSymbol } from './internal/types';
10
-
11
- export const CacheModelSymbol = Symbol.for('@travetto/cache:model');
6
+ import { CacheError } from './error.ts';
7
+ import { CacheUtil } from './util.ts';
8
+ import { CacheAware, CacheConfigSymbol, CacheModelSymbol, EvictConfigSymbol } from './types.ts';
12
9
 
13
10
  const INFINITE_MAX_AGE = TimeUtil.asMillis(10, 'y');
14
11
 
@@ -41,7 +38,7 @@ export class CacheService {
41
38
  }
42
39
 
43
40
  async postConstruct(): Promise<void> {
44
- if (isStorageSupported(this.#modelService) && (Runtime.dynamic || this.#modelService.config?.autoCreate)) {
41
+ if (ModelStorageUtil.isSupported(this.#modelService) && (Runtime.dynamic || this.#modelService.config?.autoCreate)) {
45
42
  await this.#modelService.createModel?.(CacheRecord);
46
43
  }
47
44
  }
@@ -52,7 +49,7 @@ export class CacheService {
52
49
  * @param extendOnAccess should the expiry be extended on access
53
50
  */
54
51
  async get(id: string, extendOnAccess = true): Promise<unknown> {
55
- const { expiresAt, issuedAt } = await this.#modelService.get(CacheRecord, id);
52
+ const { expiresAt, issuedAt, entry } = await this.#modelService.get(CacheRecord, id);
56
53
 
57
54
  const delta = expiresAt.getTime() - Date.now();
58
55
  const maxAge = expiresAt.getTime() - issuedAt.getTime();
@@ -66,16 +63,16 @@ export class CacheService {
66
63
  if (extendOnAccess) {
67
64
  const threshold = maxAge / 2;
68
65
  if (delta < threshold) {
69
- await this.#modelService.updatePartial(CacheRecord, {
66
+ // Do not wait
67
+ this.#modelService.updatePartial(CacheRecord, {
70
68
  id,
71
69
  expiresAt: TimeUtil.fromNow(maxAge),
72
70
  issuedAt: new Date()
73
- }); // Do not wait
71
+ });
74
72
  }
75
73
  }
76
74
 
77
- const res = await this.#modelService.get(CacheRecord, id);
78
- return Util.decodeSafeJSON(res.entry);
75
+ return Util.decodeSafeJSON(entry);
79
76
  }
80
77
 
81
78
  /**
@@ -112,7 +109,7 @@ export class CacheService {
112
109
  * @param id
113
110
  */
114
111
  async deleteAll(keySpace: string): Promise<void> {
115
- if (isIndexedSupported(this.#modelService)) {
112
+ if (ModelIndexedUtil.isSupported(this.#modelService)) {
116
113
  const removes: Promise<void>[] = [];
117
114
  for await (const item of this.#modelService.listByIndex(CacheRecord, 'keySpace', { keySpace })) {
118
115
  removes.push(this.#modelService.delete(CacheRecord, item.id));
@@ -127,7 +124,7 @@ export class CacheService {
127
124
  * Purge the cache store of all data, if supported
128
125
  */
129
126
  async purge(): Promise<void> {
130
- if (isStorageSupported(this.#modelService) && this.#modelService.truncateModel) {
127
+ if (ModelStorageUtil.isSupported(this.#modelService) && this.#modelService.truncateModel) {
131
128
  await this.#modelService.truncateModel(CacheRecord);
132
129
  } else {
133
130
  console.warn(`${this.#modelService.constructor.name} does not support truncating the data set`);
package/src/types.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import { TypedFunction } from '@travetto/runtime';
2
2
 
3
+ export const CacheConfigSymbol: unique symbol = Symbol.for('@travetto/cache:cache');
4
+ export const EvictConfigSymbol: unique symbol = Symbol.for('@travetto/cache:evict');
5
+ export const CacheModelSymbol: unique symbol = Symbol.for('@travetto/cache:model');
6
+
3
7
  /**
4
8
  * A minimal config for a cache operation
5
9
  */
@@ -35,4 +39,13 @@ export interface CacheConfig extends CoreCacheConfig {
35
39
  * Whether or not to extends the TTL on access
36
40
  */
37
41
  extendOnAccess?: boolean;
38
- }
42
+ }
43
+
44
+ /**
45
+ * Describes a class as being cache aware or not
46
+ */
47
+ export interface CacheAware {
48
+ [CacheConfigSymbol]?: Record<string, CacheConfig>;
49
+ [EvictConfigSymbol]?: Record<string, CoreCacheConfig>;
50
+ }
51
+
package/src/util.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { BinaryUtil, Util } from '@travetto/runtime';
2
2
 
3
- import { CoreCacheConfig } from './types';
3
+ import { CoreCacheConfig } from './types.ts';
4
4
 
5
5
  /**
6
6
  * Standard cache utilities
@@ -2,16 +2,17 @@ import assert from 'node:assert';
2
2
  import timers from 'node:timers/promises';
3
3
 
4
4
  import { Suite, Test } from '@travetto/test';
5
- import { ModelExpirySupport } from '@travetto/model';
5
+ import { ModelExpirySupport, ModelIndexedUtil } from '@travetto/model';
6
6
  import { Inject, Injectable } from '@travetto/di';
7
- import { InjectableSuite } from '@travetto/di/support/test/suite';
8
- import { ModelSuite } from '@travetto/model/support/test/suite';
9
- import { isIndexedSupported } from '@travetto/model/src/internal/service/common';
10
7
  import { castTo, Class } from '@travetto/runtime';
11
8
  import { Schema } from '@travetto/schema';
12
9
 
13
- import { Cache, EvictCache } from '../../src/decorator';
14
- import { CacheModelSymbol, CacheService } from '../../src/service';
10
+ import { InjectableSuite } from '@travetto/di/support/test/suite.ts';
11
+ import { ModelSuite } from '@travetto/model/support/test/suite.ts';
12
+
13
+ import { Cache, EvictCache } from '../../src/decorator.ts';
14
+ import { CacheService } from '../../src/service.ts';
15
+ import { CacheModelSymbol } from '../../src/types.ts';
15
16
 
16
17
  @Schema()
17
18
  class User { }
@@ -216,7 +217,7 @@ export abstract class CacheServiceSuite {
216
217
 
217
218
  @Test()
218
219
  async allEviction() {
219
- if (!isIndexedSupported(this.serviceClass.prototype)) {
220
+ if (!ModelIndexedUtil.isSupported(this.serviceClass.prototype)) {
220
221
  return;
221
222
  }
222
223
 
@@ -1,9 +0,0 @@
1
- import { CacheConfig, CoreCacheConfig } from '../types';
2
-
3
- export const CacheConfigSymbol = Symbol.for('@travetto/cache:cache');
4
- export const EvictConfigSymbol = Symbol.for('@travetto/cache:evict');
5
-
6
- export interface CacheAware {
7
- [CacheConfigSymbol]?: Record<string, CacheConfig>;
8
- [EvictConfigSymbol]?: Record<string, CoreCacheConfig>;
9
- }