16
16
package org.bson.codecs.kotlinx.utils
17
17
18
18
import kotlinx.serialization.ExperimentalSerializationApi
19
+ import kotlinx.serialization.SerializationException
19
20
import kotlinx.serialization.descriptors.SerialDescriptor
21
+ import kotlinx.serialization.descriptors.elementNames
22
+ import kotlinx.serialization.json.JsonNamingStrategy
20
23
import kotlinx.serialization.modules.SerializersModule
21
24
import org.bson.AbstractBsonReader
22
25
import org.bson.BsonWriter
@@ -28,6 +31,7 @@ import org.bson.codecs.kotlinx.BsonDocumentDecoder
28
31
import org.bson.codecs.kotlinx.BsonEncoder
29
32
import org.bson.codecs.kotlinx.BsonEncoderImpl
30
33
import org.bson.codecs.kotlinx.BsonMapDecoder
34
+ import org.bson.codecs.kotlinx.BsonNamingStrategy
31
35
import org.bson.codecs.kotlinx.BsonPolymorphicDecoder
32
36
import org.bson.codecs.kotlinx.JsonBsonArrayDecoder
33
37
import org.bson.codecs.kotlinx.JsonBsonDecoderImpl
@@ -59,6 +63,8 @@ internal object BsonCodecUtils {
59
63
}
60
64
}
61
65
66
+ private val cachedElementNamesByDescriptor: MutableMap <String , Map <String , String >> = mutableMapOf ()
67
+
62
68
internal fun createBsonEncoder (
63
69
writer : BsonWriter ,
64
70
serializersModule : SerializersModule ,
@@ -116,4 +122,73 @@ internal object BsonCodecUtils {
116
122
return if (hasJsonDecoder) JsonBsonMapDecoder (descriptor, reader, serializersModule, configuration)
117
123
else BsonMapDecoder (descriptor, reader, serializersModule, configuration)
118
124
}
125
+
126
+ internal fun cacheElementNamesByDescriptor (descriptor : SerialDescriptor , configuration : BsonConfiguration ) {
127
+ val convertedNameMap =
128
+ when (configuration.bsonNamingStrategy) {
129
+ BsonNamingStrategy .SNAKE_CASE -> {
130
+ val snakeCasedNames = descriptor.elementNames.associateWith { name -> convertCamelCase(name, ' _' ) }
131
+
132
+ snakeCasedNames.entries
133
+ .groupBy { entry -> entry.value }
134
+ .filter { group -> group.value.size > 1 }
135
+ .entries
136
+ .fold(StringBuilder (" " )) { acc, group ->
137
+ val keys = group.value.joinToString(" , " ) { entry -> entry.key }
138
+ acc.append(" $keys in ${descriptor.serialName} generate same name: ${group.key} .\n " )
139
+ }
140
+ .toString()
141
+ .takeIf { it.trim().isNotEmpty() }
142
+ ?.let { errorMessage: String -> throw SerializationException (errorMessage) }
143
+
144
+ snakeCasedNames.entries.associate { it.value to it.key }
145
+ }
146
+ else -> emptyMap()
147
+ }
148
+
149
+ cachedElementNamesByDescriptor[descriptor.serialName] = convertedNameMap
150
+ }
151
+
152
+ internal fun getCachedElementNamesByDescriptor (descriptor : SerialDescriptor ): Map <String , String > {
153
+ return cachedElementNamesByDescriptor[descriptor.serialName] ? : emptyMap()
154
+ }
155
+
156
+ // https://github.com/Kotlin/kotlinx.serialization/blob/f9f160a680da9f92c3bb121ae3644c96e57ba42e/formats/json/commonMain/src/kotlinx/serialization/json/JsonNamingStrategy.kt#L142-L174
157
+ internal fun convertCamelCase (value : String , delimiter : Char ) =
158
+ buildString(value.length * 2 ) {
159
+ var bufferedChar: Char? = null
160
+ var previousUpperCharsCount = 0
161
+
162
+ value.forEach { c ->
163
+ if (c.isUpperCase()) {
164
+ if (previousUpperCharsCount == 0 && isNotEmpty() && last() != delimiter) append(delimiter)
165
+
166
+ bufferedChar?.let (::append)
167
+
168
+ previousUpperCharsCount++
169
+ bufferedChar = c.lowercaseChar()
170
+ } else {
171
+ if (bufferedChar != null ) {
172
+ if (previousUpperCharsCount > 1 && c.isLetter()) {
173
+ append(delimiter)
174
+ }
175
+ append(bufferedChar)
176
+ previousUpperCharsCount = 0
177
+ bufferedChar = null
178
+ }
179
+ append(c)
180
+ }
181
+ }
182
+
183
+ if (bufferedChar != null ) {
184
+ append(bufferedChar)
185
+ }
186
+ }
187
+
188
+ internal fun BsonNamingStrategy?.toJsonNamingStrategy (): JsonNamingStrategy ? {
189
+ return when (this ) {
190
+ BsonNamingStrategy .SNAKE_CASE -> JsonNamingStrategy .SnakeCase
191
+ else -> null
192
+ }
193
+ }
119
194
}
0 commit comments