import { inject } from '@loopback/context' ; import { DefaultKeyValueRepository } from '@loopback/repository' ; import { promisify } from 'util' ; import { RedisDataSource } from '../datasources/redis.datasource' ; import { ShoppingCart , ShoppingCartItem } from '../models' ; import { retry , Task } from '../utils/retry' ; export class ShoppingCartRepository extends DefaultKeyValueRepository < ShoppingCart > { constructor ( @ inject ( 'datasources.redis' ) dataSource ) { super ( ShoppingCart , dataSource ) ; } param userId param item returns addItem ( userId , item ) { const task = { run : async ( ) => { const addItemToCart = ( cart ) => { cart = cart ?? new ShoppingCart ( { userId } ) ; cart . items = cart . items ?? [ ] ; cart . items . push ( item ) ; return cart ; } ; const result = await this . checkAndSet ( userId , addItemToCart ) ; return { done : result != null , value : result , } ; } , description : `update the shopping cart for '${ userId }'` , } ; return retry ( task , { maxTries : 10 , interval : 10 } ) ; } param userId param check returns async checkAndSet ( userId , check ) { const connector = this . kvModelClass . dataSource ! . connector ! ; const execute = promisify ( ( cmd , args , cb ) => { connector . execute ! ( cmd , args , cb ) ; } ) ; /**
         * - WATCH userId
         * - GET userId
         * - check(cart)
         * - MULTI
         * - SET userId
         * - EXEC
         */ await execute ( 'WATCH' , [ userId ] ) ; let cart = await this . get ( userId ) ; cart = check ( cart ) ; if ( ! cart ) return null ; await execute ( 'MULTI' , [ ] ) ; await this . set ( userId , cart ) ; const result = await execute ( 'EXEC' , [ ] ) ; return result == null ? null : cart ; } }