Skip to content

Commit 2f952fd

Browse files
committed
Merge branch 'main' into springboot-4
# Conflicts: # gradle/libs.versions.toml # util/build.gradle.kts
2 parents 98bc2dc + 05355d2 commit 2f952fd

47 files changed

Lines changed: 2361 additions & 22 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
util/build/test-results/test/TEST-*.xml
7878
7979
- name: Upload coverage reports
80-
uses: codecov/codecov-action@v6
80+
uses: codecov/codecov-action@v7
8181
with:
8282
files: build/reports/kover/report.xml
8383
fail_ci_if_error: false

.github/workflows/renovate.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
uses: actions/checkout@v6
3030

3131
- name: Self-hosted Renovate
32-
uses: renovatebot/github-action@v46.1.14
32+
uses: renovatebot/github-action@v46.1.15
3333
with:
3434
configurationFile: .github/renovate-config.js
3535
token: ${{ secrets.RENOVATE_TOKEN }}

gradle/libs.versions.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
[versions]
22
springBoot = "4.0.6"
33
kotlin = "2.2.21"
4-
kotlinCollectionsImmutable = "0.4.0"
4+
kotlinCollectionsImmutable = "0.5.0"
55
zjsonpatch = "0.6.2"
66
jmh = "1.37"
77
jmh-plugin = "0.7.3"
88
kotlinpoet = "2.3.0"
99
ktfmt = "0.61"
10-
fory = "1.0.0"
10+
fory = "1.1.0"
1111

1212
# Caplin Dependencies
13-
datasource = "8.0.11-1836-95c6e774"
13+
datasource = "8.0.12-1871-367ddb14"
1414

1515
# Test Dependencies
1616
kotest = "6.1.11"
1717
turbine = "1.2.1"
18-
mockk = "1.14.9"
18+
mockk = "1.14.11"
1919

2020
# Spring BOM should manage other dependencies versions.
2121

util/README.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,69 @@
33
Utility classes and functions commonly used in DataSource integrations, such as efficiently observable Maps, and stream
44
transformations.
55

6-
@see com.caplin.integration.datasourcex.util.flow.FlowMap
6+
## Key components
7+
8+
### Observable maps and shared flows
9+
10+
| Component | Description |
11+
| --- | --- |
12+
| `FlowMap` / `MutableFlowMap` | A `Map` that is also observable via `asFlow`, `asFlowWithState`, and per-key `valueFlow`. Built with `mutableFlowMapOf` / `toMutableFlowMap`, or collected from an event stream with `flowMapIn`. |
13+
| `CompletingSharedFlow` / `MutableCompletingSharedFlow` | A `SharedFlow` variant that also propagates completion and error events to subscribers. Built with `shareInCompleting`. |
14+
| `SharedFlowCache` | Keyed cache of `SharedFlow`s, sharing one upstream collection per key and evicting a key once its upstream ends so the cache can't grow unbounded. Built with `sharedFlowCache(...)`, or `completingSharedFlowCache(...)` for a `CompletingSharedFlowCache` that propagates completion/errors. |
15+
| `CompletingSharedFlowCache` / `LoadingCompletingSharedFlowCache` | Keyed cache of `CompletingSharedFlow`s, sharing one underlying collection per key. |
16+
17+
### Stores
18+
19+
| Component | Description |
20+
| --- | --- |
21+
| `FlowStore` / `MutableFlowStore` | A store-backed map exposing a delta-only stream plus a read-through, Caffeine-bounded cache. Built with `flowStore` / `flowStoreIn` / `mutableFlowStore`. |
22+
| `AsyncFlowStore` / `AsyncMutableFlowStore` | Suspending views of the stores whose reads/writes dispatch the store I/O themselves. |
23+
| `Store` / `StoreReader` / `StoreWriter` | The SPI you implement to back a `MutableFlowStore`; mutations enlist on the caller's transaction and publish on commit. |
24+
| `TxContext` / `Versioned` | The transaction handle a write enlists on, and a value paired with the store-assigned version. |
25+
26+
### Flow operators
27+
28+
| Operator | Description |
29+
| --- | --- |
30+
| `bufferingDebounce` | Buffers elements until a quiet period elapses, then emits them as a `List`. |
31+
| `throttleLatest` | Emits at most once per interval, keeping the latest value and dropping older ones. |
32+
| `flatMapFirst` | Applies a function to the first element together with the entire upstream flow. |
33+
| `demultiplexBy` | Groups elements by a key selector and processes each group's sub-flow. |
34+
| `retryWithExponentialBackoff` | Retries the upstream on error with an exponential delay between attempts. |
35+
| `cast` | Casts a `Flow<*>` to a `Flow<T>`. |
36+
| `timeoutFirst` / `timeoutFirstOrNull` / `timeoutFirstOrDefault` | Errors / emits null / emits a default if no first element arrives within a timeout. |
37+
| `materialize` / `dematerialize` (and `*Unboxed`) | Convert between flow values and `ValueOrCompletion` events. |
38+
39+
### Event models and folds
40+
41+
| Component | Description |
42+
| --- | --- |
43+
| `MapEvent` / `SimpleMapEvent` / `SetEvent` / `VersionedMapEvent` | Sealed event types describing map and set mutations (with or without old values / versions). |
44+
| `FlowMapStreamEvent` / `ValueOrCompletion` | Materialised stream events: initial-state-plus-deltas, and value-or-terminal-signal. |
45+
| `runningFoldToMap*` / `runningFoldToSet` | Fold a delta stream into a live `Flow` of map / set snapshots. |
46+
| `conflateKeys` / `toEvents` | Collapse per-key updates, and expand a collection stream into entry events. |
47+
48+
### Serialization
49+
50+
| Component | Description |
51+
| --- | --- |
52+
| `registerDataSourceSerializers` / `registerPersistentCollectionSerializers` | Register Fory serializers for the event types and persistent collections. |
53+
| `DataSourceModule`, `registerDataSourceModule` / `addDataSourceModule` | Jackson 2 / Jackson 3 modules that serialize the event types without annotations. |
54+
| `Jackson2JsonHandler` / `Jackson3JsonHandler` | `JsonHandler` implementations backed by a Jackson `ObjectMapper`. |
55+
56+
### DataSource and general utilities
57+
58+
| Component | Description |
59+
| --- | --- |
60+
| `AntPatternNamespace` | A `Namespace` matching subjects by Ant-style patterns, with path-variable extraction. |
61+
| `SimpleDataSourceFactory` / `SimpleDataSourceConfig` | Build a `DataSource` from a simplified config for tests and examples. |
62+
| `KLogger` | An slf4j `Logger` wrapper with lazily-evaluated message lambdas. |
63+
| `ReadWriteLock` | A non-reentrant suspending read/write lock. |
64+
| `withTimeout` | A coroutine timeout that throws `TimeoutException` rather than a `CancellationException`. |
65+
66+
@see com.caplin.integration.datasourcex.util.flow.FlowMap
67+
@see com.caplin.integration.datasourcex.util.store.MutableFlowStore
68+
69+
Participating in an application-owned jOOQ transaction:
70+
71+
@sample samples.StoreSamples.jooqSample

util/api/datasourcex-util.api

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,11 @@ public abstract interface class com/caplin/integration/datasourcex/util/flow/Flo
185185
}
186186

187187
public final class com/caplin/integration/datasourcex/util/flow/FlowMapKt {
188+
public static final fun flowMapIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
188189
public static final fun mutableFlowMapOf ()Lcom/caplin/integration/datasourcex/util/flow/MutableFlowMap;
189190
public static final fun mutableFlowMapOf ([Lkotlin/Pair;)Lcom/caplin/integration/datasourcex/util/flow/MutableFlowMap;
190191
public static final fun runningFoldToMapFlowMapStreamEvent (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
192+
public static final fun simpleFlowMapIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
191193
public static final fun simpleToFlowMapIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
192194
public static final fun toFlowMapIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
193195
public static final fun toMutableFlowMap (Ljava/util/Map;)Lcom/caplin/integration/datasourcex/util/flow/MutableFlowMap;
@@ -371,6 +373,17 @@ public final class com/caplin/integration/datasourcex/util/flow/SetEventKt {
371373
public static final fun toEvents (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
372374
}
373375

376+
public final class com/caplin/integration/datasourcex/util/flow/SharedFlowCache {
377+
public final fun get (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/SharedFlow;
378+
}
379+
380+
public final class com/caplin/integration/datasourcex/util/flow/SharedFlowCacheKt {
381+
public static final fun completingSharedFlowCache (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;I)Lcom/caplin/integration/datasourcex/util/flow/CompletingSharedFlowCache;
382+
public static synthetic fun completingSharedFlowCache$default (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;IILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/flow/CompletingSharedFlowCache;
383+
public static final fun sharedFlowCache (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;I)Lcom/caplin/integration/datasourcex/util/flow/SharedFlowCache;
384+
public static synthetic fun sharedFlowCache$default (Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;IILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/flow/SharedFlowCache;
385+
}
386+
374387
public abstract interface class com/caplin/integration/datasourcex/util/flow/SimpleMapEvent {
375388
}
376389

@@ -464,6 +477,39 @@ public final class com/caplin/integration/datasourcex/util/flow/ValueOrCompletio
464477
public static final fun materializeUnboxed (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow;
465478
}
466479

480+
public abstract interface class com/caplin/integration/datasourcex/util/flow/VersionedMapEvent {
481+
public abstract fun getKey ()Ljava/lang/Object;
482+
public abstract fun getVersion ()J
483+
}
484+
485+
public final class com/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Removed : com/caplin/integration/datasourcex/util/flow/VersionedMapEvent {
486+
public fun <init> (Ljava/lang/Object;J)V
487+
public final fun component1 ()Ljava/lang/Object;
488+
public final fun component2 ()J
489+
public final fun copy (Ljava/lang/Object;J)Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Removed;
490+
public static synthetic fun copy$default (Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Removed;Ljava/lang/Object;JILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Removed;
491+
public fun equals (Ljava/lang/Object;)Z
492+
public fun getKey ()Ljava/lang/Object;
493+
public fun getVersion ()J
494+
public fun hashCode ()I
495+
public fun toString ()Ljava/lang/String;
496+
}
497+
498+
public final class com/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Upsert : com/caplin/integration/datasourcex/util/flow/VersionedMapEvent {
499+
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;J)V
500+
public final fun component1 ()Ljava/lang/Object;
501+
public final fun component2 ()Ljava/lang/Object;
502+
public final fun component3 ()J
503+
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;J)Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Upsert;
504+
public static synthetic fun copy$default (Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Upsert;Ljava/lang/Object;Ljava/lang/Object;JILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/flow/VersionedMapEvent$Upsert;
505+
public fun equals (Ljava/lang/Object;)Z
506+
public fun getKey ()Ljava/lang/Object;
507+
public final fun getValue ()Ljava/lang/Object;
508+
public fun getVersion ()J
509+
public fun hashCode ()I
510+
public fun toString ()Ljava/lang/String;
511+
}
512+
467513
public final class com/caplin/integration/datasourcex/util/serialization/fory/DataSourceModuleKt {
468514
public static final fun registerDataSourceSerializers (Lorg/apache/fory/Fory;Z)Lorg/apache/fory/Fory;
469515
public static synthetic fun registerDataSourceSerializers$default (Lorg/apache/fory/Fory;ZILjava/lang/Object;)Lorg/apache/fory/Fory;
@@ -518,3 +564,100 @@ public final class com/caplin/integration/datasourcex/util/serialization/jackson
518564
public fun toObject (Ltools/jackson/databind/JsonNode;Ljava/lang/Class;)Ljava/lang/Object;
519565
}
520566

567+
public abstract interface class com/caplin/integration/datasourcex/util/store/AsyncFlowStore {
568+
public abstract fun asFlow ()Lkotlinx/coroutines/flow/SharedFlow;
569+
public abstract fun asFlow (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
570+
public static synthetic fun asFlow$default (Lcom/caplin/integration/datasourcex/util/store/AsyncFlowStore;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
571+
public abstract fun get (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
572+
public abstract fun valueFlow (Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
573+
}
574+
575+
public final class com/caplin/integration/datasourcex/util/store/AsyncFlowStore$DefaultImpls {
576+
public static synthetic fun asFlow$default (Lcom/caplin/integration/datasourcex/util/store/AsyncFlowStore;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
577+
}
578+
579+
public abstract interface class com/caplin/integration/datasourcex/util/store/AsyncMutableFlowStore : com/caplin/integration/datasourcex/util/store/AsyncFlowStore {
580+
public abstract fun get (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
581+
public abstract fun put (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
582+
public abstract fun putAll (Ljava/util/Map;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
583+
public abstract fun remove (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
584+
}
585+
586+
public abstract interface class com/caplin/integration/datasourcex/util/store/FlowStore {
587+
public abstract fun asFlow ()Lkotlinx/coroutines/flow/SharedFlow;
588+
public abstract fun asFlow (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
589+
public static synthetic fun asFlow$default (Lcom/caplin/integration/datasourcex/util/store/FlowStore;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
590+
public abstract fun get (Ljava/lang/Object;)Ljava/lang/Object;
591+
public abstract fun getAsync ()Lcom/caplin/integration/datasourcex/util/store/AsyncFlowStore;
592+
public abstract fun valueFlow (Ljava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
593+
}
594+
595+
public final class com/caplin/integration/datasourcex/util/store/FlowStore$DefaultImpls {
596+
public static synthetic fun asFlow$default (Lcom/caplin/integration/datasourcex/util/store/FlowStore;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/flow/Flow;
597+
}
598+
599+
public final class com/caplin/integration/datasourcex/util/store/FlowStoreKt {
600+
public static final fun flowStore (Lcom/caplin/integration/datasourcex/util/store/StoreReader;Lkotlinx/coroutines/flow/Flow;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineDispatcher;I)Lcom/caplin/integration/datasourcex/util/store/FlowStore;
601+
public static synthetic fun flowStore$default (Lcom/caplin/integration/datasourcex/util/store/StoreReader;Lkotlinx/coroutines/flow/Flow;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineDispatcher;IILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/store/FlowStore;
602+
public static final fun flowStoreIn (Lkotlinx/coroutines/flow/Flow;Lcom/caplin/integration/datasourcex/util/store/StoreReader;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineDispatcher;I)Lcom/caplin/integration/datasourcex/util/store/FlowStore;
603+
public static synthetic fun flowStoreIn$default (Lkotlinx/coroutines/flow/Flow;Lcom/caplin/integration/datasourcex/util/store/StoreReader;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/CoroutineDispatcher;IILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/store/FlowStore;
604+
}
605+
606+
public abstract interface class com/caplin/integration/datasourcex/util/store/MutableFlowStore : com/caplin/integration/datasourcex/util/store/FlowStore {
607+
public abstract fun get (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
608+
public abstract fun getAsync ()Lcom/caplin/integration/datasourcex/util/store/AsyncMutableFlowStore;
609+
public abstract fun put (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
610+
public abstract fun putAll (Ljava/util/Map;Ljava/lang/Object;)V
611+
public abstract fun remove (Ljava/lang/Object;Ljava/lang/Object;)V
612+
}
613+
614+
public final class com/caplin/integration/datasourcex/util/store/MutableFlowStoreKt {
615+
public static final fun mutableFlowStore (Lcom/caplin/integration/datasourcex/util/store/Store;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;)Lcom/caplin/integration/datasourcex/util/store/MutableFlowStore;
616+
public static synthetic fun mutableFlowStore$default (Lcom/caplin/integration/datasourcex/util/store/Store;Lcom/github/benmanes/caffeine/cache/Caffeine;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/store/MutableFlowStore;
617+
}
618+
619+
public abstract interface class com/caplin/integration/datasourcex/util/store/Store : com/caplin/integration/datasourcex/util/store/StoreReader, com/caplin/integration/datasourcex/util/store/StoreWriter {
620+
}
621+
622+
public final class com/caplin/integration/datasourcex/util/store/Store$DefaultImpls {
623+
public static fun writeAll (Lcom/caplin/integration/datasourcex/util/store/Store;Ljava/util/Map;Lcom/caplin/integration/datasourcex/util/store/TxContext;)Ljava/util/Map;
624+
}
625+
626+
public abstract interface class com/caplin/integration/datasourcex/util/store/StoreReader {
627+
public abstract fun load (Ljava/lang/Object;)Lcom/caplin/integration/datasourcex/util/store/Versioned;
628+
}
629+
630+
public abstract interface class com/caplin/integration/datasourcex/util/store/StoreWriter {
631+
public abstract fun delete (Ljava/lang/Object;Lcom/caplin/integration/datasourcex/util/store/TxContext;)J
632+
public abstract fun load (Ljava/lang/Object;Lcom/caplin/integration/datasourcex/util/store/TxContext;)Lcom/caplin/integration/datasourcex/util/store/Versioned;
633+
public abstract fun write (Ljava/lang/Object;Ljava/lang/Object;Lcom/caplin/integration/datasourcex/util/store/TxContext;)J
634+
public fun writeAll (Ljava/util/Map;Lcom/caplin/integration/datasourcex/util/store/TxContext;)Ljava/util/Map;
635+
}
636+
637+
public final class com/caplin/integration/datasourcex/util/store/StoreWriter$DefaultImpls {
638+
public static fun writeAll (Lcom/caplin/integration/datasourcex/util/store/StoreWriter;Ljava/util/Map;Lcom/caplin/integration/datasourcex/util/store/TxContext;)Ljava/util/Map;
639+
}
640+
641+
public abstract interface class com/caplin/integration/datasourcex/util/store/TxContext {
642+
public abstract fun getTransaction ()Ljava/lang/Object;
643+
public abstract fun onCommitEnd (Lkotlin/jvm/functions/Function0;)V
644+
public fun onRollback (Lkotlin/jvm/functions/Function0;)V
645+
}
646+
647+
public final class com/caplin/integration/datasourcex/util/store/TxContext$DefaultImpls {
648+
public static fun onRollback (Lcom/caplin/integration/datasourcex/util/store/TxContext;Lkotlin/jvm/functions/Function0;)V
649+
}
650+
651+
public final class com/caplin/integration/datasourcex/util/store/Versioned {
652+
public fun <init> (Ljava/lang/Object;J)V
653+
public final fun component1 ()Ljava/lang/Object;
654+
public final fun component2 ()J
655+
public final fun copy (Ljava/lang/Object;J)Lcom/caplin/integration/datasourcex/util/store/Versioned;
656+
public static synthetic fun copy$default (Lcom/caplin/integration/datasourcex/util/store/Versioned;Ljava/lang/Object;JILjava/lang/Object;)Lcom/caplin/integration/datasourcex/util/store/Versioned;
657+
public fun equals (Ljava/lang/Object;)Z
658+
public final fun getValue ()Ljava/lang/Object;
659+
public final fun getVersion ()J
660+
public fun hashCode ()I
661+
public fun toString ()Ljava/lang/String;
662+
}
663+

0 commit comments

Comments
 (0)