Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
ea7408da70 Update dependency com.android.tools.build:gradle to 8.13.+ 2025-10-21 22:11:04 +00:00
43 changed files with 288 additions and 842 deletions

View File

@@ -1,66 +1,5 @@
# Changelog # Changelog
## 0.28.1
* `Coroutines`:
* `runCatchingLogging` updated to rethrow `CancellationException` and log other exceptions
## 0.28.0
**THIS VERSION CONTAINS BREAKING CHANGES DUE TO EXPOSED 1.0.0 UPDATE**
* `Versions`:
* `Kotlin`: `2.2.21` -> `2.3.0`
* `Serialization`: `1.9.0` -> `1.10.0`
* `Exposed`: `0.61.0` -> `1.0.0` (**MAJOR VERSION UPDATE**)
* `Ktor`: `3.3.3` -> `3.4.0`
* `NMCP`: `1.2.0` -> `1.2.1`
* `Repos`:
* `Exposed`:
* All Exposed-based repositories have been updated to support Exposed 1.0.0 API changes
* Import paths have been migrated to new `org.jetbrains.exposed.v1.*` package structure
* `Pagination`:
* `Exposed`:
* Updated to use new Exposed 1.0.0 import paths
## 0.27.0
* `Versions`:
* `Ktor`: `3.3.2` -> `3.3.3`
* `Okio`: `3.16.2` -> `3.16.4`
* `KSP`: `2.3.2` -> `2.3.4`
* `Compose`: `1.9.3` -> `1.10.0`
* `Compose Material3`: `1.9.0` -> `1.10.0-alpha05`
## 0.26.8
* `Versions`:
* `KSLog`: `1.5.1` -> `1.5.2`
* `Compose`: `1.9.2` -> `1.9.3`
* `Ktor`: `3.3.1` -> `3.3.2`
* `Coroutines`:
* Add simple suspend function `suspendPoint` which will ensure that current coroutine is active to let it be
destroyable even in case it have non-suspendable nature
## 0.26.7
* `Versions`:
* `Kotlin`: `2.2.20` -> `2.2.21`
* `Compose`: `1.8.2` -> `1.9.2`
* `KSP`: `2.2.20-2.0.3` -> `2.3.1`
* `Coroutines`:
* Fix `SmartSemaphore.waitRelease` to wait for the exact number of permits
* Improve `SmartKeyRWLocker` tests
* `KSP`:
* `Sealed`/`ClassCasts`/`Variations`:
* Add workaround for `NoSuchElementException` to improve processors stability on new `KSP`
* `Koin`:
* `Generator`:
* Handle missing annotation values safely (`NoSuchElementException` workaround)
* `Android`:
* `Pickers`:
* Add dependency `androidx.compose.material:material-icons-extended`
## 0.26.6 ## 0.26.6
* `Versions`: * `Versions`:

View File

@@ -13,7 +13,6 @@ kotlin {
androidMain { androidMain {
dependencies { dependencies {
api project(":micro_utils.android.smalltextfield") api project(":micro_utils.android.smalltextfield")
api libs.jb.compose.icons
} }
} }
} }

View File

@@ -44,11 +44,6 @@ allprojects {
maven { url "https://nexus.inmo.dev/repository/maven-releases/" } maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
mavenLocal() mavenLocal()
} }
it.tasks.withType(AbstractTestTask).configureEach {
it.failOnNoDiscoveredTests = false
}
} }
apply from: "./extensions.gradle" apply from: "./extensions.gradle"

View File

@@ -2,27 +2,11 @@ package dev.inmo.micro_utils.coroutines
import dev.inmo.kslog.common.KSLog import dev.inmo.kslog.common.KSLog
import dev.inmo.kslog.common.e import dev.inmo.kslog.common.e
import kotlin.coroutines.cancellation.CancellationException
/**
* Executes the given [block] within a `runCatching` context and logs any exceptions that occur, excluding
* `CancellationException` which is rethrown. This method simplifies error handling by automatically logging
* the errors using the provided [logger].
*
* @param T The result type of the [block].
* @param R The receiver type on which this function operates.
* @param errorMessageBuilder A lambda to build the error log message. By default, it returns a generic error message.
* @param logger The logging instance used for logging errors. Defaults to [KSLog].
* @param block The code block to execute within the `runCatching` context.
* @return A [Result] representing the outcome of executing the [block].
*/
inline fun <T, R> R.runCatchingLogging( inline fun <T, R> R.runCatchingLogging(
noinline errorMessageBuilder: R.(Throwable) -> Any = { "Something web wrong" }, noinline errorMessageBuilder: R.(Throwable) -> Any = { "Something web wrong" },
logger: KSLog = KSLog, logger: KSLog = KSLog,
block: R.() -> T block: R.() -> T
) = runCatching(block).onFailure { ) = runCatching(block).onFailure {
when (it) { logger.e(it) { errorMessageBuilder(it) }
is CancellationException -> throw it
else -> logger.e(it) { errorMessageBuilder(it) }
}
} }

View File

@@ -72,7 +72,7 @@ sealed interface SmartSemaphore {
acquiredPermits != checkedPermits acquiredPermits != checkedPermits
} }
if (shouldContinue) { if (shouldContinue) {
waitRelease(checkedPermits - acquiredPermits) waitRelease()
} }
} while (shouldContinue && currentCoroutineContext().isActive) } while (shouldContinue && currentCoroutineContext().isActive)
} catch (e: Throwable) { } catch (e: Throwable) {

View File

@@ -1,15 +0,0 @@
package dev.inmo.micro_utils.coroutines
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
/**
* Ensures that the current coroutine context is still active and throws a [kotlinx.coroutines.CancellationException]
* if the coroutine has been canceled.
*
* This function provides a convenient way to check the active status of a coroutine, which is useful
* to identify cancellation points in long-running or suspendable operations.
*
* @throws kotlinx.coroutines.CancellationException if the coroutine context is no longer active.
*/
suspend fun suspendPoint() = currentCoroutineContext().ensureActive()

View File

@@ -4,7 +4,6 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlin.test.BeforeTest
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFails import kotlin.test.assertFails
@@ -14,517 +13,184 @@ import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
class SmartKeyRWLockerTests { class SmartKeyRWLockerTests {
private lateinit var locker: SmartKeyRWLocker<String>
@BeforeTest
fun setup() {
locker = SmartKeyRWLocker()
}
// ==================== Global Read Tests ====================
@Test @Test
fun testGlobalReadAllowsMultipleConcurrentReads() = runTest { fun writeLockKeyFailedOnGlobalWriteLockTest() = runTest {
val results = mutableListOf<Boolean>() val locker = SmartKeyRWLocker<String>()
val testKey = "test"
locker.acquireRead()
val jobs = List(5) {
launch {
locker.acquireRead()
delay(100.milliseconds)
results.add(true)
locker.releaseRead()
}
}
jobs.joinAll()
locker.releaseRead()
assertEquals(5, results.size)
}
@Test
fun testGlobalReadBlocksGlobalWrite() = runTest {
locker.acquireRead()
var writeAcquired = false
val writeJob = launch {
locker.lockWrite()
writeAcquired = true
locker.unlockWrite()
}
delay(200.milliseconds)
assertFalse(writeAcquired, "Write should be blocked by global read")
locker.releaseRead()
writeJob.join()
assertTrue(writeAcquired, "Write should succeed after read released")
}
@Test
fun testGlobalReadBlocksAllKeyWrites() = runTest {
locker.acquireRead()
val writeFlags = mutableMapOf<String, Boolean>()
val keys = listOf("key1", "key2", "key3")
val jobs = keys.map { key ->
launch {
locker.lockWrite(key)
writeFlags[key] = true
locker.unlockWrite(key)
}
}
delay(200.milliseconds)
assertTrue(writeFlags.isEmpty(), "No writes should succeed while global read active")
locker.releaseRead()
jobs.joinAll()
assertEquals(keys.size, writeFlags.size, "All writes should succeed after global read released")
}
// ==================== Global Write Tests ====================
@Test
fun testGlobalWriteBlocksAllOperations() = runTest {
locker.lockWrite() locker.lockWrite()
var globalReadAcquired = false assertTrue { locker.isWriteLocked() }
var keyReadAcquired = false
var keyWriteAcquired = false
val jobs = listOf( assertFails {
launch { realWithTimeout(1.seconds) {
locker.lockWrite(testKey)
}
}
assertFalse { locker.isWriteLocked(testKey) }
locker.unlockWrite()
assertFalse { locker.isWriteLocked() }
realWithTimeout(1.seconds) {
locker.lockWrite(testKey)
}
assertTrue { locker.isWriteLocked(testKey) }
assertTrue { locker.unlockWrite(testKey) }
assertFalse { locker.isWriteLocked(testKey) }
}
@Test
fun writeLockKeyFailedOnGlobalReadLockTest() = runTest {
val locker = SmartKeyRWLocker<String>()
val testKey = "test"
locker.acquireRead()
assertEquals(Int.MAX_VALUE - 1, locker.readSemaphore().freePermits)
assertFails {
realWithTimeout(1.seconds) {
locker.lockWrite(testKey)
}
}
assertFalse { locker.isWriteLocked(testKey) }
locker.releaseRead()
assertEquals(Int.MAX_VALUE, locker.readSemaphore().freePermits)
realWithTimeout(1.seconds) {
locker.lockWrite(testKey)
}
assertTrue { locker.isWriteLocked(testKey) }
assertTrue { locker.unlockWrite(testKey) }
assertFalse { locker.isWriteLocked(testKey) }
}
@Test
fun readLockFailedOnWriteLockKeyTest() = runTest {
val locker = SmartKeyRWLocker<String>()
val testKey = "test"
locker.lockWrite(testKey)
assertTrue { locker.isWriteLocked(testKey) }
assertFails {
realWithTimeout(1.seconds) {
locker.acquireRead() locker.acquireRead()
globalReadAcquired = true
locker.releaseRead()
},
launch {
locker.acquireRead("key1")
keyReadAcquired = true
locker.releaseRead("key1")
},
launch {
locker.lockWrite("key2")
keyWriteAcquired = true
locker.unlockWrite("key2")
}
)
delay(200.milliseconds)
assertFalse(globalReadAcquired, "Global read should be blocked")
assertFalse(keyReadAcquired, "Key read should be blocked")
assertFalse(keyWriteAcquired, "Key write should be blocked")
locker.unlockWrite()
jobs.joinAll()
assertTrue(globalReadAcquired)
assertTrue(keyReadAcquired)
assertTrue(keyWriteAcquired)
}
@Test
fun testGlobalWriteIsExclusive() = runTest {
locker.lockWrite()
var secondWriteAcquired = false
val job = launch {
locker.lockWrite()
secondWriteAcquired = true
locker.unlockWrite()
}
delay(200.milliseconds)
assertFalse(secondWriteAcquired, "Second global write should be blocked")
locker.unlockWrite()
job.join()
assertTrue(secondWriteAcquired)
}
// ==================== Key Read Tests ====================
@Test
fun testKeyReadAllowsMultipleConcurrentReadsForSameKey() = runTest {
val key = "testKey"
val results = mutableListOf<Boolean>()
locker.acquireRead(key)
val jobs = List(5) {
launch {
locker.acquireRead(key)
delay(50.milliseconds)
results.add(true)
locker.releaseRead(key)
} }
} }
assertEquals(locker.readSemaphore().maxPermits - 1, locker.readSemaphore().freePermits)
jobs.joinAll() locker.unlockWrite(testKey)
locker.releaseRead(key) assertFalse { locker.isWriteLocked(testKey) }
assertEquals(5, results.size) realWithTimeout(1.seconds) {
}
@Test
fun testKeyReadAllowsReadsForDifferentKeys() = runTest {
val results = mutableMapOf<String, Boolean>()
locker.acquireRead("key1")
val jobs = listOf("key2", "key3", "key4").map { key ->
launch {
locker.acquireRead(key)
delay(50.milliseconds)
results[key] = true
locker.releaseRead(key)
}
}
jobs.joinAll()
locker.releaseRead("key1")
assertEquals(3, results.size)
}
@Test
fun testKeyReadBlocksWriteForSameKey() = runTest {
val key = "testKey"
locker.acquireRead(key)
var writeAcquired = false
val job = launch {
locker.lockWrite(key)
writeAcquired = true
locker.unlockWrite(key)
}
delay(200.milliseconds)
assertFalse(writeAcquired, "Write for same key should be blocked")
locker.releaseRead(key)
job.join()
assertTrue(writeAcquired)
}
@Test
fun testKeyReadBlocksGlobalWrite() = runTest {
locker.acquireRead("key1")
var globalWriteAcquired = false
val job = launch {
locker.lockWrite()
globalWriteAcquired = true
locker.unlockWrite()
}
delay(200.milliseconds)
assertFalse(globalWriteAcquired, "Global write should be blocked by key read")
locker.releaseRead("key1")
job.join()
assertTrue(globalWriteAcquired)
}
@Test
fun testKeyReadAllowsWriteForDifferentKey() = runTest {
locker.acquireRead("key1")
var writeAcquired = false
val job = launch {
locker.lockWrite("key2")
writeAcquired = true
locker.unlockWrite("key2")
}
job.join()
assertTrue(writeAcquired, "Write for different key should succeed")
locker.releaseRead("key1")
}
// ==================== Key Write Tests ====================
@Test
fun testKeyWriteBlocksReadForSameKey() = runTest {
val key = "testKey"
locker.lockWrite(key)
var readAcquired = false
val job = launch {
locker.acquireRead(key)
readAcquired = true
locker.releaseRead(key)
}
delay(200.milliseconds)
assertFalse(readAcquired, "Read for same key should be blocked")
locker.unlockWrite(key)
job.join()
assertTrue(readAcquired)
}
@Test
fun testKeyWriteBlocksGlobalRead() = runTest {
locker.lockWrite("key1")
var globalReadAcquired = false
val job = launch {
locker.acquireRead() locker.acquireRead()
globalReadAcquired = true }
assertEquals(locker.readSemaphore().maxPermits - 1, locker.readSemaphore().freePermits)
assertTrue { locker.releaseRead() }
assertEquals(locker.readSemaphore().maxPermits, locker.readSemaphore().freePermits)
}
@Test
fun writeLockFailedOnWriteLockKeyTest() = runTest {
val locker = SmartKeyRWLocker<String>()
val testKey = "test"
locker.lockWrite(testKey)
assertTrue { locker.isWriteLocked(testKey) }
assertFails {
realWithTimeout(1.seconds) {
locker.lockWrite()
}
}
assertFalse(locker.isWriteLocked())
locker.unlockWrite(testKey)
assertFalse { locker.isWriteLocked(testKey) }
realWithTimeout(1.seconds) {
locker.lockWrite()
}
assertTrue(locker.isWriteLocked())
assertTrue { locker.unlockWrite() }
assertFalse(locker.isWriteLocked())
}
@Test
fun readsBlockingGlobalWrite() = runTest {
val locker = SmartKeyRWLocker<String>()
val testKeys = (0 until 100).map { "test$it" }
for (i in testKeys.indices) {
val it = testKeys[i]
locker.acquireRead(it)
val previous = testKeys.take(i)
val next = testKeys.drop(i + 1)
previous.forEach {
assertTrue { locker.readSemaphoreOrNull(it) ?.freePermits == Int.MAX_VALUE - 1 }
}
next.forEach {
assertTrue { locker.readSemaphoreOrNull(it) ?.freePermits == null }
}
}
for (i in testKeys.indices) {
val it = testKeys[i]
assertFails {
realWithTimeout(13.milliseconds) { locker.lockWrite() }
}
val readPermitsBeforeLock = locker.readSemaphore().freePermits
realWithTimeout(1.seconds) { locker.acquireRead() }
locker.releaseRead() locker.releaseRead()
assertEquals(readPermitsBeforeLock, locker.readSemaphore().freePermits)
locker.releaseRead(it)
} }
delay(200.milliseconds) assertTrue { locker.readSemaphore().freePermits == Int.MAX_VALUE }
assertFalse(globalReadAcquired, "Global read should be blocked by key write") realWithTimeout(1.seconds) { locker.lockWrite() }
assertFails {
locker.unlockWrite("key1") realWithTimeout(13.milliseconds) { locker.acquireRead() }
job.join()
assertTrue(globalReadAcquired)
}
@Test
fun testKeyWriteIsExclusiveForSameKey() = runTest {
val key = "testKey"
locker.lockWrite(key)
var secondWriteAcquired = false
val job = launch {
locker.lockWrite(key)
secondWriteAcquired = true
locker.unlockWrite(key)
} }
assertTrue { locker.unlockWrite() }
delay(200.milliseconds) assertTrue { locker.readSemaphore().freePermits == Int.MAX_VALUE }
assertFalse(secondWriteAcquired, "Second write for same key should be blocked")
locker.unlockWrite(key)
job.join()
assertTrue(secondWriteAcquired)
} }
@Test @Test
fun testKeyWriteAllowsOperationsOnDifferentKeys() = runTest { fun writesBlockingGlobalWrite() = runTest {
locker.lockWrite("key1") val locker = SmartKeyRWLocker<String>()
val results = mutableMapOf<String, Boolean>() val testKeys = (0 until 100).map { "test$it" }
val jobs = listOf( for (i in testKeys.indices) {
launch { val it = testKeys[i]
locker.acquireRead("key2") locker.lockWrite(it)
results["read-key2"] = true val previous = testKeys.take(i)
locker.releaseRead("key2") val next = testKeys.drop(i + 1)
},
launch { previous.forEach {
locker.lockWrite("key3") assertTrue { locker.writeMutexOrNull(it) ?.isLocked == true }
results["write-key3"] = true
locker.unlockWrite("key3")
} }
) next.forEach {
assertTrue { locker.writeMutexOrNull(it) ?.isLocked != true }
jobs.joinAll()
assertEquals(2, results.size, "Operations on different keys should succeed")
locker.unlockWrite("key1")
}
// ==================== Complex Scenarios ====================
@Test
fun testMultipleReadersThenWriter() = runTest {
val key = "testKey"
val readCount = 5
val readers = mutableListOf<Job>()
repeat(readCount) {
readers.add(launch {
locker.acquireRead(key)
delay(100.milliseconds)
locker.releaseRead(key)
})
}
delay(50.milliseconds) // Let readers acquire
var writerExecuted = false
val writer = launch {
locker.lockWrite(key)
writerExecuted = true
locker.unlockWrite(key)
}
delay(50.milliseconds)
assertFalse(writerExecuted, "Writer should wait for all readers")
readers.joinAll()
writer.join()
assertTrue(writerExecuted, "Writer should execute after all readers done")
}
@Test
fun testWriterThenMultipleReaders() = runTest {
val key = "testKey"
locker.lockWrite(key)
val readerFlags = mutableListOf<Boolean>()
val readers = List(5) {
launch {
locker.acquireRead(key)
readerFlags.add(true)
locker.releaseRead(key)
} }
} }
delay(200.milliseconds) for (i in testKeys.indices) {
assertTrue(readerFlags.isEmpty(), "Readers should be blocked by writer") val it = testKeys[i]
assertFails { realWithTimeout(13.milliseconds) { locker.lockWrite() } }
locker.unlockWrite(key) val readPermitsBeforeLock = locker.readSemaphore().freePermits
readers.joinAll() assertFails { realWithTimeout(13.milliseconds) { locker.acquireRead() } }
assertEquals(readPermitsBeforeLock, locker.readSemaphore().freePermits)
assertEquals(5, readerFlags.size, "All readers should succeed after writer") locker.unlockWrite(it)
}
@Test
fun testCascadingLocksWithDifferentKeys() = runTest {
val executed = mutableMapOf<String, Boolean>()
launch {
locker.lockWrite("key1")
executed["write-key1-start"] = true
delay(100.milliseconds)
locker.unlockWrite("key1")
executed["write-key1-end"] = true
} }
delay(50.milliseconds) assertTrue { locker.readSemaphore().freePermits == Int.MAX_VALUE }
realWithTimeout(1.seconds) { locker.lockWrite() }
launch { assertFails {
locker.acquireRead("key2") realWithTimeout(13.milliseconds) { locker.acquireRead() }
executed["read-key2"] = true
delay(100.milliseconds)
locker.releaseRead("key2")
} }
assertTrue { locker.unlockWrite() }
delay(200.milliseconds) assertTrue { locker.readSemaphore().freePermits == Int.MAX_VALUE }
assertTrue(executed["write-key1-start"] == true)
assertTrue(executed["read-key2"] == true)
assertTrue(executed["write-key1-end"] == true)
}
@Test
fun testReleaseWithoutAcquireReturnsFalse() = runTest {
assertFalse(locker.releaseRead(), "Release without acquire should return false")
assertFalse(locker.releaseRead("key1"), "Release without acquire should return false")
}
@Test
fun testUnlockWithoutLockReturnsFalse() = runTest {
assertFalse(locker.unlockWrite(), "Unlock without lock should return false")
assertFalse(locker.unlockWrite("key1"), "Unlock without lock should return false")
}
@Test
fun testProperReleaseReturnsTrue() = runTest {
locker.acquireRead()
assertTrue(locker.releaseRead(), "Release after acquire should return true")
locker.acquireRead("key1")
assertTrue(locker.releaseRead("key1"), "Release after acquire should return true")
}
@Test
fun testProperUnlockReturnsTrue() = runTest {
locker.lockWrite()
assertTrue(locker.unlockWrite(), "Unlock after lock should return true")
locker.lockWrite("key1")
assertTrue(locker.unlockWrite("key1"), "Unlock after lock should return true")
}
// ==================== Stress Tests ====================
@Test
fun stressTestWithMixedOperations() = runTest(timeout = 10.seconds) {
val operations = 100
val keys = listOf("key1", "key2", "key3", "key4", "key5")
val jobs = mutableListOf<Job>()
repeat(operations) { i ->
val key = keys[i % keys.size]
when (i % 4) {
0 -> jobs.add(launch {
locker.acquireRead(key)
delay(10.milliseconds)
locker.releaseRead(key)
})
1 -> jobs.add(launch {
locker.lockWrite(key)
delay(10.milliseconds)
locker.unlockWrite(key)
})
2 -> jobs.add(launch {
locker.acquireRead()
delay(10.milliseconds)
locker.releaseRead()
})
3 -> jobs.add(launch {
locker.lockWrite()
delay(10.milliseconds)
locker.unlockWrite()
})
}
}
jobs.joinAll()
// If we reach here without deadlock or exceptions, test passes
}
@Test
fun testFairnessReadersDontStarveWriters() = runTest(timeout = 5.seconds) {
val key = "testKey"
var writerExecuted = false
// Start continuous readers
val readers = List(10) {
launch {
repeat(5) {
locker.acquireRead(key)
delay(50.milliseconds)
locker.releaseRead(key)
delay(10.milliseconds)
}
}
}
delay(100.milliseconds)
// Try to acquire write lock
val writer = launch {
locker.lockWrite(key)
writerExecuted = true
locker.unlockWrite(key)
}
readers.joinAll()
writer.join()
assertTrue(writerExecuted, "Writer should eventually execute")
} }
} }

View File

@@ -26,7 +26,7 @@ kotlin {
project.parent.subprojects.forEach { project.parent.subprojects.forEach {
if ( if (
it.name != project.name it != project
&& it.hasProperty("kotlin") && it.hasProperty("kotlin")
&& it.kotlin.sourceSets.any { it.name.contains("commonMain") } && it.kotlin.sourceSets.any { it.name.contains("commonMain") }
&& it.kotlin.sourceSets.any { it.name.contains("jsMain") } && it.kotlin.sourceSets.any { it.name.contains("jsMain") }
@@ -44,7 +44,7 @@ kotlin {
project.parent.subprojects.forEach { project.parent.subprojects.forEach {
if ( if (
it.name != project.name it != project
&& it.hasProperty("kotlin") && it.hasProperty("kotlin")
&& it.kotlin.sourceSets.any { it.name.contains("commonMain") } && it.kotlin.sourceSets.any { it.name.contains("commonMain") }
&& it.kotlin.sourceSets.any { it.name.contains("jsMain") } && it.kotlin.sourceSets.any { it.name.contains("jsMain") }
@@ -60,7 +60,7 @@ kotlin {
project.parent.subprojects.forEach { project.parent.subprojects.forEach {
if ( if (
it.name != project.name it != project
&& it.hasProperty("kotlin") && it.hasProperty("kotlin")
&& it.kotlin.sourceSets.any { it.name.contains("commonMain") } && it.kotlin.sourceSets.any { it.name.contains("commonMain") }
&& it.kotlin.sourceSets.any { it.name.contains("jvmMain") } && it.kotlin.sourceSets.any { it.name.contains("jvmMain") }
@@ -76,7 +76,7 @@ kotlin {
project.parent.subprojects.forEach { project.parent.subprojects.forEach {
if ( if (
it.name != project.name it != project
&& it.hasProperty("kotlin") && it.hasProperty("kotlin")
&& it.kotlin.sourceSets.any { it.name.contains("commonMain") } && it.kotlin.sourceSets.any { it.name.contains("commonMain") }
&& it.kotlin.sourceSets.any { it.name.contains("androidMain") } && it.kotlin.sourceSets.any { it.name.contains("androidMain") }

View File

@@ -1,15 +1,9 @@
interface InjectedExecOps {
@Inject //@javax.inject.Inject
ExecOperations getExecOps()
}
private String getCurrentVersionChangelog() { private String getCurrentVersionChangelog() {
OutputStream changelogDataOS = new ByteArrayOutputStream() OutputStream changelogDataOS = new ByteArrayOutputStream()
exec {
def injected = project.objects.newInstance(InjectedExecOps)
injected.execOps.exec {
commandLine 'chmod', "+x", './changelog_parser.sh' commandLine 'chmod', "+x", './changelog_parser.sh'
} }
injected.execOps.exec { exec {
standardOutput = changelogDataOS standardOutput = changelogDataOS
commandLine './changelog_parser.sh', "${project.version}", 'CHANGELOG.md' commandLine './changelog_parser.sh', "${project.version}", 'CHANGELOG.md'
} }

View File

@@ -8,8 +8,8 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
## https://github.com/google/ksp/issues/2491 # https://github.com/google/ksp/issues/2491
#ksp.useKSP2=false ksp.useKSP2=false
# JS NPM # JS NPM
@@ -18,5 +18,5 @@ crypto_js_version=4.1.1
# Project data # Project data
group=dev.inmo group=dev.inmo
version=0.28.1 version=0.26.6
android_code_version=310 android_code_version=305

View File

@@ -1,40 +1,38 @@
[versions] [versions]
kt = "2.3.0" kt = "2.2.20"
kt-serialization = "1.10.0" kt-serialization = "1.9.0"
kt-coroutines = "1.10.2" kt-coroutines = "1.10.2"
kotlinx-browser = "0.5.0" kotlinx-browser = "0.5.0"
kslog = "1.5.2" kslog = "1.5.1"
jb-compose = "1.10.0" jb-compose = "1.8.2"
jb-compose-material3 = "1.10.0-alpha05" jb-exposed = "0.61.0"
jb-compose-icons = "1.7.8"
jb-exposed = "1.0.0"
jb-dokka = "2.1.0" jb-dokka = "2.1.0"
# 3.51.0.0 contains bug, checking with ./gradlew :micro_utils.repos.exposed:jvmTest # 3.50.3.0 contains bug https://github.com/InsanusMokrassar/MicroUtils/actions/runs/18138301958/job/51629588088
sqlite = "3.50.1.0" sqlite = "3.50.1.0"
korlibs = "5.4.0" korlibs = "5.4.0"
uuid = "0.8.4" uuid = "0.8.4"
ktor = "3.4.0" ktor = "3.3.1"
gh-release = "2.5.2" gh-release = "2.5.2"
koin = "4.1.1" koin = "4.1.1"
okio = "3.16.4" okio = "3.16.2"
ksp = "2.3.4" ksp = "2.2.20-2.0.3"
kotlin-poet = "2.2.0" kotlin-poet = "2.2.0"
versions = "0.53.0" versions = "0.52.0"
nmcp = "1.2.1" nmcp = "1.1.0"
android-gradle = "8.12.+" android-gradle = "8.13.+"
dexcount = "4.0.0" dexcount = "4.0.0"
android-coreKtx = "1.17.0" android-coreKtx = "1.17.0"
@@ -91,8 +89,7 @@ jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-
jb-exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "jb-exposed" } jb-exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "jb-exposed" }
sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" } sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" }
jb-compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "jb-compose-material3" } jb-compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "jb-compose" }
jb-compose-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "jb-compose-icons" }
android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" } android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" }
android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" } android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" }

View File

@@ -1,9 +1,6 @@
kotlin { kotlin {
androidTarget { androidTarget {
publishLibraryVariants( publishAllLibraryVariants()
"release",
"debug",
)
compilations.all { compilations.all {
kotlinOptions { kotlinOptions {
jvmTarget = "17" jvmTarget = "17"

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -27,7 +27,6 @@ import com.squareup.kotlinpoet.ksp.toClassName
import com.squareup.kotlinpoet.ksp.toTypeName import com.squareup.kotlinpoet.ksp.toTypeName
import com.squareup.kotlinpoet.ksp.writeTo import com.squareup.kotlinpoet.ksp.writeTo
import dev.inmo.micro_ksp.generator.safeClassName import dev.inmo.micro_ksp.generator.safeClassName
import dev.inmo.micro_ksp.generator.withNoSuchElementWorkaround
import dev.inmo.micro_utils.koin.annotations.GenerateGenericKoinDefinition import dev.inmo.micro_utils.koin.annotations.GenerateGenericKoinDefinition
import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition
import org.koin.core.Koin import org.koin.core.Koin
@@ -241,14 +240,9 @@ class Processor(
ksFile.getAnnotationsByType(GenerateKoinDefinition::class).forEach { ksFile.getAnnotationsByType(GenerateKoinDefinition::class).forEach {
val type = safeClassName { it.type } val type = safeClassName { it.type }
val targetType = runCatching { val targetType = runCatching {
type.parameterizedBy( type.parameterizedBy(*(it.typeArgs.takeIf { it.isNotEmpty() } ?.map { it.asTypeName() } ?.toTypedArray() ?: return@runCatching type))
*withNoSuchElementWorkaround(emptyArray()) {
it.typeArgs.takeIf { it.isNotEmpty() } ?.map { it.asTypeName() } ?.toTypedArray() ?: return@runCatching type
}
)
}.getOrElse { e -> }.getOrElse { e ->
when (e) { when (e) {
is IllegalArgumentException if (e.message ?.contains("no type argument") == true) -> return@getOrElse type
is KSTypeNotPresentException -> e.ksType.toClassName() is KSTypeNotPresentException -> e.ksType.toClassName()
} }
if (e is KSTypesNotPresentException) { if (e is KSTypesNotPresentException) {
@@ -257,32 +251,14 @@ class Processor(
throw e throw e
} }
}.copy( }.copy(
nullable = withNoSuchElementWorkaround(true) { it.nullable } nullable = it.nullable
) )
addCodeForType( addCodeForType(targetType, it.name, it.nullable, it.generateSingle, it.generateFactory)
targetType,
it.name,
withNoSuchElementWorkaround(true) {
it.nullable
},
withNoSuchElementWorkaround(true) {
it.generateSingle
},
withNoSuchElementWorkaround(true) {
it.generateFactory
}
)
} }
ksFile.getAnnotationsByType(GenerateGenericKoinDefinition::class).forEach { ksFile.getAnnotationsByType(GenerateGenericKoinDefinition::class).forEach {
val targetType = TypeVariableName("T", Any::class) val targetType = TypeVariableName("T", Any::class)
addCodeForType( addCodeForType(targetType, it.name, it.nullable, it.generateSingle, it.generateFactory)
targetType = targetType,
name = it.name,
nullable = withNoSuchElementWorkaround(true) { it.nullable },
generateSingle = withNoSuchElementWorkaround(true) { it.generateSingle },
generateFactory = withNoSuchElementWorkaround(true) { it.generateFactory }
)
} }
}.build().let { }.build().let {
File( File(

View File

@@ -10,7 +10,6 @@ import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.* import com.google.devtools.ksp.symbol.*
import com.squareup.kotlinpoet.* import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ksp.toClassName import com.squareup.kotlinpoet.ksp.toClassName
import dev.inmo.micro_ksp.generator.withNoSuchElementWorkaround
import dev.inmo.micro_ksp.generator.writeFile import dev.inmo.micro_ksp.generator.writeFile
import dev.inmo.micro_utils.ksp.classcasts.ClassCastsExcluded import dev.inmo.micro_utils.ksp.classcasts.ClassCastsExcluded
import dev.inmo.micro_utils.ksp.classcasts.ClassCastsIncluded import dev.inmo.micro_utils.ksp.classcasts.ClassCastsIncluded
@@ -26,11 +25,7 @@ class Processor(
) { ) {
val rootAnnotation = ksClassDeclaration.getAnnotationsByType(ClassCastsIncluded::class).first() val rootAnnotation = ksClassDeclaration.getAnnotationsByType(ClassCastsIncluded::class).first()
val (includeRegex: Regex?, excludeRegex: Regex?) = rootAnnotation.let { val (includeRegex: Regex?, excludeRegex: Regex?) = rootAnnotation.let {
withNoSuchElementWorkaround("") { it.typesRegex.takeIf { it.isNotEmpty() } ?.let(::Regex) to it.excludeRegex.takeIf { it.isNotEmpty() } ?.let(::Regex)
it.typesRegex
}.takeIf { it.isNotEmpty() } ?.let(::Regex) to withNoSuchElementWorkaround("") {
it.excludeRegex
}.takeIf { it.isNotEmpty() } ?.let(::Regex)
} }
val classesSubtypes = mutableMapOf<KSClassDeclaration, MutableSet<KSClassDeclaration>>() val classesSubtypes = mutableMapOf<KSClassDeclaration, MutableSet<KSClassDeclaration>>()
@@ -54,9 +49,7 @@ class Processor(
when { when {
potentialSubtype === ksClassDeclaration -> {} potentialSubtype === ksClassDeclaration -> {}
potentialSubtype.isAnnotationPresent(ClassCastsExcluded::class) -> return@forEach potentialSubtype.isAnnotationPresent(ClassCastsExcluded::class) -> return@forEach
potentialSubtype !is KSClassDeclaration || !potentialSubtype.checkSupertypeLevel( potentialSubtype !is KSClassDeclaration || !potentialSubtype.checkSupertypeLevel(rootAnnotation.levelsToInclude.takeIf { it >= 0 }) -> return@forEach
withNoSuchElementWorkaround(-1) { rootAnnotation.levelsToInclude }.takeIf { it >= 0 }
) -> return@forEach
excludeRegex ?.matches(simpleName) == true -> return@forEach excludeRegex ?.matches(simpleName) == true -> return@forEach
includeRegex ?.matches(simpleName) == false -> {} includeRegex ?.matches(simpleName) == false -> {}
else -> classesSubtypes.getOrPut(ksClassDeclaration) { mutableSetOf() }.add(potentialSubtype) else -> classesSubtypes.getOrPut(ksClassDeclaration) { mutableSetOf() }.add(potentialSubtype)
@@ -103,9 +96,7 @@ class Processor(
@OptIn(KspExperimental::class) @OptIn(KspExperimental::class)
override fun process(resolver: Resolver): List<KSAnnotated> { override fun process(resolver: Resolver): List<KSAnnotated> {
(resolver.getSymbolsWithAnnotation(ClassCastsIncluded::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach { (resolver.getSymbolsWithAnnotation(ClassCastsIncluded::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach {
val prefix = withNoSuchElementWorkaround("") { val prefix = it.getAnnotationsByType(ClassCastsIncluded::class).first().outputFilePrefix
it.getAnnotationsByType(ClassCastsIncluded::class).first().outputFilePrefix
}
it.writeFile(prefix = prefix, suffix = "ClassCasts") { it.writeFile(prefix = prefix, suffix = "ClassCasts") {
FileSpec.builder( FileSpec.builder(
it.packageName.asString(), it.packageName.asString(),

View File

@@ -1,12 +0,0 @@
package dev.inmo.micro_ksp.generator
inline fun <T> withNoSuchElementWorkaround(
default: T,
block: () -> T
): T = runCatching(block).getOrElse {
if (it is NoSuchElementException) {
default
} else {
throw it
}
}

View File

@@ -12,7 +12,6 @@ import com.squareup.kotlinpoet.ksp.toClassName
import dev.inmo.micro_ksp.generator.buildSubFileName import dev.inmo.micro_ksp.generator.buildSubFileName
import dev.inmo.micro_ksp.generator.companion import dev.inmo.micro_ksp.generator.companion
import dev.inmo.micro_ksp.generator.findSubClasses import dev.inmo.micro_ksp.generator.findSubClasses
import dev.inmo.micro_ksp.generator.withNoSuchElementWorkaround
import dev.inmo.micro_ksp.generator.writeFile import dev.inmo.micro_ksp.generator.writeFile
import dev.inmo.micro_utils.ksp.sealed.GenerateSealedTypesWorkaround import dev.inmo.micro_utils.ksp.sealed.GenerateSealedTypesWorkaround
import dev.inmo.micro_utils.ksp.sealed.GenerateSealedWorkaround import dev.inmo.micro_utils.ksp.sealed.GenerateSealedWorkaround
@@ -114,7 +113,7 @@ class Processor(
val annotation = ksClassDeclaration.getGenerateSealedTypesWorkaroundAnnotation val annotation = ksClassDeclaration.getGenerateSealedTypesWorkaroundAnnotation
val subClasses = ksClassDeclaration.resolveSubclasses( val subClasses = ksClassDeclaration.resolveSubclasses(
searchIn = resolver.getAllFiles(), searchIn = resolver.getAllFiles(),
allowNonSealed = withNoSuchElementWorkaround(null) { annotation ?.includeNonSealedSubTypes } ?: false allowNonSealed = annotation ?.includeNonSealedSubTypes ?: false
).distinct() ).distinct()
val subClassesNames = subClasses.filter { val subClassesNames = subClasses.filter {
it.getAnnotationsByType(GenerateSealedTypesWorkaround.Exclude::class).count() == 0 it.getAnnotationsByType(GenerateSealedTypesWorkaround.Exclude::class).count() == 0
@@ -165,15 +164,7 @@ class Processor(
@OptIn(KspExperimental::class) @OptIn(KspExperimental::class)
override fun process(resolver: Resolver): List<KSAnnotated> { override fun process(resolver: Resolver): List<KSAnnotated> {
(resolver.getSymbolsWithAnnotation(GenerateSealedWorkaround::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach { (resolver.getSymbolsWithAnnotation(GenerateSealedWorkaround::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach {
val prefix = runCatching { val prefix = (it.getGenerateSealedWorkaroundAnnotation) ?.prefix ?.takeIf {
(it.getGenerateSealedWorkaroundAnnotation) ?.prefix
}.getOrElse {
if (it is NoSuchElementException) {
""
} else {
throw it
}
} ?.takeIf {
it.isNotEmpty() it.isNotEmpty()
} ?: it.buildSubFileName.replaceFirst(it.simpleName.asString(), "") } ?: it.buildSubFileName.replaceFirst(it.simpleName.asString(), "")
it.writeFile(prefix = prefix, suffix = "SealedWorkaround") { it.writeFile(prefix = prefix, suffix = "SealedWorkaround") {
@@ -193,9 +184,7 @@ class Processor(
} }
} }
(resolver.getSymbolsWithAnnotation(GenerateSealedTypesWorkaround::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach { (resolver.getSymbolsWithAnnotation(GenerateSealedTypesWorkaround::class.qualifiedName!!)).filterIsInstance<KSClassDeclaration>().forEach {
val prefix = withNoSuchElementWorkaround("") { val prefix = (it.getGenerateSealedTypesWorkaroundAnnotation) ?.prefix ?.takeIf {
(it.getGenerateSealedTypesWorkaroundAnnotation)?.prefix
} ?.takeIf {
it.isNotEmpty() it.isNotEmpty()
} ?: it.buildSubFileName.replaceFirst(it.simpleName.asString(), "") } ?: it.buildSubFileName.replaceFirst(it.simpleName.asString(), "")
it.writeFile(prefix = prefix, suffix = "SealedTypesWorkaround") { it.writeFile(prefix = prefix, suffix = "SealedTypesWorkaround") {

View File

@@ -16,7 +16,6 @@ import com.squareup.kotlinpoet.ksp.toTypeName
import dev.inmo.micro_ksp.generator.convertToClassName import dev.inmo.micro_ksp.generator.convertToClassName
import dev.inmo.micro_ksp.generator.convertToClassNames import dev.inmo.micro_ksp.generator.convertToClassNames
import dev.inmo.micro_ksp.generator.findSubClasses import dev.inmo.micro_ksp.generator.findSubClasses
import dev.inmo.micro_ksp.generator.withNoSuchElementWorkaround
import dev.inmo.micro_ksp.generator.writeFile import dev.inmo.micro_ksp.generator.writeFile
import dev.inmo.micro_utils.ksp.variations.GenerateVariations import dev.inmo.micro_utils.ksp.variations.GenerateVariations
import dev.inmo.micro_utils.ksp.variations.GenerationVariant import dev.inmo.micro_utils.ksp.variations.GenerationVariant
@@ -219,9 +218,7 @@ class Processor(
@OptIn(KspExperimental::class) @OptIn(KspExperimental::class)
override fun process(resolver: Resolver): List<KSAnnotated> { override fun process(resolver: Resolver): List<KSAnnotated> {
(resolver.getSymbolsWithAnnotation(GenerateVariations::class.qualifiedName!!)).filterIsInstance<KSFunctionDeclaration>().forEach { (resolver.getSymbolsWithAnnotation(GenerateVariations::class.qualifiedName!!)).filterIsInstance<KSFunctionDeclaration>().forEach {
val prefix = withNoSuchElementWorkaround("") { val prefix = (it.getAnnotationsByType(GenerateVariations::class)).firstOrNull() ?.prefix ?.takeIf {
(it.getAnnotationsByType(GenerateVariations::class)).firstOrNull() ?.prefix
} ?.takeIf {
it.isNotEmpty() it.isNotEmpty()
} ?: it.simpleName.asString().replaceFirst(it.simpleName.asString(), "") } ?: it.simpleName.asString().replaceFirst(it.simpleName.asString(), "")
it.writeFile(prefix = prefix, suffix = "GeneratedVariation") { it.writeFile(prefix = prefix, suffix = "GeneratedVariation") {

View File

@@ -23,9 +23,7 @@ dependencies {
implementation libs.ktor.client.java implementation libs.ktor.client.java
} }
application { mainClassName="MainKt"
mainClass = "MainKt"
}
java { java {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17

View File

@@ -14,7 +14,7 @@ kotlin {
} }
jvmMain { jvmMain {
dependencies { dependencies {
api libs.jb.exposed.jdbc api libs.jb.exposed
} }
} }
} }

View File

@@ -1,8 +1,6 @@
package dev.inmo.micro_utils.pagination package dev.inmo.micro_utils.pagination
import org.jetbrains.exposed.v1.core.Expression import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.jdbc.Query
fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? = null) = fun Query.paginate(with: Pagination, orderBy: Pair<Expression<*>, SortOrder>? = null) =
limit(with.size) limit(with.size)

View File

@@ -2,8 +2,8 @@ package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadCRUDRepo import dev.inmo.micro_utils.repos.ReadCRUDRepo
import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>( abstract class AbstractExposedReadCRUDRepo<ObjectType, IdType>(
tableName: String tableName: String

View File

@@ -4,12 +4,9 @@ import dev.inmo.micro_utils.repos.UpdatedValuePair
import dev.inmo.micro_utils.repos.WriteCRUDRepo import dev.inmo.micro_utils.repos.WriteCRUDRepo
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.v1.core.statements.InsertStatement import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.statements.*
import org.jetbrains.exposed.v1.jdbc.deleteWhere import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.update
import java.util.Objects import java.util.Objects
abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
@@ -96,7 +93,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
return transaction(db = database) { return transaction(db = database) {
update( update(
{ {
selectById( id) selectById(this, id)
} }
) { ) {
update(id, value, it as UpdateBuilder<Int>) update(id, value, it as UpdateBuilder<Int>)
@@ -105,7 +102,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
if (it > 0) { if (it > 0) {
transaction(db = database) { transaction(db = database) {
selectAll().where { selectAll().where {
selectById(id) selectById(this, id)
}.limit(1).firstOrNull() ?.asObject }.limit(1).firstOrNull() ?.asObject
} }
} else { } else {
@@ -140,7 +137,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
override suspend fun deleteById(ids: List<IdType>) { override suspend fun deleteById(ids: List<IdType>) {
onBeforeDelete(ids) onBeforeDelete(ids)
transaction(db = database) { transaction(db = database) {
val deleted = deleteWhere { selectByIds(ids) } val deleted = deleteWhere { selectByIds(it, ids) }
if (deleted == ids.size) { if (deleted == ids.size) {
ids ids
} else { } else {

View File

@@ -1,6 +1,6 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.v1.core.Column import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.sql.Table
typealias ColumnAllocator<T> = Table.() -> Column<T> typealias ColumnAllocator<T> = Table.() -> Column<T>

View File

@@ -1,10 +1,10 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.v1.core.Column import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.v1.core.isNotNull import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNotNull
import org.jetbrains.exposed.v1.core.isNull import org.jetbrains.exposed.sql.SqlExpressionBuilder.isNull
import org.jetbrains.exposed.v1.core.neq import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
fun <T> Column<T?>.eqOrIsNull( fun <T> Column<T?>.eqOrIsNull(
value: T? value: T?

View File

@@ -1,14 +1,12 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.or
interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo { interface CommonExposedRepo<IdType, ObjectType> : ExposedRepo {
val ResultRow.asObject: ObjectType val ResultRow.asObject: ObjectType
val ResultRow.asId: IdType val ResultRow.asId: IdType
val selectById: (IdType) -> Op<Boolean> val selectById: ISqlExpressionBuilder.(IdType) -> Op<Boolean>
val selectByIds: (List<IdType>) -> Op<Boolean> val selectByIds: ISqlExpressionBuilder.(List<IdType>) -> Op<Boolean>
get() = { get() = {
if (it.isEmpty()) { if (it.isEmpty()) {
Op.FALSE Op.FALSE

View File

@@ -1,3 +1,5 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.sql.*
interface ExposedCRUDRepo<ObjectType, IdType> : CommonExposedRepo<IdType, ObjectType> interface ExposedCRUDRepo<ObjectType, IdType> : CommonExposedRepo<IdType, ObjectType>

View File

@@ -1,11 +1,7 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import dev.inmo.micro_utils.repos.Repo import dev.inmo.micro_utils.repos.Repo
import org.jetbrains.exposed.v1.core.FieldSet import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.Transaction
import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.Query
import org.jetbrains.exposed.v1.jdbc.selectAll
interface ExposedRepo : Repo, FieldSet { interface ExposedRepo : Repo, FieldSet {
val database: Database val database: Database

View File

@@ -1,15 +1,11 @@
package dev.inmo.micro_utils.repos.exposed package dev.inmo.micro_utils.repos.exposed
import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.Transaction import org.jetbrains.exposed.sql.SchemaUtils.addMissingColumnsStatements
import org.jetbrains.exposed.v1.core.exposedLogger import org.jetbrains.exposed.sql.SchemaUtils.checkMappingConsistence
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.SchemaUtils.createStatements
import org.jetbrains.exposed.v1.jdbc.SchemaUtils import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.v1.jdbc.SchemaUtils.addMissingColumnsStatements import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.SchemaUtils.checkMappingConsistence
import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
/** /**
* Code in this function mostly duplicates Exposed [SchemaUtils.createMissingTablesAndColumns]. It made due to deprecation * Code in this function mostly duplicates Exposed [SchemaUtils.createMissingTablesAndColumns]. It made due to deprecation
@@ -45,9 +41,9 @@ fun initTablesInTransaction(vararg tables: Table, database: Database, inBatch: B
} }
} }
with(TransactionManager.current()) { with(TransactionManager.current()) {
db.dialectMetadata.resetCaches() db.dialect.resetCaches()
val createStatements = logTimeSpent("Preparing create tables statements", withLogs) { val createStatements = logTimeSpent("Preparing create tables statements", withLogs) {
SchemaUtils.createStatements(*tables) createStatements(*tables)
} }
logTimeSpent("Executing create tables statements", withLogs) { logTimeSpent("Executing create tables statements", withLogs) {
execStatements(inBatch, createStatements) execStatements(inBatch, createStatements)
@@ -70,7 +66,7 @@ fun initTablesInTransaction(vararg tables: Table, database: Database, inBatch: B
execStatements(inBatch, modifyTablesStatements) execStatements(inBatch, modifyTablesStatements)
commit() commit()
} }
db.dialectMetadata.resetCaches() db.dialect.resetCaches()
} }
} }
} }

View File

@@ -3,14 +3,9 @@ package dev.inmo.micro_utils.repos.exposed.keyvalue
import dev.inmo.micro_utils.repos.KeyValueRepo import dev.inmo.micro_utils.repos.KeyValueRepo
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.update import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.statements.*
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.deleteAll
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.update
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
abstract class AbstractExposedKeyValueRepo<Key, Value>( abstract class AbstractExposedKeyValueRepo<Key, Value>(
override val database: Database, override val database: Database,
@@ -59,7 +54,7 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
override suspend fun unset(toUnset: List<Key>) { override suspend fun unset(toUnset: List<Key>) {
transaction(database) { transaction(database) {
toUnset.mapNotNull { item -> toUnset.mapNotNull { item ->
if (deleteWhere { selectById(item) } > 0) { if (deleteWhere { selectById(it, item) } > 0) {
item item
} else { } else {
null null
@@ -74,7 +69,7 @@ abstract class AbstractExposedKeyValueRepo<Key, Value>(
transaction(database) { transaction(database) {
toUnset.flatMap { toUnset.flatMap {
val keys = selectAll().where { selectByValue(it) }.mapNotNull { it.asKey } val keys = selectAll().where { selectByValue(it) }.mapNotNull { it.asKey }
deleteWhere { selectByIds(keys) } deleteWhere { selectByIds(it, keys) }
keys keys
} }
}.distinct().forEach { }.distinct().forEach {

View File

@@ -4,12 +4,8 @@ import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValueRepo import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.exposed.* import dev.inmo.micro_utils.repos.exposed.*
import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated
import org.jetbrains.exposed.v1.core.Column import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
abstract class AbstractExposedReadKeyValueRepo<Key, Value>( abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
override val database: Database, override val database: Database,
@@ -25,7 +21,7 @@ abstract class AbstractExposedReadKeyValueRepo<Key, Value>(
abstract val ResultRow.asKey: Key abstract val ResultRow.asKey: Key
override val ResultRow.asId: Key override val ResultRow.asId: Key
get() = asKey get() = asKey
abstract val selectByValue: (Value) -> Op<Boolean> abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
override suspend fun get(k: Key): Value? = transaction(database) { override suspend fun get(k: Key): Value? = transaction(database) {
selectAll().where { selectById(k) }.limit(1).firstOrNull() ?.asObject selectAll().where { selectById(k) }.limit(1).firstOrNull() ?.asObject

View File

@@ -4,14 +4,11 @@ import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.inList import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.v1.jdbc.deleteAll import org.jetbrains.exposed.sql.SqlExpressionBuilder.inSubQuery
import org.jetbrains.exposed.v1.jdbc.deleteWhere import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.update
open class ExposedKeyValueRepo<Key, Value>( open class ExposedKeyValueRepo<Key, Value>(
database: Database, database: Database,

View File

@@ -1,13 +1,13 @@
package dev.inmo.micro_utils.repos.exposed.keyvalue package dev.inmo.micro_utils.repos.exposed.keyvalue
import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValueRepo import dev.inmo.micro_utils.repos.ReadKeyValueRepo
import dev.inmo.micro_utils.repos.exposed.* import dev.inmo.micro_utils.repos.exposed.*
import org.jetbrains.exposed.v1.core.Column import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.sql.statements.UpdateBuilder
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.Database
open class ExposedReadKeyValueRepo<Key, Value>( open class ExposedReadKeyValueRepo<Key, Value>(
database: Database, database: Database,
@@ -20,10 +20,10 @@ open class ExposedReadKeyValueRepo<Key, Value>(
val valueColumn: Column<Value> = valueColumnAllocator() val valueColumn: Column<Value> = valueColumnAllocator()
override val ResultRow.asKey: Key override val ResultRow.asKey: Key
get() = get(keyColumn) get() = get(keyColumn)
override val selectByValue: (Value) -> Op<Boolean> = { valueColumn.eq(it) } override val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val ResultRow.asObject: Value override val ResultRow.asObject: Value
get() = get(valueColumn) get() = get(valueColumn)
override val selectById: (Key) -> Op<Boolean> = { keyColumn.eq(it) } override val selectById: ISqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
override val primaryKey: Table.PrimaryKey override val primaryKey: Table.PrimaryKey
get() = PrimaryKey(keyColumn, valueColumn) get() = PrimaryKey(keyColumn, valueColumn)

View File

@@ -3,13 +3,9 @@ package dev.inmo.micro_utils.repos.exposed.onetomany
import dev.inmo.micro_utils.repos.KeyValuesRepo import dev.inmo.micro_utils.repos.KeyValuesRepo
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.statements.UpdateBuilder
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.batchInsert
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
abstract class AbstractExposedKeyValuesRepo<Key, Value>( abstract class AbstractExposedKeyValuesRepo<Key, Value>(
override val database: Database, override val database: Database,
@@ -64,7 +60,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
val oldObjects = selectAll().where { selectByIds(toSet.keys.toList()) }.map { it.asKey to it.asObject } val oldObjects = selectAll().where { selectByIds(toSet.keys.toList()) }.map { it.asKey to it.asObject }
deleteWhere { deleteWhere {
selectByIds(toSet.keys.toList()) selectByIds(it, toSet.keys.toList())
} }
val inserted = batchInsert( val inserted = batchInsert(
prepreparedData, prepreparedData,
@@ -108,7 +104,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
transaction(database) { transaction(database) {
toRemove.keys.flatMap { k -> toRemove.keys.flatMap { k ->
toRemove[k] ?.mapNotNull { v -> toRemove[k] ?.mapNotNull { v ->
if (deleteWhere { selectById(k).and(selectByValue(v)) } > 0 ) { if (deleteWhere { selectById(it, k).and(SqlExpressionBuilder.selectByValue(v)) } > 0 ) {
k to v k to v
} else { } else {
null null
@@ -122,7 +118,7 @@ abstract class AbstractExposedKeyValuesRepo<Key, Value>(
override suspend fun clear(k: Key) { override suspend fun clear(k: Key) {
transaction(database) { transaction(database) {
deleteWhere { selectById(k) } deleteWhere { selectById(it, k) }
}.also { _onDataCleared.emit(k) } }.also { _onDataCleared.emit(k) }
} }
} }

View File

@@ -4,14 +4,8 @@ import dev.inmo.micro_utils.pagination.*
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.* import dev.inmo.micro_utils.repos.exposed.*
import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated import dev.inmo.micro_utils.repos.exposed.utils.selectPaginated
import org.jetbrains.exposed.v1.core.Column import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.core.Table
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
abstract class AbstractExposedReadKeyValuesRepo<Key, Value>( abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
override val database: Database, override val database: Database,
@@ -23,7 +17,7 @@ abstract class AbstractExposedReadKeyValuesRepo<Key, Value>(
abstract val ResultRow.asKey: Key abstract val ResultRow.asKey: Key
override val ResultRow.asId: Key override val ResultRow.asId: Key
get() = asKey get() = asKey
abstract val selectByValue: (Value) -> Op<Boolean> abstract val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean>
override suspend fun count(k: Key): Long = transaction(database) { selectAll().where { selectById(k) }.count() } override suspend fun count(k: Key): Long = transaction(database) { selectAll().where { selectById(k) }.count() }

View File

@@ -4,13 +4,10 @@ import dev.inmo.micro_utils.repos.KeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.ColumnAllocator import dev.inmo.micro_utils.repos.exposed.ColumnAllocator
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.v1.core.inList import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value> typealias ExposedOneToManyKeyValueRepo1<Key, Value> = ExposedKeyValuesRepo<Key, Value>
open class ExposedKeyValuesRepo<Key, Value>( open class ExposedKeyValuesRepo<Key, Value>(
@@ -37,7 +34,7 @@ open class ExposedKeyValuesRepo<Key, Value>(
get() = _onDataCleared get() = _onDataCleared
override suspend fun add(toAdd: Map<Key, List<Value>>) { override suspend fun add(toAdd: Map<Key, List<Value>>) {
transaction (database) { transaction(database) {
toAdd.keys.flatMap { k -> toAdd.keys.flatMap { k ->
toAdd[k] ?.mapNotNull { v -> toAdd[k] ?.mapNotNull { v ->
if (selectAll().where { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) { if (selectAll().where { keyColumn.eq(k).and(valueColumn.eq(v)) }.limit(1).count() > 0) {
@@ -76,7 +73,7 @@ open class ExposedKeyValuesRepo<Key, Value>(
override suspend fun removeWithValue(v: Value) { override suspend fun removeWithValue(v: Value) {
transaction(database) { transaction(database) {
val keys = selectAll().where { selectByValue(v) }.map { it.asKey } val keys = selectAll().where { selectByValue(v) }.map { it.asKey }
deleteWhere { selectByValue(v) } deleteWhere { SqlExpressionBuilder.selectByValue(v) }
keys keys
}.forEach { }.forEach {
_onValueRemoved.emit(it to v) _onValueRemoved.emit(it to v)

View File

@@ -2,11 +2,7 @@ package dev.inmo.micro_utils.repos.exposed.onetomany
import dev.inmo.micro_utils.repos.ReadKeyValuesRepo import dev.inmo.micro_utils.repos.ReadKeyValuesRepo
import dev.inmo.micro_utils.repos.exposed.* import dev.inmo.micro_utils.repos.exposed.*
import org.jetbrains.exposed.v1.core.Column import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.Op
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.jdbc.Database
typealias ExposedReadOneToManyKeyValueRepo<Key, Value> = ExposedReadKeyValuesRepo<Key, Value> typealias ExposedReadOneToManyKeyValueRepo<Key, Value> = ExposedReadKeyValuesRepo<Key, Value>
@@ -19,10 +15,10 @@ open class ExposedReadKeyValuesRepo<Key, Value>(
override val keyColumn: Column<Key> = keyColumnAllocator() override val keyColumn: Column<Key> = keyColumnAllocator()
override val ResultRow.asKey: Key override val ResultRow.asKey: Key
get() = get(keyColumn) get() = get(keyColumn)
override val selectByValue: (Value) -> Op<Boolean> = { valueColumn.eq(it) } override val selectByValue: ISqlExpressionBuilder.(Value) -> Op<Boolean> = { valueColumn.eq(it) }
override val ResultRow.asObject: Value override val ResultRow.asObject: Value
get() = get(valueColumn) get() = get(valueColumn)
override val selectById: (Key) -> Op<Boolean> = { keyColumn.eq(it) } override val selectById: ISqlExpressionBuilder.(Key) -> Op<Boolean> = { keyColumn.eq(it) }
val valueColumn: Column<Value> = valueColumnAllocator() val valueColumn: Column<Value> = valueColumnAllocator()
init { initTable() } init { initTable() }

View File

@@ -1,10 +1,7 @@
package dev.inmo.micro_utils.repos.exposed.utils package dev.inmo.micro_utils.repos.exposed.utils
import dev.inmo.micro_utils.pagination.* import dev.inmo.micro_utils.pagination.*
import org.jetbrains.exposed.v1.core.Expression import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.ResultRow
import org.jetbrains.exposed.v1.core.SortOrder
import org.jetbrains.exposed.v1.jdbc.Query
fun <T> Query.selectPaginated( fun <T> Query.selectPaginated(
pagination: Pagination, pagination: Pagination,

View File

@@ -3,12 +3,8 @@ package dev.inmo.micro_utils.repos.exposed.versions
import dev.inmo.micro_utils.repos.exposed.ExposedRepo import dev.inmo.micro_utils.repos.exposed.ExposedRepo
import dev.inmo.micro_utils.repos.exposed.initTable import dev.inmo.micro_utils.repos.exposed.initTable
import dev.inmo.micro_utils.repos.versions.* import dev.inmo.micro_utils.repos.versions.*
import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.Database
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.jetbrains.exposed.v1.jdbc.update
/** /**
* Use this method to create [StandardVersionsRepo] based on [Database] with [ExposedStandardVersionsRepoProxy] as * Use this method to create [StandardVersionsRepo] based on [Database] with [ExposedStandardVersionsRepoProxy] as

View File

@@ -1,8 +1,8 @@
package full package full
import com.benasher44.uuid.uuid4 import com.benasher44.uuid.uuid4
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.v1.jdbc.transactions.transactionManager import org.jetbrains.exposed.sql.transactions.transactionManager
import org.sqlite.JDBC import org.sqlite.JDBC
import java.io.File import java.io.File
import java.sql.Connection import java.sql.Connection

View File

@@ -5,12 +5,12 @@ import dev.inmo.micro_utils.repos.CRUDRepo
import dev.inmo.micro_utils.repos.common.tests.CommonCRUDRepoTests import dev.inmo.micro_utils.repos.common.tests.CommonCRUDRepoTests
import dev.inmo.micro_utils.repos.exposed.AbstractExposedCRUDRepo import dev.inmo.micro_utils.repos.exposed.AbstractExposedCRUDRepo
import dev.inmo.micro_utils.repos.exposed.initTable import dev.inmo.micro_utils.repos.exposed.initTable
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.sql.ISqlExpressionBuilder
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.v1.core.statements.InsertStatement import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.statements.UpdateBuilder
import java.io.File import java.io.File
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
@@ -29,7 +29,7 @@ class ExposedCRUDRepoTests : CommonCRUDRepoTests() {
asId, asId,
get(dataColumn) get(dataColumn)
) )
override val selectById: (String) -> Op<Boolean> = { idColumn.eq(it) } override val selectById: ISqlExpressionBuilder.(String) -> Op<Boolean> = { idColumn.eq(it) }
init { init {
initTable() initTable()

View File

@@ -4,11 +4,11 @@ import dev.inmo.micro_utils.repos.KeyValueRepo
import dev.inmo.micro_utils.repos.common.tests.CommonKeyValueRepoTests import dev.inmo.micro_utils.repos.common.tests.CommonKeyValueRepoTests
import dev.inmo.micro_utils.repos.exposed.initTable import dev.inmo.micro_utils.repos.exposed.initTable
import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo import dev.inmo.micro_utils.repos.exposed.keyvalue.AbstractExposedKeyValueRepo
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.sql.ISqlExpressionBuilder
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.statements.UpdateBuilder
import java.io.File import java.io.File
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
@@ -22,10 +22,10 @@ class ExposedKeyValueRepoTests : CommonKeyValueRepoTests() {
override val ResultRow.asKey: String override val ResultRow.asKey: String
get() = get(keyColumn) get() = get(keyColumn)
override val selectByValue: (String) -> Op<Boolean> = { dataColumn.eq(it) } override val selectByValue: ISqlExpressionBuilder.(String) -> Op<Boolean> = { dataColumn.eq(it) }
override val ResultRow.asObject: String override val ResultRow.asObject: String
get() = get(dataColumn) get() = get(dataColumn)
override val selectById: (String) -> Op<Boolean> = { keyColumn.eq(it) } override val selectById: ISqlExpressionBuilder.(String) -> Op<Boolean> = { keyColumn.eq(it) }
init { init {
initTable() initTable()

View File

@@ -4,11 +4,11 @@ import dev.inmo.micro_utils.repos.KeyValuesRepo
import dev.inmo.micro_utils.repos.common.tests.CommonKeyValuesRepoTests import dev.inmo.micro_utils.repos.common.tests.CommonKeyValuesRepoTests
import dev.inmo.micro_utils.repos.exposed.initTable import dev.inmo.micro_utils.repos.exposed.initTable
import dev.inmo.micro_utils.repos.exposed.onetomany.AbstractExposedKeyValuesRepo import dev.inmo.micro_utils.repos.exposed.onetomany.AbstractExposedKeyValuesRepo
import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.v1.core.ResultRow import org.jetbrains.exposed.sql.ISqlExpressionBuilder
import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.v1.core.statements.UpdateBuilder import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.v1.jdbc.Database import org.jetbrains.exposed.sql.statements.UpdateBuilder
import java.io.File import java.io.File
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
@@ -22,10 +22,10 @@ class ExposedKeyValuesRepoTests : CommonKeyValuesRepoTests() {
override val ResultRow.asKey: String override val ResultRow.asKey: String
get() = get(keyColumn) get() = get(keyColumn)
override val selectByValue: (String) -> Op<Boolean> = { dataColumn.eq(it) } override val selectByValue: ISqlExpressionBuilder.(String) -> Op<Boolean> = { dataColumn.eq(it) }
override val ResultRow.asObject: String override val ResultRow.asObject: String
get() = get(dataColumn) get() = get(dataColumn)
override val selectById: (String) -> Op<Boolean> = { keyColumn.eq(it) } override val selectById: ISqlExpressionBuilder.(String) -> Op<Boolean> = { keyColumn.eq(it) }
init { init {
initTable() initTable()