All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sttp.tapir.macros.SchemaMacros.scala Maven / Gradle / Ivy

The newest version!
package sttp.tapir.macros

import magnolia1.Magnolia
import sttp.tapir.Schema
import sttp.tapir.generic.Configuration
import sttp.tapir.generic.auto.SchemaMagnoliaDerivation
import sttp.tapir.internal.{ModifySchemaMacro, OneOfMacro, SchemaEnumerationMacro, SchemaMapMacro}

trait SchemaMacros[T] {

  /** Modifies nested schemas for case classes and case class families (sealed traits / enums), accessible with `path`, using the given
    * `modification` function. To traverse collections, use `.each`.
    *
    * Should only be used if the schema hasn't been created by `.map`ping another one. In such a case, the shape of the schema doesn't
    * correspond to the type `T`, but to some lower-level representation of the type.
    *
    * If the shape of the schema doesn't correspond to the path, the schema remains unchanged.
    */
  def modify[U](path: T => U)(modification: Schema[U] => Schema[U]): Schema[T] = macro ModifySchemaMacro.generateModify[T, U]
}

trait SchemaCompanionMacros extends SchemaMagnoliaDerivation {
  implicit def schemaForMap[V: Schema]: Schema[Map[String, V]] = macro SchemaMapMacro.generateSchemaForStringMap[V]

  /** Create a schema for a map with arbitrary keys. The schema for the keys `K` should be a string, however this cannot be verified at
    * compile-time and is not verified at run-time.
    *
    * The given `keyToString` conversion function is used during validation.
    *
    * If you'd like this schema to be available as an implicit for a given type of keys, create an custom implicit, e.g.:
    *
    * {{{
    * case class MyKey(value: String) extends AnyVal
    * implicit val schemaForMyMap = Schema.schemaForMap[MyKey, MyValue](_.value)
    * }}}
    */
  def schemaForMap[K, V: Schema](keyToString: K => String): Schema[Map[K, V]] =
    macro SchemaMapMacro.generateSchemaForMap[K, V]

  /** Create a coproduct schema (e.g. for a `sealed trait`), where the value of the discriminator between child types is a read of a field
    * of the base type. The field, if not yet present, is added to each child schema.
    *
    * The schemas of the child types have to be provided explicitly with their value mappings in `mapping`.
    *
    * Note that if the discriminator value is some transformation of the child's type name (obtained using the implicit [[Configuration]]),
    * the coproduct schema can be derived automatically or semi-automatically.
    *
    * @param discriminatorSchema
    *   The schema that is used when adding the discriminator as a field to child schemas (if it's not yet in the schema).
    */
  def oneOfUsingField[E, V](extractor: E => V, asString: V => String)(
      mapping: (V, Schema[_])*
  )(implicit conf: Configuration, discriminatorSchema: Schema[V]): Schema[E] = macro OneOfMacro.generateOneOfUsingField[E, V]

  /** Create a coproduct schema for a `sealed trait` or `sealed abstract class`, where to discriminate between child types a wrapper product
    * is used. The name of the sole field in this product corresponds to the type's name, transformed using the implicit [[Configuration]].
    */
  def oneOfWrapped[E](implicit conf: Configuration): Schema[E] = macro OneOfMacro.generateOneOfWrapped[E]

  def derived[T]: Schema[T] = macro Magnolia.gen[T]

  /** Creates a schema for an enumeration, where the validator is derived using [[sttp.tapir.Validator.derivedEnumeration]]. This requires
    * that all subtypes of the sealed hierarchy `T` must be `object`s.
    *
    * This method cannot be implicit, as there's no way to constraint the type `T` to be a sealed trait / class enumeration, so that this
    * would be invoked only when necessary.
    */
  def derivedEnumeration[T]: CreateDerivedEnumerationSchema[T] = macro SchemaEnumerationMacro.derivedEnumeration[T]

  /** Creates a schema for an [[Enumeration]], where the validator is created using the enumeration's values. Unlike the default
    * [[derivedEnumerationValue]] method, which provides the schema implicitly, this variant allows customising how the schema is created.
    * This is useful if the low-level representation of the schema is different than a `String`, or if the enumeration's values should be
    * encoded in a different way than using `.toString`.
    *
    * Because of technical limitations of macros, the customisation arguments can't be given here directly, instead being delegated to
    * [[CreateDerivedEnumerationSchema]].
    */
  def derivedEnumerationValueCustomise[T <: scala.Enumeration#Value]: CreateDerivedEnumerationSchema[T] =
    macro SchemaEnumerationMacro.derivedEnumerationValueCustomise[T]

  /** Create a schema for an [[Enumeration]], where the validator is created using the enumeration's values. The low-level representation of
    * the enum is a `String`, and the enum values in the documentation will be encoded using `.toString`.
    */
  implicit def derivedEnumerationValue[T <: scala.Enumeration#Value]: Schema[T] = macro SchemaEnumerationMacro.derivedEnumerationValue[T]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy