-
Notifications
You must be signed in to change notification settings - Fork 162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add defaultValue to Schema #80
Conversation
def structure: Chunk[Field[_]] | ||
def annotations: Chunk[Any] = Chunk.empty | ||
// TODO: make this much more robust | ||
def defaultValue: Either[String, R] = self.rawConstruct(structure.map(_.schema.defaultValue.getOrElse(()))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what the best method is for lifting a Chunk[Either[String, A]]
to an Either[String, Chunk[A]]
.
In fp-ts
, I would generally use Traverse
to take care of this, but wasn't sure what the most semantic/idiomatic way to do this in ZIO was.
I also asked the question in Discord and was informed about zio-prelude
's analogous methods, but I wanted to avoid adding additional dependencies to zio-schema
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a dependency on zio-prelude
is fine but if we wanted to do it the old fashioned way it would be
structure.map(_.schema.defaultValue()).foldRight[Either[String,Chunk[A]](Right(Chunk.empty) {
case (_, e @ Left(_)) => e
case (Left(e), _) => Left[String,List[Unit]](e)
case (Right(value), Right(values)) => Right(values :+ value)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest avoiding to add ZIO Prelude just yet since it doesn't yet have a 1.0 release. This implementation looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments but overall nicely done! Thanks for your work on this!
def structure: Chunk[Field[_]] | ||
def annotations: Chunk[Any] = Chunk.empty | ||
// TODO: make this much more robust | ||
def defaultValue: Either[String, R] = self.rawConstruct(structure.map(_.schema.defaultValue.getOrElse(()))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a dependency on zio-prelude
is fine but if we wanted to do it the old fashioned way it would be
structure.map(_.schema.defaultValue()).foldRight[Either[String,Chunk[A]](Right(Chunk.empty) {
case (_, e @ Left(_)) => e
case (Left(e), _) => Left[String,List[Unit]](e)
case (Right(value), Right(values)) => Right(values :+ value)
}
def defaultValue: Either[String, (String, _)] = | ||
if (structure.isEmpty) | ||
Left(s"cannot access default value for enumeration with no members") | ||
else | ||
structure.head._2.defaultValue.map((structure.head._1, _)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in this case we should require a default case be specified when the Enumeration
is constructed. So maybe change to
final case class Enumeration(structure: ListMap[String,Schema[_]], defaultCase: Option[String] = None) extends Schema[(String,_)] {
def defaultValue: Either[String,(String,_)] =
defaultCase match {
case Some(id) => structure.get(id).map(_.defaultValue.map(id -> _)).getOrElse(Left("invalid default case"))
case None => Left("no default case is defined")
}
extends Schema[Z] { | ||
def defaultValue: Either[String, Z] = case1.codec.defaultValue | ||
} | ||
|
||
final case class CaseObject[Z](instance: Z) extends Schema[Z] | ||
final case class EnumN[Z](cases: Seq[Case[_, Z]]) extends Schema[Z] { | ||
|
||
def defaultValue: Either[String, Z] = | ||
if (cases.isEmpty) | ||
Left("cannot access default value for enum with no members") | ||
else | ||
cases.head.codec.defaultValue.asInstanceOf[Either[String, Z]] | ||
} | ||
|
||
final case class CaseObject[Z](instance: Z) extends Schema[Z] { | ||
def defaultValue: Either[String, Z] = Right(instance) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. It feels a little wonky to just declare on subtype as the default but these are also constructed using macros so we can't really allow one to be declared by the user (we could, but it would require an annotation which hasn't been defined yet). Maybe for these we just have defaultValue
return `Left("no default value can be determined"). If we want to allow a default to be specified in the future then we can do it with an annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest we just use the first subtype. Or we could do the "smallest" subtype, but first is more predictable.
Both Haskell and Scala type class derivation libraries choose to order the terms in a sum type (for Ord[A]
) according to declaration order, so there's a precedent for this.
} | ||
|
||
implicit object BoolType extends StandardType[Boolean] { | ||
def defaultValue: Either[String, Boolean] = Right(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Bool should default to false
to match the behavior of an uninitialized Boolean
in Java and Scala.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@jdegoes Is there any particular reason we want |
@thinkharderdev The only reason it has to return |
Thank you @thinkharderdev and @jdegoes for your review and suggestions! Apologies for the delay - I have been on vacation. I made the requested change to the I also left the Please let me know if you think any additional changes are necessary! Also as an aside, I am happy to work on a |
@IMax153 Thank you for your work on this! Can you resolve conflicts so we can see if the automated build passes? |
@jdegoes - thank you! I believe I've resolved all conflicts. Also, as I mentioned - if you guys would like me to try to add a |
@IMax153 @thinkharderdev Would be great to get this in by the ZIO Hackathon!! |
@jdegoes Thank you very much for the reminder on this PR! I've gone ahead and merged As we discussed, I am using the first defined Please let me know what you think! I am open to any and all feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your work on this!
* added basic documentation with example * added more dependencies to docs * incorporated feedback by @thinkharderdev * fixed wording 'ZIO-Schema' -> 'ZIO Schema' * fixed naming of other zio libraries * fix sbt publish setting * added examples subproject * docs: fixed mdoc link and added version placeholder in overview/index.md * docs: incorporated suggestions by @TobiasPfeifer * scalafmt for build.sbt * incorporated suggestions by @thinkharderdev * Support for annotations on all types (#147) * Add addonation to Schema[A] interface and add as field in Schema.Sequence * Add annotation field to Schema.Transform * Add annotation field to Schema.Primitive * Add annotations field to Schema.Optional * Add annotations field to Schema.Fail * Add annotations field to Schema.Tuple * Add annotations field to EitherSchema * Add annotations field to Schema.Lazy * Add annotations field to Schema.Meta * Add remaining assertion equality checks to equalsSchema * Remove annotations from Record[A] (since it exists in Schema[A] already) and add annotations field to Schema.GenericRecord * Fix test case for schema generation on annotated ADT * Fix handling of annotations for Lazy (and thus failing tests) * Wherever we accept an annotations chunk in the constructor/method we default it to Chunk.empty * Add `def annotate(annotation: Any): Schema[A]` to Schema * Replace usage of Chunk.appended with :+ to fix 2.12.12 compilation * Provide direct support for Map (#142) * Provide direct support for Map Unit tests for json serdes Unit tests for protobuf serdes * run scalafmt * Rebased/reformatted * Rebased/reformatted, and added a minimum contribution guide * Run sbt `prepare test` instead of `fmt test` * Add defaultValue to Schema (#80) * feat(schema): add first draft defaultValue implementation for Schema * feat(schema): add missing test cases * feat(schema): change default value for BoolType to false * feat(schema): fold default values in Record type appropriately * fix(zio-schema): fix failing test * feat(zio-schema): add defaultValue implementation for MapSchema * patch(zio-schema): remove orElse for Scala 2.12 compat * first commit * [zio-schema-examples] sbt setup * [zio-schema-examples] readme init * [zio-schema-examples] example 1 * [zio-schema-examples] example 2 * [zio-schema-examples] example 3 (WIP) * [zio-schema-examples] example 3 * [zio-schema-examples] Example3: Don't share domain with other samples * [zio-schema-examples] Example4 transforming DTOs * [zio-schema-examples] Example5 diffing * [zio-schema-examples] example 4: fixed map/flatmap in example * [zio-schema-examples] example 4: another try to converting DTOs * [zio-schema-examples] example 6 reified optics stub * [zio-schema-examples] example 6 reified optics examples * [zio-schema-examples] example 1 + 2: schema fixes for newest zio-schema * [zio-schema-examples] Problem 7: Initial code * [zio-schema-examples] Example 6: adding employee now works * [zio-schema-examples] Example 7: added notes on performance requirements * [zio-schema-examples] Example 7: added parameter list to methods, fixed names * [zio-schema-examples] Example 7: added Person and Profile schema as implicits * [zio-schema-examples] Example 7: renamed method for viewing, added Runner * [zio-schema-examples] Example 7: sketched toDynamicValue method * [zio-schema-examples] Example 7: implemented toDynamicValue method * [zio-schema-examples] Example 7: primitive impl of decode using toDV * [zio-schema-examples] Example 7: produce multiple solutions, pick working one * [zio-schema-examples] Example 7: introduce QueryParam type alias and compile-function * [zio-schema-examples] Example 7: return static function on error case * [zio-schema-examples] Example 7: initial impl of Primitive(standardtype) * [zio-schema-examples] Example 7: implemented fail * [zio-schema-examples] Example 7: simple impl of lazy * [zio-schema-examples] Example 7: better lazy impl with `lazy val` * [zio-schema-examples] Example 7: impl of Meta * [zio-schema-examples] Example 7: impl of CaseClass1 * [zio-schema-examples] Example 7: impl of CaseClass2 * [zio-schema-examples] Example 7: impl of CaseClass3 * [zio-schema-examples] Example 7: extracted compiler to builder * [zio-schema-examples] Example 7: implemented Transform * [zio-schema-examples] * Example for an Encoder and Decoder using the DynamicValue API * Add scalafmt * Update zio-schema 0.1.2 * Update examples to account for annotations * revert local changes * moved sources to appropriate place * fixed example * [zio-schema-examples] reverted changes to build.sbt * [zio-schema-examples] removed additional build.sbt, fixed problems in example7, added explicit import in build.sbt * [zio-schema-examples] scalaFmt applied * Fix build for scala 2.12 and apply linter * Fix compilation errors for scala 2.12 * Unused imports Co-authored-by: Dominik Dorn <dominik@dominikdorn.com> Co-authored-by: Alexander van Olst <alexvanolst@gmail.com> Co-authored-by: Pierangelo Cecchetto <pierangeloc@gmail.com> Co-authored-by: Maxwell Brown <maxwellbrown1990@gmail.com> Co-authored-by: calvinlfer <calvin.l.fer@gmail.com>
* feat(schema): add first draft defaultValue implementation for Schema * feat(schema): add missing test cases * feat(schema): change default value for BoolType to false * feat(schema): fold default values in Record type appropriately * fix(zio-schema): fix failing test * feat(zio-schema): add defaultValue implementation for MapSchema * patch(zio-schema): remove orElse for Scala 2.12 compat
* added basic documentation with example * added more dependencies to docs * incorporated feedback by @thinkharderdev * fixed wording 'ZIO-Schema' -> 'ZIO Schema' * fixed naming of other zio libraries * fix sbt publish setting * added examples subproject * docs: fixed mdoc link and added version placeholder in overview/index.md * docs: incorporated suggestions by @TobiasPfeifer * scalafmt for build.sbt * incorporated suggestions by @thinkharderdev * Support for annotations on all types (zio#147) * Add addonation to Schema[A] interface and add as field in Schema.Sequence * Add annotation field to Schema.Transform * Add annotation field to Schema.Primitive * Add annotations field to Schema.Optional * Add annotations field to Schema.Fail * Add annotations field to Schema.Tuple * Add annotations field to EitherSchema * Add annotations field to Schema.Lazy * Add annotations field to Schema.Meta * Add remaining assertion equality checks to equalsSchema * Remove annotations from Record[A] (since it exists in Schema[A] already) and add annotations field to Schema.GenericRecord * Fix test case for schema generation on annotated ADT * Fix handling of annotations for Lazy (and thus failing tests) * Wherever we accept an annotations chunk in the constructor/method we default it to Chunk.empty * Add `def annotate(annotation: Any): Schema[A]` to Schema * Replace usage of Chunk.appended with :+ to fix 2.12.12 compilation * Provide direct support for Map (zio#142) * Provide direct support for Map Unit tests for json serdes Unit tests for protobuf serdes * run scalafmt * Rebased/reformatted * Rebased/reformatted, and added a minimum contribution guide * Run sbt `prepare test` instead of `fmt test` * Add defaultValue to Schema (zio#80) * feat(schema): add first draft defaultValue implementation for Schema * feat(schema): add missing test cases * feat(schema): change default value for BoolType to false * feat(schema): fold default values in Record type appropriately * fix(zio-schema): fix failing test * feat(zio-schema): add defaultValue implementation for MapSchema * patch(zio-schema): remove orElse for Scala 2.12 compat * first commit * [zio-schema-examples] sbt setup * [zio-schema-examples] readme init * [zio-schema-examples] example 1 * [zio-schema-examples] example 2 * [zio-schema-examples] example 3 (WIP) * [zio-schema-examples] example 3 * [zio-schema-examples] Example3: Don't share domain with other samples * [zio-schema-examples] Example4 transforming DTOs * [zio-schema-examples] Example5 diffing * [zio-schema-examples] example 4: fixed map/flatmap in example * [zio-schema-examples] example 4: another try to converting DTOs * [zio-schema-examples] example 6 reified optics stub * [zio-schema-examples] example 6 reified optics examples * [zio-schema-examples] example 1 + 2: schema fixes for newest zio-schema * [zio-schema-examples] Problem 7: Initial code * [zio-schema-examples] Example 6: adding employee now works * [zio-schema-examples] Example 7: added notes on performance requirements * [zio-schema-examples] Example 7: added parameter list to methods, fixed names * [zio-schema-examples] Example 7: added Person and Profile schema as implicits * [zio-schema-examples] Example 7: renamed method for viewing, added Runner * [zio-schema-examples] Example 7: sketched toDynamicValue method * [zio-schema-examples] Example 7: implemented toDynamicValue method * [zio-schema-examples] Example 7: primitive impl of decode using toDV * [zio-schema-examples] Example 7: produce multiple solutions, pick working one * [zio-schema-examples] Example 7: introduce QueryParam type alias and compile-function * [zio-schema-examples] Example 7: return static function on error case * [zio-schema-examples] Example 7: initial impl of Primitive(standardtype) * [zio-schema-examples] Example 7: implemented fail * [zio-schema-examples] Example 7: simple impl of lazy * [zio-schema-examples] Example 7: better lazy impl with `lazy val` * [zio-schema-examples] Example 7: impl of Meta * [zio-schema-examples] Example 7: impl of CaseClass1 * [zio-schema-examples] Example 7: impl of CaseClass2 * [zio-schema-examples] Example 7: impl of CaseClass3 * [zio-schema-examples] Example 7: extracted compiler to builder * [zio-schema-examples] Example 7: implemented Transform * [zio-schema-examples] * Example for an Encoder and Decoder using the DynamicValue API * Add scalafmt * Update zio-schema 0.1.2 * Update examples to account for annotations * revert local changes * moved sources to appropriate place * fixed example * [zio-schema-examples] reverted changes to build.sbt * [zio-schema-examples] removed additional build.sbt, fixed problems in example7, added explicit import in build.sbt * [zio-schema-examples] scalaFmt applied * Fix build for scala 2.12 and apply linter * Fix compilation errors for scala 2.12 * Unused imports Co-authored-by: Dominik Dorn <dominik@dominikdorn.com> Co-authored-by: Alexander van Olst <alexvanolst@gmail.com> Co-authored-by: Pierangelo Cecchetto <pierangeloc@gmail.com> Co-authored-by: Maxwell Brown <maxwellbrown1990@gmail.com> Co-authored-by: calvinlfer <calvin.l.fer@gmail.com>
This PR adds a
defaultValue
method to theSchema
trait, which will return an appropriate value a givenSchema
and closes #74.Disclaimer: I am incredibly new to both Scala and ZIO, so any and all constructive criticism and feedback is most welcome 🙏.
Additional Context
For
StandardType
s, I defaulted the primitive values to the following:Basic Primitives
UnitType
->()
StringType
->""
BoolType
->true
ShortType
->0
IntType
->0
LongType
->0
FloatType
->0.0
DoubleType
->0.0
BinaryType
->Chunk.empty
CharType
->'\u0000'
(the empty character''
does not compile, so I went with theNUL
character code)BigDecimalType
->BigDecimal.ZERO
BigIntegerType
->BigInteger.ZERO
java.time
PrimitivesDayOfWeekType
->java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek
Month
->java.time.Month.JANUARY
MonthDay
->java.time.MonthDay.of(java.time.Month.JANUARY, 1)
Period
->java.time.Period.ZERO
Year
->java.time.Year.now
YearMonth
->java.time.YearMonth.now
ZoneId
->java.time.ZoneId.systemDefault
ZoneOffset
->java.time.ZoneOffset.UTC
Duration
->java.time.Duration.ZERO
Instant
->java.time.Instant.EPOCH
LocalDate
->java.time.LocalDate.now
LocalTime
->java.time.LocalTime.MIDNIGHT
LocalDateTime
->java.time.LocalDateTime.now
OffsetTime
->java.time.OffsetTime.now
OffsetDateTime
->java.time.OffsetDateTime.now
ZonedDateTime
->java.time.ZonedDateTime.now
I also added a new test suite (
DefaultValueSpec
) to the current array of test suites.