diff --git a/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala b/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala index fcf48816..4264cc3b 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala @@ -24,7 +24,6 @@ package org.bitlap.cache import org.bitlap.cache.GenericCache.Aux import org.bitlap.common.{ CaseClassExtractor, CaseClassField } -import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.{ ExecutionContext, Future } /** @author @@ -39,15 +38,8 @@ object Cache { keyBuilder: CacheKeyBuilder[K] ): CacheRef[K, T, Future] = new CacheRef[K, cache.Out, Future] { - private lazy val initFlag = new AtomicBoolean(false) - - override def init(initKvs: => Map[K, cache.Out]): Future[Unit] = - if (initFlag.compareAndSet(false, true)) { - putTAll(initKvs) - } else Future.successful(()) - - override def putTAll(map: => Map[K, cache.Out]): Future[Unit] = - cache.putAll(map) + override def batchPutT(data: => Map[K, cache.Out]): Future[Unit] = + cache.putAll(data) override def getT(key: K): Future[Option[cache.Out]] = cache.get(key) @@ -62,7 +54,15 @@ object Cache { override def clear(): Future[Unit] = cache.clear() + override def remove(key: K): Future[Unit] = cache.remove(key) + override def getAllT: Future[Map[K, cache.Out]] = cache.getAll + + override def safeRefreshT(allNewData: Map[K, T]): Future[Unit] = + this.getAllT.map { t => + val invalidData = t.keySet.filterNot(allNewData.keySet) + this.batchPutT(allNewData).map(_ => invalidData.foreach(this.remove)) + } } def getSyncCache[K, T <: Product](implicit @@ -70,15 +70,8 @@ object Cache { keyBuilder: CacheKeyBuilder[K] ): CacheRef[K, T, Identity] = new CacheRef[K, cache.Out, Identity] { - private lazy val initFlag = new AtomicBoolean(false) - - override def init(initKvs: => Map[K, cache.Out]): Identity[Unit] = - if (initFlag.compareAndSet(false, true)) { - putTAll(initKvs) - } else () - - override def putTAll(map: => Map[K, cache.Out]): Identity[Unit] = - map.foreach(kv => cache.put(kv._1, kv._2)) + override def batchPutT(data: => Map[K, cache.Out]): Identity[Unit] = + data.foreach(kv => cache.put(kv._1, kv._2)) override def getT(key: K): Identity[Option[cache.Out]] = cache.get(key) @@ -92,6 +85,14 @@ object Cache { override def clear(): Identity[Unit] = cache.clear() override def getAllT: Identity[Map[K, cache.Out]] = cache.getAll + + override def remove(key: K): Identity[Unit] = cache.remove(key) + + override def safeRefreshT(allNewData: Map[K, cache.Out]): Identity[Unit] = { + val invalidData = this.getAllT.keySet.filterNot(allNewData.keySet) + this.batchPutT(allNewData) + invalidData.foreach(this.remove) + } } } diff --git a/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala b/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala index f3d24744..522cce1c 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala @@ -30,15 +30,18 @@ import java.util.Collections * @version 1.0,2022/7/5 */ trait CacheAdapter[V] { + def getAllKeys: Set[String] - def putAll(map: Map[String, V]): Unit + def batchPut(data: Map[String, V]): Unit def put(k: String, v: V): Unit def get(k: String): V def clear(): Unit + + def remove(k: String): Unit } object CacheAdapter { @@ -60,13 +63,15 @@ object CacheAdapter { override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet - override def putAll(map: Map[String, V]): Unit = underlyingCache.putAll(map.asJava) + override def batchPut(data: Map[String, V]): Unit = underlyingCache.putAll(data.asJava) override def put(k: String, v: V): Unit = underlyingCache.put(k, v) override def get(k: String): V = underlyingCache.get(k) override def clear(): Unit = underlyingCache.clear() + + override def remove(k: String): Unit = underlyingCache.remove(k) } class ConcurrentMapCacheAdapter[V](underlyingCache: java.util.concurrent.ConcurrentMap[String, V]) @@ -74,13 +79,15 @@ object CacheAdapter { override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet - override def putAll(map: Map[String, V]): Unit = underlyingCache.putAll(map.asJava) + override def batchPut(data: Map[String, V]): Unit = underlyingCache.putAll(data.asJava) override def put(k: String, v: V): Unit = underlyingCache.put(k, v) override def get(k: String): V = underlyingCache.get(k) override def clear(): Unit = underlyingCache.clear() + + override def remove(k: String): Unit = underlyingCache.remove(k) } } diff --git a/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala b/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala index 17b05a68..8be1943d 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala @@ -29,9 +29,7 @@ import org.bitlap.common.CaseClassField */ trait CacheRef[In, T <: Product, F[_]] { - def init(initKvs: => Map[In, T]): F[Unit] - - def putTAll(map: => Map[In, T]): F[Unit] + def batchPutT(data: => Map[In, T]): F[Unit] def getT(key: In): F[Option[T]] @@ -42,4 +40,8 @@ trait CacheRef[In, T <: Product, F[_]] { def getAllT: F[Map[In, T]] def clear(): F[Unit] + + def remove(key: In): F[Unit] + + def safeRefreshT(allNewData: Map[In, T]): F[Unit] } diff --git a/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala b/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala index cac6b805..407a89ad 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala @@ -41,6 +41,8 @@ sealed trait GenericCache[K, F[_]] { def clear(): F[Unit] + def remove(key: K)(implicit keyBuilder: CacheKeyBuilder[K]): F[Unit] + } object GenericCache { @@ -48,7 +50,7 @@ object GenericCache { type Aux[K, Out0, F[_]] = GenericCache[K, F] { type Out = Out0 } def apply[K, Out0 <: Product](cacheStrategy: CacheStrategy): Aux[K, Out0, Identity] = new GenericCache[K, Identity] { - private val adaptedCache: CacheAdapter[Out0] = CacheAdapter.adapted[Out0](cacheStrategy) + private val cacheAdapter: CacheAdapter[Out0] = CacheAdapter.adapted[Out0](cacheStrategy) override type Out = Out0 @@ -57,27 +59,30 @@ object GenericCache { )(implicit keyBuilder: CacheKeyBuilder[K] ): Identity[Option[Out]] = { - val v = adaptedCache.get(keyBuilder.generateKey(key)) + val v = cacheAdapter.get(keyBuilder.generateKey(key)) if (v == null) None else Option(v) } override def put(key: K, value: Out)(implicit keyBuilder: CacheKeyBuilder[K] ): Identity[Unit] = - adaptedCache.put(keyBuilder.generateKey(key), value) + cacheAdapter.put(keyBuilder.generateKey(key), value) override def putAll(map: Map[K, Out0])(implicit keyBuilder: CacheKeyBuilder[K]): Identity[Unit] = - adaptedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) + cacheAdapter.batchPut(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) - override def clear(): Identity[Unit] = adaptedCache.clear() + override def clear(): Identity[Unit] = cacheAdapter.clear() override def getAll(implicit keyBuilder: CacheKeyBuilder[K]): Identity[Map[K, Out0]] = - adaptedCache.getAllKeys - .map(key => keyBuilder.unGenerateKey(key) -> adaptedCache.get(key)) + cacheAdapter.getAllKeys + .map(key => keyBuilder.unGenerateKey(key) -> cacheAdapter.get(key)) .collect { case (k, out) if out != null => k -> out } .toMap + + override def remove(key: K)(implicit keyBuilder: CacheKeyBuilder[K]): Identity[Unit] = + cacheAdapter.remove(keyBuilder.generateKey(key)) } def apply[K, Out0 <: Product]( @@ -86,36 +91,40 @@ object GenericCache { ): Aux[K, Out0, Future] = new GenericCache[K, Future] { implicit val ec = executionContext - private val adaptedCache: CacheAdapter[Out0] = CacheAdapter.adapted[Out0](cacheStrategy) + private val cacheAdapter: CacheAdapter[Out0] = CacheAdapter.adapted[Out0](cacheStrategy) override type Out = Out0 override def get(key: K)(implicit keyBuilder: CacheKeyBuilder[K]): Future[Option[Out]] = Future { - val v = adaptedCache.get(keyBuilder.generateKey(key)) + val v = cacheAdapter.get(keyBuilder.generateKey(key)) if (v == null) None else Option(v) } def put(key: K, value: Out)(implicit keyBuilder: CacheKeyBuilder[K]): Future[Unit] = Future { - adaptedCache.put(keyBuilder.generateKey(key), value) + cacheAdapter.put(keyBuilder.generateKey(key), value) }.map(_ => ()) override def putAll(map: Map[K, Out0])(implicit keyBuilder: CacheKeyBuilder[K]): Future[Unit] = Future { - adaptedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) + cacheAdapter.batchPut(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) } override def getAll(implicit keyBuilder: CacheKeyBuilder[K]): Future[Map[K, Out0]] = Future { - adaptedCache.getAllKeys - .map(key => keyBuilder.unGenerateKey(key) -> adaptedCache.get(key)) + cacheAdapter.getAllKeys + .map(key => keyBuilder.unGenerateKey(key) -> cacheAdapter.get(key)) .collect { case (k, out) if out != null => k -> out } .toMap } - override def clear(): Future[Unit] = Future.successful(adaptedCache.clear()) + override def clear(): Future[Unit] = Future.successful(cacheAdapter.clear()) + + override def remove(key: K)(implicit keyBuilder: CacheKeyBuilder[K]): Future[Unit] = Future { + cacheAdapter.remove(keyBuilder.generateKey(key)) + } } } diff --git a/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala b/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala index 603c841a..6cf2dad6 100644 --- a/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala @@ -42,7 +42,7 @@ class CacheCustomCaseSpec extends AnyFlatSpec with Matchers { "cache1" should "ok while uses lru cache" in { implicit val lruCache = CacheImplicits.testEntitySyncLruCache val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) cache.putT("etc3", TestEntity("eth3", "hello3", "world2")) @@ -54,7 +54,7 @@ class CacheCustomCaseSpec extends AnyFlatSpec with Matchers { val result2: Option[TestEntity] = cache.getT("etc1") result2 shouldBe None - cache.putTAll(data) + cache.batchPutT(data) val result3: Option[TestEntity] = cache.getT("etc1") result3 shouldBe Some(TestEntity("eth1", "hello1", "world2")) @@ -70,16 +70,18 @@ class CacheCustomCaseSpec extends AnyFlatSpec with Matchers { override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet - override def putAll(map: Map[String, TestEntity]): Unit = underlyingCache.putAll(map.asJava) + override def batchPut(data: Map[String, TestEntity]): Unit = underlyingCache.putAll(data.asJava) override def put(k: String, v: TestEntity): Unit = underlyingCache.put(k, v) override def get(k: String): TestEntity = underlyingCache.get(k) override def clear(): Unit = underlyingCache.clear() + + override def remove(k: String): Unit = underlyingCache.remove(k) })) val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) val result: Option[TestEntity] = cache.getT("btc") result shouldBe Some(TestEntity("btc", "hello1", "world1")) diff --git a/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala b/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala index dd47193d..c12b56d1 100644 --- a/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala @@ -45,7 +45,7 @@ class CacheSpec extends AnyFlatSpec with Matchers { "cache1" should "get entity from cache successfully" in { val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) val result: Option[TestEntity] = cache.getT("etc") result shouldBe data.get("etc") @@ -55,7 +55,7 @@ class CacheSpec extends AnyFlatSpec with Matchers { "cache2" should "get entity's field from cache successfully" in { val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) val result = cache.getTField("etc", CaseClassField[TestEntity](_.key)) result shouldBe Some("world2") @@ -65,14 +65,14 @@ class CacheSpec extends AnyFlatSpec with Matchers { "cache3" should "get entity's field after refresh" in { val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) val newData = Map( "btc" -> TestEntity("btc", "hello1", "world1"), "btc-zh-cn" -> TestEntity("btc", "你好啊", "你好哦"), "etc" -> TestEntity("eth", "hello2", "world2") ) cache.clear() - cache.putTAll(newData) + cache.batchPutT(newData) val result: Option[TestEntity] = cache.getT("btc-zh-cn") result shouldBe newData.get("btc-zh-cn") @@ -91,9 +91,9 @@ class CacheSpec extends AnyFlatSpec with Matchers { val cache = Cache.getAsyncCache[String, TestEntity] val ret = for { - _ <- cache.init(newData) + _ <- cache.batchPutT(newData) btcKey <- cache.getTField("btc", CaseClassField[TestEntity](_.key)) - _ <- cache.putTAll(newData2) + _ <- cache.batchPutT(newData2) ethKey <- cache.getTField("eth", CaseClassField[TestEntity](_.key)) } yield btcKey -> ethKey @@ -109,7 +109,7 @@ class CacheSpec extends AnyFlatSpec with Matchers { val cache = Cache.getAsyncCache[String, TestEntity] val ret = for { - _ <- cache.init(newData) + _ <- cache.batchPutT(newData) btcKey <- cache.getTField("btc", CaseClassField[TestEntity](_.key)) _ <- cache.clear() ethKey <- cache.getTField("eth", CaseClassField[TestEntity](_.key)) @@ -121,7 +121,7 @@ class CacheSpec extends AnyFlatSpec with Matchers { "cache6" should "get entity with selectField successfully" in { val cache = Cache.getSyncCache[String, TestEntity] - cache.init(data) + cache.batchPutT(data) val id: Identity[Option[CaseClassField#Field]] = cache.getTField("etc", CaseClassField[TestEntity](_.id)) @@ -133,4 +133,22 @@ class CacheSpec extends AnyFlatSpec with Matchers { println(value) value shouldBe data.get("etc").map(_.value) } + + "cache7" should "refresh successfully" in { + val cache = Cache.getSyncCache[String, TestEntity] + cache.batchPutT(data) + val result: Option[TestEntity] = cache.getT("etc") + result shouldBe data.get("etc") + + val newData = Map( + "btc" -> TestEntity("btc", "id123", "btc_key123"), + "btc-zh-cn" -> TestEntity("btc", "id123", "btc_zh_key123") + ) + + cache.safeRefreshT(newData) + + val result2 = cache.getT("eth") + result2 shouldBe None + } + } diff --git a/smt-cacheable-caffeine/src/main/scala/org/bitlap/cacheable/caffeine/Implicits.scala b/smt-cacheable-caffeine/src/main/scala/org/bitlap/cacheable/caffeine/Implicits.scala index 73a236bd..fdef2917 100644 --- a/smt-cacheable-caffeine/src/main/scala/org/bitlap/cacheable/caffeine/Implicits.scala +++ b/smt-cacheable-caffeine/src/main/scala/org/bitlap/cacheable/caffeine/Implicits.scala @@ -22,6 +22,7 @@ package org.bitlap.cacheable.caffeine import zio.Chunk +import zio.Task import scala.concurrent.Await import org.bitlap.cacheable.core._ @@ -36,8 +37,8 @@ import zio.stream.ZStream */ object Implicits { - implicit def StreamUpdateCache[T]: ZStreamUpdateCache[Any, Throwable, T] = new ZStreamUpdateCache[Any, Throwable, T] { - override def evict(business: => ZStream[Any, Throwable, T])(identities: List[String]): ZStream[Any, Throwable, T] = + implicit def StreamUpdateCache[T]: ZStreamUpdateCache[T] = new ZStreamUpdateCache[T] { + override def evict(business: => UZStream[T])(identities: List[String]): UZStream[T] = for { updateResult <- ZStream .fromIterable(identities) @@ -49,10 +50,10 @@ object Implicits { } yield updateResult } - implicit def StreamReadCache[T]: ZStreamCache[Any, Throwable, T] = new ZStreamCache[Any, Throwable, T] { + implicit def StreamReadCache[T]: ZStreamCache[T] = new ZStreamCache[T] { override def getIfPresent( - business: => ZStream[Any, Throwable, T] - )(identities: List[String], args: List[_]): ZStream[Any, Throwable, T] = { + business: => UZStream[T] + )(identities: List[String], args: List[_]): UZStream[T] = { val key = cacheKey(identities) val field = cacheField(args) val syncResultFuture = zio.Runtime.global.unsafeRunToFuture(business.runCollect) @@ -80,8 +81,8 @@ object Implicits { } } - implicit def UpdateCache[T]: ZIOUpdateCache[Any, Throwable, T] = new ZIOUpdateCache[Any, Throwable, T] { - override def evict(business: => ZIO[Any, Throwable, T])(identities: List[String]): ZIO[Any, Throwable, T] = + implicit def UpdateCache[T]: ZIOUpdateCache[T] = new ZIOUpdateCache[T] { + override def evict(business: => Task[T])(identities: List[String]): Task[T] = for { updateResult <- ZIO.foreach_(identities)(key => ZCaffeine.del(key)) *> business tap (updateResult => Utils @@ -91,10 +92,10 @@ object Implicits { } yield updateResult } - implicit def ReadCache[T]: ZIOCache[Any, Throwable, T] = new ZIOCache[Any, Throwable, T] { + implicit def ReadCache[T]: ZIOCache[T] = new ZIOCache[T] { override def getIfPresent( - business: => ZIO[Any, Throwable, T] - )(identities: List[String], args: List[_]): ZIO[Any, Throwable, T] = { + business: => Task[T] + )(identities: List[String], args: List[_]): Task[T] = { val key = cacheKey(identities) val field = cacheField(args) for { diff --git a/smt-cacheable-caffeine/src/test/scala/org/bitlap/cacheable/caffeine/CustomCacheableTest.scala b/smt-cacheable-caffeine/src/test/scala/org/bitlap/cacheable/caffeine/CustomCacheableTest.scala index 214ee5f8..a07def33 100644 --- a/smt-cacheable-caffeine/src/test/scala/org/bitlap/cacheable/caffeine/CustomCacheableTest.scala +++ b/smt-cacheable-caffeine/src/test/scala/org/bitlap/cacheable/caffeine/CustomCacheableTest.scala @@ -27,6 +27,7 @@ import org.scalatest.matchers.should.Matchers import zio.ZIO import scala.util.Random +import zio.Task /** @author * 梦境迷离 @@ -36,16 +37,16 @@ import scala.util.Random class CustomCacheableTest extends AnyFlatSpec with Matchers { "create a custom cacheable by implicit" should "" in { - implicit def cache: ZIOCache[Any, Throwable, String] = new ZIOCache[Any, Throwable, String] { + implicit def cache: ZIOCache[String] = new ZIOCache[String] { override def getIfPresent( - business: => ZIO[Any, Throwable, String] - )(identities: List[String], args: List[_]): ZIO[Any, Throwable, String] = { + business: => Task[String] + )(identities: List[String], args: List[_]): Task[String] = { println("hello world!!") business } } - def readIOFunction(id: Int, key: String): ZIO[Any, Throwable, String] = { + def readIOFunction(id: Int, key: String): Task[String] = { val $result = ZIO.effect("hello world" + Random.nextInt()) Cache($result)(List("UseCaseExample", "readIOFunction"), List(id, key)) } diff --git a/smt-cacheable-redis/src/main/scala/org/bitlap/cacheable/redis/Implicits.scala b/smt-cacheable-redis/src/main/scala/org/bitlap/cacheable/redis/Implicits.scala index 3d89d0cd..dabc5074 100644 --- a/smt-cacheable-redis/src/main/scala/org/bitlap/cacheable/redis/Implicits.scala +++ b/smt-cacheable-redis/src/main/scala/org/bitlap/cacheable/redis/Implicits.scala @@ -27,6 +27,8 @@ import zio.schema.Schema import zio.stream.ZStream import zio.Chunk import java.util.concurrent.atomic.AtomicLong +import org.bitlap.cacheable.core.UZStream +import zio.Task /** redis cache * @@ -36,11 +38,9 @@ import java.util.concurrent.atomic.AtomicLong */ object Implicits { - implicit def StreamUpdateCache[T: Schema]: ZStreamUpdateCache[Any, Throwable, T] = - new ZStreamUpdateCache[Any, Throwable, T] { - override def evict( - business: => ZStream[Any, Throwable, T] - )(identities: List[String]): ZStream[Any, Throwable, T] = + implicit def StreamUpdateCache[T: Schema]: ZStreamUpdateCache[T] = + new ZStreamUpdateCache[T] { + override def evict(business: => UZStream[T])(identities: List[String]): UZStream[T] = for { updateResult <- ZStream .fromIterable(identities) @@ -51,9 +51,9 @@ object Implicits { } yield updateResult } - implicit def StreamReadCache[T: Schema]: ZStreamCache[Any, Throwable, T] = new ZStreamCache[Any, Throwable, T] { + implicit def StreamReadCache[T: Schema]: ZStreamCache[T] = new ZStreamCache[T] { override def getIfPresent( - business: => ZStream[Any, Throwable, T] + business: => UZStream[T] )(identities: List[String], args: List[_]): ZStream[Any, Throwable, T] = { val key = cacheKey(identities) val field = cacheField(args) @@ -78,8 +78,8 @@ object Implicits { } } - implicit def UpdateCache[T: Schema]: ZIOUpdateCache[Any, Throwable, T] = new ZIOUpdateCache[Any, Throwable, T] { - override def evict(business: => ZIO[Any, Throwable, T])(identities: List[String]): ZIO[Any, Throwable, T] = + implicit def UpdateCache[T: Schema]: ZIOUpdateCache[T] = new ZIOUpdateCache[T] { + override def evict(business: => Task[T])(identities: List[String]): Task[T] = for { updateResult <- ZIO.foreach_(identities)(key => ZRedisService.del(key)) *> business _ <- Utils @@ -88,10 +88,10 @@ object Implicits { } yield updateResult } - implicit def ReadCache[T: Schema]: ZIOCache[Any, Throwable, T] = new ZIOCache[Any, Throwable, T] { + implicit def ReadCache[T: Schema]: ZIOCache[T] = new ZIOCache[T] { override def getIfPresent( - business: => ZIO[Any, Throwable, T] - )(identities: List[String], args: List[_]): ZIO[Any, Throwable, T] = { + business: => Task[T] + )(identities: List[String], args: List[_]): Task[T] = { val key = cacheKey(identities) val field = cacheField(args) for { diff --git a/smt-cacheable-redis/src/test/scala/org/bitlap/cacheable/redis/CustomCacheableTest.scala b/smt-cacheable-redis/src/test/scala/org/bitlap/cacheable/redis/CustomCacheableTest.scala index 485ed465..986af0e1 100644 --- a/smt-cacheable-redis/src/test/scala/org/bitlap/cacheable/redis/CustomCacheableTest.scala +++ b/smt-cacheable-redis/src/test/scala/org/bitlap/cacheable/redis/CustomCacheableTest.scala @@ -27,6 +27,7 @@ import org.scalatest.matchers.should.Matchers import zio.ZIO import zio.schema.Schema.Primitive import zio.schema.{ Schema, StandardType } +import zio.Task import scala.util.Random @@ -40,9 +41,9 @@ class CustomCacheableTest extends AnyFlatSpec with Matchers { "create a custom cacheable by implicit" should "" in { implicit val schema: Schema[String] = Primitive(StandardType.StringType) - implicit def cache[T: Schema]: ZIOCache[Any, Throwable, String] = new ZIOCache[Any, Throwable, String] { + implicit def cache[T: Schema]: ZIOCache[String] = new ZIOCache[String] { override def getIfPresent( - business: => ZIO[Any, Throwable, String] + business: => Task[String] )(identities: List[String], args: List[_]): ZIO[Any, Throwable, String] = { println("hello world!!") business diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/Cache.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/Cache.scala index fcb15675..09a5fe27 100644 --- a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/Cache.scala +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/Cache.scala @@ -20,16 +20,14 @@ */ package org.bitlap.cacheable.core - -import zio.ZIO -import zio.stream.ZStream +import zio.Task /** A distributed cache for zio. * * @tparam Z * The result type of the function that returns the ZIO or ZStream effect. */ -trait Cache[Z] { +trait Cache[T, F[_]] { /** Get cache or getAndSet cache from Cache while read data. * @@ -42,7 +40,7 @@ trait Cache[Z] { * @return * The result fo the business function. */ - def getIfPresent(business: => Z)(identities: List[String], args: List[_]): Z + def getIfPresent(business: => F[T])(identities: List[String], args: List[_]): F[T] /** Evict cache while data update. * @@ -53,7 +51,7 @@ trait Cache[Z] { * @return * The result fo the business function. */ - def evict(business: => Z)(identities: List[String]): Z + def evict(business: => F[T])(identities: List[String]): F[T] /** Build a string for cache key. * @@ -77,24 +75,24 @@ trait Cache[Z] { object Cache { - def apply[R, E, T](business: => ZStream[R, E, T])(identities: List[String], args: List[_])(implicit - streamCache: ZStreamCache[R, E, T] - ): ZStream[R, E, T] = + def apply[T](business: => UZStream[T])(identities: List[String], args: List[_])(implicit + streamCache: ZStreamCache[T] + ): UZStream[T] = streamCache.getIfPresent(business)(identities, args) - def apply[R, E, T](business: => ZIO[R, E, T])(identities: List[String], args: List[_])(implicit - cache: ZIOCache[R, E, T] - ): ZIO[R, E, T] = + def apply[T](business: => Task[T])(identities: List[String], args: List[_])(implicit + cache: ZIOCache[T] + ): Task[T] = cache.getIfPresent(business)(identities, args) - def evict[R, E, T](business: => ZStream[R, E, T])(identities: List[String])(implicit - streamCache: ZStreamUpdateCache[R, E, T] - ): ZStream[R, E, T] = + def evict[T](business: => UZStream[T])(identities: List[String])(implicit + streamCache: ZStreamUpdateCache[T] + ): UZStream[T] = streamCache.evict(business)(identities) - def evict[R, E, T](business: => ZIO[R, E, T])(identities: List[String])(implicit - cache: ZIOUpdateCache[R, E, T] - ): ZIO[R, E, T] = + def evict[T](business: => Task[T])(identities: List[String])(implicit + cache: ZIOUpdateCache[T] + ): Task[T] = cache.evict(business)(identities) } diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOCache.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOCache.scala index f9661659..863b5363 100644 --- a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOCache.scala +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOCache.scala @@ -21,7 +21,7 @@ package org.bitlap.cacheable.core -import zio.ZIO +import zio.Task /** Redis Cache for ZIO. * @@ -29,11 +29,11 @@ import zio.ZIO * 梦境迷离 * @version 2.0,2022/3/18 */ -trait ZIOCache[R, E, T] extends Cache[ZIO[R, E, T]] { +trait ZIOCache[T] extends Cache[T, Task] { - override def getIfPresent(business: => ZIO[R, E, T])(identities: List[String], args: List[_]): ZIO[R, E, T] + override def getIfPresent(business: => Task[T])(identities: List[String], args: List[_]): Task[T] - override final def evict(business: => ZIO[R, E, T])(identities: List[String]): ZIO[R, E, T] = + override def evict(business: => Task[T])(identities: List[String]): Task[T] = throw new UnsupportedOperationException() override def toString: String = "ZIOCache" diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOUpdateCache.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOUpdateCache.scala index d4bc3755..3c4e9b6c 100644 --- a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOUpdateCache.scala +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZIOUpdateCache.scala @@ -21,7 +21,7 @@ package org.bitlap.cacheable.core -import zio.ZIO +import zio.Task /** Redis Update Cache for ZIO. * @@ -29,12 +29,12 @@ import zio.ZIO * 梦境迷离 * @version 2.0,2022/3/18 */ -trait ZIOUpdateCache[R, E, T] extends Cache[ZIO[R, E, T]] { +trait ZIOUpdateCache[T] extends Cache[T, Task] { - override final def getIfPresent(business: => ZIO[R, E, T])(identities: List[String], args: List[_]): ZIO[R, E, T] = + override final def getIfPresent(business: => Task[T])(identities: List[String], args: List[_]): Task[T] = throw new UnsupportedOperationException() - override def evict(business: => ZIO[R, E, T])(identities: List[String]): ZIO[R, E, T] + override def evict(business: => Task[T])(identities: List[String]): Task[T] override def toString: String = "ZIOUpdateCache" diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamCache.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamCache.scala index 5077a86a..fa8ecad0 100644 --- a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamCache.scala +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamCache.scala @@ -21,19 +21,17 @@ package org.bitlap.cacheable.core -import zio.stream.ZStream - /** Redis Cache for ZStream. * * @author * 梦境迷离 * @version 2.0,2022/3/19 */ -trait ZStreamCache[R, E, T] extends Cache[ZStream[R, E, T]] { +trait ZStreamCache[T] extends Cache[T, UZStream] { - override def getIfPresent(business: => ZStream[R, E, T])(identities: List[String], args: List[_]): ZStream[R, E, T] + override def getIfPresent(business: => UZStream[T])(identities: List[String], args: List[_]): UZStream[T] - override final def evict(business: => ZStream[R, E, T])(identities: List[String]): ZStream[R, E, T] = + override final def evict(business: => UZStream[T])(identities: List[String]): UZStream[T] = throw new UnsupportedOperationException() override def toString: String = "ZStreamCache" diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamUpdateCache.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamUpdateCache.scala index 149bff81..2d057e6c 100644 --- a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamUpdateCache.scala +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/ZStreamUpdateCache.scala @@ -21,21 +21,19 @@ package org.bitlap.cacheable.core -import zio.stream.ZStream - /** Redis Update Cache for ZStream. * * @author * 梦境迷离 * @version 2.0,2022/3/19 */ -trait ZStreamUpdateCache[R, E, T] extends Cache[ZStream[R, E, T]] { +trait ZStreamUpdateCache[T] extends Cache[T, UZStream] { override final def getIfPresent( - business: => ZStream[R, E, T] - )(identities: List[String], args: List[_]): ZStream[R, E, T] = throw new UnsupportedOperationException() + business: => UZStream[T] + )(identities: List[String], args: List[_]): UZStream[T] = throw new UnsupportedOperationException() - override def evict(business: => ZStream[R, E, T])(identities: List[String]): ZStream[R, E, T] + override def evict(business: => UZStream[T])(identities: List[String]): UZStream[T] override def toString: String = "ZStreamUpdateCache" diff --git a/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/package.scala b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/package.scala new file mode 100644 index 00000000..5c6044aa --- /dev/null +++ b/smt-cacheable/src/main/scala/org/bitlap/cacheable/core/package.scala @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 bitlap + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.bitlap.cacheable + +/** @author + * 梦境迷离 + * @version 1.0,2022/7/22 + */ +package object core { + type UZStream[+A] = zio.stream.Stream[Throwable, A] +} diff --git a/smt-common/src/main/scala/org/bitlap/common/internal/CaseClassExtractorMacro.scala b/smt-common/src/main/scala/org/bitlap/common/internal/CaseClassExtractorMacro.scala index 765075d1..969a8cf5 100644 --- a/smt-common/src/main/scala/org/bitlap/common/internal/CaseClassExtractorMacro.scala +++ b/smt-common/src/main/scala/org/bitlap/common/internal/CaseClassExtractorMacro.scala @@ -40,7 +40,7 @@ object CaseClassExtractorMacro { // scalafmt: { maxColumn = 400 } val tree = q""" - if ($t == null) None else { + if ($t == null) _root_.scala.None else { val _field = $field _field.${TermName(CaseClassField.fieldNamesTermName)}.find(kv => kv._2 == _field.${TermName(CaseClassField.stringifyTermName)}) .map(kv => $t.productElement(kv._1))