Skip to content

Commit 2bf037a

Browse files
Automated commit of generated code
1 parent 1d6756e commit 2bf037a

File tree

9 files changed

+200
-66
lines changed

9 files changed

+200
-66
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/api/schema.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,9 @@ internal fun MutableMap<ColumnPath, Int>.putColumnsOrder(schema: DataFrameSchema
2222
val columnPath = path + name
2323
this[columnPath] = i
2424
when (column) {
25-
is ColumnSchema.Frame -> {
26-
putColumnsOrder(column.schema, columnPath)
27-
}
28-
29-
is ColumnSchema.Group -> {
30-
putColumnsOrder(column.schema, columnPath)
31-
}
25+
is ColumnSchema.Frame -> putColumnsOrder(column.schema, columnPath)
26+
is ColumnSchema.Group -> putColumnsOrder(column.schema, columnPath)
27+
is ColumnSchema.Value -> Unit
3228
}
3329
}
3430
}

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/codeGen/CodeGeneratorImpl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,13 @@ import org.jetbrains.kotlinx.dataframe.columns.ColumnGroup
3434
import org.jetbrains.kotlinx.dataframe.impl.toSnakeCase
3535
import org.jetbrains.kotlinx.dataframe.keywords.HardKeywords
3636
import org.jetbrains.kotlinx.dataframe.keywords.ModifierKeywords
37+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode
3738
import org.jetbrains.kotlinx.dataframe.schema.DataFrameSchema
3839

3940
private fun renderNullability(nullable: Boolean) = if (nullable) "?" else ""
4041

4142
internal fun Iterable<Marker>.filterRequiredForSchema(schema: DataFrameSchema) =
42-
filter { it.isOpen && it.schema.compare(schema).isSuperOrEqual() }
43+
filter { it.isOpen && it.schema.compare(schema, ComparisonMode.STRICT_FOR_NESTED_SCHEMAS).isSuperOrEqual() }
4344

4445
internal val charsToQuote = """[ `(){}\[\].<>'"/|\\!?@:;%^&*#$-]""".toRegex()
4546

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/codeGen/SchemaProcessorImpl.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.jetbrains.kotlinx.dataframe.codeGen.MarkerVisibility
77
import org.jetbrains.kotlinx.dataframe.codeGen.SchemaProcessor
88
import org.jetbrains.kotlinx.dataframe.codeGen.ValidFieldName
99
import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema
10+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode
1011
import org.jetbrains.kotlinx.dataframe.schema.DataFrameSchema
1112

1213
internal class SchemaProcessorImpl(
@@ -23,7 +24,7 @@ internal class SchemaProcessorImpl(
2324

2425
private fun DataFrameSchema.getAllSuperMarkers() =
2526
registeredMarkers
26-
.filter { it.isOpen && it.schema.compare(this).isSuperOrEqual() }
27+
.filter { it.isOpen && it.schema.compare(this, ComparisonMode.STRICT_FOR_NESTED_SCHEMAS).isSuperOrEqual() }
2728

2829
private fun List<Marker>.onlyLeafs(): List<Marker> {
2930
val skip = flatMap { it.allSuperMarkers.keys }.toSet()

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/schema/DataFrameSchemaImpl.kt

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,58 @@ package org.jetbrains.kotlinx.dataframe.impl.schema
33
import org.jetbrains.kotlinx.dataframe.impl.renderType
44
import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema
55
import org.jetbrains.kotlinx.dataframe.schema.CompareResult
6+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.Equals
7+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.IsDerived
8+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.IsSuper
9+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.None
10+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode
11+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.STRICT
12+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.STRICT_FOR_NESTED_SCHEMAS
613
import org.jetbrains.kotlinx.dataframe.schema.DataFrameSchema
14+
import org.jetbrains.kotlinx.dataframe.schema.plus
15+
import kotlin.collections.forEach
716

817
public class DataFrameSchemaImpl(override val columns: Map<String, ColumnSchema>) : DataFrameSchema {
918

10-
override fun compare(other: DataFrameSchema, strictlyEqualNestedSchemas: Boolean): CompareResult {
19+
override fun compare(other: DataFrameSchema, comparisonMode: ComparisonMode): CompareResult {
1120
require(other is DataFrameSchemaImpl)
12-
if (this === other) return CompareResult.Equals
13-
var result = CompareResult.Equals
14-
columns.forEach {
15-
val otherColumn = other.columns[it.key]
16-
if (otherColumn == null) {
17-
result = result.combine(if (strictlyEqualNestedSchemas) CompareResult.None else CompareResult.IsDerived)
18-
} else {
19-
result = result.combine(it.value.compareStrictlyEqualNestedSchemas(otherColumn))
21+
if (this === other) return Equals
22+
23+
var result: CompareResult = Equals
24+
25+
// check for each column in this schema if there is a column with the same name in the other schema
26+
// - if so, check those schemas for equality, taking comparisonMode into account
27+
// - if not, consider the other schema derived from this (or unrelated (None) if comparisonMode == STRICT)
28+
this.columns.forEach { (thisColName, thisSchema) ->
29+
val otherSchema = other.columns[thisColName]
30+
result += when {
31+
otherSchema != null -> {
32+
// increase comparisonMode strictness when dealing with nested schemas of FrameColumns or ColumnGroups
33+
val newComparisonMode =
34+
if (comparisonMode == STRICT_FOR_NESTED_SCHEMAS && thisSchema !is ColumnSchema.Value) {
35+
STRICT
36+
} else {
37+
comparisonMode
38+
}
39+
40+
thisSchema.compare(other = otherSchema, comparisonMode = newComparisonMode)
41+
}
42+
43+
else -> if (comparisonMode == STRICT) None else IsDerived
2044
}
21-
if (result == CompareResult.None) return CompareResult.None
45+
if (result == None) return None
2246
}
23-
other.columns.forEach {
24-
val thisField = columns[it.key]
25-
if (thisField == null) {
26-
result = result.combine(if (strictlyEqualNestedSchemas) CompareResult.None else CompareResult.IsSuper)
27-
if (result == CompareResult.None) return CompareResult.None
28-
}
47+
// then check for each column in the other schema if there is a column with the same name in this schema
48+
// if not, consider the other schema as super to this (or unrelated (None) if comparisonMode == STRICT)
49+
other.columns.forEach { (otherColName, _) ->
50+
if (this.columns[otherColName] != null) return@forEach
51+
result += if (comparisonMode == STRICT) None else IsSuper
52+
if (result == None) return None
2953
}
3054
return result
3155
}
3256

33-
override fun equals(other: Any?): Boolean = other is DataFrameSchema && compare(other).isEqual()
57+
override fun equals(other: Any?): Boolean = other is DataFrameSchema && this.compare(other).isEqual()
3458

3559
override fun toString(): String = render()
3660

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/schema/ColumnSchema.kt

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import org.jetbrains.kotlinx.dataframe.AnyRow
55
import org.jetbrains.kotlinx.dataframe.DataFrame
66
import org.jetbrains.kotlinx.dataframe.DataRow
77
import org.jetbrains.kotlinx.dataframe.columns.ColumnKind
8+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.LENIENT
9+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.STRICT
810
import kotlin.reflect.KType
911
import kotlin.reflect.full.isSubtypeOf
1012
import kotlin.reflect.full.isSupertypeOf
1113
import kotlin.reflect.typeOf
1214

13-
public abstract class ColumnSchema {
15+
public sealed class ColumnSchema {
1416

1517
/** Either [Value] or [Group] or [Frame]. */
1618
public abstract val kind: ColumnKind
@@ -39,9 +41,10 @@ public abstract class ColumnSchema {
3941
override val nullable: Boolean = type.isMarkedNullable
4042
override val contentType: KType? = null
4143

42-
public fun compare(other: Value): CompareResult =
44+
public fun compare(other: Value, comparisonMode: ComparisonMode = LENIENT): CompareResult =
4345
when {
4446
type == other.type -> CompareResult.Equals
47+
comparisonMode == STRICT -> CompareResult.None
4548
type.isSubtypeOf(other.type) -> CompareResult.IsDerived
4649
type.isSupertypeOf(other.type) -> CompareResult.IsSuper
4750
else -> CompareResult.None
@@ -55,10 +58,11 @@ public abstract class ColumnSchema {
5558
override val nullable: Boolean = false
5659
override val type: KType get() = typeOf<AnyRow>()
5760

58-
public fun compare(other: Group): CompareResult = schema.compare(other.schema)
59-
60-
internal fun compareStrictlyEqualNestedSchemas(other: Group): CompareResult =
61-
schema.compare(other.schema, strictlyEqualNestedSchemas = true)
61+
public fun compare(other: Group, comparisonMode: ComparisonMode = LENIENT): CompareResult =
62+
schema.compare(
63+
other = other.schema,
64+
comparisonMode = comparisonMode,
65+
)
6266
}
6367

6468
public class Frame(
@@ -69,14 +73,11 @@ public abstract class ColumnSchema {
6973
public override val kind: ColumnKind = ColumnKind.Frame
7074
override val type: KType get() = typeOf<AnyFrame>()
7175

72-
public fun compare(other: Frame): CompareResult =
73-
schema.compare(other.schema).combine(CompareResult.compareNullability(nullable, other.nullable))
74-
75-
internal fun compareStrictlyEqualNestedSchemas(other: Frame): CompareResult =
76+
public fun compare(other: Frame, comparisonMode: ComparisonMode = LENIENT): CompareResult =
7677
schema.compare(
77-
other.schema,
78-
strictlyEqualNestedSchemas = true,
79-
).combine(CompareResult.compareNullability(nullable, other.nullable))
78+
other = other.schema,
79+
comparisonMode = comparisonMode,
80+
) + CompareResult.compareNullability(thisIsNullable = nullable, otherIsNullable = other.nullable)
8081
}
8182

8283
/** Checks equality just on kind, type, or schema. */
@@ -88,37 +89,27 @@ public abstract class ColumnSchema {
8889
is Value -> type == (otherType as Value).type
8990
is Group -> schema == (otherType as Group).schema
9091
is Frame -> schema == (otherType as Frame).schema
91-
else -> throw NotImplementedError()
9292
}
9393
}
9494

95-
public fun compare(other: ColumnSchema): CompareResult = compare(other, false)
96-
97-
internal fun compareStrictlyEqualNestedSchemas(other: ColumnSchema): CompareResult = compare(other, true)
98-
99-
private fun compare(other: ColumnSchema, strictlyEqualNestedSchemas: Boolean): CompareResult {
95+
public fun compare(other: ColumnSchema, comparisonMode: ComparisonMode = LENIENT): CompareResult {
10096
if (kind != other.kind) return CompareResult.None
10197
if (this === other) return CompareResult.Equals
10298
return when (this) {
103-
is Value -> compare(other as Value)
104-
105-
is Group -> if (strictlyEqualNestedSchemas) {
106-
compareStrictlyEqualNestedSchemas(
107-
other as Group,
108-
)
109-
} else {
110-
compare(other as Group)
111-
}
112-
113-
is Frame -> if (strictlyEqualNestedSchemas) {
114-
compareStrictlyEqualNestedSchemas(
115-
other as Frame,
116-
)
117-
} else {
118-
compare(other as Frame)
119-
}
99+
is Value -> compare(other as Value, comparisonMode)
100+
is Group -> compare(other as Group, comparisonMode)
101+
is Frame -> compare(other as Frame, comparisonMode)
102+
}
103+
}
120104

121-
else -> throw NotImplementedError()
105+
override fun hashCode(): Int {
106+
var result = nullable.hashCode()
107+
result = 31 * result + kind.hashCode()
108+
result = 31 * result + when (this) {
109+
is Value -> type.hashCode()
110+
is Group -> schema.hashCode()
111+
is Frame -> schema.hashCode()
122112
}
113+
return result
123114
}
124115
}

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/schema/CompareResult.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ public enum class CompareResult {
2828
}
2929
}
3030
}
31+
32+
public operator fun CompareResult.plus(other: CompareResult): CompareResult = this.combine(other)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.jetbrains.kotlinx.dataframe.schema
2+
3+
public enum class ComparisonMode {
4+
/**
5+
* In this mode, all [CompareResults][CompareResult] can occur.
6+
*
7+
* If this schema has columns the other has not, the other is considered [CompareResult.IsDerived].
8+
* If the other schema has columns this has not, this is considered [CompareResult.IsSuper].
9+
*/
10+
LENIENT,
11+
12+
/**
13+
* Columns must all be present in the other schema with the same name and type.
14+
* [CompareResult.IsDerived] and [CompareResult.IsSuper] will result in [CompareResult.None] in this mode.
15+
*/
16+
STRICT,
17+
18+
/** Works like [LENIENT] at the top-level, but turns to [STRICT] for nested schemas. */
19+
STRICT_FOR_NESTED_SCHEMAS,
20+
}

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/schema/DataFrameSchema.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ public interface DataFrameSchema {
55
public val columns: Map<String, ColumnSchema>
66

77
/**
8-
* By default generated markers for leafs aren't used as supertypes: @DataSchema(isOpen = false)
9-
* strictlyEqualNestedSchemas = true takes this into account for internal codegen logic
8+
* @param comparisonMode The [mode][ComparisonMode] to compare the schema's by.
9+
* By default, generated markers for leafs aren't used as supertypes: `@DataSchema(isOpen = false)`
10+
* Setting [comparisonMode] to [ComparisonMode.STRICT_FOR_NESTED_SCHEMAS] takes this into account
11+
* for internal codegen logic.
1012
*/
11-
public fun compare(other: DataFrameSchema, strictlyEqualNestedSchemas: Boolean = false): CompareResult
13+
public fun compare(other: DataFrameSchema, comparisonMode: ComparisonMode = ComparisonMode.LENIENT): CompareResult
1214
}

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/codeGen/MatchSchemeTests.kt

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,19 @@ import org.jetbrains.kotlinx.dataframe.DataRow
66
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
77
import org.jetbrains.kotlinx.dataframe.api.add
88
import org.jetbrains.kotlinx.dataframe.api.cast
9+
import org.jetbrains.kotlinx.dataframe.api.columnOf
10+
import org.jetbrains.kotlinx.dataframe.api.dataFrameOf
911
import org.jetbrains.kotlinx.dataframe.api.generateCode
12+
import org.jetbrains.kotlinx.dataframe.api.schema
1013
import org.jetbrains.kotlinx.dataframe.impl.codeGen.ReplCodeGenerator
1114
import org.jetbrains.kotlinx.dataframe.io.readJsonStr
15+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.Equals
16+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.IsDerived
17+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.IsSuper
18+
import org.jetbrains.kotlinx.dataframe.schema.CompareResult.None
19+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.LENIENT
20+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.STRICT
21+
import org.jetbrains.kotlinx.dataframe.schema.ComparisonMode.STRICT_FOR_NESTED_SCHEMAS
1222
import org.junit.Test
1323

1424
class MatchSchemeTests {
@@ -99,4 +109,91 @@ class MatchSchemeTests {
99109
val res = df.generateCode(false, true)
100110
println(res)
101111
}
112+
113+
@Test
114+
fun `simple data schema comparison`() {
115+
val scheme1 = dataFrameOf(
116+
"a" to columnOf(1, 2, 3, null),
117+
"b" to columnOf(1.0, 2.0, 3.0, 4.0),
118+
).schema()
119+
120+
val scheme2 = dataFrameOf(
121+
"a" to columnOf(1, 2, 3, 4),
122+
"b" to columnOf(1.0, 2.0, 3.0, 4.0),
123+
).schema()
124+
125+
val scheme3 = dataFrameOf(
126+
"c" to columnOf(1, 2, 3, 4),
127+
).schema()
128+
129+
scheme1.compare(scheme1, LENIENT) shouldBe Equals
130+
scheme2.compare(scheme2, LENIENT) shouldBe Equals
131+
scheme1.compare(scheme2, LENIENT) shouldBe IsSuper
132+
scheme2.compare(scheme1, LENIENT) shouldBe IsDerived
133+
scheme1.compare(scheme3, LENIENT) shouldBe None
134+
135+
scheme1.compare(scheme1, STRICT_FOR_NESTED_SCHEMAS) shouldBe Equals
136+
scheme2.compare(scheme2, STRICT_FOR_NESTED_SCHEMAS) shouldBe Equals
137+
scheme1.compare(scheme2, STRICT_FOR_NESTED_SCHEMAS) shouldBe IsSuper
138+
scheme2.compare(scheme1, STRICT_FOR_NESTED_SCHEMAS) shouldBe IsDerived
139+
scheme1.compare(scheme3, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
140+
141+
scheme1.compare(scheme1, STRICT) shouldBe Equals
142+
scheme2.compare(scheme2, STRICT) shouldBe Equals
143+
scheme1.compare(scheme2, STRICT) shouldBe None
144+
scheme2.compare(scheme1, STRICT) shouldBe None
145+
}
146+
147+
@Test
148+
fun `nested data schema comparison`() {
149+
val scheme1 = dataFrameOf(
150+
"a" to columnOf(
151+
"b" to columnOf(1.0, 2.0, 3.0, null),
152+
),
153+
).schema()
154+
155+
val scheme2 = dataFrameOf(
156+
"a" to columnOf(
157+
"b" to columnOf(1.0, 2.0, 3.0, 4.0),
158+
),
159+
).schema()
160+
161+
val scheme3 = dataFrameOf(
162+
"c" to columnOf(1, 2, 3, 4),
163+
).schema()
164+
165+
val scheme4 = dataFrameOf(
166+
"a" to columnOf(
167+
"b" to columnOf(1.0, 2.0, 3.0, null),
168+
),
169+
"c" to columnOf(1, 2, 3, 4),
170+
).schema()
171+
172+
scheme1.compare(scheme1, LENIENT) shouldBe Equals
173+
scheme2.compare(scheme2, LENIENT) shouldBe Equals
174+
scheme1.compare(scheme2, LENIENT) shouldBe IsSuper
175+
scheme2.compare(scheme1, LENIENT) shouldBe IsDerived
176+
scheme1.compare(scheme3, LENIENT) shouldBe None
177+
178+
scheme1.compare(scheme4, LENIENT) shouldBe IsSuper
179+
scheme4.compare(scheme1, LENIENT) shouldBe IsDerived
180+
181+
scheme1.compare(scheme1, STRICT_FOR_NESTED_SCHEMAS) shouldBe Equals
182+
scheme2.compare(scheme2, STRICT_FOR_NESTED_SCHEMAS) shouldBe Equals
183+
scheme1.compare(scheme2, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
184+
scheme2.compare(scheme1, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
185+
scheme1.compare(scheme3, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
186+
187+
scheme1.compare(scheme4, STRICT_FOR_NESTED_SCHEMAS) shouldBe IsSuper
188+
scheme4.compare(scheme1, STRICT_FOR_NESTED_SCHEMAS) shouldBe IsDerived
189+
scheme2.compare(scheme4, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
190+
scheme4.compare(scheme2, STRICT_FOR_NESTED_SCHEMAS) shouldBe None
191+
192+
scheme1.compare(scheme1, STRICT) shouldBe Equals
193+
scheme2.compare(scheme2, STRICT) shouldBe Equals
194+
scheme1.compare(scheme2, STRICT) shouldBe None
195+
scheme2.compare(scheme1, STRICT) shouldBe None
196+
scheme1.compare(scheme3, STRICT) shouldBe None
197+
scheme3.compare(scheme1, STRICT) shouldBe None
198+
}
102199
}

0 commit comments

Comments
 (0)