diff --git a/.codecov.yml b/.codecov.yml index b4155669..35ffca38 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -24,3 +24,4 @@ ignore: - "**/ZRedisService.scala" - "**/BenchmarkRuntime.scala" - "**/CacheableBenchmarks.scala" + - "examples/**/*" diff --git a/build.sbt b/build.sbt index d9962283..34e5d05b 100644 --- a/build.sbt +++ b/build.sbt @@ -181,7 +181,10 @@ lazy val `smt` = (project in file(".")) `smt-csv`, `smt-csv-derive`, `smt-cache`, - `smt-common` + `smt-common`, + `scala2-11`, + `scala2-12`, + `scala2-13` ) .settings( commands ++= Commands.value, @@ -208,13 +211,12 @@ lazy val `smt` = (project in file(".")) ) ) -//FIXME root doesnot aggregate these examples lazy val `scala2-13` = (project in file("examples/scala2-13")) .settings(scalaVersion := scala213) .settings( libraryDependencies ++= Seq( - "org.bitlap" %% "smt-tools" % lastVersionForExamples, - "org.bitlap" %% "smt-cacheable-core" % lastVersionForExamples, + "org.bitlap" %% "smt-annotations" % lastVersionForExamples, + "org.bitlap" %% "smt-cacheable" % lastVersionForExamples, "org.bitlap" %% "smt-cacheable-redis" % lastVersionForExamples, "org.bitlap" %% "smt-cacheable-caffeine" % lastVersionForExamples, "dev.zio" %% "zio-redis" % zioRedisVersion, @@ -230,8 +232,8 @@ lazy val `scala2-12` = (project in file("examples/scala2-12")) .settings(scalaVersion := scala212) .settings( libraryDependencies ++= Seq( - "org.bitlap" %% "smt-tools" % lastVersionForExamples, - "org.bitlap" %% "smt-cacheable-core" % lastVersionForExamples, + "org.bitlap" %% "smt-annotations" % lastVersionForExamples, + "org.bitlap" %% "smt-cacheable" % lastVersionForExamples, "org.bitlap" %% "smt-cacheable-redis" % lastVersionForExamples, "org.bitlap" %% "smt-cacheable-caffeine" % lastVersionForExamples, "dev.zio" %% "zio-redis" % zioRedisVersion, @@ -247,7 +249,7 @@ lazy val `scala2-11` = (project in file("examples/scala2-11")) .settings(scalaVersion := scala211) .settings( libraryDependencies ++= Seq( - "org.bitlap" %% "smt-tools" % lastVersionForExamples + "org.bitlap" %% "smt-annotations" % lastVersionForExamples ) ) .settings( diff --git a/examples/scala2-11/src/main/scala/org/bitlap/tools/Main.scala b/examples/scala2-11/src/main/scala/org/bitlap/tools/Main.scala index d49797aa..1dc064f8 100644 --- a/examples/scala2-11/src/main/scala/org/bitlap/tools/Main.scala +++ b/examples/scala2-11/src/main/scala/org/bitlap/tools/Main.scala @@ -1,16 +1,15 @@ package org.bitlap.tools -/** - * - * @author 梦境迷离 - * @since 2021/6/16 - * @version 1.0 +/** @author + * 梦境迷离 + * @since 2021/6/16 + * @version 1.0 */ object Main extends App { @toString(includeInternalFields = true, includeFieldNames = true) class TestClass(val i: Int = 0, var j: Int) { - val y: Int = 0 + val y: Int = 0 var z: String = "hello" var x: String = "world" } diff --git a/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheExample.scala b/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheExample.scala index d2215baa..a1dbbaf9 100644 --- a/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheExample.scala +++ b/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheExample.scala @@ -29,11 +29,11 @@ import zio.stream.ZStream import scala.util.Random -/** - * use these function to test it. +/** use these function to test it. * - * @author 梦境迷离 - * @version 1.0,2022/3/18 + * @author + * 梦境迷离 + * @version 1.0,2022/3/18 */ object CacheExample extends zio.App { @@ -54,16 +54,15 @@ object CacheExample extends zio.App { } @cacheable // caffeine - def readStreamEntityFunction(id: Int, key: String): ZStream[Any, Throwable, CacheValue] = { + def readStreamEntityFunction(id: Int, key: String): ZStream[Any, Throwable, CacheValue] = ZStream.fromEffect(ZIO.effect(CacheValue(Random.nextInt() + ""))) - } override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = (for { cache1 <- readStreamEntityFunction(1, "hello-world").runHead cache2 <- updateStreamFunction(2, "helloworld").runHead - _ <- Utils.debug(s"${cache1.toString} ${cache2.toString}") - _ <- putStrLn("Hello good to meet you!") + _ <- Utils.debug(s"${cache1.toString} ${cache2.toString}") + _ <- putStrLn("Hello good to meet you!") } yield ()).foldM( e => Utils.debug(s"error => $e").exitCode, _ => UIO.effectTotal(ExitCode.success) diff --git a/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheValue.scala b/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheValue.scala index fd44a2a4..4ea94e1e 100644 --- a/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheValue.scala +++ b/examples/scala2-12/src/main/scala/org/bitlap/tools/CacheValue.scala @@ -1,10 +1,9 @@ package org.bitlap.tools import zio.schema.{ DeriveSchema, Schema } -/** - * - * @author 梦境迷离 - * @version 1.0,2022/3/22 +/** @author + * 梦境迷离 + * @version 1.0,2022/3/22 */ case class CacheValue(i: String) diff --git a/examples/scala2-12/src/main/scala/org/bitlap/tools/Main.scala b/examples/scala2-12/src/main/scala/org/bitlap/tools/Main.scala index d49797aa..1dc064f8 100644 --- a/examples/scala2-12/src/main/scala/org/bitlap/tools/Main.scala +++ b/examples/scala2-12/src/main/scala/org/bitlap/tools/Main.scala @@ -1,16 +1,15 @@ package org.bitlap.tools -/** - * - * @author 梦境迷离 - * @since 2021/6/16 - * @version 1.0 +/** @author + * 梦境迷离 + * @since 2021/6/16 + * @version 1.0 */ object Main extends App { @toString(includeInternalFields = true, includeFieldNames = true) class TestClass(val i: Int = 0, var j: Int) { - val y: Int = 0 + val y: Int = 0 var z: String = "hello" var x: String = "world" } diff --git a/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheExample.scala b/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheExample.scala index 5cfdc57e..37a3ca67 100644 --- a/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheExample.scala +++ b/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheExample.scala @@ -29,11 +29,11 @@ import zio.stream.ZStream import zio.{ ExitCode, UIO, URIO, ZIO } import org.bitlap.cacheable.core.cacheable -/** - * use these function to test it. +/** use these function to test it. * - * @author 梦境迷离 - * @version 1.0,2022/3/18 + * @author + * 梦境迷离 + * @version 1.0,2022/3/18 */ object CacheExample extends zio.App { @@ -54,16 +54,15 @@ object CacheExample extends zio.App { } @cacheable // caffeine - def readStreamEntityFunction(id: Int, key: String): ZStream[Any, Throwable, CacheValue] = { + def readStreamEntityFunction(id: Int, key: String): ZStream[Any, Throwable, CacheValue] = ZStream.fromEffect(ZIO.effect(CacheValue(Random.nextInt() + ""))) - } override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = (for { cache1 <- readStreamEntityFunction(1, "hello-world").runHead cache2 <- updateStreamFunction(2, "helloworld").runHead - _ <- Utils.debug(s"${cache1.toString} ${cache2.toString}") - _ <- putStrLn("Hello good to meet you!") + _ <- Utils.debug(s"${cache1.toString} ${cache2.toString}") + _ <- putStrLn("Hello good to meet you!") } yield ()).foldM( e => Utils.debug(s"error => $e").exitCode, _ => UIO.effectTotal(ExitCode.success) diff --git a/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheValue.scala b/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheValue.scala index 8e16ec2d..58b6b091 100644 --- a/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheValue.scala +++ b/examples/scala2-13/src/main/scala/org/bitlap/tools/CacheValue.scala @@ -2,10 +2,9 @@ package org.bitlap.tools import zio.schema.{ DeriveSchema, Schema } -/** - * - * @author 梦境迷离 - * @version 1.0,2022/3/22 +/** @author + * 梦境迷离 + * @version 1.0,2022/3/22 */ // The case class should be here, not in the test diff --git a/examples/scala2-13/src/main/scala/org/bitlap/tools/Main.scala b/examples/scala2-13/src/main/scala/org/bitlap/tools/Main.scala index eb016075..1f3bf788 100644 --- a/examples/scala2-13/src/main/scala/org/bitlap/tools/Main.scala +++ b/examples/scala2-13/src/main/scala/org/bitlap/tools/Main.scala @@ -1,16 +1,15 @@ package org.bitlap.tools -/** - * - * @author 梦境迷离 - * @since 2021/6/16 - * @version 1.0 +/** @author + * 梦境迷离 + * @since 2021/6/16 + * @version 1.0 */ object Main extends App { @toString(includeInternalFields = true, includeFieldNames = true) class TestClass(val i: Int = 0, var j: Int) { - val y: Int = 0 + val y: Int = 0 var z: String = "hello" var x: String = "world" } @@ -21,14 +20,14 @@ object Main extends App { @toString(includeInternalFields = false, includeFieldNames = true) @apply @builder class A2(int: Int, val j: Int, var k: Option[String] = None, t: Option[Long] = Some(1L)) { - private val a: Int = 1 - var b: Int = 1 + private val a: Int = 1 + var b: Int = 1 protected var c: Int = _ def helloWorld: String = "hello world" } - println(A2(1, 2, None, None)) //use apply and toString - println(A2.builder().int(1).j(2).k(Option("hello")).t(None).build()) //use builder and toString + println(A2(1, 2, None, None)) // use apply and toString + println(A2.builder().int(1).j(2).k(Option("hello")).t(None).build()) // use builder and toString } 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 199b5c3c..fcf48816 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/Cache.scala @@ -61,6 +61,8 @@ object Cache { ) override def clear(): Future[Unit] = cache.clear() + + override def getAllT: Future[Map[K, cache.Out]] = cache.getAll } def getSyncCache[K, T <: Product](implicit @@ -88,6 +90,8 @@ object Cache { getT(key).flatMap(t => CaseClassExtractor.ofValue[cache.Out](t, field).asInstanceOf[Option[field.Field]]) override def clear(): Identity[Unit] = cache.clear() + + override def getAllT: Identity[Map[K, cache.Out]] = cache.getAll } } diff --git a/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala b/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala new file mode 100644 index 00000000..f3d24744 --- /dev/null +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheAdapter.scala @@ -0,0 +1,86 @@ +/* + * 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.cache + +import scala.jdk.CollectionConverters._ + +import java.util.Collections + +/** @author + * 梦境迷离 + * @version 1.0,2022/7/5 + */ +trait CacheAdapter[V] { + def getAllKeys: Set[String] + + def putAll(map: Map[String, V]): Unit + + def put(k: String, v: V): Unit + + def get(k: String): V + + def clear(): Unit +} + +object CacheAdapter { + + def adapted[V](cacheType: CacheStrategy): CacheAdapter[V] = + cacheType match { + case CacheStrategy.Lru(maxSize) => + new LruHashMapCacheAdapter( + Collections.synchronizedMap(new java.util.LinkedHashMap[String, V](16, 0.75f, true) { + override def removeEldestEntry(eldest: java.util.Map.Entry[String, V]): Boolean = size > maxSize + }) + ) + case CacheStrategy.Normal => + new ConcurrentMapCacheAdapter(new java.util.concurrent.ConcurrentHashMap[String, V]()) + case CacheStrategy.CustomCacheStrategy(cacheAdapter) => cacheAdapter.asInstanceOf[CacheAdapter[V]] + } + + class LruHashMapCacheAdapter[V](underlyingCache: java.util.Map[String, V]) extends CacheAdapter[V] { + + override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet + + override def putAll(map: Map[String, V]): Unit = underlyingCache.putAll(map.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() + } + + class ConcurrentMapCacheAdapter[V](underlyingCache: java.util.concurrent.ConcurrentMap[String, V]) + extends CacheAdapter[V] { + + override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet + + override def putAll(map: Map[String, V]): Unit = underlyingCache.putAll(map.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() + } + +} diff --git a/smt-cache/src/main/scala/org/bitlap/cache/CacheKeyBuilder.scala b/smt-cache/src/main/scala/org/bitlap/cache/CacheKeyBuilder.scala index 00ab909d..a1f5d586 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/CacheKeyBuilder.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheKeyBuilder.scala @@ -22,8 +22,6 @@ package org.bitlap.cache import java.util.UUID -import java.time.LocalDateTime -import java.time.ZonedDateTime /** @author * 梦境迷离 @@ -31,35 +29,39 @@ import java.time.ZonedDateTime */ trait CacheKeyBuilder[T] { def generateKey(key: T): String + + def unGenerateKey(key: String): T } object CacheKeyBuilder { implicit val intKey: CacheKeyBuilder[Int] = new CacheKeyBuilder[Int] { override def generateKey(key: Int): String = key.toString + + override def unGenerateKey(key: String): Int = key.toInt } implicit val stringKey: CacheKeyBuilder[String] = new CacheKeyBuilder[String] { override def generateKey(key: String): String = key + + override def unGenerateKey(key: String): String = key } implicit val longKey: CacheKeyBuilder[Long] = new CacheKeyBuilder[Long] { override def generateKey(key: Long): String = key.toString + + override def unGenerateKey(key: String): Long = key.toLong } implicit val doubleKey: CacheKeyBuilder[Double] = new CacheKeyBuilder[Double] { override def generateKey(key: Double): String = String.valueOf(key) + + override def unGenerateKey(key: String): Double = key.toDouble } implicit val uuidKey: CacheKeyBuilder[UUID] = new CacheKeyBuilder[UUID] { override def generateKey(key: UUID): String = key.toString - } - - implicit val localDateTimeKey: CacheKeyBuilder[LocalDateTime] = new CacheKeyBuilder[LocalDateTime] { - override def generateKey(key: LocalDateTime): String = key.toString - } - implicit val zoneDateTimeKey: CacheKeyBuilder[ZonedDateTime] = new CacheKeyBuilder[ZonedDateTime] { - override def generateKey(key: ZonedDateTime): String = key.toString + override def unGenerateKey(key: String): UUID = UUID.fromString(key) } } 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 499e776f..17b05a68 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheRef.scala @@ -39,5 +39,7 @@ trait CacheRef[In, T <: Product, F[_]] { def getTField(key: In, field: CaseClassField): F[Option[field.Field]] + def getAllT: F[Map[In, T]] + def clear(): F[Unit] } diff --git a/smt-cache/src/main/scala/org/bitlap/cache/CacheStrategy.scala b/smt-cache/src/main/scala/org/bitlap/cache/CacheStrategy.scala index 7fe66117..f84dceb6 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/CacheStrategy.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/CacheStrategy.scala @@ -29,6 +29,7 @@ trait CacheStrategy object CacheStrategy { - case class Lru(maxSize: Int = 1000) extends CacheStrategy - case object Normal extends CacheStrategy + case class Lru(maxSize: Int = 1000) extends CacheStrategy + case object Normal extends CacheStrategy + case class CustomCacheStrategy[V](cacheAdapter: CacheAdapter[V]) extends CacheStrategy } 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 1ee9b18e..cac6b805 100644 --- a/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala +++ b/smt-cache/src/main/scala/org/bitlap/cache/GenericCache.scala @@ -20,10 +20,8 @@ */ package org.bitlap.cache -import java.util -import java.util.Collections + import scala.concurrent.{ ExecutionContext, Future } -import scala.jdk.CollectionConverters._ /** @author * 梦境迷离 @@ -39,35 +37,47 @@ sealed trait GenericCache[K, F[_]] { def putAll(map: Map[K, Out])(implicit keyBuilder: CacheKeyBuilder[K]): F[Unit] + def getAll(implicit keyBuilder: CacheKeyBuilder[K]): F[Map[K, Out]] + def clear(): F[Unit] } + 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 typedCache = getCacheByStrategy[Out0](cacheStrategy) override type Out = Out0 + override def get( key: K )(implicit keyBuilder: CacheKeyBuilder[K] ): Identity[Option[Out]] = { - val v = typedCache.get(keyBuilder.generateKey(key)) + val v = adaptedCache.get(keyBuilder.generateKey(key)) if (v == null) None else Option(v) } override def put(key: K, value: Out)(implicit keyBuilder: CacheKeyBuilder[K] ): Identity[Unit] = - typedCache.put(keyBuilder.generateKey(key), value) + adaptedCache.put(keyBuilder.generateKey(key), value) override def putAll(map: Map[K, Out0])(implicit keyBuilder: CacheKeyBuilder[K]): Identity[Unit] = - typedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2).asJava) + adaptedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) + + override def clear(): Identity[Unit] = adaptedCache.clear() - override def clear(): Identity[Unit] = typedCache.clear() + override def getAll(implicit keyBuilder: CacheKeyBuilder[K]): Identity[Map[K, Out0]] = + adaptedCache.getAllKeys + .map(key => keyBuilder.unGenerateKey(key) -> adaptedCache.get(key)) + .collect { + case (k, out) if out != null => k -> out + } + .toMap } def apply[K, Out0 <: Product]( @@ -75,36 +85,37 @@ object GenericCache { executionContext: ExecutionContext ): Aux[K, Out0, Future] = new GenericCache[K, Future] { - implicit val ec = executionContext - private val typedCache = getCacheByStrategy[Out0](cacheStrategy) + implicit val ec = executionContext + private val adaptedCache: 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 = typedCache.get(keyBuilder.generateKey(key)) - println(s"key => $key | value => $v") + val v = adaptedCache.get(keyBuilder.generateKey(key)) if (v == null) None else Option(v) } def put(key: K, value: Out)(implicit keyBuilder: CacheKeyBuilder[K]): Future[Unit] = Future { - typedCache.put(keyBuilder.generateKey(key), value) + adaptedCache.put(keyBuilder.generateKey(key), value) }.map(_ => ()) override def putAll(map: Map[K, Out0])(implicit keyBuilder: CacheKeyBuilder[K]): Future[Unit] = Future { - println(s"all map => ${map.mkString(" | ")}") - typedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2).asJava) + adaptedCache.putAll(map.map(kv => keyBuilder.generateKey(kv._1) -> kv._2)) } - override def clear(): Future[Unit] = Future.successful(typedCache.clear()) - } + override def getAll(implicit keyBuilder: CacheKeyBuilder[K]): Future[Map[K, Out0]] = + Future { + adaptedCache.getAllKeys + .map(key => keyBuilder.unGenerateKey(key) -> adaptedCache.get(key)) + .collect { + case (k, out) if out != null => k -> out + } + .toMap + } - private def getCacheByStrategy[Out0](cacheType: CacheStrategy): util.Map[String, Out0] = - cacheType match { - case CacheStrategy.Lru(maxSize) => - Collections.synchronizedMap(new java.util.LinkedHashMap[String, Out0](maxSize, 0.75f, true)) - case CacheStrategy.Normal => new java.util.concurrent.ConcurrentHashMap[String, Out0]() - // TODO other cache, redis cache, caffeine cache + override def clear(): Future[Unit] = Future.successful(adaptedCache.clear()) } } diff --git a/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala b/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala new file mode 100644 index 00000000..603c841a --- /dev/null +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheCustomCaseSpec.scala @@ -0,0 +1,89 @@ +/* + * 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.cache + +import java.util +import scala.jdk.CollectionConverters._ +import org.bitlap.common.TestEntity +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +/** @author + * 梦境迷离 + * @version 1.0,7/5/22 + */ +class CacheCustomCaseSpec extends AnyFlatSpec with Matchers { + + private val data = Map( + "btc" -> TestEntity("btc", "hello1", "world1"), + "etc1" -> TestEntity("eth1", "hello1", "world2"), + "etc2" -> TestEntity("eth2", "hello2", "world2") + ) + + "cache1" should "ok while uses lru cache" in { + implicit val lruCache = CacheImplicits.testEntitySyncLruCache + val cache = Cache.getSyncCache[String, TestEntity] + cache.init(data) + + cache.putT("etc3", TestEntity("eth3", "hello3", "world2")) + + val result: Option[TestEntity] = cache.getT("btc") + result shouldBe None + + cache.clear() + + val result2: Option[TestEntity] = cache.getT("etc1") + result2 shouldBe None + + cache.putTAll(data) + + val result3: Option[TestEntity] = cache.getT("etc1") + result3 shouldBe Some(TestEntity("eth1", "hello1", "world2")) + + val result4 = cache.getAllT + result4 shouldBe data + } + + "cache2" should "ok while defines a custom cache" in { + implicit val customCache = + GenericCache[String, TestEntity](CacheStrategy.CustomCacheStrategy(new CacheAdapter[TestEntity] { + lazy val underlyingCache: util.HashMap[String, TestEntity] = new util.HashMap[String, TestEntity]() + + override def getAllKeys: Set[String] = underlyingCache.keySet().asScala.toSet + + override def putAll(map: Map[String, TestEntity]): Unit = underlyingCache.putAll(map.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() + })) + val cache = Cache.getSyncCache[String, TestEntity] + cache.init(data) + val result: Option[TestEntity] = cache.getT("btc") + result shouldBe Some(TestEntity("btc", "hello1", "world1")) + + val result2 = cache.getAllT + result2 shouldBe data + } +} diff --git a/smt-cache/src/test/scala/org/bitlap/cache/CacheImplicits.scala b/smt-cache/src/test/scala/org/bitlap/cache/CacheImplicits.scala index 926281ac..933d9366 100644 --- a/smt-cache/src/test/scala/org/bitlap/cache/CacheImplicits.scala +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheImplicits.scala @@ -33,4 +33,7 @@ object CacheImplicits { implicit lazy val testEntityAsyncCache = GenericCache[String, TestEntity](CacheStrategy.Normal, ExecutionContext.Implicits.global) + implicit lazy val testEntitySyncLruCache = + GenericCache[String, TestEntity](CacheStrategy.Lru(3)) + } diff --git a/smt-cache/src/test/scala/org/bitlap/cache/CacheKeyBuilderSpec.scala b/smt-cache/src/test/scala/org/bitlap/cache/CacheKeyBuilderSpec.scala new file mode 100644 index 00000000..217ed3e4 --- /dev/null +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheKeyBuilderSpec.scala @@ -0,0 +1,24 @@ +package org.bitlap.cache + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import java.util.UUID + +/** @author + * 梦境迷离 + * @version 1.0,7/5/22 + */ +class CacheKeyBuilderSpec extends AnyFlatSpec with Matchers { + + "CacheKeyBuilder1" should "ok while uses uuid type" in { + val now = UUID.randomUUID() + val str = CacheKeyBuilder.uuidKey.generateKey(now) + + println(str) + + val v = CacheKeyBuilder.uuidKey.unGenerateKey(str) + v shouldBe now + } + +} 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 f9efc057..dd47193d 100644 --- a/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala +++ b/smt-cache/src/test/scala/org/bitlap/cache/CacheSpec.scala @@ -24,7 +24,6 @@ import org.bitlap.common.CaseClassField import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import org.bitlap.cache.CacheImplicits._ import scala.concurrent.Await import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.DurationInt @@ -36,6 +35,9 @@ import org.bitlap.common.TestEntity */ class CacheSpec extends AnyFlatSpec with Matchers { + private implicit val syncCache = CacheImplicits.testEntitySyncCache + private implicit val asyncCache = CacheImplicits.testEntityAsyncCache + private val data = Map( "btc" -> TestEntity("btc", "hello1", "world1"), "etc" -> TestEntity("eth", "hello2", "world2") @@ -46,6 +48,9 @@ class CacheSpec extends AnyFlatSpec with Matchers { cache.init(data) val result: Option[TestEntity] = cache.getT("etc") result shouldBe data.get("etc") + + val result2 = cache.getAllT + result2 shouldBe data } "cache2" should "get entity's field from cache successfully" in {