Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
bin
.gradle/
**/build
/*/ignite/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.modelix.model.client2

import org.modelix.model.IVersion
import org.modelix.model.mutable.IMutableModelTree
import org.modelix.model.mutable.asMutableReadonly

interface IReplicatedOrReadonlyModel {

fun getMutableModelTree(): IMutableModelTree
fun getCurrentVersion(): IVersion
fun dispose()

class Replicated(private val model: ReplicatedModel) : IReplicatedOrReadonlyModel {
override fun getMutableModelTree(): IMutableModelTree = model.getVersionedModelTree()
override fun getCurrentVersion(): IVersion = model.getCurrentVersion()
override fun dispose() {
model.dispose()
}
}

class Readonly(private val version: IVersion) : IReplicatedOrReadonlyModel {
override fun getMutableModelTree(): IMutableModelTree = version.getModelTree().asMutableReadonly()
override fun getCurrentVersion(): IVersion = version
override fun dispose() {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,14 @@ interface ClientJS {
@JsExport
data class ReplicatedModelParameters(
val repositoryId: String,
val branchId: String,
val branchId: String? = null,
val idScheme: IdSchemeJS,
)
val versionHash: String? = null,
) {
init {
require((branchId != null) xor (versionHash != null)) { "Exactly one of branchId or versionHash must be provided" }
}
}

internal class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {

Expand Down Expand Up @@ -289,13 +294,27 @@ internal class ClientJSImpl(private val modelClient: ModelClientV2) : ClientJS {
return GlobalScope.promise {
val models = parameters.map { parameters ->
val modelClient = modelClient
val branchReference = RepositoryId(parameters.repositoryId).getBranchReference(parameters.branchId)
val repositoryId = RepositoryId(parameters.repositoryId)
val branchReference = parameters.branchId?.let { repositoryId.getBranchReference(it) }
val idGenerator: (TreeId) -> INodeIdGenerator<INodeReference> = when (parameters.idScheme) {
IdSchemeJS.READONLY -> { treeId -> DummyIdGenerator() }
IdSchemeJS.MODELIX -> { treeId -> ModelixIdGenerator(modelClient.getIdGenerator(), treeId) }
IdSchemeJS.MPS -> { treeId -> MPSIdGenerator(modelClient.getIdGenerator(), treeId) }
}
modelClient.getReplicatedModel(branchReference, idGenerator).also { it.start() }
if (branchReference == null) {
if (parameters.versionHash != null) {
modelClient.loadVersion(repositoryId, parameters.versionHash, null)
.let { IReplicatedOrReadonlyModel.Readonly(it) }
} else {
modelClient.getReplicatedModel(repositoryId.getBranchReference(), idGenerator)
.also { it.start() }
.let { IReplicatedOrReadonlyModel.Replicated(it) }
}
} else {
modelClient.getReplicatedModel(branchReference, idGenerator)
.also { it.start() }
.let { IReplicatedOrReadonlyModel.Replicated(it) }
}
}
ReplicatedModelJSImpl(models)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.promise
import kotlinx.datetime.toJSDate
import org.modelix.model.IVersion
import kotlin.js.Promise

internal class ReplicatedModelJSImpl(private val models: List<ReplicatedModel>) : ReplicatedModelJS {
internal class ReplicatedModelJSImpl(private val models: List<IReplicatedOrReadonlyModel>) : ReplicatedModelJS {

private val mutableModelTree = MutableModelTreeJsImpl(models.map { it.getVersionedModelTree() })
private val mutableModelTree = MutableModelTreeJsImpl(models.map { it.getMutableModelTree() })

override fun dispose() {
// TODO The models are passed to the constructor, so this class shouldn't be responsible for their lifecycle.
Expand All @@ -23,19 +24,19 @@ internal class ReplicatedModelJSImpl(private val models: List<ReplicatedModel>)

override fun getCurrentVersionInformation(): Promise<VersionInformationJS> {
return GlobalScope.promise {
models.first().getCurrentVersionInformation()
models.first().getCurrentVersion().toVersionInformationJS()
}
}

override fun getCurrentVersionInformations(): Promise<Array<VersionInformationJS>> {
return GlobalScope.promise {
models.map { it.getCurrentVersionInformation() }.toTypedArray()
models.map { it.getCurrentVersion().toVersionInformationJS() }.toTypedArray()
}
}

private fun ReplicatedModel.getCurrentVersionInformation(): VersionInformationJS {
val currentVersion = getCurrentVersion()
val currentVersionAuthor = currentVersion.author
private fun IVersion.toVersionInformationJS(): VersionInformationJS {
val currentVersion = this
val currentVersionAuthor = currentVersion.getAuthor()
val currentVersionTime = currentVersion.getTimestamp()?.toJSDate()
return VersionInformationJS(currentVersionAuthor, currentVersionTime, currentVersion.getContentHash())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.modelix.model.client2

import kotlin.test.Test
import kotlin.test.assertFailsWith

class ReplicatedModelHashTest {

@Test
fun ReplicatedModelParameters_validation() {
// Valid: branchId
// branchId is positional 2nd arg.
ReplicatedModelParameters("repo", "branch", IdSchemeJS.MODELIX)

// Valid: versionHash
// branchId must be null.
ReplicatedModelParameters(
repositoryId = "repo",
branchId = null,
idScheme = IdSchemeJS.MODELIX,
versionHash = "hash",
)

// Invalid: both branchId and versionHash
assertFailsWith<IllegalArgumentException> {
ReplicatedModelParameters(
repositoryId = "repo",
branchId = "branch",
idScheme = IdSchemeJS.MODELIX,
versionHash = "hash",
)
}

// Invalid: neither
assertFailsWith<IllegalArgumentException> {
ReplicatedModelParameters(
repositoryId = "repo",
branchId = null,
idScheme = IdSchemeJS.MODELIX,
)
}
}
}
2 changes: 1 addition & 1 deletion vue-model-api/src/useReplicatedModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ test("test wrapper backwards compatibility", (done) => {
// Mock implementation that returns a dummy object with a branch
const branchId = parameters[0].branchId;
const rootNode = loadModelsFromJson([JSON.stringify({ root: {} })]);
rootNode.setPropertyValue(toRoleJS("branchId"), branchId);
rootNode.setPropertyValue(toRoleJS("branchId"), branchId ?? undefined);

const branch = {
rootNode,
Expand Down
2 changes: 1 addition & 1 deletion vue-model-api/src/useReplicatedModels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ test("test branch connects", (done) => {
const branchId = parameters[0].branchId;
return Promise.resolve(
new SuccessfulReplicatedModelJS(
branchId,
branchId!,
) as unknown as ReplicatedModelJS,
);
}
Expand Down
Loading