chore(): Reorganize modules (#7210)

**What**
Move all modules to the modules directory
This commit is contained in:
Adrien de Peretti
2024-05-02 17:33:34 +02:00
committed by GitHub
parent 7a351eef09
commit 4eae25e1ef
870 changed files with 91 additions and 62 deletions

View File

@@ -0,0 +1,15 @@
import { ModuleExports } from "@medusajs/modules-sdk"
import Loader from "./loaders"
import { RedisCacheService } from "./services"
const service = RedisCacheService
const loaders = [Loader]
const moduleDefinition: ModuleExports = {
service,
loaders,
}
export default moduleDefinition
export * from "./initialize"
export * from "./types"

View File

@@ -0,0 +1,23 @@
import {
ExternalModuleDeclaration,
InternalModuleDeclaration,
MedusaModule,
Modules,
} from "@medusajs/modules-sdk"
import { ICacheService } from "@medusajs/types"
import { RedisCacheModuleOptions } from "../types"
export const initialize = async (
options?: RedisCacheModuleOptions | ExternalModuleDeclaration
): Promise<ICacheService> => {
const serviceKey = Modules.CACHE
const loaded = await MedusaModule.bootstrap<ICacheService>({
moduleKey: serviceKey,
defaultPath: "@medusajs/cache-redis",
declaration: options as
| InternalModuleDeclaration
| ExternalModuleDeclaration,
})
return loaded[serviceKey]
}

View File

@@ -0,0 +1,37 @@
import { LoaderOptions } from "@medusajs/modules-sdk"
import { asValue } from "awilix"
import Redis from "ioredis"
import { RedisCacheModuleOptions } from "../types"
export default async ({
container,
logger,
options,
}: LoaderOptions): Promise<void> => {
const { redisUrl, redisOptions } = options as RedisCacheModuleOptions
if (!redisUrl) {
throw Error(
"No `redisUrl` provided in `cacheService` module options. It is required for the Redis Cache Module."
)
}
const connection = new Redis(redisUrl, {
// Lazy connect to properly handle connection errors
lazyConnect: true,
...(redisOptions ?? {}),
})
try {
await connection.connect()
logger?.info(`Connection to Redis in module 'cache-redis' established`)
} catch (err) {
logger?.error(
`An error occurred while connecting to Redis in module 'cache-redis': ${err}`
)
}
container.register({
cacheRedisConnection: asValue(connection),
})
}

View File

@@ -0,0 +1,29 @@
import { RedisCacheService } from "../index"
const redisClientMock = {
set: jest.fn(),
get: jest.fn(),
}
describe("RedisCacheService", () => {
let cacheService
beforeEach(() => {
jest.clearAllMocks()
})
it("Underlying client methods are called", async () => {
cacheService = new RedisCacheService(
{
cacheRedisConnection: redisClientMock,
},
{}
)
await cacheService.set("test-key", "value")
expect(redisClientMock.set).toBeCalled()
await cacheService.get("test-key")
expect(redisClientMock.get).toBeCalled()
})
})

View File

@@ -0,0 +1 @@
export { default as RedisCacheService } from "./redis-cache"

View File

@@ -0,0 +1,98 @@
import { ICacheService } from "@medusajs/types"
import { Redis } from "ioredis"
import { RedisCacheModuleOptions } from "../types"
const DEFAULT_NAMESPACE = "medusa"
const DEFAULT_CACHE_TIME = 30 // 30 seconds
const EXPIRY_MODE = "EX" // "EX" stands for an expiry time in second
type InjectedDependencies = {
cacheRedisConnection: Redis
}
class RedisCacheService implements ICacheService {
protected readonly TTL: number
protected readonly redis: Redis
private readonly namespace: string
constructor(
{ cacheRedisConnection }: InjectedDependencies,
options: RedisCacheModuleOptions = {}
) {
this.redis = cacheRedisConnection
this.TTL = options.ttl ?? DEFAULT_CACHE_TIME
this.namespace = options.namespace || DEFAULT_NAMESPACE
}
__hooks = {
onApplicationShutdown: async () => {
this.redis.disconnect()
},
}
/**
* Set a key/value pair to the cache.
* If the ttl is 0 it will act like the value should not be cached at all.
* @param key
* @param data
* @param ttl
*/
async set(
key: string,
data: Record<string, unknown>,
ttl: number = this.TTL
): Promise<void> {
if (ttl === 0) {
return
}
await this.redis.set(
this.getCacheKey(key),
JSON.stringify(data),
EXPIRY_MODE,
ttl
)
}
/**
* Retrieve a cached value belonging to the given key.
* @param cacheKey
*/
async get<T>(cacheKey: string): Promise<T | null> {
cacheKey = this.getCacheKey(cacheKey)
try {
const cached = await this.redis.get(cacheKey)
if (cached) {
return JSON.parse(cached)
}
} catch (err) {
await this.redis.del(cacheKey)
}
return null
}
/**
* Invalidate cache for a specific key. a key can be either a specific key or more global such as "ps:*".
* @param key
*/
async invalidate(key: string): Promise<void> {
const keys = await this.redis.keys(this.getCacheKey(key))
const pipeline = this.redis.pipeline()
keys.forEach(function (key) {
pipeline.del(key)
})
await pipeline.exec()
}
/**
* Returns namespaced cache key
* @param key
*/
private getCacheKey(key: string) {
return this.namespace ? `${this.namespace}:${key}` : key
}
}
export default RedisCacheService

View File

@@ -0,0 +1,27 @@
import { RedisOptions } from "ioredis"
/**
* Module config type
*/
export type RedisCacheModuleOptions = {
/**
* Time to keep data in cache (in seconds)
*/
ttl?: number
/**
* Redis connection string
*/
redisUrl?: string
/**
* Redis client options
*/
redisOptions?: RedisOptions
/**
* Prefix for event keys
* @default `medusa:`
*/
namespace?: string
}