Skip to content

Commit

Permalink
Merge pull request #838 from drik98/feature/allow-registry-handlers-t…
Browse files Browse the repository at this point in the history
…o-branch-js

feat(model-client): allow adding change handlers to branches in JS
  • Loading branch information
odzhychko authored Jun 24, 2024
2 parents 1bebf29 + 2db41e6 commit 41a6081
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 202 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export function useFakeRootNode(nodeData: object = DEFAULT_NODE_DATA) {
const { loadModelsFromJson } = org.modelix.model.client2;
const rootNode = loadModelsFromJson(
[JSON.stringify(nodeData)],
// for the purpose of the test a change handler is not needed
() => {}
);

function getUntypedNode(role: string = "children1") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
* limitations under the License.
*/

@file:OptIn(UnstableModelixFeature::class)

package org.modelix.model.client2

import INodeJS
import INodeReferenceJS
import org.modelix.kotlin.utils.UnstableModelixFeature
import org.modelix.model.api.IBranch
import org.modelix.model.api.IBranchListener
import org.modelix.model.api.INodeReferenceSerializer
import org.modelix.model.api.ITree
import org.modelix.model.api.ITreeChangeVisitor
import org.modelix.model.api.PNodeAdapter
import org.modelix.model.api.getRootNode
import org.modelix.model.area.getArea

Expand All @@ -34,7 +40,19 @@ class BranchJSImpl(
private val branch: IBranch,
) : BranchJS {

private val changeHandlers = mutableSetOf<ChangeHandler>()

private val jsRootNode = toNodeJs(branch.getRootNode())
private val changeListener = ChangeListener(branch) { change ->
changeHandlers.forEach {
changeHandler ->
changeHandler(change)
}
}

init {
branch.addListener(changeListener)
}

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

override fun addListener(handler: ChangeHandler) {
changeHandlers.add(handler)
}
override fun removeListener(handler: ChangeHandler) {
changeHandlers.remove(handler)
}

override fun dispose() {
dispose.invoke()
}
}

class ChangeListener(private val branch: IBranch, private val changeCallback: (ChangeJS) -> Unit) : IBranchListener {

fun nodeIdToInode(nodeId: Long): INodeJS {
return toNodeJs(PNodeAdapter(nodeId, branch))
}

override fun treeChanged(oldTree: ITree?, newTree: ITree) {
if (oldTree == null) {
return
}
newTree.visitChanges(
oldTree,
object : ITreeChangeVisitor {
override fun containmentChanged(nodeId: Long) {
changeCallback(ContainmentChanged(nodeIdToInode(nodeId)))
}

override fun conceptChanged(nodeId: Long) {
changeCallback(ConceptChanged(nodeIdToInode(nodeId)))
}

override fun childrenChanged(nodeId: Long, role: String?) {
changeCallback(ChildrenChanged(nodeIdToInode(nodeId), role))
}

override fun referenceChanged(nodeId: Long, role: String) {
changeCallback(ReferenceChanged(nodeIdToInode(nodeId), role))
}

override fun propertyChanged(nodeId: Long, role: String) {
changeCallback(PropertyChanged(nodeIdToInode(nodeId), role))
}
},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

@file:OptIn(UnstableModelixFeature::class)
@file:OptIn(UnstableModelixFeature::class, UnstableModelixFeature::class)

package org.modelix.model.client2

Expand All @@ -25,13 +25,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
import org.modelix.kotlin.utils.UnstableModelixFeature
import org.modelix.model.ModelFacade
import org.modelix.model.api.IBranch
import org.modelix.model.api.IBranchListener
import org.modelix.model.api.INode
import org.modelix.model.api.ITree
import org.modelix.model.api.ITreeChangeVisitor
import org.modelix.model.api.JSNodeConverter
import org.modelix.model.api.PNodeAdapter
import org.modelix.model.data.ModelData
import org.modelix.model.lazy.RepositoryId
import org.modelix.model.withAutoTransactions
Expand All @@ -43,11 +38,8 @@ import kotlin.js.Promise
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
)
@JsExport
fun loadModelsFromJson(
json: Array<String>,
changeCallback: (ChangeJS) -> Unit,
): INodeJS {
val branch = loadModelsFromJsonAsBranch(json, changeCallback)
fun loadModelsFromJson(json: Array<String>): INodeJS {
val branch = loadModelsFromJsonAsBranch(json)
return branch.rootNode
}

Expand All @@ -56,13 +48,9 @@ fun loadModelsFromJson(
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
)
@JsExport
fun loadModelsFromJsonAsBranch(
json: Array<String>,
changeCallback: (ChangeJS) -> Unit,
): BranchJS {
fun loadModelsFromJsonAsBranch(json: Array<String>): BranchJS {
val branch = ModelFacade.toLocalBranch(ModelFacade.newLocalTree())
json.forEach { ModelData.fromJson(it).load(branch) }
branch.addListener(ChangeListener(branch, changeCallback))
return BranchJSImpl({}, branch.withAutoTransactions())
}

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

fun connectBranch(
repositoryId: String,
branchId: String,
changeCallback: (ChangeJS) -> Unit,
): Promise<BranchJS>
fun connectBranch(repositoryId: String, branchId: String): Promise<BranchJS>

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

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

@DelicateCoroutinesApi
override fun connectBranch(
repositoryId: String,
branchId: String,
changeCallback: (ChangeJS) -> Unit,
): Promise<BranchJS> {
override fun connectBranch(repositoryId: String, branchId: String): Promise<BranchJS> {
return GlobalScope.promise {
val modelClient = modelClient
val branchReference = RepositoryId(repositoryId).getBranchReference(branchId)
val model: ReplicatedModel = modelClient.getReplicatedModel(branchReference)
model.start()
val branch = model.getBranch()
branch.addListener(ChangeListener(branch, changeCallback))
val branchWithAutoTransaction = branch.withAutoTransactions()
return@promise BranchJSImpl({ model.dispose() }, branchWithAutoTransaction)
}
Expand All @@ -143,6 +122,8 @@ class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
}
}

typealias ChangeHandler = (ChangeJS) -> Unit

@UnstableModelixFeature(
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
Expand All @@ -152,43 +133,8 @@ interface BranchJS {
val rootNode: INodeJS
fun dispose()
fun resolveNode(reference: INodeReferenceJS): INodeJS?
}

class ChangeListener(private val branch: IBranch, private val changeCallback: (ChangeJS) -> Unit) : IBranchListener {

fun nodeIdToInode(nodeId: Long): INodeJS {
return toNodeJs(PNodeAdapter(nodeId, branch))
}

override fun treeChanged(oldTree: ITree?, newTree: ITree) {
if (oldTree == null) {
return
}
newTree.visitChanges(
oldTree,
object : ITreeChangeVisitor {
override fun containmentChanged(nodeId: Long) {
changeCallback(ContainmentChanged(nodeIdToInode(nodeId)))
}

override fun conceptChanged(nodeId: Long) {
changeCallback(ConceptChanged(nodeIdToInode(nodeId)))
}

override fun childrenChanged(nodeId: Long, role: String?) {
changeCallback(ChildrenChanged(nodeIdToInode(nodeId), role))
}

override fun referenceChanged(nodeId: Long, role: String) {
changeCallback(ReferenceChanged(nodeIdToInode(nodeId), role))
}

override fun propertyChanged(nodeId: Long, role: String) {
changeCallback(PropertyChanged(nodeIdToInode(nodeId), role))
}
},
)
}
fun addListener(handler: ChangeHandler)
fun removeListener(handler: ChangeHandler)
}

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

0 comments on commit 41a6081

Please sign in to comment.