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,12 @@
import { ModuleExports } from "@medusajs/modules-sdk"
import InMemoryCacheService from "./services/inmemory-cache"
const service = InMemoryCacheService
const moduleDefinition: ModuleExports = {
service,
}
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 { InMemoryCacheModuleOptions } from "../types"
export const initialize = async (
options?: InMemoryCacheModuleOptions | ExternalModuleDeclaration
): Promise<ICacheService> => {
const serviceKey = Modules.CACHE
const loaded = await MedusaModule.bootstrap<ICacheService>({
moduleKey: serviceKey,
defaultPath: "@medusajs/cache-inmemory",
declaration: options as
| InternalModuleDeclaration
| ExternalModuleDeclaration,
})
return loaded[serviceKey]
}

View File

@@ -0,0 +1,96 @@
import { InMemoryCacheService } from "../index"
jest.setTimeout(40000)
describe("InMemoryCacheService", () => {
let inMemoryCache
beforeEach(() => {
jest.clearAllMocks()
})
it("Stores and retrieves data", async () => {
inMemoryCache = new InMemoryCacheService({}, {})
await inMemoryCache.set("cache-key", { data: "value" })
expect(await inMemoryCache.get("cache-key")).toEqual({ data: "value" })
})
it("Invalidates single record", async () => {
inMemoryCache = new InMemoryCacheService({}, {})
await inMemoryCache.set("cache-key", { data: "value" })
await inMemoryCache.invalidate("cache-key")
expect(await inMemoryCache.get("cache-key")).toEqual(null)
})
it("Invalidates multiple keys with wildcard (end matching)", async () => {
inMemoryCache = new InMemoryCacheService({}, {})
await inMemoryCache.set("cache-key:id_1:x:y", { data: "value" })
await inMemoryCache.set("cache-key:id_2:x:y", { data: "value" })
await inMemoryCache.set("cache-key:id_3:x:y", { data: "value" })
await inMemoryCache.set("cache-key-old", { data: "value" })
await inMemoryCache.invalidate("cache-key:*")
expect(await inMemoryCache.get("cache-key:id1:x:y")).toEqual(null)
expect(await inMemoryCache.get("cache-key:id2:x:y")).toEqual(null)
expect(await inMemoryCache.get("cache-key:id3:x:y")).toEqual(null)
expect(await inMemoryCache.get("cache-key-old")).toEqual({ data: "value" })
})
it("Invalidates multiple keys with wildcard (middle matching)", async () => {
inMemoryCache = new InMemoryCacheService({}, {})
await inMemoryCache.set("cache-key:1:new", { data: "value" })
await inMemoryCache.set("cache-key:2:new", { data: "value" })
await inMemoryCache.set("cache-key:3:new", { data: "value" })
await inMemoryCache.set("cache-key:4:old", { data: "value" })
await inMemoryCache.invalidate("cache-key:*:new")
expect(await inMemoryCache.get("cache-key:1:new")).toEqual(null)
expect(await inMemoryCache.get("cache-key:2:new")).toEqual(null)
expect(await inMemoryCache.get("cache-key:3:new")).toEqual(null)
expect(await inMemoryCache.get("cache-key:4:old")).toEqual({
data: "value",
})
})
it("Removes data after TTL", async () => {
inMemoryCache = new InMemoryCacheService({}, {})
await inMemoryCache.set("cache-key", { data: "value" }, 2)
expect(await inMemoryCache.get("cache-key")).toEqual({ data: "value" })
await new Promise((res) => setTimeout(res, 3000))
expect(await inMemoryCache.get("cache-key")).toEqual(null)
})
it("Removes data after default TTL if TTL params isn't passed", async () => {
inMemoryCache = new InMemoryCacheService({})
await inMemoryCache.set("cache-key", { data: "value" })
expect(await inMemoryCache.get("cache-key")).toEqual({ data: "value" })
await new Promise((res) => setTimeout(res, 33000))
expect(await inMemoryCache.get("cache-key")).toEqual(null)
})
it("Removes data after TTL from the config if TTL params isn't passed", async () => {
inMemoryCache = new InMemoryCacheService({}, { ttl: 1 })
await inMemoryCache.set("cache-key", { data: "value" })
expect(await inMemoryCache.get("cache-key")).toEqual({ data: "value" })
await new Promise((res) => setTimeout(res, 2000))
expect(await inMemoryCache.get("cache-key")).toEqual(null)
})
})

View File

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

View File

@@ -0,0 +1,106 @@
import { ICacheService } from "@medusajs/types"
import { CacheRecord, InMemoryCacheModuleOptions } from "../types"
const DEFAULT_TTL = 30 // seconds
type InjectedDependencies = {}
/**
* Class represents basic, in-memory, cache store.
*/
class InMemoryCacheService implements ICacheService {
protected readonly TTL: number
protected readonly store = new Map<string, CacheRecord<any>>()
protected readonly timoutRefs = new Map<string, NodeJS.Timeout>()
constructor(
deps: InjectedDependencies,
options: InMemoryCacheModuleOptions = {}
) {
this.TTL = options.ttl ?? DEFAULT_TTL
}
/**
* Retrieve data from the cache.
* @param key - cache key
*/
async get<T>(key: string): Promise<T | null> {
const now = Date.now()
const record: CacheRecord<T> | undefined = this.store.get(key)
const recordExpire = record?.expire ?? Infinity
if (!record || recordExpire < now) {
return null
}
return record.data
}
/**
* Set data to the cache.
* @param key - cache key under which the data is stored
* @param data - data to be stored in the cache
* @param ttl - expiration time in seconds
*/
async set<T>(key: string, data: T, ttl: number = this.TTL): Promise<void> {
if (ttl === 0) {
return
}
const record: CacheRecord<T> = { data, expire: ttl * 1000 + Date.now() }
const oldRecord = this.store.get(key)
if (oldRecord) {
clearTimeout(this.timoutRefs.get(key))
this.timoutRefs.delete(key)
}
const ref = setTimeout(async () => {
await this.invalidate(key)
}, ttl * 1000)
ref.unref()
this.timoutRefs.set(key, ref)
this.store.set(key, record)
}
/**
* Delete data from the cache.
* Could use wildcard (*) matcher e.g. `invalidate("ps:*")` to delete all keys that start with "ps:"
*
* @param key - cache key
*/
async invalidate(key: string): Promise<void> {
let keys = [key]
if (key.includes("*")) {
const regExp = new RegExp(key.replace("*", ".*"))
keys = Array.from(this.store.keys()).filter((k) => k.match(regExp))
}
keys.forEach((key) => {
const timeoutRef = this.timoutRefs.get(key)
if (timeoutRef) {
clearTimeout(timeoutRef)
this.timoutRefs.delete(key)
}
this.store.delete(key)
})
}
/**
* Delete the entire cache.
*/
async clear() {
this.timoutRefs.forEach((ref) => clearTimeout(ref))
this.timoutRefs.clear()
this.store.clear()
}
}
export default InMemoryCacheService

View File

@@ -0,0 +1,17 @@
/**
* Shape of a record saved in `in-memory` cache
*/
export type CacheRecord<T> = {
data: T
/**
* Timestamp in milliseconds
*/
expire: number
}
export type InMemoryCacheModuleOptions = {
/**
* Time to keep data in cache (in seconds)
*/
ttl?: number
}