diff --git a/modules/kv/src/main/scala/gs/predicate/v0/kv/KeyExists.scala b/modules/kv/src/main/scala/gs/predicate/v0/kv/KeyExists.scala index bd58b3f..786b54e 100644 --- a/modules/kv/src/main/scala/gs/predicate/v0/kv/KeyExists.scala +++ b/modules/kv/src/main/scala/gs/predicate/v0/kv/KeyExists.scala @@ -1,6 +1,6 @@ package gs.predicate.v0.kv -import cats.effect.Sync +import cats.Functor import cats.syntax.all.* import gs.predicate.v0.api.Predicate import gs.uuid.v0.UUID @@ -12,7 +12,7 @@ import gs.uuid.v0.UUID * @param key * The key that should exist. */ -final class KeyExists[F[_]: Sync, K, V]( +final class KeyExists[F[_]: Functor, K, V]( val id: UUID, val key: K ) extends Predicate[F, KeyValueProvider[F, K, V]]: @@ -21,3 +21,10 @@ final class KeyExists[F[_]: Sync, K, V]( */ override def eval(input: KeyValueProvider[F, K, V]): F[Predicate.Result] = input.exists(key).map(Predicate.Result.apply) + +object KeyExists: + + def apply[F[_]: Functor, K, V](key: K): KeyExists[F, K, V] = + new KeyExists[F, K, V](UUID.v7(), key) + +end KeyExists diff --git a/modules/kv/src/main/scala/gs/predicate/v0/kv/ValueEquals.scala b/modules/kv/src/main/scala/gs/predicate/v0/kv/ValueEquals.scala index bc31119..bd42ac5 100644 --- a/modules/kv/src/main/scala/gs/predicate/v0/kv/ValueEquals.scala +++ b/modules/kv/src/main/scala/gs/predicate/v0/kv/ValueEquals.scala @@ -1,6 +1,6 @@ package gs.predicate.v0.kv -import cats.effect.Sync +import cats.Functor import cats.syntax.all.* import gs.predicate.v0.api.Predicate import gs.uuid.v0.UUID @@ -15,7 +15,7 @@ import gs.uuid.v0.UUID * @param value * The value that must be associated with the key. */ -final class ValueEquals[F[_]: Sync, K, V]( +final class ValueEquals[F[_]: Functor, K, V]( val id: UUID, val key: K, val expectedValue: V @@ -31,3 +31,16 @@ final class ValueEquals[F[_]: Sync, K, V]( case Some(value) => Predicate.Result(value == expectedValue) case _ => Predicate.Result.missed() } + +object ValueEquals: + + def apply[F[_]: Functor, K, V]( + key: K, + value: V + )( + using + CanEqual[V, V] + ): ValueEquals[F, K, V] = + new ValueEquals[F, K, V](UUID.v7(), key, value) + +end ValueEquals diff --git a/modules/kv/src/test/scala/gs/predicate/v0/kv/KeyExistsTests.scala b/modules/kv/src/test/scala/gs/predicate/v0/kv/KeyExistsTests.scala new file mode 100644 index 0000000..8622c90 --- /dev/null +++ b/modules/kv/src/test/scala/gs/predicate/v0/kv/KeyExistsTests.scala @@ -0,0 +1,47 @@ +package gs.predicate.v0.kv + +import cats.effect.IO +import cats.effect.std.MapRef +import gs.datagen.v0.Gen +import gs.datagen.v0.generators.Size +import gs.predicate.v0.api.Predicate +import support.IOSuite + +class KeyExistsTests extends IOSuite: + + import KeyExistsTests.Data + + iotest("should find a key that exists within some provider") { + val p = KeyExists[IO, String, String](Data.ExistingKey) + for + provider <- KeyExistsTests.newProvider(Data.KeyValues) + result <- p.eval(provider) + yield + // TODO: assertPredicateMatched(result) + assertEquals(result, Predicate.Result.matched()) + } + + iotest("should not find a key that does not exist within some provider") { + val p = KeyExists[IO, String, String](Data.NotExistingKey) + for + provider <- KeyExistsTests.newProvider(Data.KeyValues) + result <- p.eval(provider) + yield assertEquals(result, Predicate.Result.missed()) + } + +object KeyExistsTests: + + object Data: + + val ExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(8)).gen() + val NotExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(6)).gen() + val ExistingValue: String = Gen.string.alphaNumeric(Size.Fixed(10)).gen() + val KeyValues: Map[String, String] = Map(ExistingKey -> ExistingValue) + + end Data + + def newProvider(data: Map[String, String]): IO[KeyValueStringProvider[IO]] = + for map <- MapRef.ofSingleImmutableMap[IO, String, String](data) + yield new MemoryMapStringProvider(map) + +end KeyExistsTests diff --git a/modules/kv/src/test/scala/gs/predicate/v0/kv/ValueEqualsTests.scala b/modules/kv/src/test/scala/gs/predicate/v0/kv/ValueEqualsTests.scala new file mode 100644 index 0000000..c96a110 --- /dev/null +++ b/modules/kv/src/test/scala/gs/predicate/v0/kv/ValueEqualsTests.scala @@ -0,0 +1,56 @@ +package gs.predicate.v0.kv + +import cats.effect.IO +import cats.effect.std.MapRef +import gs.datagen.v0.Gen +import gs.datagen.v0.generators.Size +import gs.predicate.v0.api.Predicate +import support.IOSuite + +class ValueEqualsTests extends IOSuite: + + import ValueEqualsTests.Data + + iotest("should find an exact match against some value") { + val p = + ValueEquals[IO, String, String](Data.ExistingKey, Data.ExistingValue) + for + provider <- ValueEqualsTests.newProvider(Data.KeyValues) + result <- p.eval(provider) + yield assertEquals(result, Predicate.Result.matched()) + } + + iotest("should not find a value if it is not associated to a key") { + val p = + ValueEquals[IO, String, String](Data.ExistingKey, Data.NotExistingValue) + for + provider <- ValueEqualsTests.newProvider(Data.KeyValues) + result <- p.eval(provider) + yield assertEquals(result, Predicate.Result.missed()) + } + + iotest("should not find a key that does not exist within some provider") { + val p = ValueEquals[IO, String, String](Data.NotExistingKey, "") + for + provider <- ValueEqualsTests.newProvider(Data.KeyValues) + result <- p.eval(provider) + yield assertEquals(result, Predicate.Result.missed()) + } + +object ValueEqualsTests: + + object Data: + + val ExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(8)).gen() + val NotExistingKey: String = Gen.string.alphaNumeric(Size.Fixed(6)).gen() + val ExistingValue: String = Gen.string.alphaNumeric(Size.Fixed(10)).gen() + val NotExistingValue: String = Gen.string.alphaNumeric(Size.Fixed(4)).gen() + val KeyValues: Map[String, String] = Map(ExistingKey -> ExistingValue) + + end Data + + def newProvider(data: Map[String, String]): IO[KeyValueStringProvider[IO]] = + for map <- MapRef.ofSingleImmutableMap[IO, String, String](data) + yield new MemoryMapStringProvider(map) + +end ValueEqualsTests