CaseClass
CaseClass represents an immutable case class in the IR. Use it when generating Scala code from data models, APIs, or structured dataโit's the most frequently chosen type definition.
Use Casesโ
- Modeling product types (records) from OpenAPI schemas, JSON Schema, or data formats
- Defining data transfer objects (DTOs) with named fields
- Creating immutable value types with automatic
equals,hashCode,copy
Constructionโ
Build a case class with a name and field list:
import zio.blocks.codegen.ir._
val person = CaseClass(
name = "Person",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef.String)
)
)
With optional type parameters:
import zio.blocks.codegen.ir._
val box = CaseClass(
name = "Box",
fields = List(Field("value", TypeRef("T"))),
typeParams = List(TypeParam("T"))
)
With derives clauses:
import zio.blocks.codegen.ir._
val user = CaseClass(
name = "User",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String)
),
derives = List("Show", "Eq", "Codec")
)
Key Operationsโ
All CaseClass instances support these core operations:
Accessing Componentsโ
Extract parts of a case class:
import zio.blocks.codegen.ir._
val person = CaseClass(
name = "Person",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef.String)
)
)
Access each component by reading their properties:
import zio.blocks.codegen.ir._
val person = CaseClass(
name = "Person",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef.String)
)
)
Each component can be accessed and displayed:
import zio.blocks.codegen.ir._
person.name // "Person"
// res4: String = "Person"
person.fields // List[Field]
// res5: List[Field] = List(
// Field(
// name = "id",
// typeRef = TypeRef(name = "Long", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// ),
// Field(
// name = "name",
// typeRef = TypeRef(name = "String", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// ),
// Field(
// name = "email",
// typeRef = TypeRef(name = "String", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// )
// )
person.typeParams // List[TypeParam] (empty if not generic)
// res6: List[TypeParam] = List()
person.derives // List[String]
// res7: List[String] = List()
person.annotations // List[Annotation]
// res8: List[Annotation] = List()
person.isValueClass // Boolean
// res9: Boolean = false
Building with Copyโ
Use the copy method to modify a case class:
import zio.blocks.codegen.ir._
val person = CaseClass(
name = "Person",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef.String)
)
)
Create a new version with additional fields:
import zio.blocks.codegen.ir._
val extended = person.copy(
fields = person.fields :+ Field("phone", TypeRef.String),
derives = List("Show")
)
// extended: CaseClass = CaseClass(
// name = "Person",
// fields = List(
// Field(
// name = "id",
// typeRef = TypeRef(name = "Long", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// ),
// Field(
// name = "name",
// typeRef = TypeRef(name = "String", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// ),
// Field(
// name = "email",
// typeRef = TypeRef(name = "String", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// ),
// Field(
// name = "phone",
// typeRef = TypeRef(name = "String", typeArgs = List()),
// defaultValue = None,
// annotations = List(),
// doc = None
// )
// ),
// typeParams = List(),
// extendsTypes = List(),
// derives = List("Show"),
// annotations = List(),
// companion = None,
// doc = None,
// isValueClass = false
// )
Adding a Companion Objectโ
Case classes can have companion objects with static members:
import zio.blocks.codegen.ir._
val withCompanion = CaseClass(
name = "Config",
fields = List(Field("timeout", TypeRef.Long)),
companion = Some(
CompanionObject(
members = List(
ObjectMember.ValMember("Default", TypeRef("Config"), "Config(5000L)")
)
)
)
)
Examplesโ
Here are concrete examples demonstrating typical CaseClass usage patterns:
Example 1: Simple Case Classโ
A basic case class with primitive fields:
import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._
val order = CaseClass(
name = "Order",
fields = List(
Field("id", TypeRef.Long),
Field("total", TypeRef("BigDecimal")),
Field("status", TypeRef.String)
)
)
val file = ScalaFile(
packageDecl = PackageDecl("com.shop"),
types = List(order)
)
Emits:
import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, EmitterConfig())
// res13: String = """package com.shop
//
// case class Order(
// id: Long,
// total: BigDecimal,
// status: String,
// )
// """
Example 2: Nested Typesโ
A case class with optional and collection fields:
import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._
val user = CaseClass(
name = "User",
fields = List(
Field("id", TypeRef.Long),
Field("name", TypeRef.String),
Field("email", TypeRef("Option", List(TypeRef.String))),
Field("tags", TypeRef("List", List(TypeRef.String)))
)
)
val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(user)
)
Emits:
import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, EmitterConfig())
// res15: String = """package com.example
//
// case class User(
// id: Long,
// name: String,
// email: Option[String],
// tags: List[String],
// )
// """
Example 3: Generic Case Classโ
A polymorphic case class with type parameters:
import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._
val page = CaseClass(
name = "Page",
fields = List(
Field("items", TypeRef("List", List(TypeRef("T")))),
Field("total", TypeRef.Long),
Field("pageSize", TypeRef.Int)
),
typeParams = List(TypeParam("T"))
)
val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(page)
)
Emits:
import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, EmitterConfig())
// res17: String = """package com.example
//
// case class Page[T](
// items: List[T],
// total: Long,
// pageSize: Int,
// )
// """
Example 4: Case Class with Derivesโ
Automatic typeclass derivation:
import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._
val product = CaseClass(
name = "Product",
fields = List(
Field("id", TypeRef.String),
Field("name", TypeRef.String),
Field("price", TypeRef("java.math.BigDecimal"))
)
)
val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(product)
)
Emits:
import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, EmitterConfig())
// res19: String = """package com.example
//
// case class Product(
// id: String,
// name: String,
// price: java.math.BigDecimal,
// )
// """
Example 5: Case Class with Companionโ
A case class with factory methods in the companion:
import zio.blocks.codegen.ir._
import zio.blocks.codegen.emit._
val config = CaseClass(
name = "AppConfig",
fields = List(
Field("host", TypeRef.String),
Field("port", TypeRef.Int)
),
companion = Some(
CompanionObject(
members = List(
ObjectMember.ValMember(
"Default",
TypeRef("AppConfig"),
"AppConfig(\"localhost\", 8080)"
)
)
)
)
)
val file = ScalaFile(
packageDecl = PackageDecl("com.example"),
types = List(config)
)
Emits:
import zio.blocks.codegen.emit._
ScalaEmitter.emit(file, EmitterConfig())
// res21: String = """package com.example
//
// case class AppConfig(
// host: String,
// port: Int,
// )
//
// object AppConfig {
// val Default: AppConfig = AppConfig("localhost", 8080)
// }
// """