@@ -2,25 +2,61 @@ package com.github.rssh.appcontext
22
33import scala .quoted .*
44
5+ /**
6+ * Annotation to mark class as a key for component cache.
7+ * Useful for cases when we have multiple implementation of some generic component.
8+ * i.e.
9+ * <code>
10+ * @appContextCacheClass[UserRepository]
11+ * class UserRepositoryTestImpl(using AppContextProviders[...]) extends UserRepository {
12+ * ...
13+ * }
14+ * </code>
15+ * @tparam T
16+ */
517class appContextCacheClass [T ] extends scala.annotation.StaticAnnotation
618
719
8-
20+ /**
21+ * Application context is a way, to resolve components dependencies.
22+ * Each component should provide an AppContextProvider, and
23+ * AppContext[Component] will instantiate this components with dependencies.
24+ */
925object AppContext {
1026
11-
27+ /**
28+ * Get component from application context.
29+ * For this component should have an implicit AppContextProvider.
30+ * @see AppContextProvider
31+ * @tparam T - component to instantiate
32+ * @return
33+ */
1234 def apply [T ](using AppContextProvider [T ]): T =
1335 summon[AppContextProvider [T ]].get
1436
37+ /**
38+ * Type for component cache.
39+ * By convention, if component depends from cache then it's AppContextProvider should check
40+ * if this component is already in cache and instantiate new (and update cache) only if it's not found.
41+ */
1542 opaque type Cache = AppContextCacheMap [String , Any ]
1643
44+ /**
45+ * Type for cache key.
46+ * By convention, usually this is a type.show.
47+ */
1748 opaque type CacheKey [T ] = String
1849
50+ /**
51+ * Create empty cache.
52+ * @return empty cache
53+ */
1954 def newCache : Cache = AppContextCacheMap .empty
2055
56+
2157 inline def cacheKey [T ] = $ { cacheKeyImpl[T ] }
2258
23- def cacheKeyImpl [T : Type ](using Quotes ): Expr [CacheKey [T ]] = {
59+ private def cacheKeyImpl [T : Type ](using Quotes ): Expr [CacheKey [T ]] = {
2460 import quotes .reflect .*
2561 val annotationClass = TypeRepr .of[appContextCacheClass[? ]]
2662 // val keyNameExpr = TypeRepr.of[T].classSymbol.get.annotations.find(_.tpe <:< annotationClass) match
@@ -45,16 +81,44 @@ object AppContext {
4581 def customCacheKey [T ](key : String ): CacheKey [T ] = key
4682
4783 extension (c : Cache )
48-
84+
85+ /**
86+ * Get component from cache.
87+ * @tparam T - component type
88+ * @return Some(component) or None if component is not found.
89+ */
4990 inline def get [T ]: Option [T ] =
5091 c.get(cacheKey[T ]).asInstanceOf [Option [T ]]
51-
92+
93+ /**
94+ * Get component from cache or create new one and update cache.
95+ * @param value - function to create new component
96+ * @tparam T - component type
97+ * @return just created or cached component
98+ */
5299 inline def getOrCreate [T ](value : => T ): T =
53100 c.getOrElseUpdate(cacheKey[T ], value).asInstanceOf [T ]
54-
101+
102+ /**
103+ * Put component to cache, replacing old if needed
104+ * @param value
105+ * @tparam T
106+ */
55107 inline def put [T ](value : T ): Unit =
56108 c.put(cacheKey[T ], value)
109+
110+ /**
111+ * Modify component in cache.
112+ * @param f - function to remap
113+ * @tparam T - component type
114+ */
115+ inline def modify [T ](f : Option [T ] => Option [T ]): Unit =
116+ c.updateWith(cacheKey[T ])(v => f(v.asInstanceOf [Option [T ]]))
57117
118+ /**
119+ * Remove component from cache.
120+ * @tparam T - component type
121+ */
58122 inline def remove [T ]: Unit =
59123 c.remove(cacheKey[T ])
60124
0 commit comments