mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-31 04:05:32 +00:00 
			
		
		
		
	Compare commits
	
		
			20 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| caf9c821f3 | |||
| ca4c6db96f | |||
| 6b2298c752 | |||
| a1bf43def9 | |||
| 15e9254e00 | |||
| afe5a72c6f | |||
| 750a8b9ecf | |||
| 27fc3f93e0 | |||
| 8166d4b99b | |||
| b61d2ae2eb | |||
| 4790fe0aea | |||
| bc37b11cee | |||
| 223fed910f | |||
| b85ab7b061 | |||
| 888dc299c9 | |||
| e113dc28ed | |||
| 31e55d2307 | |||
| e90645f248 | |||
| 4bb7ba2571 | |||
| 8d31c25bf8 | 
							
								
								
									
										26
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,31 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## 0.9.21 | ||||||
|  |  | ||||||
|  | * `Repos`: | ||||||
|  |     * `Exposed`: | ||||||
|  |         * fixes in `AbstractExposedWriteCRUDRepo` | ||||||
|  |  | ||||||
|  | ## 0.9.20 | ||||||
|  |  | ||||||
|  | * `Repos`: | ||||||
|  |     * `Common`: | ||||||
|  |         * Fixes in `OneToManyAndroidRepo` | ||||||
|  |         * New `CursorIterator` | ||||||
|  |  | ||||||
|  | ## 0.9.19 | ||||||
|  |  | ||||||
|  | * `Versions`: | ||||||
|  |     * `Coroutines`: `1.6.0` -> `1.6.1` | ||||||
|  | * `Repos`: | ||||||
|  |     * `Exposed`: | ||||||
|  |         * Fixes in `ExposedStandardVersionsRepoProxy` | ||||||
|  |  | ||||||
|  | ## 0.9.18 | ||||||
|  |  | ||||||
|  | * `Common` | ||||||
|  |     * New extensions for `Element`: `Element#onActionOutside` and `Element#onClickOutside` | ||||||
|  |  | ||||||
| ## 0.9.17 | ## 0.9.17 | ||||||
|  |  | ||||||
| * `Common`: | * `Common`: | ||||||
|   | |||||||
| @@ -51,7 +51,6 @@ class EitherSerializer<T1, T2>( | |||||||
|     private val t1EitherSerializer = EitherFirst.serializer(t1Serializer, t2Serializer) |     private val t1EitherSerializer = EitherFirst.serializer(t1Serializer, t2Serializer) | ||||||
|     private val t2EitherSerializer = EitherSecond.serializer(t1Serializer, t2Serializer) |     private val t2EitherSerializer = EitherSecond.serializer(t1Serializer, t2Serializer) | ||||||
|  |  | ||||||
|     @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) |  | ||||||
|     override fun deserialize(decoder: Decoder): Either<T1, T2> { |     override fun deserialize(decoder: Decoder): Either<T1, T2> { | ||||||
|         return decoder.decodeStructure(descriptor) { |         return decoder.decodeStructure(descriptor) { | ||||||
|             var type: String? = null |             var type: String? = null | ||||||
| @@ -83,7 +82,6 @@ class EitherSerializer<T1, T2>( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) |  | ||||||
|     override fun serialize(encoder: Encoder, value: Either<T1, T2>) { |     override fun serialize(encoder: Encoder, value: Either<T1, T2>) { | ||||||
|         encoder.encodeStructure(descriptor) { |         encoder.encodeStructure(descriptor) { | ||||||
|             when (value) { |             when (value) { | ||||||
|   | |||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | package dev.inmo.micro_utils.common | ||||||
|  |  | ||||||
|  | import kotlinx.browser.document | ||||||
|  | import org.w3c.dom.* | ||||||
|  | import org.w3c.dom.events.Event | ||||||
|  | import org.w3c.dom.events.EventListener | ||||||
|  |  | ||||||
|  | fun Element.onActionOutside(type: String, options: dynamic = null, callback: (Event) -> Unit): EventListener { | ||||||
|  |     lateinit var observer: MutationObserver | ||||||
|  |     val listener = EventListener { | ||||||
|  |         val elementsToCheck = mutableListOf<Element>(this@onActionOutside) | ||||||
|  |         while (it.target != this@onActionOutside && elementsToCheck.isNotEmpty()) { | ||||||
|  |             val childrenGettingElement = elementsToCheck.removeFirst() | ||||||
|  |             for (i in 0 until childrenGettingElement.childElementCount) { | ||||||
|  |                 elementsToCheck.add(childrenGettingElement.children[i] ?: continue) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (elementsToCheck.isEmpty()) { | ||||||
|  |             callback(it) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (options == null) { | ||||||
|  |         document.addEventListener(type, listener) | ||||||
|  |     } else { | ||||||
|  |         document.addEventListener(type, listener, options) | ||||||
|  |     } | ||||||
|  |     observer = onRemoved { | ||||||
|  |         if (options == null) { | ||||||
|  |             document.removeEventListener(type, listener) | ||||||
|  |         } else { | ||||||
|  |             document.removeEventListener(type, listener, options) | ||||||
|  |         } | ||||||
|  |         observer.disconnect() | ||||||
|  |     } | ||||||
|  |     return listener | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fun Element.onClickOutside(options: dynamic = null, callback: (Event) -> Unit) = onActionOutside("click", options, callback) | ||||||
| @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 | |||||||
| # Project data | # Project data | ||||||
|  |  | ||||||
| group=dev.inmo | group=dev.inmo | ||||||
| version=0.9.17 | version=0.9.21 | ||||||
| android_code_version=107 | android_code_version=111 | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|  |  | ||||||
| kt = "1.6.10" | kt = "1.6.10" | ||||||
| kt-serialization = "1.3.2" | kt-serialization = "1.3.2" | ||||||
| kt-coroutines = "1.6.0" | kt-coroutines = "1.6.1" | ||||||
|  |  | ||||||
| jb-compose = "1.1.1" | jb-compose = "1.1.1" | ||||||
| jb-exposed = "0.37.3" | jb-exposed = "0.37.3" | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import dev.inmo.micro_utils.pagination.* | |||||||
|  * Example: |  * Example: | ||||||
|  * |  * | ||||||
|  * * `|__f__l_______________________|` will be transformed to `|_______________________f__l__|` |  * * `|__f__l_______________________|` will be transformed to `|_______________________f__l__|` | ||||||
|  * * `|__f__l_|` will be transformed to `|__f__l_|` |  * * `|__f__l_|` will be transformed to `|_f__l__|` | ||||||
|  * |  * | ||||||
|  * @return Reversed version of this [Pagination] |  * @return Reversed version of this [Pagination] | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -13,12 +13,12 @@ interface VersionsRepo<T> : Repo { | |||||||
|      * By default, instance of this interface will check that version of table with name [tableName] is less than |      * By default, instance of this interface will check that version of table with name [tableName] is less than | ||||||
|      * [version] or is absent |      * [version] or is absent | ||||||
|      * |      * | ||||||
|      * * In case if [tableName] didn't found, will be called [onCreate] and version of table will be set up to [version] |      * In case if [tableName] didn't found, will be called [onCreate]. Then in case if [tableName] have version less | ||||||
|      * * In case if [tableName] have version less than parameter [version], it will increase version one-by-one |      * than parameter [version] or null, it will increase version one-by-one until database version will be equal to | ||||||
|      * until database version will be equal to [version] |      * [version] | ||||||
|      * |      * | ||||||
|      * @param version Current version of table |      * @param version Current version of table | ||||||
|      * @param onCreate This callback will be called in case when table have no information about table |      * @param onCreate This callback will be called in case when repo have no information about table | ||||||
|      * @param onUpdate This callback will be called after **iterative** changing of version. It is expected that parameter |      * @param onUpdate This callback will be called after **iterative** changing of version. It is expected that parameter | ||||||
|      * "to" will always be greater than "from" |      * "to" will always be greater than "from" | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | package dev.inmo.micro_utils.repos | ||||||
|  |  | ||||||
|  | import android.database.Cursor | ||||||
|  |  | ||||||
|  | class CursorIterator( | ||||||
|  |     private val c: Cursor | ||||||
|  | ) : Iterator<Cursor> { | ||||||
|  |     private var i = 0 | ||||||
|  |  | ||||||
|  |     init { | ||||||
|  |         c.moveToFirst() | ||||||
|  |     } | ||||||
|  |     override fun hasNext(): Boolean { | ||||||
|  |         return i < c.count | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun next(): Cursor { | ||||||
|  |         i++ | ||||||
|  |         return if (c.moveToNext()) { | ||||||
|  |             c | ||||||
|  |         } else { | ||||||
|  |             throw NoSuchElementException() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | operator fun Cursor.iterator(): CursorIterator = CursorIterator(this) | ||||||
| @@ -143,7 +143,12 @@ class OneToManyAndroidRepo<Key, Value>( | |||||||
|     }.toLong() |     }.toLong() | ||||||
|  |  | ||||||
|     override suspend fun count(k: Key): Long = helper.blockingReadableTransaction { |     override suspend fun count(k: Key): Long = helper.blockingReadableTransaction { | ||||||
|         selectDistinct(tableName, columns = valueColumnArray, selection = "$idColumnName=?", selectionArgs = arrayOf(k.keyAsString()), limit = FirstPagePagination(1).limitClause()).use { |         selectDistinct( | ||||||
|  |             tableName, | ||||||
|  |             columns = valueColumnArray, | ||||||
|  |             selection = "$idColumnName=?", | ||||||
|  |             selectionArgs = arrayOf(k.keyAsString()) | ||||||
|  |         ).use { | ||||||
|             it.count |             it.count | ||||||
|         } |         } | ||||||
|     }.toLong() |     }.toLong() | ||||||
|   | |||||||
| @@ -17,13 +17,19 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|     ExposedCRUDRepo<ObjectType, IdType>, |     ExposedCRUDRepo<ObjectType, IdType>, | ||||||
|     WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> |     WriteStandardCRUDRepo<ObjectType, IdType, InputValueType> | ||||||
| { | { | ||||||
|     protected val newObjectsChannel = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) |     protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) | ||||||
|     protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) |     protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize) | ||||||
|     protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize) |     protected val _deletedObjectsIdsFlow = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize) | ||||||
|  |     @Deprecated("Renamed", ReplaceWith("_newObjectsFlow")) | ||||||
|  |     protected val newObjectsChannel = _newObjectsFlow | ||||||
|  |     @Deprecated("Renamed", ReplaceWith("_updatedObjectsFlow")) | ||||||
|  |     protected val updateObjectsChannel = _updatedObjectsFlow | ||||||
|  |     @Deprecated("Renamed", ReplaceWith("_deletedObjectsIdsFlow")) | ||||||
|  |     protected val deleteObjectsIdsChannel = _deletedObjectsIdsFlow | ||||||
|  |  | ||||||
|     override val newObjectsFlow: Flow<ObjectType> = newObjectsChannel.asSharedFlow() |     override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow() | ||||||
|     override val updatedObjectsFlow: Flow<ObjectType> = updateObjectsChannel.asSharedFlow() |     override val updatedObjectsFlow: Flow<ObjectType> = _updatedObjectsFlow.asSharedFlow() | ||||||
|     override val deletedObjectsIdsFlow: Flow<IdType> = deleteObjectsIdsChannel.asSharedFlow() |     override val deletedObjectsIdsFlow: Flow<IdType> = _deletedObjectsIdsFlow.asSharedFlow() | ||||||
|  |  | ||||||
|     protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType |     protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType | ||||||
|     abstract val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean> |     abstract val selectByIds: SqlExpressionBuilder.(List<IdType>) -> Op<Boolean> | ||||||
| @@ -43,7 +49,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|         return transaction(db = database) { |         return transaction(db = database) { | ||||||
|             values.map { value -> createWithoutNotification(value) } |             values.map { value -> createWithoutNotification(value) } | ||||||
|         }.onEach { |         }.onEach { | ||||||
|             newObjectsChannel.emit(it) |             _newObjectsFlow.emit(it) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -74,7 +80,7 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|         onBeforeUpdate(listOf(id to value)) |         onBeforeUpdate(listOf(id to value)) | ||||||
|         return updateWithoutNotification(id, value).also { |         return updateWithoutNotification(id, value).also { | ||||||
|             if (it != null) { |             if (it != null) { | ||||||
|                 updateObjectsChannel.emit(it) |                 _updatedObjectsFlow.emit(it) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -85,16 +91,25 @@ abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>( | |||||||
|                 values.map { (id, value) -> updateWithoutNotification(id, value) } |                 values.map { (id, value) -> updateWithoutNotification(id, value) } | ||||||
|             }.filterNotNull() |             }.filterNotNull() | ||||||
|         ).onEach { |         ).onEach { | ||||||
|             updateObjectsChannel.emit(it) |             _updatedObjectsFlow.emit(it) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     protected open suspend fun onBeforeDelete(ids: List<IdType>) {} |     protected open suspend fun onBeforeDelete(ids: List<IdType>) {} | ||||||
|     override suspend fun deleteById(ids: List<IdType>) { |     override suspend fun deleteById(ids: List<IdType>) { | ||||||
|         onBeforeDelete(ids) |         onBeforeDelete(ids) | ||||||
|         transaction(db = database) { |         transaction(db = database) { | ||||||
|             deleteWhere(null, null) { |             val deleted = deleteWhere(null, null) { | ||||||
|                 selectByIds(ids) |                 selectByIds(ids) | ||||||
|             } |             } | ||||||
|  |             if (deleted == ids.size) { | ||||||
|  |                 ids | ||||||
|  |             } else { | ||||||
|  |                 ids.filter { | ||||||
|  |                     select { selectById(it) }.limit(1).none() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }.forEach { | ||||||
|  |             _deletedObjectsIdsFlow.emit(it) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ class ExposedStandardVersionsRepoProxy( | |||||||
|     override val database: Database |     override val database: Database | ||||||
| ) : StandardVersionsRepoProxy<Database>, Table("ExposedVersionsProxy"), ExposedRepo { | ) : StandardVersionsRepoProxy<Database>, Table("ExposedVersionsProxy"), ExposedRepo { | ||||||
|     val tableNameColumn = text("tableName") |     val tableNameColumn = text("tableName") | ||||||
|     val tableVersionColumn = integer("tableName") |     val tableVersionColumn = integer("tableVersion") | ||||||
|  |  | ||||||
|     init { |     init { | ||||||
|         initTable() |         initTable() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user