Skip to content

Commit 306474d

Browse files
committed
refactor(model-api): extract replaceNode into IReplaceableNode
1 parent 2741984 commit 306474d

File tree

13 files changed

+35
-50
lines changed

13 files changed

+35
-50
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.modelix.model.api.ConceptReference
2222
import org.modelix.model.api.INode
2323
import org.modelix.model.api.INodeReference
2424
import org.modelix.model.api.INodeResolutionScope
25+
import org.modelix.model.api.IReplaceableNode
2526
import org.modelix.model.api.SerializedNodeReference
2627
import org.modelix.model.api.getDescendants
2728
import org.modelix.model.api.isChildRoleOrdered
@@ -273,7 +274,7 @@ class ModelImporter(
273274
if (existingNode.getConceptReference() == newConcept) {
274275
return existingNode
275276
}
276-
requireNotNull(newConcept) { "Unexpected null concept" }
277+
require(existingNode is IReplaceableNode) { "Concept has changed but node is not replaceable. node=$existingNode" }
277278
return existingNode.replaceNode(newConcept)
278279
}
279280

light-model-client/src/commonMain/kotlin/org/modelix/client/light/LightModelClient.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,6 @@ class LightModelClient internal constructor(
455455
}
456456
}
457457

458-
override fun replaceNode(concept: ConceptReference): INode {
459-
TODO("Not yet implemented")
460-
}
461-
462458
override fun removeChild(child: INode) {
463459
require(child is NodeAdapter && child.getClient() == getClient()) { "Unsupported child type: $child" }
464460
requiresWrite {

model-api/src/commonMain/kotlin/org/modelix/model/api/INode.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,6 @@ interface INode {
4747

4848
fun tryGetConcept(): IConcept? = getConceptReference()?.tryResolve()
4949

50-
/**
51-
* Replaces this node with a new node of the given concept that uses the same id as this node.
52-
* Properties, references and children will be the same.
53-
*
54-
* @param concept the concept of the new node
55-
* @return replacement for this node with the new given concept
56-
*/
57-
fun replaceNode(concept: ConceptReference): INode {
58-
throw UnsupportedOperationException() // Default implementation to avoid breaking change
59-
}
60-
6150
/**
6251
* Role of this node in its parent node if it exists,or null otherwise.
6352
*/
@@ -308,6 +297,20 @@ interface IDeprecatedNodeDefaults : INode {
308297
override fun getReferenceLinks(): List<IReferenceLink>
309298
}
310299

300+
/**
301+
* Interface for nodes that can be replaced by a new instance.
302+
*/
303+
interface IReplaceableNode : INode {
304+
/**
305+
* Replaces this node with a new node of the given concept that uses the same id as this node.
306+
* Properties, references and children will be the same.
307+
*
308+
* @param concept the concept of the new node
309+
* @return replacement for this node with the new given concept
310+
*/
311+
fun replaceNode(concept: ConceptReference?): INode
312+
}
313+
311314
@Deprecated("Use .key(INode), .key(IBranch), .key(ITransaction) or .key(ITree)")
312315
fun IRole.key(): String = RoleAccessContext.getKey(this)
313316
fun IRole.key(node: INode): String = if (node.usesRoleIds()) getUID() else getSimpleName()

model-api/src/commonMain/kotlin/org/modelix/model/api/PNodeAdapter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map
2020
import kotlinx.coroutines.flow.mapNotNull
2121
import org.modelix.model.area.PArea
2222

23-
open class PNodeAdapter(val nodeId: Long, val branch: IBranch) : INode, INodeEx {
23+
open class PNodeAdapter(val nodeId: Long, val branch: IBranch) : INode, INodeEx, IReplaceableNode {
2424

2525
init {
2626
require(nodeId != 0L, { "Invalid node 0" })
@@ -82,7 +82,7 @@ open class PNodeAdapter(val nodeId: Long, val branch: IBranch) : INode, INodeEx
8282
return PNodeAdapter(branch.writeTransaction.addNewChild(nodeId, role.key(this), index, concept), branch)
8383
}
8484

85-
override fun replaceNode(concept: ConceptReference): INode {
85+
override fun replaceNode(concept: ConceptReference?): INode {
8686
branch.writeTransaction.setConcept(nodeId, concept)
8787
return this
8888
}

model-api/src/commonMain/kotlin/org/modelix/model/area/AreaWithMounts.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.modelix.model.api.IConceptReference
2020
import org.modelix.model.api.INode
2121
import org.modelix.model.api.INodeReference
2222
import org.modelix.model.api.INodeWrapper
23+
import org.modelix.model.api.IReplaceableNode
2324

2425
@Deprecated("not supported anymore")
2526
class AreaWithMounts(val rootArea: IArea, mounts: Map<INode, IArea>) : IArea {
@@ -151,7 +152,7 @@ class AreaWithMounts(val rootArea: IArea, mounts: Map<INode, IArea>) : IArea {
151152
val mountValues: List<IAreaReference>,
152153
) : IAreaReference
153154

154-
inner class NodeWrapper(val node: INode) : INode, INodeWrapper {
155+
inner class NodeWrapper(val node: INode) : INode, INodeWrapper, IReplaceableNode {
155156
override fun getWrappedNode(): INode = node
156157

157158
override fun getArea(): IArea = this@AreaWithMounts
@@ -160,7 +161,8 @@ class AreaWithMounts(val rootArea: IArea, mounts: Map<INode, IArea>) : IArea {
160161
return node.getChildren(role).map { NodeWrapper(getMountedArea(it)?.getRoot() ?: it) }
161162
}
162163

163-
override fun replaceNode(concept: ConceptReference): INode {
164+
override fun replaceNode(concept: ConceptReference?): INode {
165+
check(node is IReplaceableNode)
164166
return NodeWrapper(node.replaceNode(concept))
165167
}
166168

model-api/src/commonMain/kotlin/org/modelix/model/area/CompositeArea.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.modelix.model.api.IConceptReference
2020
import org.modelix.model.api.INode
2121
import org.modelix.model.api.INodeReference
2222
import org.modelix.model.api.INodeWrapper
23+
import org.modelix.model.api.IReplaceableNode
2324

2425
@Deprecated("not supported anymore")
2526
class CompositeArea : IArea {
@@ -164,10 +165,6 @@ class CompositeArea : IArea {
164165
throw UnsupportedOperationException("Read only. Create a new CompositeArea instance instead.")
165166
}
166167

167-
override fun replaceNode(concept: ConceptReference): INode {
168-
throw UnsupportedOperationException("Root cannot have a concept.")
169-
}
170-
171168
override fun removeChild(child: INode) {
172169
throw UnsupportedOperationException("Read only. Create a new CompositeArea instance instead.")
173170
}
@@ -214,7 +211,7 @@ class CompositeArea : IArea {
214211
}
215212
}
216213

217-
inner class NodeWrapper(val node: INode) : INode, INodeWrapper {
214+
inner class NodeWrapper(val node: INode) : INode, INodeWrapper, IReplaceableNode {
218215

219216
override fun getWrappedNode(): INode = node
220217

@@ -224,7 +221,10 @@ class CompositeArea : IArea {
224221
return node.getChildren(role).map { NodeWrapper(it) }
225222
}
226223

227-
override fun replaceNode(concept: ConceptReference): INode = NodeWrapper(node.replaceNode(concept))
224+
override fun replaceNode(concept: ConceptReference?): INode {
225+
require(node is IReplaceableNode)
226+
return NodeWrapper(node.replaceNode(concept))
227+
}
228228

229229
override fun removeChild(child: INode) {
230230
node.removeChild(unwrapNode(child))

model-client/src/commonTest/kotlin/org/modelix/model/api/CompositeAreaTest.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ class MyNode(val name: String) : INode {
2424
override val concept: IConcept?
2525
get() = TODO("Not yet implemented")
2626

27-
override fun replaceNode(concept: ConceptReference): INode {
28-
TODO("Not yet implemented")
29-
}
30-
3127
override val roleInParent: String?
3228
get() = TODO("Not yet implemented")
3329
override val parent: INode?

model-client/src/commonTest/kotlin/org/modelix/model/api/NodeUtilTest.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ class SimpleTestNode(override val concept: IConcept? = null) : INode {
8787
override val reference: INodeReference
8888
get() = TODO("Not yet implemented")
8989

90-
override fun replaceNode(concept: ConceptReference): INode {
91-
TODO("Not yet implemented")
92-
}
93-
9490
override var roleInParent: String? = null
9591
override var parent: INode? = null
9692

model-datastructure/src/jvmMain/kotlin/org/modelix/model/InMemoryModel.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,6 @@ data class InMemoryNode(val model: InMemoryModel, val nodeId: Long) : INode, INo
317317
throw UnsupportedOperationException("read-only")
318318
}
319319

320-
override fun replaceNode(concept: ConceptReference): INode {
321-
throw UnsupportedOperationException("read-only")
322-
}
323-
324320
override fun removeChild(child: INode) {
325321
throw UnsupportedOperationException("read-only")
326322
}

modelql-client/src/commonMain/kotlin/org/modelix/modelql/client/ModelQLNode.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,6 @@ abstract class ModelQLNode(val client: ModelQLClient) : INode, ISupportsModelQL,
149149
return addNewChild(resolveChildLinkOrFallback(role), index, concept)
150150
}
151151

152-
override fun replaceNode(concept: ConceptReference): INode {
153-
throw UnsupportedOperationException("ModelQL currently does not support replacing nodes.")
154-
}
155-
156152
override fun removeChild(child: INode) {
157153
blockingQuery { child.reference.asMono().resolve().remove() }
158154
}

0 commit comments

Comments
 (0)