Skip to content

Commit

Permalink
fix snake case (#814)
Browse files Browse the repository at this point in the history
  • Loading branch information
senia-psm authored Dec 5, 2022
1 parent 8cbd5fb commit 8e631b7
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 10 deletions.
36 changes: 36 additions & 0 deletions zio-json/shared/src/main/scala-2.x/zio/json/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ case object CamelCase extends JsonMemberFormat {
override def apply(memberName: String): String =
jsonMemberNames.enforceCamelOrPascalCase(memberName, toPascal = false)
}

case object PascalCase extends JsonMemberFormat {
override def apply(memberName: String): String = jsonMemberNames.enforceCamelOrPascalCase(memberName, toPascal = true)
}
Expand All @@ -60,6 +61,18 @@ case object IdentityFormat extends JsonMemberFormat {
override def apply(memberName: String): String = memberName
}

/** zio-json version 0.3.0 formats. abc123Def -> abc_123_def */
object ziojson_03 {
case object SnakeCase extends JsonMemberFormat {
override def apply(memberName: String): String =
jsonMemberNames.enforceSnakeOrKebabCaseSeparateNumbers(memberName, '_')
}
case object KebabCase extends JsonMemberFormat {
override def apply(memberName: String): String =
jsonMemberNames.enforceSnakeOrKebabCaseSeparateNumbers(memberName, '-')
}
}

/**
* If used on a case class, determines the strategy of member names
* transformation during serialization and deserialization. Four common
Expand Down Expand Up @@ -105,6 +118,29 @@ private[json] object jsonMemberNames {
}

def enforceSnakeOrKebabCase(s: String, separator: Char): String = {
val len = s.length
val sb = new StringBuilder(len << 1)
var i = 0
var isPrecedingNotUpperCased = false
while (i < len) isPrecedingNotUpperCased = {
val ch = s.charAt(i)
i += 1
if (ch == '_' || ch == '-') {
sb.append(separator)
false
} else if (!isUpperCase(ch)) {
sb.append(ch)
true
} else {
if (isPrecedingNotUpperCased || i > 1 && i < len && !isUpperCase(s.charAt(i))) sb.append(separator)
sb.append(toLowerCase(ch))
false
}
}
sb.toString
}

def enforceSnakeOrKebabCaseSeparateNumbers(s: String, separator: Char): String = {
val len = s.length
val sb = new StringBuilder(len << 1)
var i = 0
Expand Down
35 changes: 35 additions & 0 deletions zio-json/shared/src/main/scala-3/zio/json/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ case object KebabCase extends JsonMemberFormat {
override def apply(memberName: String): String = jsonMemberNames.enforceSnakeOrKebabCase(memberName, '-')
}

/** zio-json version 0.3.0 formats. abc123Def -> abc_123_def */
object ziojson_03 {
case object SnakeCase extends JsonMemberFormat {
override def apply(memberName: String): String =
jsonMemberNames.enforceSnakeOrKebabCaseSeparateNumbers(memberName, '_')
}
case object KebabCase extends JsonMemberFormat {
override def apply(memberName: String): String =
jsonMemberNames.enforceSnakeOrKebabCaseSeparateNumbers(memberName, '-')
}
}

/**
* If used on a case class, determines the strategy of member names
* transformation during serialization and deserialization. Four common
Expand Down Expand Up @@ -108,6 +120,29 @@ private[json] object jsonMemberNames {
val len = s.length
val sb = new StringBuilder(len << 1)
var i = 0
var isPrecedingNotUpperCased = false
while (i < len) isPrecedingNotUpperCased = {
val ch = s.charAt(i)
i += 1
if (ch == '_' || ch == '-') {
sb.append(separator)
false
} else if (!isUpperCase(ch)) {
sb.append(ch)
true
} else {
if (isPrecedingNotUpperCased || i > 1 && i < len && !isUpperCase(s.charAt(i))) sb.append(separator)
sb.append(toLowerCase(ch))
false
}
}
sb.toString
}

def enforceSnakeOrKebabCaseSeparateNumbers(s: String, separator: Char): String = {
val len = s.length
val sb = new StringBuilder(len << 1)
var i = 0
var isPrecedingLowerCased = false
while (i < len) isPrecedingLowerCased = {
val ch = s.charAt(i)
Expand Down
45 changes: 35 additions & 10 deletions zio-json/shared/src/test/scala/zio/json/CodecSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,31 @@ object CodecSpec extends ZIOSpecDefault {
},
test("key transformation") {
import exampletransformkeys._
val kebabed = """{"shish-kebab":""}"""
val snaked = """{"indiana_jones":""}"""
val pascaled = """{"AndersHejlsberg":""}"""
val cameled = """{"smallTalk":""}"""
val indianaJones = """{"wHATcASEiStHIS":""}"""
val overrides = """{"not_modified":"","but-this-should-be":0}"""
val kebabed = """{"shish123-kebab":""}"""
val snaked = """{"indiana123_jones":""}"""
val pascaled = """{"Anders123Hejlsberg":""}"""
val cameled = """{"small123Talk":""}"""
val indianaJones = """{"wHATcASEiStHIS":""}"""
val overrides = """{"not_modified":"","but-this-should-be":0}"""
val kebabedLegacy = """{"shish-123-kebab":""}"""
val snakedLegacy = """{"indiana_123_jones":""}"""

assert(kebabed.fromJson[Kebabed])(isRight(equalTo(Kebabed("")))) &&
assert(kebabedLegacy.fromJson[legacy.Kebabed])(isRight(equalTo(legacy.Kebabed("")))) &&
assert(snaked.fromJson[Snaked])(isRight(equalTo(Snaked("")))) &&
assert(snakedLegacy.fromJson[legacy.Snaked])(isRight(equalTo(legacy.Snaked("")))) &&
assert(pascaled.fromJson[Pascaled])(isRight(equalTo(Pascaled("")))) &&
assert(cameled.fromJson[Cameled])(isRight(equalTo(Cameled("")))) &&
assert(indianaJones.fromJson[Custom])(isRight(equalTo(Custom("")))) &&
assert(overrides.fromJson[OverridesAlsoWork])(isRight(equalTo(OverridesAlsoWork("", 0)))) &&
assertTrue(Kebabed("").toJson == kebabed) &&
assertTrue(Kebabed("").toJsonAST.toOption.get == kebabed.fromJson[Json].toOption.get) &&
assertTrue(legacy.Kebabed("").toJson == kebabedLegacy) &&
assertTrue(legacy.Kebabed("").toJsonAST.toOption.get == kebabedLegacy.fromJson[Json].toOption.get) &&
assertTrue(Snaked("").toJson == snaked) &&
assertTrue(Snaked("").toJsonAST.toOption.get == snaked.fromJson[Json].toOption.get) &&
assertTrue(legacy.Snaked("").toJson == snakedLegacy) &&
assertTrue(legacy.Snaked("").toJsonAST.toOption.get == snakedLegacy.fromJson[Json].toOption.get) &&
assertTrue(Pascaled("").toJson == pascaled) &&
assertTrue(Pascaled("").toJsonAST.toOption.get == pascaled.fromJson[Json].toOption.get) &&
assertTrue(Cameled("").toJson == cameled) &&
Expand Down Expand Up @@ -237,25 +245,25 @@ object CodecSpec extends ZIOSpecDefault {

object exampletransformkeys {
@jsonMemberNames(KebabCase)
case class Kebabed(shishKebab: String)
case class Kebabed(shish123Kebab: String)
object Kebabed {
implicit val codec: JsonCodec[Kebabed] = DeriveJsonCodec.gen[Kebabed]
}

@jsonMemberNames(SnakeCase)
case class Snaked(indianaJones: String)
case class Snaked(indiana123Jones: String)
object Snaked {
implicit val codec: JsonCodec[Snaked] = DeriveJsonCodec.gen[Snaked]
}

@jsonMemberNames(PascalCase)
case class Pascaled(andersHejlsberg: String)
case class Pascaled(anders123Hejlsberg: String)
object Pascaled {
implicit val codec: JsonCodec[Pascaled] = DeriveJsonCodec.gen[Pascaled]
}

@jsonMemberNames(CamelCase)
case class Cameled(small_talk: String)
case class Cameled(small123_talk: String)
object Cameled {
implicit val codec: JsonCodec[Cameled] = DeriveJsonCodec.gen[Cameled]
}
Expand All @@ -277,6 +285,23 @@ object CodecSpec extends ZIOSpecDefault {
object OverridesAlsoWork {
implicit val codec: JsonCodec[OverridesAlsoWork] = DeriveJsonCodec.gen[OverridesAlsoWork]
}

object legacy {
@jsonMemberNames(ziojson_03.KebabCase)
case class Kebabed(shish123Kebab: String)

object Kebabed {
implicit val codec: JsonCodec[Kebabed] = DeriveJsonCodec.gen[Kebabed]
}

@jsonMemberNames(ziojson_03.SnakeCase)
case class Snaked(indiana123Jones: String)

object Snaked {
implicit val codec: JsonCodec[Snaked] = DeriveJsonCodec.gen[Snaked]
}

}
}

object logEvent {
Expand Down

0 comments on commit 8e631b7

Please sign in to comment.