Skip to content

Commit 370c9ec

Browse files
committed
feat(model-api): allow access to a model without starting a transaction
In a single threaded environment (JavaScript) transaction, at least for read access, are not really needed. They just make it hard to integrate with e.g. Angular. There is now an IBranch implementation that automatically starts a transactions for each access.
1 parent 5562b68 commit 370c9ec

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,9 @@ interface IBranch {
4141
fun addListener(l: IBranchListener)
4242
fun removeListener(l: IBranchListener)
4343
}
44+
45+
interface IBranchWrapper : IBranch {
46+
fun unwrapBranch(): IBranch
47+
}
48+
49+
fun IBranch.deepUnwrap(): IBranch = if (this is IBranchWrapper) unwrapBranch().deepUnwrap() else this
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package org.modelix.model
15+
16+
import org.modelix.model.api.IBranch
17+
import org.modelix.model.api.IBranchWrapper
18+
import org.modelix.model.api.IConcept
19+
import org.modelix.model.api.IConceptReference
20+
import org.modelix.model.api.INodeReference
21+
import org.modelix.model.api.IReadTransaction
22+
import org.modelix.model.api.ITransaction
23+
import org.modelix.model.api.ITree
24+
import org.modelix.model.api.IWriteTransaction
25+
26+
class AutoTransactionsBranch(private val branch: IBranch) : IBranch by branch, IBranchWrapper {
27+
override val transaction: ITransaction
28+
get() = if (isInTransaction()) branch.transaction else AutoReadTransaction(branch)
29+
override val readTransaction: IReadTransaction
30+
get() = if (isInTransaction()) branch.readTransaction else AutoReadTransaction(branch)
31+
override val writeTransaction: IWriteTransaction
32+
get() = if (isInTransaction()) branch.writeTransaction else AutoWriteTransaction(branch)
33+
34+
private fun isInTransaction() = branch.canRead()
35+
override fun unwrapBranch(): IBranch = branch
36+
}
37+
38+
39+
open class AutoTransaction(override val branch: IBranch) : ITransaction {
40+
override val tree: ITree
41+
get() = branch.computeReadT { it.tree }
42+
43+
override fun containsNode(nodeId: Long): Boolean = branch.computeReadT { it.containsNode(nodeId) }
44+
override fun getConcept(nodeId: Long): IConcept? = branch.computeReadT { it.getConcept(nodeId) }
45+
override fun getConceptReference(nodeId: Long): IConceptReference? = branch.computeReadT { it.getConceptReference(nodeId) }
46+
override fun getParent(nodeId: Long): Long = branch.computeReadT { it.getParent(nodeId) }
47+
override fun getRole(nodeId: Long): String? = branch.computeReadT { it.getRole(nodeId) }
48+
override fun getProperty(nodeId: Long, role: String): String? = branch.computeReadT { it.getProperty(nodeId, role) }
49+
override fun getReferenceTarget(sourceId: Long, role: String): INodeReference? = branch.computeReadT { it.getReferenceTarget(sourceId, role) }
50+
override fun getChildren(parentId: Long, role: String?): Iterable<Long> = branch.computeReadT { it.getChildren(parentId, role) }
51+
override fun getAllChildren(parentId: Long): Iterable<Long> = branch.computeReadT { it.getAllChildren(parentId) }
52+
override fun getReferenceRoles(sourceId: Long): Iterable<String> = branch.computeReadT { it.getReferenceRoles(sourceId) }
53+
override fun getPropertyRoles(sourceId: Long): Iterable<String> = branch.computeReadT { it.getPropertyRoles(sourceId) }
54+
override fun getUserObject(key: Any): Any? = null
55+
override fun putUserObject(key: Any, value: Any?) {}
56+
}
57+
58+
class AutoReadTransaction(branch: IBranch) : AutoTransaction(branch), IReadTransaction
59+
60+
class AutoWriteTransaction(branch: IBranch) : AutoTransaction(branch), IWriteTransaction {
61+
override fun setProperty(nodeId: Long, role: String, value: String?) =
62+
branch.computeWriteT { it.setProperty(nodeId, role, value) }
63+
override fun setReferenceTarget(sourceId: Long, role: String, target: INodeReference?) =
64+
branch.computeWriteT { it.setReferenceTarget(sourceId, role, target) }
65+
override fun moveChild(newParentId: Long, newRole: String?, newIndex: Int, childId: Long) =
66+
branch.computeWriteT { it.moveChild(newParentId, newRole, newIndex, childId) }
67+
override fun addNewChild(parentId: Long, role: String?, index: Int, concept: IConcept?): Long =
68+
branch.computeWriteT { it.addNewChild(parentId, role, index, concept) }
69+
override fun addNewChild(parentId: Long, role: String?, index: Int, concept: IConceptReference?): Long =
70+
branch.computeWriteT { it.addNewChild(parentId, role, index, concept) }
71+
override fun addNewChild(parentId: Long, role: String?, index: Int, childId: Long, concept: IConcept?) =
72+
branch.computeWriteT { it.addNewChild(parentId, role, index, childId, concept) }
73+
override fun addNewChild(
74+
parentId: Long,
75+
role: String?,
76+
index: Int,
77+
childId: Long,
78+
concept: IConceptReference?
79+
) = branch.computeWriteT { it.addNewChild(parentId, role, index, childId, concept) }
80+
override fun deleteNode(nodeId: Long) = branch.computeWriteT { it.deleteNode(nodeId) }
81+
82+
override var tree: ITree
83+
get() = branch.computeReadT { it.tree }
84+
set(value) { branch.computeWriteT { it.tree = value } }
85+
}
86+
87+
fun IBranch.withAutoTransactions() = AutoTransactionsBranch(this)

0 commit comments

Comments
 (0)