From f8e487eeb6e7c0afcc9d73d4eb3b9ecfec2d4c43 Mon Sep 17 00:00:00 2001 From: d1snin Date: Sat, 11 Nov 2023 00:02:16 +0300 Subject: [PATCH] fix: better block index processing --- .../beam/daemon/database/BlockRepository.kt | 103 ++++++++++++--- .../d1s/beam/daemon/service/BlockService.kt | 118 ++++++++++++++---- http/daemon.http | 21 ++-- 3 files changed, 187 insertions(+), 55 deletions(-) diff --git a/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/database/BlockRepository.kt b/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/database/BlockRepository.kt index af639946..4cf2decc 100644 --- a/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/database/BlockRepository.kt +++ b/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/database/BlockRepository.kt @@ -16,6 +16,7 @@ package dev.d1s.beam.daemon.database +import dev.d1s.beam.commons.BlockIndex import dev.d1s.beam.commons.RowIndex import dev.d1s.beam.daemon.entity.BlockEntities import dev.d1s.beam.daemon.entity.BlockEntity @@ -25,9 +26,7 @@ import dev.d1s.beam.daemon.util.withIoCatching import org.koin.core.component.KoinComponent import org.koin.core.component.inject import org.ktorm.database.Database -import org.ktorm.dsl.and -import org.ktorm.dsl.eq -import org.ktorm.dsl.greaterEq +import org.ktorm.dsl.* import org.ktorm.entity.* import java.util.* @@ -37,16 +36,38 @@ interface BlockRepository { suspend fun findBlockById(id: UUID): Result + suspend fun findBlockInSpaceByRowAndIndex(space: SpaceEntity, row: RowIndex, index: BlockIndex): Result + suspend fun countBlocksInSpace(space: SpaceEntity): Result suspend fun findBlocksInSpace(space: SpaceEntity): Result suspend fun findLatestBlockIndexInSpaceByRow(space: SpaceEntity, row: RowIndex): Result + suspend fun findBlocksInSpaceByRowWhichIndexIsGreater( + space: SpaceEntity, + row: RowIndex, + index: BlockIndex + ): Result + suspend fun findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo( space: SpaceEntity, row: RowIndex, - index: Int + index: BlockIndex + ): Result + + suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenEndExclusive( + space: SpaceEntity, + row: RowIndex, + start: BlockIndex, + endExclusive: BlockIndex + ): Result + + suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenStartExclusive( + space: SpaceEntity, + row: RowIndex, + startExclusive: BlockIndex, + end: BlockIndex ): Result suspend fun updateBlock(block: BlockEntity): Result @@ -72,39 +93,81 @@ class DefaultBlockRepository : BlockRepository, KoinComponent { withIoCatching { database.blocks.find { it.id eq id - } ?: error("Block not found by ID $id") + } ?: error("Block not found by ID '$id'") + } + + override suspend fun findBlockInSpaceByRowAndIndex( + space: SpaceEntity, + row: RowIndex, + index: BlockIndex + ): Result = + withIoCatching { + database.blocks.find { + (it.spaceId eq space.id) and (it.row eq row) and (it.index eq index) + } ?: error("Block not found in space '${space.id}' by row $row and index $index") } override suspend fun countBlocksInSpace(space: SpaceEntity): Result = withIoCatching { - findBlocksInSpaceAsSequence(space).count() + findBlocksInSpaceAsSequence(space, sorted = false).count() } override suspend fun findBlocksInSpace(space: SpaceEntity): Result = withIoCatching { - findBlocksInSpaceAsSequence(space).toList() + findBlocksInSpaceAsSequence(space, sorted = false).toList() } override suspend fun findLatestBlockIndexInSpaceByRow(space: SpaceEntity, row: RowIndex): Result = withIoCatching { - findBlocksInSpaceAsSequence(space, row).sortedByDescending { - it.index - }.first().requiredIndex + findBlocksInSpaceAsSequence(space, row).first().requiredIndex + } + + override suspend fun findBlocksInSpaceByRowWhichIndexIsGreater( + space: SpaceEntity, + row: RowIndex, + index: BlockIndex + ): Result = + withIoCatching { + findBlocksInSpaceAsSequence(space, row).filter { + it.index greater index + }.toList() } override suspend fun findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo( space: SpaceEntity, row: RowIndex, - index: Int + index: BlockIndex ): Result = withIoCatching { - findBlocksInSpaceAsSequence(space, row).sortedByDescending { - it.index - }.filter { + findBlocksInSpaceAsSequence(space, row).filter { it.index greaterEq index }.toList() } + override suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenEndExclusive( + space: SpaceEntity, + row: RowIndex, + start: BlockIndex, + endExclusive: BlockIndex + ): Result = + withIoCatching { + findBlocksInSpaceAsSequence(space, row).filter { + (it.index greaterEq start) and (it.index less endExclusive) + }.toList() + } + + override suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenStartExclusive( + space: SpaceEntity, + row: RowIndex, + startExclusive: BlockIndex, + end: BlockIndex + ): Result = + withIoCatching { + findBlocksInSpaceAsSequence(space, row).filter { + (it.index greater startExclusive) and (it.index lessEq end) + }.toList() + } + override suspend fun updateBlock(block: BlockEntity): Result = withIoCatching { block.apply { @@ -128,8 +191,16 @@ class DefaultBlockRepository : BlockRepository, KoinComponent { Unit } - private fun findBlocksInSpaceAsSequence(space: SpaceEntity, row: RowIndex? = null) = - database.blocks.filter { block -> + private fun findBlocksInSpaceAsSequence(space: SpaceEntity, row: RowIndex? = null, sorted: Boolean = true) = + database.blocks.let { + if (sorted) { + it.sortedByDescending { block -> + block.index + } + } else { + it + } + }.filter { block -> (block.spaceId eq space.id).let { if (row != null) { it and (block.row eq row) diff --git a/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/service/BlockService.kt b/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/service/BlockService.kt index 9fe8e220..dc990e9f 100644 --- a/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/service/BlockService.kt +++ b/beam-daemon/src/main/kotlin/dev/d1s/beam/daemon/service/BlockService.kt @@ -16,10 +16,7 @@ package dev.d1s.beam.daemon.service -import dev.d1s.beam.commons.Block -import dev.d1s.beam.commons.BlockId -import dev.d1s.beam.commons.LanguageCode -import dev.d1s.beam.commons.SpaceIdentifier +import dev.d1s.beam.commons.* import dev.d1s.beam.commons.event.EntityUpdate import dev.d1s.beam.commons.event.EventReferences import dev.d1s.beam.commons.validation.Limits @@ -96,7 +93,7 @@ class DefaultBlockService : BlockService, KoinComponent { translationService.verifyLocationsExist(block).getOrThrow() processBlockRow(block) - processBlockIndex(block) + processBlockIndexOnCreation(block) val addedBlock = blockRepository.addBlock(block).getOrThrow() val translatedBlock = translateOptionally(addedBlock, languageCode) @@ -177,10 +174,11 @@ class DefaultBlockService : BlockService, KoinComponent { translationService.verifyLocationsExist(modification).getOrThrow() processBlockRow(modification) - processBlockIndex(modification) + processBlockIndexOnUpdate(modification, originalBlock) originalBlock.apply { this.row = modification.row + this.index = modification.index this.size = modification.size this.entities = modification.entities this.metadata = modification.metadata @@ -205,6 +203,8 @@ class DefaultBlockService : BlockService, KoinComponent { val (block, blockDto) = getBlock(id, requireDto = true).getOrThrow() requireNotNull(blockDto) + processBlockIndexOnRemoval(block) + blockRepository.removeBlock(block).getOrThrow() sendBlockRemovedEvent(blockDto) @@ -227,7 +227,88 @@ class DefaultBlockService : BlockService, KoinComponent { rowService.createRowIfDoesntExist(block.row, block.space).getOrThrow() } - private suspend fun processBlockIndex(block: BlockEntity) { + private suspend fun processBlockIndexOnCreation(block: BlockEntity) { + val (index, latestIndex) = prepareBlockIndexProcessing(block) + + val space = block.space + val row = block.row + + when { + index == latestIndex + 1 -> {} + index <= latestIndex -> { + val blocksToUpdate = + blockRepository.findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo(space, row, index) + .getOrThrow() + + blocksToUpdate.forEach { + it.index = it.requiredIndex + 1 + } + + blockRepository.updateBlocks(blocksToUpdate).getOrThrow() + } + } + } + + private suspend fun processBlockIndexOnUpdate(block: BlockEntity, originalBlock: BlockEntity) { + val initialIndex = originalBlock.requiredIndex + val (index, _) = prepareBlockIndexProcessing(block) + + val space = block.space + val row = block.row + + when { + initialIndex < index -> { + val blocksToUpdate = + blockRepository.findBlocksInSpaceByRowWhichIndexIsBetweenStartExclusive( + space, + row, + initialIndex, + index + ).getOrThrow() + + blocksToUpdate.forEach { + it.index = it.requiredIndex - 1 + } + } + + initialIndex > index -> { + val blocksToUpdate = + blockRepository.findBlocksInSpaceByRowWhichIndexIsBetweenEndExclusive( + space, + row, + initialIndex, + index + ).getOrThrow() + + blocksToUpdate.forEach { + it.index = it.requiredIndex + 1 + } + } + } + + val blockWithNewIndex = blockRepository.findBlockInSpaceByRowAndIndex(space, row, index).getOrThrow() + blockWithNewIndex.index = initialIndex + blockRepository.updateBlock(blockWithNewIndex) + } + + private suspend fun processBlockIndexOnRemoval(block: BlockEntity) { + val (index, _) = prepareBlockIndexProcessing(block) + + val space = block.space + val row = block.row + + val blocksToUpdate = + blockRepository.findBlocksInSpaceByRowWhichIndexIsGreater(space, row, index) + .getOrThrow() + + blocksToUpdate.forEach { + it.index = it.requiredIndex - 1 + } + + blockRepository.updateBlocks(blocksToUpdate).getOrThrow() + } + + private suspend fun prepareBlockIndexProcessing(block: BlockEntity): Pair { val space = block.space val row = block.row @@ -247,28 +328,15 @@ class DefaultBlockService : BlockService, KoinComponent { latestIndex = START_INDEX } + if (requiredIndex > (latestIndex + 1) || requiredIndex < START_INDEX) { + throw BadRequestException("Block index is out of bounds") + } + logger.d { "Processing block index. index: $requiredIndex; latestIndex: $latestIndex" } - when { - requiredIndex == latestIndex + 1 -> {} - requiredIndex <= latestIndex -> { - val blocksToUpdate = - blockRepository.findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo(space, row, requiredIndex) - .getOrThrow() - - blocksToUpdate.forEach { - it.index = it.requiredIndex + 1 - } - - blockRepository.updateBlocks(blocksToUpdate) - } - - else -> { - throw BadRequestException("Block index is out of bounds") - } - } + return requiredIndex to latestIndex } // Я боюсь наступления вечера... diff --git a/http/daemon.http b/http/daemon.http index 51573a13..d86380ce 100644 --- a/http/daemon.http +++ b/http/daemon.http @@ -90,8 +90,8 @@ Authorization: Bearer {{token}} Content-Type: application/json { - "row": 1, - "index": 0, + "row": 0, + "index": null, "size": "MEDIUM", "entities": [ { @@ -109,25 +109,18 @@ Content-Type: application/json GET http://localhost:8573/blocks?space=root&language=ru ### PUT Block -PUT http://localhost:8573/blocks/5883fe73-29a6-46b5-9c7e-d907727bf530 +PUT http://localhost:8573/blocks/d35814a3-ab38-49bd-8a83-85d0b7d530ed Authorization: Bearer {{token}} Content-Type: application/json { - "index": 0, - "size": "EXTRA_LARGE", + "row": 0, + "index": null, + "size": "MEDIUM", "entities": [ { - "type": "space", - "parameters": { - "identifier": "root" - } - }, - { - "type": "button-link", + "type": "void", "parameters": { - "text": "Does it work?", - "url": "https://github.com/d1snin/beam" } } ],