Skip to content

Commit 2a03aab

Browse files
committed
Improve model definition storage so it also stores dependent models/enums. Add tests for those types of migration.
1 parent 1a1f6cd commit 2a03aab

File tree

8 files changed

+75
-8
lines changed

8 files changed

+75
-8
lines changed

core/src/commonMain/kotlin/maryk/core/definitions/Definitions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ data class Definitions(
4141

4242
constructor(vararg definition: MarykPrimitive) : this(definition.toList())
4343

44-
internal companion object : SingleValueDataModel<List<TypedValue<PrimitiveType, MarykPrimitive>>, List<MarykPrimitive>, Definitions, Companion, ContainsDefinitionsContext>(
44+
companion object : SingleValueDataModel<List<TypedValue<PrimitiveType, MarykPrimitive>>, List<MarykPrimitive>, Definitions, Companion, ContainsDefinitionsContext>(
4545
{ Companion.definitions }
4646
) {
4747
val definitions by list(

core/src/commonMain/kotlin/maryk/core/properties/definitions/IsPropertyDefinition.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ interface IsPropertyDefinition<T : Any> {
4747
addIncompatibilityReason: ((String) -> Unit)? = null
4848
): Boolean {
4949
var compatible = true
50-
if (this::class != definition::class) {
50+
if (!this::class.isInstance(definition)) {
5151
addIncompatibilityReason?.invoke("Definitions are not of same types: ${this::class.simpleName} vs ${definition::class.simpleName}")
5252
compatible = false
5353
}

store/rocksdb/src/commonMain/kotlin/maryk/datastore/rocksdb/RocksDBDataStore.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,10 @@ class RocksDBDataStore(
163163
}
164164
is NeedsMigration -> {
165165
val succeeded = migrationHandler?.invoke(this, migrationStatus.storedDataModel as StoredRootDataModelDefinition, dataModel)
166-
?: throw MigrationException("Migration needed: No migration handler present")
166+
?: throw MigrationException("Migration needed: No migration handler present. \n$migrationStatus")
167167

168168
if (!succeeded) {
169-
throw MigrationException("Migration could not be handled for ${dataModel.Meta.name} & ${(migrationStatus.storedDataModel as? StoredRootDataModelDefinition)?.Meta?.version}")
169+
throw MigrationException("Migration could not be handled for ${dataModel.Meta.name} & ${(migrationStatus.storedDataModel as? StoredRootDataModelDefinition)?.Meta?.version}\n$migrationStatus")
170170
}
171171

172172
migrationStatus.indicesToIndex?.let {

store/rocksdb/src/commonMain/kotlin/maryk/datastore/rocksdb/model/checkModelIfMigrationIsNeeded.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package maryk.datastore.rocksdb.model
22

3+
import maryk.core.definitions.Definitions
34
import maryk.core.exceptions.StorageException
45
import maryk.core.models.IsRootDataModel
56
import maryk.core.models.RootDataModel
@@ -29,12 +30,19 @@ fun checkModelIfMigrationIsNeeded(
2930

3031
return when {
3132
dataModel.Meta.version != version || !onlyCheckVersion -> {
33+
val context = DefinitionsConversionContext()
34+
35+
// Read currently stored dependent model
36+
rocksDB.get(modelColumnFamily, modelDependentsDefinitionKey)?.let { dependentModelBytes ->
37+
var readIndex = 0
38+
Definitions.Serializer.readProtoBuf(dependentModelBytes.size, { dependentModelBytes[readIndex++] }, context).toDataObject()
39+
}
40+
3241
// Read currently stored model
3342
val modelBytes = rocksDB.get(modelColumnFamily, modelDefinitionKey)
3443
?: throw StorageException("Model is unexpectedly missing in metadata for ${dataModel.Meta.name}")
3544

3645
var readIndex = 0
37-
val context = DefinitionsConversionContext()
3846
val storedDataModel = RootDataModel.Model.Serializer.readProtoBuf(modelBytes.size, { modelBytes[readIndex++] }, context).toDataObject()
3947

4048
// Check by comparing the data models for if migration is needed

store/rocksdb/src/commonMain/kotlin/maryk/datastore/rocksdb/model/modelKeys.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ package maryk.datastore.rocksdb.model
33
internal val modelNameKey = byteArrayOf(0)
44
internal val modelVersionKey = byteArrayOf(1)
55
internal val modelDefinitionKey = byteArrayOf(2)
6+
internal val modelDependentsDefinitionKey = byteArrayOf(3)

store/rocksdb/src/commonMain/kotlin/maryk/datastore/rocksdb/model/storeModelDefinition.kt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package maryk.datastore.rocksdb.model
22

3+
import maryk.core.definitions.Definitions
4+
import maryk.core.definitions.MarykPrimitive
35
import maryk.core.models.IsRootDataModel
46
import maryk.core.models.RootDataModel
57
import maryk.core.protobuf.WriteCache
@@ -16,11 +18,28 @@ fun storeModelDefinition(
1618
rocksDB.put(modelColumnFamily, modelVersionKey, dataModel.Meta.version.toByteArray())
1719

1820
val context = DefinitionsConversionContext()
19-
val cache = WriteCache()
20-
val modelByteSize = RootDataModel.Model.Serializer.calculateObjectProtoBufLength(dataModel as RootDataModel<*>, cache, context)
21+
22+
val modelCache = WriteCache()
23+
val modelByteSize = RootDataModel.Model.Serializer.calculateObjectProtoBufLength(dataModel as RootDataModel<*>, modelCache, context)
24+
25+
if (context.dataModels.isNotEmpty()) {
26+
val dependentCache = WriteCache()
27+
val dependents = Definitions(buildList {
28+
context.dataModels.values.forEach { add(it(Unit) as MarykPrimitive) }
29+
context.enums.values.forEach { add(it as MarykPrimitive) }
30+
context.typeEnums.values.forEach { add(it as MarykPrimitive) }
31+
})
32+
val depModelByteSize = Definitions.Serializer.calculateObjectProtoBufLength(dependents, dependentCache, context)
33+
val dependentBytes = ByteArray(depModelByteSize)
34+
var depWriteIndex = 0
35+
Definitions.Serializer.writeObjectProtoBuf(dependents, dependentCache, { dependentBytes[depWriteIndex++] = it }, context)
36+
37+
rocksDB.put(modelColumnFamily, modelDependentsDefinitionKey, dependentBytes)
38+
}
39+
2140
val bytes = ByteArray(modelByteSize)
2241
var writeIndex = 0
23-
RootDataModel.Model.Serializer.writeObjectProtoBuf(dataModel, cache, { bytes[writeIndex++] = it }, context)
42+
RootDataModel.Model.Serializer.writeObjectProtoBuf(dataModel, modelCache, { bytes[writeIndex++] = it }, context)
2443

2544
rocksDB.put(modelColumnFamily, modelDefinitionKey, bytes)
2645
}

store/rocksdb/src/commonTest/kotlin/maryk/datastore/rocksdb/RocksDBDataStoreMigrationTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import maryk.test.models.ModelV1
1616
import maryk.test.models.ModelV1_1
1717
import maryk.test.models.ModelV2
1818
import maryk.test.models.ModelV2ExtraIndex
19+
import maryk.test.models.ModelWithDependents
1920
import maryk.test.runSuspendingTest
2021
import kotlin.test.Test
2122
import kotlin.test.assertEquals
@@ -81,6 +82,30 @@ class RocksDBDataStoreMigrationTest {
8182
Unit
8283
}
8384

85+
@Test
86+
fun testMigrationWithDependents() = runSuspendingTest {
87+
val path = "$basePath/migrationWithDeps"
88+
var dataStore = RocksDBDataStore(
89+
keepAllVersions = true,
90+
relativePath = path,
91+
dataModelsById = mapOf(
92+
1u to ModelWithDependents,
93+
)
94+
)
95+
96+
dataStore.close()
97+
98+
dataStore = RocksDBDataStore(
99+
keepAllVersions = true,
100+
relativePath = path,
101+
dataModelsById = mapOf(
102+
1u to ModelWithDependents,
103+
)
104+
)
105+
106+
dataStore.close()
107+
}
108+
84109
@Test
85110
fun testMigrationWithIndex() = runSuspendingTest {
86111
val path = "$basePath/migration2"

testmodels/src/commonMain/kotlin/maryk/test/models/MigrationDataModels.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
package maryk.test.models
44

5+
import maryk.core.models.DataModel
56
import maryk.core.models.RootDataModel
7+
import maryk.core.properties.definitions.embed
8+
import maryk.core.properties.definitions.enum
69
import maryk.core.properties.definitions.number
710
import maryk.core.properties.definitions.string
811
import maryk.core.properties.types.Version
@@ -86,3 +89,14 @@ object ModelV2ReservedNamesAndIndices : RootDataModel<ModelV2ReservedNamesAndInd
8689
) {
8790
val newNumber by number(index = 2u, type = SInt32, required = false)
8891
}
92+
93+
object DependentModel : DataModel<DependentModel>() {
94+
val value by string(index = 1u, default = "haha", regEx = "ha.*")
95+
}
96+
97+
object ModelWithDependents : RootDataModel<ModelV2ReservedNamesAndIndices>(
98+
version = Version(1, 0),
99+
) {
100+
val dep by embed(index = 1u, dataModel = { DependentModel })
101+
val enum by enum(index = 2u, enum = Option)
102+
}

0 commit comments

Comments
 (0)