@@ -51,6 +51,49 @@ export class TestWithMixinRepository extends CacheMixin(
5151}
5252```
5353
54+ ### Using with Sequelize Repositories
55+
56+ For repositories based on ` SequelizeCrudRepository ` from ` @loopback/sequelize ` , use the ` SequelizeCacheMixin ` :
57+
58+ ``` ts
59+ import {SequelizeCacheMixin } from ' @sourceloop/cache/sequelize' ;
60+ import {SequelizeCrudRepository , SequelizeDataSource } from ' @loopback/sequelize' ;
61+
62+ export class UserRepository extends SequelizeCacheMixin (
63+ SequelizeCrudRepository < User , number , {}> ,
64+ {
65+ ttl: 1800 , // Time to live in seconds (optional)
66+ invalidationTags: [' users' ], // Tags for cache invalidation on writes
67+ cachedItemTags: [' user-item' ], // Tags for individual cache entries
68+ disableCachedFetch: false , // Disable caching if needed (optional)
69+ },
70+ ) {
71+ cacheIdentifier = ' userRepo' ; // Required: unique cache namespace
72+
73+ constructor (
74+ @inject (' datasources.postgres' ) dataSource : SequelizeDataSource ,
75+ ) {
76+ super (User , dataSource );
77+ }
78+ }
79+ ```
80+
81+ ** Note:** Import from ` @sourceloop/cache/sequelize ` for Sequelize-specific caching.
82+
83+ ** Difference from CacheMixin:**
84+ - ` CacheMixin ` works with ` DefaultCrudRepository ` (Juggler-based)
85+ - ` SequelizeCacheMixin ` works with ` SequelizeCrudRepository ` (Sequelize-based)
86+ - Use the appropriate mixin based on your repository type
87+
88+ ** Configuration Options:**
89+
90+ | Option | Type | Default | Description |
91+ | --------| ------| ---------| -------------|
92+ | ` ttl ` | ` number ` | ` 86400 ` (1 day) | Cache expiration time in seconds |
93+ | ` invalidationTags ` | ` string[] ` | ` [] ` | Tags to invalidate on create/update/delete |
94+ | ` cachedItemTags ` | ` string[] ` | ` [] ` | Tags to apply to cached items |
95+ | ` disableCachedFetch ` | ` boolean ` | ` false ` | Bypass cache for all reads |
96+
5497### In a controller or service
5598
5699To add caching to a service or controller, just implement the ` ICachedService ` interface, adding a binding for the ` ICacheService ` and the applying the relevant decorators to the methods you want cached -
@@ -98,3 +141,189 @@ export class TestController implements ICachedService {
98141 }
99142 // / ...
100143` ` `
144+
145+ ## Advanced Usage
146+
147+ ### Cache Strategies
148+
149+ The component supports two cache strategies:
150+
151+ #### 1. InMemoryStoreStrategy (Default)
152+
153+ Uses an in-memory Map. Suitable for development and single-instance deployments.
154+
155+ ` ` ` ts
156+ import {InMemoryStoreStrategy } from ' @sourceloop/cache' ;
157+
158+ this .bind (CacheComponentBindings .CacheConfig ).to ({
159+ ttl: 3600 ,
160+ strategy: InMemoryStoreStrategy ,
161+ });
162+ ` ` `
163+
164+ #### 2. RedisStoreStrategy
165+
166+ Uses Redis for distributed caching. Recommended for production.
167+
168+ ` ` ` ts
169+ import {RedisStoreStrategy } from ' @sourceloop/cache' ;
170+ import {juggler } from ' @loopback/repository' ;
171+
172+ const redisDs = new juggler .DataSource ({
173+ name: ' redisCacheStore' ,
174+ connector: ' kv-redis' ,
175+ host: process .env .REDIS_HOST ,
176+ port: Number (process .env .REDIS_PORT ),
177+ password: process .env .REDIS_PASSWORD ,
178+ });
179+
180+ this .dataSource (redisDs );
181+
182+ this .bind (CacheComponentBindings .CacheConfig ).to ({
183+ ttl: 3600 ,
184+ strategy: RedisStoreStrategy ,
185+ datasourceName: ' redisCacheStore' ,
186+ });
187+ ` ` `
188+
189+ ### Cache Invalidation
190+
191+ Cache can be invalidated in two ways:
192+
193+ #### 1. Automatic Invalidation (Mixins)
194+
195+ Write operations ( ` create ` , ` update ` , ` delete ` ) automatically invalidate cache entries tagged with ` invalidationTags ` .
196+
197+ #### 2. Manual Invalidation (Decorators)
198+
199+ Use ` @cacheInvalidator ()` decorator on methods that modify data:
200+
201+ ` ` ` ts
202+ @cacheInvalidator ([' users' , ' notifications' ])
203+ async updateUserStatus(userId : number , status : string ) {
204+ // This will invalidate all cache entries tagged with 'users' or 'notifications'
205+ return this .userRepository .updateById (userId , {status });
206+ }
207+ ` ` `
208+
209+ ### Cache Customization
210+
211+ #### Per-Method Options
212+
213+ Override cache behavior for specific method calls:
214+
215+ ` ` ` ts
216+ // Force fresh data from database
217+ const users = await this .userRepository .find (undefined , {
218+ forceUpdate: true ,
219+ });
220+
221+ // Add custom tags
222+ const user = await this .userRepository .findById (1 , undefined , {
223+ tags: [' admin-user' , ' high-priority' ],
224+ });
225+ ` ` `
226+
227+ #### Tenant-Aware Caching
228+
229+ Cache keys automatically include tenant ID when ` AUTH_USER_KEY ` is bound:
230+
231+ ` ` ` ts
232+ import {AUTH_USER_KEY } from ' @sourceloop/cache' ;
233+
234+ this .bind (AUTH_USER_KEY ).to ({
235+ tenantId: ' tenant-123' ,
236+ username: ' admin' ,
237+ });
238+ ` ` `
239+
240+ ## API Reference
241+
242+ ### Decorators
243+
244+ #### ` @cachedItem ()`
245+ Cache the return value of a method.
246+
247+ ` ` ` ts
248+ @cachedItem ()
249+ async getUser(id : number ): Promise <User > {
250+ return this .userRepository .findById (id );
251+ }
252+ ` ` `
253+
254+ #### ` @cacheInvalidator (tags : string [])`
255+ Invalidate cache entries matching the given tags.
256+
257+ ` ` ` ts
258+ @cacheInvalidator ([' users' ])
259+ async updateUser(id : number , data : Partial <User >): Promise <User > {
260+ return this .userRepository .updateById (id , data );
261+ }
262+ ` ` `
263+
264+ ### Interfaces
265+
266+ #### ` ICacheMixinOptions `
267+
268+ Configuration options for cache mixins.
269+
270+ ` ` ` ts
271+ interface ICacheMixinOptions {
272+ ttl ?: number ; // Time to live in seconds
273+ invalidationTags ?: string []; // Tags for write operations
274+ cachedItemTags ?: string []; // Tags for read operations
275+ disableCachedFetch ?: boolean ; // Disable caching
276+ }
277+ ` ` `
278+
279+ #### ` ICachedMethodOptions `
280+
281+ Options for individual method calls.
282+
283+ ` ` ` ts
284+ interface ICachedMethodOptions {
285+ forceUpdate ?: boolean ; // Force fresh data from source
286+ tags ?: string []; // Additional cache tags
287+ }
288+ ` ` `
289+
290+ ## Migration from CacheMixin to SequelizeCacheMixin
291+
292+ If you're migrating from Juggler to Sequelize repositories:
293+
294+ 1. **Update import:**
295+ ` ` ` ts
296+ // Before
297+ import {CacheMixin } from ' @sourceloop/cache' ;
298+
299+ // After
300+ import {SequelizeCacheMixin } from ' @sourceloop/cache/sequelize' ;
301+ ` ` `
302+
303+ 2. **Update repository base:**
304+ ` ` ` ts
305+ // Before
306+ export class UserRepo extends CacheMixin (
307+ DefaultCrudRepository < User , number , {}> ,
308+ options ,
309+ ) { ... }
310+
311+ // After
312+ export class UserRepo extends SequelizeCacheMixin (
313+ SequelizeCrudRepository < User , number , {}> ,
314+ options ,
315+ ) { ... }
316+ ` ` `
317+
318+ 3. **Update constructor:**
319+ ` ` ` ts
320+ // Before
321+ constructor (@inject (' datasources.memorydb' ) dataSource : juggler .DataSource ) { ... }
322+
323+ // After
324+ constructor (@inject (' datasources.postgres' ) dataSource : SequelizeDataSource ) { ... }
325+ ` ` `
326+
327+ ## License
328+
329+ MIT
0 commit comments