Skip to content

Commit 1a1abde

Browse files
committed
fix(model-sync-lib): fixed order of move operations and additional index issue
1 parent 2c10482 commit 1a1abde

File tree

1 file changed

+51
-30
lines changed

1 file changed

+51
-30
lines changed

model-sync-lib/src/main/kotlin/org/modelix/model/sync/ModelImporter.kt

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ class ModelImporter(private val root: INode, val stats: ImportStats? = null) {
2929
val addedNodes = addAllMissingChildren(root, originalIdToExisting, originalIdToSpec)
3030
syncAllProperties(addedNodes, originalIdToSpec)
3131

32-
3332
val allNodes = allExistingNodes + addedNodes
33+
3434
handleAllMovesAcrossParents(allNodes, originalIdToExisting, originalIdToSpec)
35+
3536
val originalIdToRef: MutableMap<String, INodeReference> = buildRefIndex(allNodes)
3637
syncAllReferences(allNodes, originalIdToSpec, originalIdToRef)
37-
deleteAllExtraChildren(allNodes, originalIdToSpec)
3838

39+
deleteAllExtraChildren(allNodes, originalIdToSpec)
3940
}
4041

4142
private fun buildExistingIndex(allNodes: List<INode>): MutableMap<String, INode> {
@@ -167,22 +168,23 @@ class ModelImporter(private val root: INode, val stats: ImportStats? = null) {
167168

168169
val targetIndices = HashMap<String?, Int>(nodeData.children.size)
169170
for (child in toBeSortedSpec) {
170-
171171
val childrenInRole = existingChildren.filter { it.roleInParent == child.role }
172-
val baseIndex = child.getIndexWithinRole(nodeData).coerceAtMost(childrenInRole.lastIndex)
172+
val baseIndex = child.getIndexWithinRole(nodeData)
173173
var offset = 0
174-
offset += childrenInRole.slice(0..baseIndex).count {
174+
offset += childrenInRole.slice(0..baseIndex.coerceAtMost(childrenInRole.lastIndex)).count {
175175
!originalIdToSpec.containsKey(it.originalId()) // node will be deleted
176176
}
177-
offset -= childrenInRole.slice(0..baseIndex).count {
178-
!existingIds.contains(it.originalId()) // node will be moved here
179-
}
177+
offset -= specifiedChildren
178+
.filter { it.role == child.role }
179+
.slice(0..baseIndex.coerceIn(0..specifiedChildren.lastIndex))
180+
.count {
181+
!existingIds.contains(it.originalId()) // node will be moved here
182+
}
180183
val index = (baseIndex + offset).coerceIn(0..childrenInRole.size)
181184
targetIndices[child.originalId()] = index
182185
}
183186

184187
existingChildren.forEach { child ->
185-
186188
val currentIndex = child.index()
187189
val targetRole = originalIdToSpec[child.originalId()]?.role
188190
val targetIndex = targetIndices[child.originalId()]
@@ -197,36 +199,55 @@ class ModelImporter(private val root: INode, val stats: ImportStats? = null) {
197199
originalIdToExisting: MutableMap<String, INode>,
198200
originalIdToSpec: MutableMap<String, NodeData>
199201
) {
200-
allNodes.forEach {
201-
originalIdToSpec[it.originalId()]?.let { spec -> handleMoveAcrossParents(it, spec, originalIdToExisting, originalIdToSpec) }
202+
val moves = collectMovesAcrossParents(allNodes, originalIdToExisting, originalIdToSpec)
203+
while (moves.isNotEmpty()) {
204+
val nextMove = moves.first { !it.nodeToBeMoved.getDescendants(false).contains(it.targetParent) }
205+
performMoveAcrossParents(nextMove.targetParent, nextMove.nodeToBeMoved, originalIdToSpec)
206+
moves.remove(nextMove)
202207
}
203208
}
204209

205-
private fun handleMoveAcrossParents(
206-
node: INode,
207-
nodeData: NodeData,
210+
private fun collectMovesAcrossParents(
211+
allNodes: List<INode>,
208212
originalIdToExisting: MutableMap<String, INode>,
209213
originalIdToSpec: MutableMap<String, NodeData>
210-
) {
214+
): MutableList<MoveAcrossParents> {
215+
val movesAcrossParents = mutableListOf<MoveAcrossParents>()
216+
allNodes.forEach {node ->
217+
val nodeData = originalIdToSpec[node.originalId()] ?: return@forEach
211218

212-
val existingChildren = node.allChildren.toList()
213-
val missingIds = nodeData.children.map { it.originalId() }.toSet()
214-
.subtract(node.allChildren.map { it.originalId() }.toSet())
215-
val toBeMovedHere = missingIds
216-
.filter { originalIdToSpec.containsKey(it) }
217-
.mapNotNull { originalIdToExisting[it] }
218-
219-
toBeMovedHere.forEach {nodeToBeMoved ->
220-
val spec = originalIdToSpec[nodeToBeMoved.originalId()]!!
221-
val childrenInRole = existingChildren.filter { it.roleInParent == spec.role }
222-
val baseTargetIndex = spec.getIndexWithinRole(nodeData).coerceAtMost(childrenInRole.size)
223-
val offset = existingChildren.slice(0 until baseTargetIndex).count {
224-
!originalIdToSpec.containsKey(it.originalId()) // node will be deleted
219+
val missingIds = nodeData.children.map { it.originalId() }.toSet()
220+
.subtract(node.allChildren.map { it.originalId() }.toSet())
221+
val toBeMovedHere = missingIds
222+
.filter { originalIdToSpec.containsKey(it) }
223+
.mapNotNull { originalIdToExisting[it] }
224+
225+
toBeMovedHere.forEach {
226+
movesAcrossParents.add(MoveAcrossParents(node, it))
225227
}
226-
val targetIndex = (baseTargetIndex + offset).coerceIn(0..childrenInRole.size)
228+
}
229+
return movesAcrossParents
230+
}
231+
232+
private data class MoveAcrossParents(val targetParent: INode, val nodeToBeMoved: INode)
227233

228-
node.moveChildWithStats(spec.role, targetIndex, nodeToBeMoved)
234+
private fun performMoveAcrossParents(
235+
node: INode,
236+
toBeMovedHere: INode,
237+
originalIdToSpec: MutableMap<String, NodeData>
238+
) {
239+
val nodeData = originalIdToSpec[node.originalId()] ?: return
240+
val existingChildren = node.allChildren.toList()
241+
val spec = originalIdToSpec[toBeMovedHere.originalId()]!!
242+
val childrenInRole = existingChildren.filter { it.roleInParent == spec.role }
243+
val baseTargetIndex = spec.getIndexWithinRole(nodeData).coerceAtMost(childrenInRole.size)
244+
val offset = childrenInRole.slice(0 until baseTargetIndex).count {
245+
!originalIdToSpec.containsKey(it.originalId()) // node will be deleted
229246
}
247+
val targetIndex = (baseTargetIndex + offset).coerceIn(0..childrenInRole.size)
248+
249+
node.moveChildWithStats(spec.role, targetIndex, toBeMovedHere)
250+
230251
}
231252

232253
private fun deleteAllExtraChildren(allNodes: List<INode>, originalIdToSpec: MutableMap<String, NodeData>) {

0 commit comments

Comments
 (0)