Skip to content

Commit 15e7c6d

Browse files
committed
feat(model-sync-lib): added stats for import
1 parent 0a218e7 commit 15e7c6d

File tree

2 files changed

+94
-23
lines changed

2 files changed

+94
-23
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.modelix.model.sync
2+
3+
class ImportStats {
4+
val additions: List<String> = mutableListOf()
5+
val deletions: List<String> = mutableListOf()
6+
val moves: List<String> = mutableListOf()
7+
val propertyChanges: List<PropertyChange> = mutableListOf()
8+
val referenceChanges: List<ReferenceChange> = mutableListOf()
9+
10+
fun addAddition(nodeId: String) {
11+
(additions as MutableList).add(nodeId)
12+
}
13+
14+
fun addDeletion(nodeId: String) {
15+
(deletions as MutableList).add(nodeId)
16+
}
17+
18+
fun addMove(nodeId: String) {
19+
(moves as MutableList).add(nodeId)
20+
}
21+
22+
fun addPropertyChange(nodeId: String, property: String) {
23+
(propertyChanges as MutableList).add(PropertyChange(nodeId, property))
24+
}
25+
26+
fun addReferenceChange(nodeId: String, reference: String) {
27+
(referenceChanges as MutableList).add(ReferenceChange(nodeId, reference))
28+
}
29+
30+
}
31+
32+
data class PropertyChange(val nodeId: String, val property: String)
33+
data class ReferenceChange(val nodeId: String, val reference: String)
34+

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

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import org.modelix.model.data.ModelData
77
import org.modelix.model.data.NodeData
88
import java.io.File
99

10-
class ModelImporter(private val root: INode) {
10+
class ModelImporter(private val root: INode, val stats: ImportStats? = null) {
1111

12-
private lateinit var originalIdToRef: MutableMap<String, INodeReference>
1312
private lateinit var originalIdToSpec: MutableMap<String, NodeData>
14-
private lateinit var originalIdToParentSpec: MutableMap<String, NodeData>
1513
private lateinit var originalIdToExisting: MutableMap<String, INode>
14+
private lateinit var originalIdToRef: MutableMap<String, INodeReference>
1615

1716
fun import(jsonFile: File) {
1817
require(jsonFile.exists())
@@ -29,9 +28,6 @@ class ModelImporter(private val root: INode) {
2928
originalIdToSpec = mutableMapOf()
3029
buildSpecIndex(data.root)
3130

32-
originalIdToParentSpec = mutableMapOf()
33-
buildParentSpecIndex(data.root)
34-
3531
syncNode(root, data.root)
3632

3733
originalIdToRef = mutableMapOf()
@@ -46,13 +42,6 @@ class ModelImporter(private val root: INode) {
4642
root.allChildren.forEach { buildExistingIndex(it) }
4743
}
4844

49-
private fun buildParentSpecIndex(nodeData: NodeData) {
50-
for (child in nodeData.children) {
51-
child.originalId()?.let { originalIdToParentSpec[it] = nodeData }
52-
buildParentSpecIndex(child)
53-
}
54-
}
55-
5645
private fun buildRefIndex(node: INode) {
5746
node.originalId()?.let { originalIdToRef[it] = node.reference }
5847
node.allChildren.forEach { buildRefIndex(it) }
@@ -69,11 +58,15 @@ class ModelImporter(private val root: INode) {
6958
}
7059

7160
private fun syncProperties(node: INode, nodeData: NodeData) {
72-
nodeData.properties.forEach { node.setPropertyValue(it.key, it.value) }
61+
nodeData.properties.forEach {
62+
if (node.getPropertyValue(it.key) != it.value) {
63+
node.setPropertyValueWithStats(it.key, it.value)
64+
}
65+
}
7366
val toBeRemoved = node.getPropertyRoles().toSet()
7467
.subtract(nodeData.properties.keys)
7568
.filter { it != NodeData.idPropertyKey }
76-
toBeRemoved.forEach { node.setPropertyValue(it, null) }
69+
toBeRemoved.forEach { node.setPropertyValueWithStats(it, null) }
7770
}
7871

7972
private fun syncAllReferences(root: INode, rootData: NodeData) {
@@ -84,9 +77,13 @@ class ModelImporter(private val root: INode) {
8477
}
8578

8679
private fun syncReferences(node: INode, nodeData: NodeData) {
87-
nodeData.references.forEach { node.setReferenceTarget(it.key, originalIdToRef[it.value]) }
80+
nodeData.references.forEach {
81+
if (node.getReferenceTargetRef(it.key) != originalIdToRef[it.value]) {
82+
node.setReferenceTargetWithStats(it.key, originalIdToRef[it.value])
83+
}
84+
}
8885
val toBeRemoved = node.getReferenceRoles().toSet().subtract(nodeData.references.keys)
89-
toBeRemoved.forEach { node.setPropertyValue(it, null) }
86+
toBeRemoved.forEach { node.setReferenceTargetWithStats(it, null) }
9087
}
9188

9289
private fun syncChildNodes(node: INode, nodeData: NodeData) {
@@ -99,20 +96,19 @@ class ModelImporter(private val root: INode) {
9996

10097
toBeAdded.forEach {
10198
val index = nodeData.children.indexOf(it)
102-
val createdNode = node.addNewChild(it.role, index, it.concept?.let { s -> ConceptReference(s) })
103-
createdNode.setPropertyValue(NodeData.idPropertyKey, it.originalId())
99+
node.addNewChildWithStats(it, index)
104100
}
105101

106102
toBeMovedHere.forEach {
107103
val actualNode = originalIdToExisting[it.originalId()]
108104
val targetIndex = it.getIndexWithinRole(nodeData)
109105
if (actualNode != null) {
110-
node.moveChild(it.role, targetIndex, actualNode)
106+
node.moveChildWithStats(it.role, targetIndex, actualNode)
111107
}
112108
}
113109

114110
val toBeRemoved = node.allChildren.filter { !originalIdToSpec.contains(it.originalId()) }
115-
toBeRemoved.forEach { node.removeChild(it) }
111+
toBeRemoved.forEach { node.removeChildWithStats(it) }
116112

117113
node.allChildren.forEach {
118114
val childData = originalIdToSpec[it.originalId()]
@@ -140,9 +136,11 @@ class ModelImporter(private val root: INode) {
140136
targetIndices[specifiedChild.originalId()] = index
141137
}
142138

143-
for (child in existingChildren) {
139+
for ((index, child) in existingChildren.withIndex()) {
144140
val targetIndex = targetIndices[child.originalId()] ?: -1
145-
node.moveChild(child.roleInParent, targetIndex, child)
141+
if (targetIndex != index) {
142+
node.moveChildWithStats(child.roleInParent, targetIndex, child)
143+
}
146144
}
147145
}
148146

@@ -158,4 +156,43 @@ class ModelImporter(private val root: INode) {
158156
return properties[NodeData.idPropertyKey] ?: id
159157
}
160158

159+
private fun INode.addNewChildWithStats(spec: NodeData, index: Int) : INode {
160+
val concept = spec.concept?.let { s -> ConceptReference(s) }
161+
162+
val createdNode = addNewChild(spec.role, index, concept)
163+
createdNode.setPropertyValue(NodeData.idPropertyKey, spec.originalId())
164+
if (this@ModelImporter.stats != null) {
165+
createdNode.originalId()?.let { stats.addAddition(it) }
166+
}
167+
return createdNode
168+
}
169+
170+
private fun INode.moveChildWithStats(role: String?, index: Int, child: INode) {
171+
if (this@ModelImporter.stats != null) {
172+
child.originalId()?.let { stats.addMove(it) }
173+
}
174+
return moveChild(role, index, child)
175+
}
176+
177+
private fun INode.removeChildWithStats(child: INode) {
178+
if (this@ModelImporter.stats != null) {
179+
child.originalId()?.let { stats.addDeletion(it) }
180+
}
181+
return removeChild(child)
182+
}
183+
184+
private fun INode.setPropertyValueWithStats(role: String, value: String?) {
185+
if (this@ModelImporter.stats != null) {
186+
this.originalId()?.let { stats.addPropertyChange(it, role) }
187+
}
188+
return setPropertyValue(role, value)
189+
}
190+
191+
private fun INode.setReferenceTargetWithStats(role: String, target: INodeReference?) {
192+
if (this@ModelImporter.stats != null) {
193+
this.originalId()?.let { stats.addReferenceChange(it, role) }
194+
}
195+
return setReferenceTarget(role, target)
196+
}
197+
161198
}

0 commit comments

Comments
 (0)