Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit 0837873

Browse files
committed
feat: enhance whitelist functionality and transaction handling
- Refactored whitelist handling by replacing separate group and server fields with `Either<String, String>`. - Added support for cascading updates in multiple tables and associated migrations. - Introduced `CoroutineTxContextProvider` to manage coroutine transaction contexts dynamically. - Updated dependencies (`spring-boot` to 3.5.4, `surf-api-gradle-plugin` to 1.21.8). - Improved cache handling with Caffeine for annotations and transaction providers. - General code cleanup and removed unused imports.
1 parent 812f598 commit 0837873

File tree

29 files changed

+588
-282
lines changed

29 files changed

+588
-282
lines changed

build.gradle.kts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
22
import dev.slne.surf.surfapi.gradle.util.slnePublic
3-
import jdk.javadoc.internal.tool.resources.javadoc
43
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmExtension
54

65
buildscript {
@@ -9,7 +8,7 @@ buildscript {
98
maven("https://repo.slne.dev/repository/maven-public/") { name = "maven-public" }
109
}
1110
dependencies {
12-
classpath("dev.slne.surf:surf-api-gradle-plugin:1.21.7+")
11+
classpath("dev.slne.surf:surf-api-gradle-plugin:1.21.8+")
1312
}
1413
}
1514

@@ -41,7 +40,7 @@ allprojects {
4140

4241
implementation(platform(project(":surf-cloud-bom")))
4342

44-
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.3")
43+
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.4")
4544
// "kapt"("org.springframework.boot:spring-boot-configuration-processor:3.4.3")
4645

4746
testImplementation(kotlin("test"))

buildSrc/src/main/kotlin/core-convention.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ repositories {
1212
}
1313

1414
dependencies {
15-
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.5.3"))
15+
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.5.4"))
1616
implementation(platform("io.ktor:ktor-bom:3.2.1"))
1717
implementation(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:2025.7.8"))
1818

gradle.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ kotlin.code.style=official
66
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
77
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
88
version=1.21.7-1.0.0-SNAPSHOT
9+
ksp.incremental=false
10+
ksp.incremental.log=true
11+
ksp.useKSP2=false

gradle/wrapper/gradle-wrapper.jar

1.65 KB
Binary file not shown.

gradlew

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/sh
22

33
#
4-
# Copyright © 2015-2021 the original authors.
4+
# Copyright © 2015 the original authors.
55
#
66
# Licensed under the Apache License, Version 2.0 (the "License");
77
# you may not use this file except in compliance with the License.
Lines changed: 236 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,275 @@
11
package dev.slne.surf.cloud.api.common.util
22

3+
import dev.slne.surf.cloud.api.common.util.Either.Companion.left
4+
import dev.slne.surf.cloud.api.common.util.Either.Companion.right
5+
import kotlinx.serialization.SerialName
36
import kotlinx.serialization.Serializable
47

8+
/**
9+
* Represents a value of one of two possible types.
10+
* An [Either] is either a [Left] containing a value of type [L],
11+
* or a [Right] containing a value of type [R].
12+
*
13+
* This implementation is **neutral**: neither side implies success or failure.
14+
* It is useful whenever a value can be one of two distinct, equally valid types.
15+
*
16+
* @param L the type of the left value.
17+
* @param R the type of the right value.
18+
* @property left the left value if present, otherwise `null`.
19+
* @property right the right value if present, otherwise `null`.
20+
*/
521
@Serializable
622
sealed class Either<L, R> {
723

8-
abstract fun <C, D> mapBoth(
9-
leftMapper: (L) -> C,
10-
rightMapper: (R) -> D
11-
): Either<C, D>
12-
13-
abstract fun <T> map(leftMapper: (L) -> T, rightMapper: (R) -> T): T
14-
24+
/** The left value if present, otherwise `null`. */
1525
abstract val left: L?
26+
27+
/** The right value if present, otherwise `null`. */
1628
abstract val right: R?
1729

18-
fun <T> mapLeft(mapper: (L) -> T): Either<T, R> = map({ left(mapper(it)) }, ::right)
19-
fun <T> mapRight(mapper: (R) -> T): Either<L, T> = map(::left) { right(mapper(it)) }
30+
/**
31+
* Indicates whether this instance holds a left value.
32+
*
33+
* @return `true` if this is a [Left]; `false` otherwise.
34+
*/
35+
val isLeft: Boolean get() = left != null
2036

21-
fun leftOrThrow(): L {
22-
return left ?: throw NoSuchElementException("Either is Right, no Left value present")
23-
}
37+
/**
38+
* Indicates whether this instance holds a right value.
39+
*
40+
* @return `true` if this is a [Right]; `false` otherwise.
41+
*/
42+
val isRight: Boolean get() = right != null
2443

25-
fun rightOrThrow(): R {
26-
return right ?: throw NoSuchElementException("Either is Left, no Right value present")
27-
}
44+
/**
45+
* Returns the left value if present.
46+
*
47+
* @return the non-null left value.
48+
* @throws NoSuchElementException if no left value is present.
49+
*/
50+
fun leftOrThrow(): L = left ?: throw NoSuchElementException("Either contains no left value")
2851

29-
fun swap(): Either<R, L> = map(::right, ::left)
30-
fun <L2> flatMap(leftMapper: (L) -> Either<L2, R>): Either<L2, R> = map(leftMapper, ::right)
52+
/**
53+
* Returns the right value if present.
54+
*
55+
* @return the non-null right value.
56+
* @throws NoSuchElementException if no right value is present.
57+
*/
58+
fun rightOrThrow(): R = right ?: throw NoSuchElementException("Either contains no right value")
3159

32-
companion object {
33-
fun <L, R> left(value: L): Either<L, R> = Left(value)
34-
fun <L, R> right(value: R): Either<L, R> = Right(value)
35-
fun <U> unwrap(either: Either<out U, out U>): U = either.map({ it }, { it })
36-
}
60+
/**
61+
* Returns the left value or `null` if absent.
62+
*
63+
* @return the left value, or `null` if this is a [Right].
64+
*/
65+
fun leftOrNull(): L? = left
3766

38-
@PublishedApi
39-
@Serializable
40-
internal class Left<L, R>(override val left: L) : Either<L, R>() {
41-
@Transient
42-
override val right: R? = null
43-
44-
override fun <C, D> mapBoth(
45-
leftMapper: (L) -> C,
46-
rightMapper: (R) -> D
47-
): Either<C, D> = Left(leftMapper(left))
67+
/**
68+
* Returns the right value or `null` if absent.
69+
*
70+
* @return the right value, or `null` if this is a [Left].
71+
*/
72+
fun rightOrNull(): R? = right
4873

49-
override fun <T> map(leftMapper: (L) -> T, rightMapper: (R) -> T): T = leftMapper(left)
74+
/**
75+
* Returns the left value if present, otherwise computes a default.
76+
*
77+
* @param default a function invoked to produce a value when no left value is present.
78+
* @return the left value or the result of [default].
79+
*/
80+
inline fun getLeftOrElse(default: () -> L): L = left ?: default()
5081

51-
override fun toString(): String = "Either.Left($left)"
82+
/**
83+
* Returns the right value if present, otherwise computes a default.
84+
*
85+
* @param default a function invoked to produce a value when no right value is present.
86+
* @return the right value or the result of [default].
87+
*/
88+
inline fun getRightOrElse(default: () -> R): R = right ?: default()
5289

53-
override fun equals(other: Any?): Boolean {
54-
if (this === other) return true
55-
if (other !is Left<*, *>) return false
90+
/**
91+
* Applies one of the given functions based on which side is present and returns its result.
92+
*
93+
* @param T the result type.
94+
* @param ifLeft function to apply when this is a [Left].
95+
* @param ifRight function to apply when this is a [Right].
96+
* @return the result of applying the appropriate function.
97+
*/
98+
inline fun <T> fold(ifLeft: (L) -> T, ifRight: (R) -> T): T = when (this) {
99+
is Left -> ifLeft(left)
100+
is Right -> ifRight(right)
101+
}
56102

57-
if (left != other.left) return false
103+
/**
104+
* Alias for [fold]. Transforms the contained value to a single common type.
105+
*
106+
* @param T the result type.
107+
* @param ifLeft function to apply when this is a [Left].
108+
* @param ifRight function to apply when this is a [Right].
109+
* @return the result of applying the appropriate function.
110+
*/
111+
inline fun <T> map(ifLeft: (L) -> T, ifRight: (R) -> T): T = fold(ifLeft, ifRight)
58112

59-
return true
113+
/**
114+
* Transforms both possible sides independently and returns a new [Either] with the mapped types.
115+
*
116+
* @param L2 the mapped left type.
117+
* @param R2 the mapped right type.
118+
* @param leftMapper function to apply to the left value.
119+
* @param rightMapper function to apply to the right value.
120+
* @return a new [Either] containing the transformed value.
121+
*/
122+
inline fun <L2, R2> mapBoth(leftMapper: (L) -> L2, rightMapper: (R) -> R2): Either<L2, R2> =
123+
when (this) {
124+
is Left -> Left(leftMapper(left))
125+
is Right -> Right(rightMapper(right))
60126
}
61127

62-
override fun hashCode(): Int {
63-
return left?.hashCode() ?: 0
64-
}
128+
/**
129+
* Transforms the left value if present, keeping the right value as-is.
130+
*
131+
* @param L2 the mapped left type.
132+
* @param leftMapper function to apply to the left value.
133+
* @return a new [Either] with the transformed left type.
134+
*/
135+
inline fun <L2> mapLeft(leftMapper: (L) -> L2): Either<L2, R> = when (this) {
136+
is Left -> Left(leftMapper(left))
137+
is Right -> Right(right)
65138
}
66139

140+
/**
141+
* Transforms the right value if present, keeping the left value as-is.
142+
*
143+
* @param R2 the mapped right type.
144+
* @param rightMapper function to apply to the right value.
145+
* @return a new [Either] with the transformed right type.
146+
*/
147+
inline fun <R2> mapRight(rightMapper: (R) -> R2): Either<L, R2> = when (this) {
148+
is Left -> Left(left)
149+
is Right -> Right(rightMapper(right))
150+
}
67151

68-
@Serializable
69-
@PublishedApi
70-
internal class Right<L, R>(override val right: R) : Either<L, R>() {
71-
@Transient
72-
override val left: L? = null
152+
/**
153+
* Swaps the sides of this instance: left becomes right and vice versa.
154+
*
155+
* @return a new [Either] with left and right values swapped.
156+
*/
157+
fun swap(): Either<R, L> = fold(::right, ::left)
73158

74-
override fun <C, D> mapBoth(
75-
leftMapper: (L) -> C,
76-
rightMapper: (R) -> D
77-
): Either<C, D> = Right(rightMapper(right))
159+
/**
160+
* Executes [action] only when this is a [Left], then returns this instance for chaining.
161+
*
162+
* @param action the side-effect to perform on the left value.
163+
* @return this instance.
164+
*/
165+
inline fun ifLeft(action: (L) -> Unit): Either<L, R> {
166+
if (this is Left) action(left)
167+
return this
168+
}
78169

79-
override fun <T> map(leftMapper: (L) -> T, rightMapper: (R) -> T): T = rightMapper(right)
80170

81-
override fun toString(): String = "Either.Right($right)"
171+
/**
172+
* Executes [action] only when this is a [Right], then returns this instance for chaining.
173+
*
174+
* @param action the side-effect to perform on the right value.
175+
* @return this instance.
176+
*/
177+
inline fun ifRight(action: (R) -> Unit): Either<L, R> {
178+
if (this is Right) action(right)
179+
return this
180+
}
82181

83-
override fun equals(other: Any?): Boolean {
84-
if (this === other) return true
85-
if (other !is Right<*, *>) return false
182+
/**
183+
* Combines two [Either] values **only if** they are of the same side type.
184+
*
185+
* If both are [Left], [combineLeft] is used. If both are [Right], [combineRight] is used.
186+
* If they differ, this instance is returned unchanged.
187+
*
188+
* @param L2 the left type of [other].
189+
* @param R2 the right type of [other].
190+
* @param other the other [Either] to combine with.
191+
* @param combineLeft function to combine two left values into one.
192+
* @param combineRight function to combine two right values into one.
193+
* @return a combined [Either] when sides match; otherwise this instance.
194+
*/
195+
inline fun <L2, R2> zipSame(
196+
other: Either<L2, R2>,
197+
combineLeft: (L, L2) -> L,
198+
combineRight: (R, R2) -> R
199+
): Either<L, R> = when (this) {
200+
is Left if other is Left -> Left(combineLeft(this.left, other.left))
201+
is Right if other is Right -> Right(combineRight(this.right, other.right))
202+
else -> this
203+
}
86204

87-
if (right != other.right) return false
205+
/**
206+
* Applies [leftMapper] when this is a [Left]; returns the right side unchanged otherwise.
207+
*
208+
* @param L2 the mapped left type.
209+
* @param leftMapper function transforming the left value into another [Either].
210+
* @return the mapped [Either] when left; otherwise the unchanged right side.
211+
*/
212+
fun <L2> flatMap(leftMapper: (L) -> Either<L2, R>): Either<L2, R> = map(leftMapper, ::right)
88213

89-
return true
90-
}
214+
companion object {
215+
216+
/**
217+
* Creates an [Either] containing the given left value.
218+
*
219+
* @param value the value to store on the left side.
220+
* @return an [Either] representing [value] as [Left].
221+
*/
222+
fun <L, R> left(value: L): Either<L, R> = Left(value)
223+
224+
/**
225+
* Creates an [Either] containing the given right value.
226+
*
227+
* @param value the value to store on the right side.
228+
* @return an [Either] representing [value] as [Right].
229+
*/
230+
fun <L, R> right(value: R): Either<L, R> = Right(value)
231+
232+
/**
233+
* Unwraps an [Either] whose left and right types are identical.
234+
*
235+
* @param either the [Either] instance to unwrap.
236+
* @param U the common value type.
237+
* @return the contained value regardless of side.
238+
*/
239+
fun <U> unwrap(either: Either<out U, out U>): U = either.fold({ it }, { it })
91240

92-
override fun hashCode(): Int {
93-
return right?.hashCode() ?: 0
241+
/**
242+
* Creates an [Either] from nullable left and right values. Exactly **one** must be non-null.
243+
*
244+
* @param left the candidate left value; may be `null`.
245+
* @param right the candidate right value; may be `null`.
246+
* @return an [Either] containing the single non-null value.
247+
* @throws IllegalStateException if both values are null or both are non-null.
248+
*/
249+
fun <L, R> of(left: L?, right: R?): Either<L, R> = when {
250+
left != null && right == null -> Left(left)
251+
right != null && left == null -> Right(right)
252+
left == null -> error("Either must have a left or right value")
253+
else -> error("Either cannot have both left and right values")
94254
}
95255
}
96-
}
97256

98-
inline fun <L, R> Either<L, R>.ifLeft(action: (L) -> Unit): Either<L, R> {
99-
if (this is Either.Left) {
100-
action(left)
257+
@PublishedApi
258+
@Serializable
259+
@SerialName("left")
260+
internal data class Left<L, R>(override val left: L) : Either<L, R>() {
261+
@Transient
262+
override val right: R? = null
263+
override fun toString(): String = "Either.Left($left)"
101264
}
102-
return this
103-
}
104265

105-
inline fun <L, R> Either<L, R>.ifRight(action: (R) -> Unit): Either<L, R> {
106-
if (this is Either.Right) {
107-
action(right)
266+
267+
@Serializable
268+
@PublishedApi
269+
@SerialName("right")
270+
internal data class Right<L, R>(override val right: R) : Either<L, R>() {
271+
@Transient
272+
override val left: L? = null
273+
override fun toString(): String = "Either.Right($right)"
108274
}
109-
return this
110275
}

0 commit comments

Comments
 (0)