Skip to content

Commit

Permalink
fix: better block index processing
Browse files Browse the repository at this point in the history
  • Loading branch information
d1snin committed Nov 10, 2023
1 parent 2370855 commit f8e487e
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.*

Expand All @@ -37,16 +36,38 @@ interface BlockRepository {

suspend fun findBlockById(id: UUID): Result<BlockEntity>

suspend fun findBlockInSpaceByRowAndIndex(space: SpaceEntity, row: RowIndex, index: BlockIndex): Result<BlockEntity>

suspend fun countBlocksInSpace(space: SpaceEntity): Result<Int>

suspend fun findBlocksInSpace(space: SpaceEntity): Result<BlockEntities>

suspend fun findLatestBlockIndexInSpaceByRow(space: SpaceEntity, row: RowIndex): Result<Int>

suspend fun findBlocksInSpaceByRowWhichIndexIsGreater(
space: SpaceEntity,
row: RowIndex,
index: BlockIndex
): Result<BlockEntities>

suspend fun findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo(
space: SpaceEntity,
row: RowIndex,
index: Int
index: BlockIndex
): Result<BlockEntities>

suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenEndExclusive(
space: SpaceEntity,
row: RowIndex,
start: BlockIndex,
endExclusive: BlockIndex
): Result<BlockEntities>

suspend fun findBlocksInSpaceByRowWhichIndexIsBetweenStartExclusive(
space: SpaceEntity,
row: RowIndex,
startExclusive: BlockIndex,
end: BlockIndex
): Result<BlockEntities>

suspend fun updateBlock(block: BlockEntity): Result<BlockEntity>
Expand All @@ -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<BlockEntity> =
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<Int> =
withIoCatching {
findBlocksInSpaceAsSequence(space).count()
findBlocksInSpaceAsSequence(space, sorted = false).count()
}

override suspend fun findBlocksInSpace(space: SpaceEntity): Result<BlockEntities> =
withIoCatching {
findBlocksInSpaceAsSequence(space).toList()
findBlocksInSpaceAsSequence(space, sorted = false).toList()
}

override suspend fun findLatestBlockIndexInSpaceByRow(space: SpaceEntity, row: RowIndex): Result<Int> =
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<BlockEntities> =
withIoCatching {
findBlocksInSpaceAsSequence(space, row).filter {
it.index greater index
}.toList()
}

override suspend fun findBlocksInSpaceByRowWhichIndexIsGreaterOrEqualTo(
space: SpaceEntity,
row: RowIndex,
index: Int
index: BlockIndex
): Result<BlockEntities> =
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<BlockEntities> =
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<BlockEntities> =
withIoCatching {
findBlocksInSpaceAsSequence(space, row).filter {
(it.index greater startExclusive) and (it.index lessEq end)
}.toList()
}

override suspend fun updateBlock(block: BlockEntity): Result<BlockEntity> =
withIoCatching {
block.apply {
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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<BlockIndex, BlockIndex> {
val space = block.space
val row = block.row

Expand All @@ -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
}

// Я боюсь наступления вечера...
Expand Down
21 changes: 7 additions & 14 deletions http/daemon.http
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ Authorization: Bearer {{token}}
Content-Type: application/json

{
"row": 1,
"index": 0,
"row": 0,
"index": null,
"size": "MEDIUM",
"entities": [
{
Expand All @@ -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"
}
}
],
Expand Down

0 comments on commit f8e487e

Please sign in to comment.