Skip to content
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

feat: Add zio-schema-quickstart #59

Merged
merged 4 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions zio-quickstart-schema/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
scalaVersion := "2.13.12"
organization := "dev.zio"
name := "zio-quickstart-restful-schema"


libraryDependencies ++= Seq(
"dev.zio" %% "zio-schema" % "1.4.1",
"dev.zio" %% "zio-schema-zio-test" % "1.4.1",
"dev.zio" %% "zio-schema-derivation" % "1.4.1",
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
"dev.zio" %% "zio-test" % "2.1.9" % Test,
"dev.zio" %% "zio-test-sbt" % "2.1.9" % Test,
"dev.zio" %% "zio-test-magnolia" % "2.1.9" % Test
)

resolvers ++= Resolver.sonatypeOssRepos("snapshots")
32 changes: 32 additions & 0 deletions zio-quickstart-schema/src/main/resources/incoming_data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Name,Email,Date of birth
Rosalia Marini,annamaria26@example.org,2021-10-29
Michela Rizzo-Traetta,pisaroniantonietta@example.com,1955-07-05
Gianpaolo Nibali,donatogagliardi@example.com,1995-06-08
Orlando Gradenigo,rcatenazzi@example.org,1970-09-07
Pasqual Disdero-Verri,rosaria88@example.com,1929-11-25
Alphons Amato,stefano58@example.net,1963-04-30
Annetta Balbi,federica81@example.org,1986-09-23
Sig. Ricciotti Gigli,bianchiflavia@example.net,1930-03-16
Isabella Petrocelli,francesca93@example.org,1972-09-27
Carolina Veneziano-Giovine,giulio81@example.net,1916-03-27
Melina Respighi,ippaziodisdero@example.org,2013-11-04
Dott. Mario Crespi,giampieroravaglioli@example.com,1920-02-23
Sig.ra Annunziata Sforza,ftomei@example.org,1952-08-27
Dott. Greca Paganini,eleanora72@example.org,1995-08-10
Virginia Draghi,krinaldi@example.org,1960-06-30
Ivo Magrassi-Ginese,qvarano@example.com,1961-07-13
Ferdinando Prodi,ybompiani@example.org,2019-02-17
Lucrezia Lucciano,tcarullo@example.com,1968-07-20
Germana Favata,marazzililiana@example.org,1983-10-12
Gioffre Sagnelli,ucontarini@example.org,2010-02-05
Elladio Garibaldi-Iannuzzi,farnesevirgilio@example.net,2002-06-02
Leopoldo Donarelli-Pagliaro,bettinaparri@example.net,1934-08-31
Dott. Cirillo Caetani,antoniorosselli@example.net,2001-08-27
Rosalia Roncalli-Gangemi,turatieugenia@example.com,1986-06-15
Rembrandt Briccialdi,imelda80@example.net,1965-07-18
Gianmarco Fanucci,ermenegildoprati@example.net,1962-09-12
Francesca Callegari,ferruccicostanzo@example.org,1917-09-09
Sig.ra Daria Nordio,donatozarlino@example.org,1911-01-24
Sig.ra Vanessa Cremonesi,virginia96@example.net,2008-05-20
Dott. Durante Treccani,borghesegionata@example.com,1933-07-12
Adelasia Satriani,rubertoarnaldo@example.com,1970-07-29
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.zio.quickstart

import zio._
import zio.schema._
import zio.schema.annotation.validate
import zio.schema.validation.Validation
import zio.stream.ZStream

// one can choose the detailed way of validation or use annotations

case class Person(
name: String,
@validate(Validation.greaterThan(18))
age: Int)

object Person {
implicit val schema : Schema[Person] = DeriveSchema.gen
}


// one can choose the detailed way of validation or use annotations

//case class Person(name: String, age: Int)

// object Person {
// implicit val schema: Schema[Person] = CaseClass2(
// id0 = TypeId.fromTypeName("Person"),
// field01 = Schema.Field(
// name0 = "name",
// schema0 = Schema[String],
// validation0 = Validation.minLength(15),
// get0 = (p: Person) => p.name,
// set0 = { (p: Person, s: String) => p.copy(name = s) }
// ),
// field02 = Schema.Field(
// name0 = "age",
// schema0 = Schema[Int],
// validation0 = Validation.greaterThan(18),
// get0 = (p: Person) => p.age,
// set0 = { (p: Person, age: Int) => p.copy(age = age) }
// ),
// construct0 = (name, age) => Person(name, age),
// )

// }

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package dev.zio.quickstart

import zio._

import java.time.LocalDate
import java.io.{File, FileNotFoundException, IOException}
import scala.io.{BufferedSource, Source}
import zio.schema

object PrepareDataUtils {

val homeDirectory = java.lang.System.getProperty("user.home")
val fileName = homeDirectory + "/Desktop/centre/scala/zio-quickstarts/zio-quickstart-schema/src/main/resources/incoming_data.txt"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use resources instead to locate the incoming_data



def openFile(name: String): IO[IOException, BufferedSource] =
ZIO.attemptBlockingIO(Source.fromFile(name))

def closeFile(bufferedSourceFile: BufferedSource): ZIO[Any, Nothing, Unit] =
ZIO.succeedBlocking(bufferedSourceFile.close())

def withFile[A](name: String)(useFile: BufferedSource => Task[A]): Task[A] =
ZIO.acquireReleaseWith(openFile(name))(closeFile)(useFile)

def prepareData(bufferedSourceFile: BufferedSource): List[Person] = {

def getPerson: Iterator[Person] = for {
line <- bufferedSourceFile.getLines().filter(incomingString => !incomingString.contains("Name"))
arr = line.split(",")
dob = arr.reverse.head
name = arr.head
age = getAge(dob)
person = Person(name, age)
} yield person

getPerson.toList

}

def getAge(dob: String): Int = {
val currYear = LocalDate.now().getYear
currYear - LocalDate.parse(dob).getYear
}

}


Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package dev.zio.quickstart

import zio._
import zio.schema._
import zio.schema.annotation.validate
import zio.schema.validation.Validation
import zio.stream.ZStream


object SchemaValidator extends ZIOAppDefault {

import PrepareDataUtils._

val res = withFile(fileName)(file => ZIO.attempt(prepareData(file)))

val runStream = ZStream
.fromIterableZIO(res)
.map{ person =>
Person.schema.validate(person) match {
case Chunk() => Right(person)
case Chunk(_) | Chunk(_, _) => Left(person)
}

}

val b = runStream
.runFold((List.empty[Person], List.empty[String])) {
case ((valid, invalid), Right(person)) => (valid :+ person, invalid) // Collect valid persons
case ((valid, invalid), Left(error)) => (valid, invalid :+ error.toString) // Collect errors
}


def run=
program


val program =
for {
count <- runStream.runFold(0)((accum, _) => accum + 1)
c <- b
_ <- Console.printLine(s"Total count: ${c._2.size}")
} yield ()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package dev.zio.quickstart

import PrepareDataUtils._
import zio.stream.ZStream
import zio.test._
import zio.{Chunk, ZIO}


object StreamWithSchemaValidation {
private val res = withFile(fileName)(file => ZIO.attempt(prepareData(file)))

private val runStream = ZStream
.fromIterableZIO(res)
.map{ person =>
val validatedRecord = Person.schema.validate(person)

validatedRecord match {
case Chunk() => Right(person)
case Chunk(_) | Chunk(_,_) => Left(person)
}
}

def getTotalNumberofPeopleAbove18: ZIO[Any, Throwable, Int] =
runStream
.runFold(0)((acc, x) =>
x match {
case Right(_) => acc + 1
case Left(_) => acc
}
)

def getTotalNumberofRecords: ZIO[Any, Throwable, Int] =
runStream
.runCount
.map(_.toInt)

def getPeopleBelow18: ZIO[Any, Throwable, Int] =
for {
peopleAbove18 <- getTotalNumberofPeopleAbove18
totalNumber <- getTotalNumberofRecords
} yield totalNumber - peopleAbove18


def getFirstPersonAbove18: ZIO[Any, Throwable, List[Person]] =
runStream
.runFold(List.empty[Person]){
case (resList, Right(person)) => resList :+ person
case (resList, Left(_)) => resList
}

def getFirstPersonbelow18: ZIO[Any, Throwable, List[Person]] =
runStream
.runFold(List.empty[Person]){
case (resList, Left(person)) => resList :+ person
case (resList, Right(_)) => resList
}

}


object SchemaValidatorSpec extends ZIOSpecDefault {

object Answers {
val firstFiveNamesOfPeopleAbove18: List[Person] = List(
Person("Michela Rizzo-Traetta", 69),
Person("Gianpaolo Nibali", 29),
Person("Orlando Gradenigo", 54),
Person("Pasqual Disdero-Verri", 95),
Person("Alphons Amato", 61)
)

val firstFiveNamesOfPeoplebelow18 = List(
Person("Rosalia Marini", 3),
Person("Melina Respighi", 11),
Person("Ferdinando Prodi", 5),
Person("Gioffre Sagnelli", 14),
Person("Sig.ra Vanessa Cremonesi", 16)
)

}
def spec: Spec[Any, Throwable] = suite("ExampleSpec")(
test("Get total number of people"){
assertZIO(StreamWithSchemaValidation.getTotalNumberofRecords)(Assertion.equalTo(31))
},
test("Get people above the age of 18"){
for {
count <- StreamWithSchemaValidation.getTotalNumberofPeopleAbove18
} yield assertTrue(count == 26)
},
test("First name in the stream"){
for {
persons <- StreamWithSchemaValidation.getFirstPersonAbove18
} yield assertTrue(persons.head == Answers.firstFiveNamesOfPeopleAbove18.head)
},
test("First five names of persons above 18"){
for {
persons <- StreamWithSchemaValidation.getFirstPersonAbove18
} yield assertTrue(persons.take(5) == Answers.firstFiveNamesOfPeopleAbove18)
},
test("First name of person below 18 is Rosalia Marina"){
for {
persons <- StreamWithSchemaValidation.getFirstPersonbelow18
nameOfFirstPerson = persons.head.name
mustBeRosalia = Answers.firstFiveNamesOfPeoplebelow18.head.name

} yield assertTrue(nameOfFirstPerson == mustBeRosalia)
}

)
}
Loading