From 8b2f73eb4c5f5f6ec29067f68490fed10dbf97d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 21 Apr 2023 22:15:44 +0200 Subject: [PATCH 1/4] upgrade: Kotlin 1.8.20 --- versions.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.properties b/versions.properties index 92c982e..2c27780 100644 --- a/versions.properties +++ b/versions.properties @@ -11,7 +11,7 @@ version.arrow=1.2.0-RC version.ch.qos.logback..logback-classic=1.4.5 -version.kotlin=1.8.10 +version.kotlin=1.8.20 version.kotlinx.coroutines=1.6.4 -- 2.51.2 From a35898a70483e564fb4ec24c8ea382e18dd1d3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 21 Apr 2023 22:39:52 +0200 Subject: [PATCH 2/4] tests(spine): Fix the ParametersTest on JS --- spine/src/commonTest/kotlin/ParametersTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spine/src/commonTest/kotlin/ParametersTest.kt b/spine/src/commonTest/kotlin/ParametersTest.kt index 584bb7b..d83196f 100644 --- a/spine/src/commonTest/kotlin/ParametersTest.kt +++ b/spine/src/commonTest/kotlin/ParametersTest.kt @@ -139,8 +139,8 @@ class ParametersTest { "uint" to "7", "ulong" to "8", - "float" to "9.0", - "double" to "10.0", + "float" to "${9.0}", // JVM: "9.0" — JS: "9" + "double" to "${10.0}", ), params.data ) } -- 2.51.2 From cecd678e34a0f4cb682f26eab3455b11034ef960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 21 Apr 2023 22:40:49 +0200 Subject: [PATCH 3/4] tests(state): Declare the lock owner to ease debugging --- .../kotlin/failure/FailureEndToEndTest.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/state/src/commonTest/kotlin/failure/FailureEndToEndTest.kt b/state/src/commonTest/kotlin/failure/FailureEndToEndTest.kt index 65f262c..5a737ad 100644 --- a/state/src/commonTest/kotlin/failure/FailureEndToEndTest.kt +++ b/state/src/commonTest/kotlin/failure/FailureEndToEndTest.kt @@ -56,7 +56,7 @@ class FailureEndToEndTest { val newId = Id(Random.nextInt()) - lock.withLock { + lock.withLock("create() by ${context.user}") { data[newId] = Counter(context.user, 0, emptySet()) } @@ -66,7 +66,7 @@ class FailureEndToEndTest { suspend fun list(context: Context) = out> { ensureNotNull(context.user) { Failures.Unauthenticated } - lock.withLock { + lock.withLock("list() by ${context.user}") { val user: User = context.user data @@ -80,7 +80,7 @@ class FailureEndToEndTest { suspend fun get(context: Context, id: Id) = out { ensureNotNull(context.user) { Failures.Unauthenticated } - val counter = lock.withLock { data[id] } + val counter = lock.withLock("get($id) by ${context.user}") { data[id] } ensureNotNull(counter) { Failures.NotFound(id) } ensure(counter.readableBy(context.user)) { Failures.NotFound(id) } // Do not tell the user why they cannot see it @@ -93,7 +93,9 @@ class FailureEndToEndTest { ensure(context.user == counter.owner) { Failures.NotTheOwner(id) } // Possible data race here, but it's an imaginary example, so it's not a big deal - lock.withLock { data[id] = counter.copy(value = counter.value + 1) } + lock.withLock("increment($id) by ${context.user}") { + data[id] = counter.copy(value = counter.value + 1) + } } // Imagine there is also a 'decrement' method @@ -104,7 +106,9 @@ class FailureEndToEndTest { ensure(context.user == counter.owner) { Failures.NotTheOwner(id) } // Possible data race here, but it's an imaginary example, so it's not a big deal - lock.withLock { data[id] = counter.copy(canRead = counter.canRead + user) } + lock.withLock("share($id, $user) by ${context.user}") { + data[id] = counter.copy(canRead = counter.canRead + user) + } } // Imagine there is also a 'unshare' method -- 2.51.2 From 7bb8bdc63f8d37046b9c4e8b6e0b5e27d6c8d563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 21 Apr 2023 22:45:54 +0200 Subject: [PATCH 4/4] refactor(backbone): Remove Backbone.request It is a duplicate of Ref.request. In practice, it is better to let the user choose if they want to create the method in the backbone too. --- backbone/README.md | 21 ++++++++----------- backbone/src/commonMain/kotlin/Backbone.kt | 10 +-------- backbone/src/commonMain/kotlin/Ref.kt | 5 +++-- .../commonTest/kotlin/BackboneCacheTest.kt | 4 +--- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/backbone/README.md b/backbone/README.md index 278a59c..6611820 100644 --- a/backbone/README.md +++ b/backbone/README.md @@ -121,15 +121,12 @@ data class Score( // The service implements the Backbone interface. interface Service : Backbone { - - // The Backbone interface adds a 'request' method - // to access the value behind a reference. // Methods should: // - only accept/return references, and not actual values - // (this is necessary to ensure the cache catches all requests, - // the 'request' method should be the only one which returns - // a real object). + // (this is necessary to ensure the cache catches all requests, + // the 'Ref.request' method should be the only one which returns + // a real object). // - return an Outcome or ProgressiveOutcome instance for error management // (see the documentation of Pedestal State). // ProgressiveFlow is used for cacheable read operations. @@ -180,8 +177,8 @@ optional `arrow-state` dependency to profit from Arrow's typed error DSL. import sun.jvm.hotspot.oops.CellTypeState.refimport java.sql.Refimport kotlin.coroutines.CoroutineScope class ClientScoreRef( - internal val id: String, - override val backbone: ClientScores, + internal val id: String, + private val backbone: ClientScores, ) : Score.Ref { // Provide convenience functions to act on this reference. @@ -207,11 +204,11 @@ class ClientScores( } } .cachedInMemory(cacheScope.job) - .expireAfter(15.minutes, cacheScope) + .expireAfter(15.minutes, cacheScope) - override fun request(ref: ClientScoreRef) = cache[ref] - - override suspend fun increment(score: ClientScoreRef, amount: Int) = out { + fun request(ref: ClientScoreRef) = cache[ref] + + override suspend fun increment(score: ClientScoreRef, amount: Int) = out { client.post("http://localhost:8080/${score.id}?amount=$amount") // We know the score was just modified, we thus clean the cache. diff --git a/backbone/src/commonMain/kotlin/Backbone.kt b/backbone/src/commonMain/kotlin/Backbone.kt index d53520e..059961b 100644 --- a/backbone/src/commonMain/kotlin/Backbone.kt +++ b/backbone/src/commonMain/kotlin/Backbone.kt @@ -1,6 +1,5 @@ package opensavvy.backbone -import opensavvy.state.coroutines.ProgressiveFlow import opensavvy.state.failure.Failure /** @@ -9,17 +8,10 @@ import opensavvy.state.failure.Failure * For more information on the Backbone pattern, please read the module-level documentation. * * @param O The object this backbone manages. - * @param F Failures that may be returned when calling [request]. + * @param F Failures that may be returned when calling [Ref.request]. * @param R The reference responsible for the object [O]. */ interface Backbone, F : Failure, O> { - /** - * Fetches the value associated with a [ref] in an external media (e.g. a remote server, a database). - * - * This function may return cached results. - */ - fun request(ref: R): ProgressiveFlow - companion object } diff --git a/backbone/src/commonMain/kotlin/Ref.kt b/backbone/src/commonMain/kotlin/Ref.kt index b4efbbc..1b0d0b5 100644 --- a/backbone/src/commonMain/kotlin/Ref.kt +++ b/backbone/src/commonMain/kotlin/Ref.kt @@ -1,5 +1,6 @@ package opensavvy.backbone +import opensavvy.cache.Cache import opensavvy.state.coroutines.ProgressiveFlow import opensavvy.state.coroutines.now import opensavvy.state.failure.Failure @@ -26,9 +27,9 @@ import opensavvy.state.failure.Failure interface Ref { /** - * Requests the referenced data, returning a value from the cache if one is stored. + * Requests the referenced data. * - * It is common to implement this method by calling [Backbone.request]. + * It is encouraged, but not mandatory, to implement this method using [Cache]. */ fun request(): ProgressiveFlow diff --git a/backbone/src/commonTest/kotlin/BackboneCacheTest.kt b/backbone/src/commonTest/kotlin/BackboneCacheTest.kt index 8741b6e..5c8f6f9 100644 --- a/backbone/src/commonTest/kotlin/BackboneCacheTest.kt +++ b/backbone/src/commonTest/kotlin/BackboneCacheTest.kt @@ -17,7 +17,7 @@ class BackboneCacheTest { data class BasicRef(val id: String, val backbone: Bone) : Ref { - override fun request() = backbone.request(this) + override fun request() = backbone.cache[this] } // Id("12") -> 12 @@ -30,8 +30,6 @@ class BackboneCacheTest { } } - override fun request(ref: BasicRef) = cache[ref] - fun of(int: Int) = BasicRef(int.toString(), this) object Invalid : CustomFailure(Invalid, "Invalid"), Failure.Key -- 2.51.2