Skip to content

Commit f667a7b

Browse files
voropaevpistreeterpondzixlmath
committed
Allow building caches based on the resolver's content (close #207)
I just took the code from then branched off master, and fixed the compilation errors Co-authored-by: Ian Streeter <[email protected]> Co-authored-by: Piotr Poniedziałek <[email protected]> Co-authored-by: Leigh-Anne Mathieson <[email protected]>
1 parent 112681d commit f667a7b

File tree

14 files changed

+1469
-93
lines changed

14 files changed

+1469
-93
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ project/plugins/project/
1818

1919
# Vagrant
2020
.vagrant
21+
22+
.bsp/
23+
.idea/

modules/core/src/main/scala/com.snowplowanalytics.iglu/client/Client.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@ package com.snowplowanalytics.iglu.client
1515
import cats.Monad
1616
import cats.data.EitherT
1717
import cats.effect.{Clock, IO}
18-
19-
import io.circe.Json
20-
18+
import io.circe.{DecodingFailure, Json}
2119
import com.snowplowanalytics.iglu.core.SelfDescribingData
22-
2320
import resolver.{InitListCache, InitSchemaCache}
2421
import resolver.registries.{Registry, RegistryLookup}
2522

@@ -42,7 +39,7 @@ final case class Client[F[_], A](resolver: Resolver[F], validator: Validator[A])
4239
for {
4340
schema <- EitherT(resolver.lookupSchema(instance.schema))
4441
schemaValidation = validator.validateSchema(schema)
45-
_ <- EitherT.fromEither(schemaValidation).leftMap(_.toClientError)
42+
_ <- EitherT.fromEither[F](schemaValidation).leftMap(_.toClientError)
4643
validation = validator.validate(instance.data, schema)
4744
_ <- EitherT.fromEither[F](validation).leftMap(_.toClientError)
4845
} yield ()
@@ -54,8 +51,10 @@ object Client {
5451
val IgluCentral: Client[IO, Json] =
5552
Client[IO, Json](Resolver(List(Registry.IgluCentral), None), CirceValidator)
5653

57-
def parseDefault[F[_]: Monad: InitSchemaCache: InitListCache](json: Json) =
58-
EitherT(Resolver.parse(json)).map { resolver =>
54+
def parseDefault[F[_]: Monad: InitSchemaCache: InitListCache](
55+
json: Json
56+
): EitherT[F, DecodingFailure, Client[F, Json]] =
57+
EitherT(Resolver.parse[F](json)).map { resolver =>
5958
Client(resolver, CirceValidator)
6059
}
6160
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2014-2022 Snowplow Analytics Ltd. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
package com.snowplowanalytics.iglu.client
14+
15+
import cats.Monad
16+
import cats.data.EitherT
17+
import cats.effect.Clock
18+
import cats.implicits._
19+
import com.snowplowanalytics.iglu.client.resolver.registries.RegistryLookup
20+
import com.snowplowanalytics.iglu.client.resolver.{InitListCache, InitSchemaCache}
21+
import com.snowplowanalytics.iglu.client.validator.CirceValidator.WithCaching.{
22+
InitValidatorCache,
23+
SchemaEvaluationCache,
24+
SchemaEvaluationKey,
25+
SchemaEvaluationResult
26+
}
27+
import com.snowplowanalytics.iglu.core.SelfDescribingData
28+
import com.snowplowanalytics.lrumap.CreateLruMap
29+
import io.circe.{DecodingFailure, Json}
30+
31+
/**
32+
* Client using 'lookupSchemaResult' resolver method (as opposed to old client relying on plain `lookupSchema` method)
33+
* which enables validator taking advantage of caching.
34+
* Should provide significant performance boost for the 'check' operation when called frequently.
35+
*/
36+
final class IgluCirceClient[F[_]] private (
37+
resolver: Resolver[F],
38+
schemaEvaluationCache: SchemaEvaluationCache[F]
39+
) {
40+
def check(
41+
instance: SelfDescribingData[Json]
42+
)(implicit
43+
M: Monad[F],
44+
L: RegistryLookup[F],
45+
C: Clock[F]
46+
): EitherT[F, ClientError, Unit] =
47+
for {
48+
resolverResult <- EitherT(resolver.lookupSchemaResult(instance.schema))
49+
validation =
50+
CirceValidator.WithCaching.validate(schemaEvaluationCache)(instance.data, resolverResult)
51+
_ <- EitherT(validation).leftMap(_.toClientError)
52+
} yield ()
53+
}
54+
55+
object IgluCirceClient {
56+
57+
def parseDefault[F[_]: Monad: InitSchemaCache: InitListCache: InitValidatorCache](
58+
json: Json
59+
): EitherT[F, DecodingFailure, IgluCirceClient[F]] =
60+
for {
61+
config <- EitherT.fromEither[F](Resolver.parseConfig(json))
62+
resolver <- Resolver.fromConfig[F](config)
63+
client <- EitherT.liftF(fromResolver(resolver, config.cacheSize))
64+
} yield client
65+
66+
def fromResolver[F[_]: Monad: InitValidatorCache](
67+
resolver: Resolver[F],
68+
cacheSize: Int
69+
): F[IgluCirceClient[F]] = {
70+
schemaEvaluationCache[F](cacheSize).map { cache =>
71+
new IgluCirceClient(resolver, cache)
72+
}
73+
}
74+
75+
private def schemaEvaluationCache[F[_]: InitValidatorCache](
76+
cacheSize: Int
77+
): F[SchemaEvaluationCache[F]] =
78+
CreateLruMap[F, SchemaEvaluationKey, SchemaEvaluationResult].create(cacheSize)
79+
80+
}

0 commit comments

Comments
 (0)