Skip to content

Commit 4dfa769

Browse files
author
Oleksandr Dzhychko
authored
Merge pull request #522 from modelix/feat/resolve-node-on-BranchJS
feat(model-client): add function to resolve a node given the node reference on BranchJS
2 parents 2d686be + b2aaa2f commit 4dfa769

File tree

3 files changed

+147
-18
lines changed

3 files changed

+147
-18
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.client2
18+
19+
import INodeJS
20+
import INodeReferenceJS
21+
import org.modelix.kotlin.utils.UnstableModelixFeature
22+
import org.modelix.model.api.IBranch
23+
import org.modelix.model.api.INodeReferenceSerializer
24+
import org.modelix.model.api.getRootNode
25+
import org.modelix.model.area.getArea
26+
27+
fun interface DisposeFunction {
28+
fun invoke()
29+
}
30+
31+
@OptIn(UnstableModelixFeature::class)
32+
class BranchJSImpl(
33+
private val dispose: DisposeFunction,
34+
private val branch: IBranch,
35+
) : BranchJS {
36+
37+
private val jsRootNode = toNodeJs(branch.getRootNode())
38+
39+
override val rootNode: INodeJS
40+
get() {
41+
return jsRootNode
42+
}
43+
44+
override fun resolveNode(reference: INodeReferenceJS): INodeJS? {
45+
val referenceObject = INodeReferenceSerializer.deserialize(reference as String)
46+
return branch.getArea().resolveNode(referenceObject)?.let(::toNodeJs)
47+
}
48+
49+
override fun dispose() {
50+
dispose.invoke()
51+
}
52+
}

model-client/src/jsMain/kotlin/org/modelix/model/client2/ClientJS.kt

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.modelix.model.client2
2020

2121
import INodeJS
22+
import INodeReferenceJS
2223
import kotlinx.coroutines.DelicateCoroutinesApi
2324
import kotlinx.coroutines.GlobalScope
2425
import kotlinx.coroutines.promise
@@ -31,7 +32,6 @@ import org.modelix.model.api.ITree
3132
import org.modelix.model.api.ITreeChangeVisitor
3233
import org.modelix.model.api.JSNodeConverter
3334
import org.modelix.model.api.PNodeAdapter
34-
import org.modelix.model.api.getRootNode
3535
import org.modelix.model.data.ModelData
3636
import org.modelix.model.lazy.RepositoryId
3737
import org.modelix.model.withAutoTransactions
@@ -47,11 +47,23 @@ fun loadModelsFromJson(
4747
json: Array<String>,
4848
changeCallback: (ChangeJS) -> Unit,
4949
): INodeJS {
50+
val branch = loadModelsFromJsonAsBranch(json, changeCallback)
51+
return branch.rootNode
52+
}
53+
54+
@UnstableModelixFeature(
55+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
56+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
57+
)
58+
@JsExport
59+
fun loadModelsFromJsonAsBranch(
60+
json: Array<String>,
61+
changeCallback: (ChangeJS) -> Unit,
62+
): BranchJS {
5063
val branch = ModelFacade.toLocalBranch(ModelFacade.newLocalTree())
5164
json.forEach { ModelData.fromJson(it).load(branch) }
5265
branch.addListener(ChangeListener(branch, changeCallback))
53-
val rootNode = branch.withAutoTransactions().getRootNode()
54-
return toNodeJs(rootNode)
66+
return BranchJSImpl({}, branch.withAutoTransactions())
5567
}
5668

5769
@UnstableModelixFeature(
@@ -121,9 +133,8 @@ class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
121133
model.start()
122134
val branch = model.getBranch()
123135
branch.addListener(ChangeListener(branch, changeCallback))
124-
val rootNode = branch.withAutoTransactions().getRootNode()
125-
val jsRootNode = toNodeJs(rootNode)
126-
return@promise BranchJSImpl(model, jsRootNode)
136+
val branchWithAutoTransaction = branch.withAutoTransactions()
137+
return@promise BranchJSImpl({ model.dispose() }, branchWithAutoTransaction)
127138
}
128139
}
129140

@@ -140,18 +151,7 @@ class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
140151
interface BranchJS {
141152
val rootNode: INodeJS
142153
fun dispose()
143-
}
144-
145-
class BranchJSImpl(private val model: ReplicatedModel, private val jsRootNode: INodeJS) : BranchJS {
146-
147-
override val rootNode: INodeJS
148-
get() {
149-
return jsRootNode
150-
}
151-
152-
override fun dispose() {
153-
model.dispose()
154-
}
154+
fun resolveNode(reference: INodeReferenceJS): INodeJS?
155155
}
156156

157157
class ChangeListener(private val branch: IBranch, private val changeCallback: (ChangeJS) -> Unit) : IBranchListener {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2023.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.client2
18+
19+
import org.modelix.kotlin.utils.UnstableModelixFeature
20+
import kotlin.test.Test
21+
import kotlin.test.assertEquals
22+
import kotlin.test.assertNull
23+
24+
@OptIn(UnstableModelixFeature::class)
25+
class BranchJSTest {
26+
27+
@Test
28+
fun canResolveNode() {
29+
// Arrange
30+
val data = """
31+
{
32+
"root": {
33+
"children": [
34+
{
35+
"id": "aNode"
36+
}
37+
]
38+
}
39+
}
40+
""".trimIndent()
41+
val branch = loadModelsFromJsonAsBranch(arrayOf(data)) {}
42+
val aNode = branch.rootNode.getAllChildren()[0]
43+
val aNodeReference = aNode.getReference()
44+
45+
// Act
46+
val resolvedNode = branch.resolveNode(aNodeReference)
47+
48+
// Assert
49+
assertEquals(aNode, resolvedNode)
50+
}
51+
52+
@Test
53+
fun canResolveNodeNonExistingNode() {
54+
// Arrange
55+
val data = """
56+
{
57+
"root": {
58+
"children": [
59+
{
60+
"id": "aNode"
61+
}
62+
]
63+
}
64+
}
65+
""".trimIndent()
66+
val branch = loadModelsFromJsonAsBranch(arrayOf(data)) {}
67+
val aNode = branch.rootNode.getAllChildren()[0]
68+
val aNodeReference = aNode.getReference()
69+
branch.rootNode.removeChild(aNode)
70+
71+
// Act
72+
val resolvedNode = branch.resolveNode(aNodeReference)
73+
74+
// Assert
75+
assertNull(resolvedNode)
76+
}
77+
}

0 commit comments

Comments
 (0)