Skip to content

Commit 41a6081

Browse files
author
Oleksandr Dzhychko
authored
Merge pull request #838 from drik98/feature/allow-registry-handlers-to-branch-js
feat(model-client): allow adding change handlers to branches in JS
2 parents 1bebf29 + 2db41e6 commit 41a6081

File tree

10 files changed

+248
-202
lines changed

10 files changed

+248
-202
lines changed

model-api-gen-gradle-test/typescript-generation/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

model-api-gen-gradle-test/typescript-generation/src/test-helpers.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ export function useFakeRootNode(nodeData: object = DEFAULT_NODE_DATA) {
2323
const { loadModelsFromJson } = org.modelix.model.client2;
2424
const rootNode = loadModelsFromJson(
2525
[JSON.stringify(nodeData)],
26-
// for the purpose of the test a change handler is not needed
27-
() => {}
2826
);
2927

3028
function getUntypedNode(role: string = "children1") {

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@
1414
* limitations under the License.
1515
*/
1616

17+
@file:OptIn(UnstableModelixFeature::class)
18+
1719
package org.modelix.model.client2
1820

1921
import INodeJS
2022
import INodeReferenceJS
2123
import org.modelix.kotlin.utils.UnstableModelixFeature
2224
import org.modelix.model.api.IBranch
25+
import org.modelix.model.api.IBranchListener
2326
import org.modelix.model.api.INodeReferenceSerializer
27+
import org.modelix.model.api.ITree
28+
import org.modelix.model.api.ITreeChangeVisitor
29+
import org.modelix.model.api.PNodeAdapter
2430
import org.modelix.model.api.getRootNode
2531
import org.modelix.model.area.getArea
2632

@@ -34,7 +40,19 @@ class BranchJSImpl(
3440
private val branch: IBranch,
3541
) : BranchJS {
3642

43+
private val changeHandlers = mutableSetOf<ChangeHandler>()
44+
3745
private val jsRootNode = toNodeJs(branch.getRootNode())
46+
private val changeListener = ChangeListener(branch) { change ->
47+
changeHandlers.forEach {
48+
changeHandler ->
49+
changeHandler(change)
50+
}
51+
}
52+
53+
init {
54+
branch.addListener(changeListener)
55+
}
3856

3957
override val rootNode: INodeJS
4058
get() {
@@ -46,7 +64,51 @@ class BranchJSImpl(
4664
return branch.getArea().resolveNode(referenceObject)?.let(::toNodeJs)
4765
}
4866

67+
override fun addListener(handler: ChangeHandler) {
68+
changeHandlers.add(handler)
69+
}
70+
override fun removeListener(handler: ChangeHandler) {
71+
changeHandlers.remove(handler)
72+
}
73+
4974
override fun dispose() {
5075
dispose.invoke()
5176
}
5277
}
78+
79+
class ChangeListener(private val branch: IBranch, private val changeCallback: (ChangeJS) -> Unit) : IBranchListener {
80+
81+
fun nodeIdToInode(nodeId: Long): INodeJS {
82+
return toNodeJs(PNodeAdapter(nodeId, branch))
83+
}
84+
85+
override fun treeChanged(oldTree: ITree?, newTree: ITree) {
86+
if (oldTree == null) {
87+
return
88+
}
89+
newTree.visitChanges(
90+
oldTree,
91+
object : ITreeChangeVisitor {
92+
override fun containmentChanged(nodeId: Long) {
93+
changeCallback(ContainmentChanged(nodeIdToInode(nodeId)))
94+
}
95+
96+
override fun conceptChanged(nodeId: Long) {
97+
changeCallback(ConceptChanged(nodeIdToInode(nodeId)))
98+
}
99+
100+
override fun childrenChanged(nodeId: Long, role: String?) {
101+
changeCallback(ChildrenChanged(nodeIdToInode(nodeId), role))
102+
}
103+
104+
override fun referenceChanged(nodeId: Long, role: String) {
105+
changeCallback(ReferenceChanged(nodeIdToInode(nodeId), role))
106+
}
107+
108+
override fun propertyChanged(nodeId: Long, role: String) {
109+
changeCallback(PropertyChanged(nodeIdToInode(nodeId), role))
110+
}
111+
},
112+
)
113+
}
114+
}

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

Lines changed: 10 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
@file:OptIn(UnstableModelixFeature::class)
17+
@file:OptIn(UnstableModelixFeature::class, UnstableModelixFeature::class)
1818

1919
package org.modelix.model.client2
2020

@@ -25,13 +25,8 @@ import kotlinx.coroutines.GlobalScope
2525
import kotlinx.coroutines.promise
2626
import org.modelix.kotlin.utils.UnstableModelixFeature
2727
import org.modelix.model.ModelFacade
28-
import org.modelix.model.api.IBranch
29-
import org.modelix.model.api.IBranchListener
3028
import org.modelix.model.api.INode
31-
import org.modelix.model.api.ITree
32-
import org.modelix.model.api.ITreeChangeVisitor
3329
import org.modelix.model.api.JSNodeConverter
34-
import org.modelix.model.api.PNodeAdapter
3530
import org.modelix.model.data.ModelData
3631
import org.modelix.model.lazy.RepositoryId
3732
import org.modelix.model.withAutoTransactions
@@ -43,11 +38,8 @@ import kotlin.js.Promise
4338
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
4439
)
4540
@JsExport
46-
fun loadModelsFromJson(
47-
json: Array<String>,
48-
changeCallback: (ChangeJS) -> Unit,
49-
): INodeJS {
50-
val branch = loadModelsFromJsonAsBranch(json, changeCallback)
41+
fun loadModelsFromJson(json: Array<String>): INodeJS {
42+
val branch = loadModelsFromJsonAsBranch(json)
5143
return branch.rootNode
5244
}
5345

@@ -56,13 +48,9 @@ fun loadModelsFromJson(
5648
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
5749
)
5850
@JsExport
59-
fun loadModelsFromJsonAsBranch(
60-
json: Array<String>,
61-
changeCallback: (ChangeJS) -> Unit,
62-
): BranchJS {
51+
fun loadModelsFromJsonAsBranch(json: Array<String>): BranchJS {
6352
val branch = ModelFacade.toLocalBranch(ModelFacade.newLocalTree())
6453
json.forEach { ModelData.fromJson(it).load(branch) }
65-
branch.addListener(ChangeListener(branch, changeCallback))
6654
return BranchJSImpl({}, branch.withAutoTransactions())
6755
}
6856

@@ -88,11 +76,7 @@ fun connectClient(url: String): Promise<ClientJS> {
8876
interface ClientJS {
8977
fun dispose()
9078

91-
fun connectBranch(
92-
repositoryId: String,
93-
branchId: String,
94-
changeCallback: (ChangeJS) -> Unit,
95-
): Promise<BranchJS>
79+
fun connectBranch(repositoryId: String, branchId: String): Promise<BranchJS>
9680

9781
fun fetchBranches(repositoryId: String): Promise<Array<String>>
9882

@@ -121,18 +105,13 @@ class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
121105
}
122106

123107
@DelicateCoroutinesApi
124-
override fun connectBranch(
125-
repositoryId: String,
126-
branchId: String,
127-
changeCallback: (ChangeJS) -> Unit,
128-
): Promise<BranchJS> {
108+
override fun connectBranch(repositoryId: String, branchId: String): Promise<BranchJS> {
129109
return GlobalScope.promise {
130110
val modelClient = modelClient
131111
val branchReference = RepositoryId(repositoryId).getBranchReference(branchId)
132112
val model: ReplicatedModel = modelClient.getReplicatedModel(branchReference)
133113
model.start()
134114
val branch = model.getBranch()
135-
branch.addListener(ChangeListener(branch, changeCallback))
136115
val branchWithAutoTransaction = branch.withAutoTransactions()
137116
return@promise BranchJSImpl({ model.dispose() }, branchWithAutoTransaction)
138117
}
@@ -143,6 +122,8 @@ class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
143122
}
144123
}
145124

125+
typealias ChangeHandler = (ChangeJS) -> Unit
126+
146127
@UnstableModelixFeature(
147128
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
148129
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
@@ -152,43 +133,8 @@ interface BranchJS {
152133
val rootNode: INodeJS
153134
fun dispose()
154135
fun resolveNode(reference: INodeReferenceJS): INodeJS?
155-
}
156-
157-
class ChangeListener(private val branch: IBranch, private val changeCallback: (ChangeJS) -> Unit) : IBranchListener {
158-
159-
fun nodeIdToInode(nodeId: Long): INodeJS {
160-
return toNodeJs(PNodeAdapter(nodeId, branch))
161-
}
162-
163-
override fun treeChanged(oldTree: ITree?, newTree: ITree) {
164-
if (oldTree == null) {
165-
return
166-
}
167-
newTree.visitChanges(
168-
oldTree,
169-
object : ITreeChangeVisitor {
170-
override fun containmentChanged(nodeId: Long) {
171-
changeCallback(ContainmentChanged(nodeIdToInode(nodeId)))
172-
}
173-
174-
override fun conceptChanged(nodeId: Long) {
175-
changeCallback(ConceptChanged(nodeIdToInode(nodeId)))
176-
}
177-
178-
override fun childrenChanged(nodeId: Long, role: String?) {
179-
changeCallback(ChildrenChanged(nodeIdToInode(nodeId), role))
180-
}
181-
182-
override fun referenceChanged(nodeId: Long, role: String) {
183-
changeCallback(ReferenceChanged(nodeIdToInode(nodeId), role))
184-
}
185-
186-
override fun propertyChanged(nodeId: Long, role: String) {
187-
changeCallback(PropertyChanged(nodeIdToInode(nodeId), role))
188-
}
189-
},
190-
)
191-
}
136+
fun addListener(handler: ChangeHandler)
137+
fun removeListener(handler: ChangeHandler)
192138
}
193139

194140
fun toNodeJs(rootNode: INode) = JSNodeConverter.nodeToJs(rootNode).unsafeCast<INodeJS>()

0 commit comments

Comments
 (0)