Skip to content

Commit

Permalink
XD-1005 support localEntityId on the schema applying step if backward…
Browse files Browse the repository at this point in the history
… compatible EntityId is enabled
  • Loading branch information
kirillvasilenko committed Apr 12, 2024
1 parent 861f69f commit 1e435d4
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ data class DeferredIndex(
) {
constructor(ownerVertexName: String, properties: List<IndexField>, unique: Boolean): this(
ownerVertexName,
indexName = "${ownerVertexName}_${properties.joinToString("_") { it.name }}",
indexName = "${ownerVertexName}_${properties.joinToString("_") { it.name }}${if (unique) "_unique" else ""}",
properties,
unique = unique
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import com.orientechnologies.orient.core.metadata.sequence.OSequence
import com.orientechnologies.orient.core.record.ODirection
import com.orientechnologies.orient.core.record.OVertex
import jetbrains.exodus.entitystore.orientdb.OVertexEntity
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.CLASS_ID_CUSTOM_PROPERTY_NAME
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.CLASS_ID_SEQUENCE_NAME
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.localEntityIdSequenceName
import mu.KotlinLogging

private val log = KotlinLogging.logger {}
Expand Down Expand Up @@ -57,10 +59,10 @@ internal class OrientDbSchemaInitializer(
private fun appendLine(s: String = "") = paddedLogger.appendLine(s)


private val indices = HashMap<String, MutableSet<DeferredIndex>>()
private val indices = HashMap<String, MutableMap<String, DeferredIndex>>()

private fun addIndex(index: DeferredIndex) {
indices.getOrPut(index.ownerVertexName) { HashSet() }.add(index)
indices.getOrPut(index.ownerVertexName) { HashMap() }[index.indexName] = index
}

private fun simplePropertyIndex(entityName: String, propertyName: String): DeferredIndex {
Expand All @@ -70,7 +72,7 @@ internal class OrientDbSchemaInitializer(
return DeferredIndex(entityName, listOf(indexField), unique = false)
}

fun getIndices(): Map<String, Set<DeferredIndex>> = indices
fun getIndices(): Map<String, Set<DeferredIndex>> = indices.map { it.key to it.value.values.toSet() }.toMap()

fun apply() {
try {
Expand Down Expand Up @@ -128,8 +130,8 @@ internal class OrientDbSchemaInitializer(
for ((indexOwner, indices) in indices) {
appendLine("$indexOwner:")
withPadding {
for (index in indices) {
appendLine(index.indexName)
for ((indexName, _) in indices) {
appendLine(indexName)
}
}
}
Expand All @@ -142,12 +144,7 @@ internal class OrientDbSchemaInitializer(
// ClassId

private fun createClassIdSequenceIfAbsent() {
val sequences = oSession.metadata.sequenceLibrary
if (sequences.getSequence(CLASS_ID_SEQUENCE_NAME) == null) {
val params = OSequence.CreateParams()
params.start = 0L
sequences.createSequence(CLASS_ID_SEQUENCE_NAME, OSequence.SEQUENCE_TYPE.ORDERED, params)
}
createSequenceIfAbsent(CLASS_ID_SEQUENCE_NAME)
}

private fun OClass.setClassIdIfAbsent() {
Expand All @@ -169,6 +166,12 @@ internal class OrientDbSchemaInitializer(

if (backwardCompatibleEntityId) {
oClass.setClassIdIfAbsent()
createSequenceIfAbsent(localEntityIdSequenceName(dnqEntity.type))
/*
* We do not apply a unique index to the localEntityId property because indices in OrientDB are polymorphic.
* So, you can not have the same value in a property in an instance of a superclass and in an instance of its subclass.
* But it exactly what happens in the original Xodus.
* */
}

/*
Expand Down Expand Up @@ -333,6 +336,12 @@ internal class OrientDbSchemaInitializer(
oClass.applySimpleProperty(propertyMetaData, required || requiredBecauseOfIndex)
}
}
if (backwardCompatibleEntityId) {
val prop = SimplePropertyMetaDataImpl(BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME, "long")
oClass.applySimpleProperty(prop, true)
// we need this index regardless what we have in indexForEverySimpleProperty
addIndex(simplePropertyIndex(dnqEntity.type, BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME))
}
}
}

Expand Down Expand Up @@ -546,6 +555,15 @@ internal class OrientDbSchemaInitializer(
return oProperty
}

private fun createSequenceIfAbsent(sequenceName: String) {
val sequences = oSession.metadata.sequenceLibrary
if (sequences.getSequence(sequenceName) == null) {
val params = OSequence.CreateParams()
params.start = 0L
sequences.createSequence(sequenceName, OSequence.SEQUENCE_TYPE.ORDERED, params)
}
}

private fun getOType(jvmTypeName: String): OType {
return when (jvmTypeName.lowercase()) {
"boolean" -> OType.BOOLEAN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ import com.orientechnologies.orient.core.metadata.schema.OType
import com.orientechnologies.orient.core.record.ODirection
import com.orientechnologies.orient.core.record.OVertex
import jetbrains.exodus.entitystore.orientdb.OVertexEntity
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.CLASS_ID_CUSTOM_PROPERTY_NAME
import jetbrains.exodus.entitystore.orientdb.OVertexEntity.Companion.localEntityIdSequenceName
import jetbrains.exodus.entitystore.orientdb.testutil.InMemoryOrientDB
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class OrientDbSchemaInitializerTest {
Expand Down Expand Up @@ -393,8 +396,62 @@ class OrientDbSchemaInitializerTest {
assertEquals(setOf<Long>(1, 2, 3, 4, 5), classIds)
}

@Test
fun `backward compatible EntityId enabled, every class gets localEntityId property`(): Unit = orientDb.withSession { oSession ->
val types = mutableListOf("type1", "type2", "type3")
val model = model {
for (type in types) {
entity(type)
}
}

val indices = oSession.applySchema(model, backwardCompatibleEntityId = true)

val sequences = oSession.metadata.sequenceLibrary
for (type in types) {
assertNotNull(oSession.getClass(type).getProperty(BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME))
// index for the localEntityId must be created regardless the indexForEverySimpleProperty param
indices.checkIndex(type, false, BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME)
// the index for localEntityId must not be unique, otherwise it will not let the same localEntityId
// for subtypes of a supertype
assertTrue(indices.getValue(type).none { it.unique })

val sequence = sequences.getSequence(localEntityIdSequenceName(type))
assertNotNull(sequence)
assertEquals(1, sequence.next())
}

// emulate the next run of the application
oSession.applySchema(model, backwardCompatibleEntityId = true)

for (type in types) {
val sequence = sequences.getSequence(localEntityIdSequenceName(type))
// sequences are the same
assertEquals(2, sequence.next())
}
}

@Test
fun `backward compatible EntityId disable, localEntityId is ignored`(): Unit = orientDb.withSession { oSession ->
val types = mutableListOf("type1", "type2", "type3")
val model = model {
for (type in types) {
entity(type)
}
}

val indices = oSession.applySchema(model)

val sequences = oSession.metadata.sequenceLibrary
for (type in types) {
assertNull(oSession.getClass(type).getProperty(BACKWARD_COMPATIBLE_LOCAL_ENTITY_ID_PROPERTY_NAME))
assertTrue(indices.isEmpty())
assertNull(sequences.getSequence(localEntityIdSequenceName(type)))
}
}

private fun OClass.checkIndex(unique: Boolean, vararg fieldNames: String) {
val indexName = "${name}_${fieldNames.joinToString("_")}"
val indexName = indexName(name, unique, *fieldNames)
val index = indexes.first { it.name == indexName }
assertEquals(unique, index.isUnique)

Expand All @@ -410,7 +467,7 @@ class OrientDbSchemaInitializerTest {
}

private fun Map<String, Set<DeferredIndex>>.checkIndex(entityName: String, unique: Boolean, vararg fieldNames: String) {
val indexName = "${entityName}_${fieldNames.joinToString("_")}"
val indexName = indexName(entityName, unique, *fieldNames)
val indices = getValue(entityName)
val index = indices.first { it.indexName == indexName }

Expand All @@ -424,6 +481,8 @@ class OrientDbSchemaInitializerTest {
}
}

private fun indexName(entityName: String, unique: Boolean, vararg fieldNames: String): String = "${entityName}_${fieldNames.joinToString("_")}${if (unique) "_unique" else ""}"

private fun ODatabaseSession.checkAssociation(edgeName: String, outClass: OClass, inClass: OClass, cardinality: AssociationEndCardinality?) {
val edge = requireEdgeClass(edgeName)

Expand Down

0 comments on commit 1e435d4

Please sign in to comment.