ScalaQuery    flatMap(Oslo)Trond Marius Øvstetun        © Mesan AS
Trond Marius Øvstetun• Sjefskonsulentog fagleder i Mesan• Lidenskapelig utvikler, arkitekt, teamleder ++• Java,    Scala, ...
Data• Vi   har behov for å lagre data                  © Mesan AS
Data• Vi   har behov for å lagre data• Ikke     alle bruker eller kan bruke NoSQL                  © Mesan AS
Data• Vi   har behov for å lagre data• Ikke     alle bruker eller kan bruke NoSQL • konservativ   it-avdeling? • legacy   ...
Data• Vi   har behov for å lagre data• Ikke     alle bruker eller kan bruke NoSQL • konservativ   it-avdeling? • legacy   ...
SQL• Hvordan jobber vi med RDBMS på best mulig måte?              © Mesan AS
SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?              © Mesan AS
SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM?              © Mesan AS
SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM? • Hibernate?                © Mesan AS
SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM? • Hibernate? • Anorm?   Mapper? Record?                 ...
ScalaQuery   © Mesan AS
ScalaQueryA type-safe database API for           Scala           © Mesan AS
ScalaQueryA type-safe database API for           Scala           © Mesan AS
En enkel domenemodell    «enumeration»                           Artist      Genre                                        ...
Koble til en database  • Med javax.sql.DataSourcedef myDs : DataSource = {...}val db = Database.forDataSource(myDs)       ...
Koble til en database• Alternativt                © Mesan AS
Koble til en database  • AlternativtDatabase.forName("jdbc/my_ds") //JNDIDatabase.forURL("jdbc:h2:test")                  ...
Gjøre noe med databasen         val db = {...}         db withSession {           do_something()         }import Database....
StaticQueryHåndkodet SQL mot databasen           © Mesan AS
Spørringerval q = StaticQuery[Int] +        "select count(id) from Artists"val count = q.first()                 © Mesan AS
Spørringerval q = StaticQuery[Int, (Int, String)] +      "select id, name from Artists where id = ?"val (id,name) = q(1001...
Mapping av resultatcase class Artist(id:Int, name:String)val q = StaticQuery.query[Int, (Int, String)](  "select id, name ...
Implisitt mapping avcase class Artist(id:Int, name:String)implicit val artMapper = GetResult(  (r: PositionedResult) => ne...
Insert / Updateimport org.scalaquery.simple.StaticQuery._val q = query[(String, String), Int](  "insert into Artists(name,...
ScalaQuery   © Mesan AS
ScalaQueryPå tide å få noe igjen?      Hva om ...        © Mesan AS
En enkel domenemodell    «enumeration»                           Artist      Genre                                        ...
Mapping til en tabellobject Artists extends Table[  (Int, String, String,    Genre.Genre, Date, Option[Date])  ]("ARTISTS"...
Mapping til en tabellobject Artists extends Table (...) {    def id = column[Int]("ID", O PrimaryKey)    def name = column...
Mapping til en tabellobject Artists extends Table (...) {  ...  def * = id ~ name ~ biography ~          maingenre ~ found...
Mapping med case-klassecase class Artist(    id:Int,name:String, bio:String,    mainGenre:Genre.Genre, founded:Date,    sp...
Bruke egne typer  column[Genre.Genre]("MAINGENRE")    object Genre extends Enumeration {        type Genre = Value        ...
Bruke egne typer    column[Duration]("DURATION")case class Duration(mins:Int, secs:Int)implicit object durationMapper exte...
Inserts    val i: Int = Artists.i.insert(      ("Seigmen", "", Genre.Rock,        date("1989-12-27"),        Some(date("20...
Enkle spørringerdef findArtist(id:Int) : Option[(...)] = {    val q = Artists.createFinderBy(_.id)    q(id).firstOption}  ...
Enkle spørringerdef findArtist(id:Int) : Option[(...)] = {    val q = Artists.createFinderBy(_.id)    q(id).firstOption}de...
Bruk av spørringerval resList = q.listval resOption = q.firstOptionval res = q.first            © Mesan AS
Mer generelle spørringerval q1 =  Artists.filter(_.maingenre === Genre.Rock)                   © Mesan AS
Mer generelle spørringerval q1 =  Artists.filter(_.maingenre === Genre.Rock)val q = for {  a <- Artists if a.maingenre ===...
Generell spørring val aQuery = for {     x1 <- generator     x2 <- generator     ...     xN <- generator     guard   } yie...
Parametrisertval qArtist = for {  n <- Parameters[String]  a <- Artists if a.name === n} yield a.id ~ a.name            © ...
Parametrisertval qArtist = for {  n <- Parameters[String]  a <- Artists if a.name === n} yield a.id ~ a.nameval qTool = qA...
Spørringer• Er   lazy• Er   immutable • Dele   og gjenbruke • Byggeklosser                   © Mesan AS
Spørringer  • Er   lazy  • Er   immutable   • Dele   og gjenbruke   • Byggeklosserval q1 = for (a <- Artists) yield aval q...
Updateval q = for {  a <- Artists if a.id === 1001} yield a.nameq.update("updated") // num affected               © Mesan AS
Deleteval q = for {  a <- Albums if a.id === 1001} yield aq.delete            © Mesan AS
Relasjoner /object Albums extends Table[(...)]("ALBUMS") {    def artist_id = column[Int]("ARTIST_ID")    def artist =    ...
Joins                                               Artist            val q = for {                                       ...
Veien videre? ScalaQuery => SLICKScala Language Integrated         © Mesan AS
SLICK• Generiskrammeverk for spørringer mot data• Ulike   backends • SQL,      NoSQL, json, WebServices,  XML ...• Nærmere...
Q&A© Mesan AS
Q&A© Mesan AS
takk for meg           tmo@mesan.no             @ovstetungithub.com/ovstetun/scala-persistence               © Mesan AS
Upcoming SlideShare
Loading in...5
×

ScalaQuery

528

Published on

My presentation held at flatMap(Oslo)

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
528
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Herfra er det nesten bare kode - ROP ut om det er noe!!!\n
  • Herfra er det nesten bare kode - ROP ut om det er noe!!!\n
  • Herfra er det nesten bare kode - ROP ut om det er noe!!!\n
  • &amp;#x201C;min faste&amp;#x201D; modell jeg bruker n&amp;#xE5;r jeg tester nye systemer/teknologier etc\nhar laget ogs&amp;#xE5; i mongo - fungerer str&amp;#xE5;lende der ogs&amp;#xE5;.\n
  • \n
  • \n
  • \n
  • settes typisk opp med cake/avhengigheter eller hvordan man &amp;#xF8;nsker\nLIFT: i boot\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • hva om jeg forteller ScalaQuery noe om databasen min?\n
  • \n
  • starte med &amp;#xE5; definere strukturen p&amp;#xE5; tabellen\n
  • legge til kolonnenne som finnes\n
  • definere projeksjoner p&amp;#xE5; kolonnene som finnes\n* M&amp;#xC5; definere STJERNE - denne brukes til og fra mapping som default\n
  • kan gj&amp;#xF8;res med caseklasser -&gt; her er resten som tidligere\n&lt;&gt; kaller eg til-og-fra - og er laget for akkurat case-klasser\n
  • ENUMS i scala, kan gj&amp;#xF8;re tilsvarende med CASE OBJECTS\n
  • mapping til/fra immutable verdiobjekter\n
  • kaller insert p&amp;#xE5; en projeksjon - med samme struktur som projeksjonen selv!\ngir kompileringsfeil ved feil struktur\ninsert er eager - gj&amp;#xF8;res med en gang mot databasen\n
  • \n
  • vanligste operatorer -&gt; trigger databasen!\n
  • kan ogs&amp;#xE5; skrives som...\n
  • Generator == tabell (eller en fremmedn&amp;#xF8;kkel)\n
  • === mappes til = i basen\nlike\nupper, st&amp;#xF8;rreEnn, mindreEnn etc - alt som finnes i databasen\n
  • ingen av disse g&amp;#xE5;r mot basen f&amp;#xF8;r man faktisk kj&amp;#xF8;rer en list/first\n
  • sp&amp;#xF8;rring representerer WHERE-delen\nyield-delen det som skal oppdateres - og inputstruktur til .update-kallet\n
  • sp&amp;#xF8;rring representerer WHERE-delen\n
  • ForeignKeyQuery\n
  • \n
  • \n
  • kommer for scala 2.10, bruker makroer\n
  • \n
  • \n
  • ScalaQuery

    1. 1. ScalaQuery flatMap(Oslo)Trond Marius Øvstetun © Mesan AS
    2. 2. Trond Marius Øvstetun• Sjefskonsulentog fagleder i Mesan• Lidenskapelig utvikler, arkitekt, teamleder ++• Java, Scala, HTML/js• Alltid på jakt etter bedre, enklere måter © Mesan AS
    3. 3. Data• Vi har behov for å lagre data © Mesan AS
    4. 4. Data• Vi har behov for å lagre data• Ikke alle bruker eller kan bruke NoSQL © Mesan AS
    5. 5. Data• Vi har behov for å lagre data• Ikke alle bruker eller kan bruke NoSQL • konservativ it-avdeling? • legacy – eksisterende data • andre behov? © Mesan AS
    6. 6. Data• Vi har behov for å lagre data• Ikke alle bruker eller kan bruke NoSQL • konservativ it-avdeling? • legacy – eksisterende data • andre behov? • av og til er relasjonsmodellen riktig © Mesan AS
    7. 7. SQL• Hvordan jobber vi med RDBMS på best mulig måte? © Mesan AS
    8. 8. SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC? © Mesan AS
    9. 9. SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM? © Mesan AS
    10. 10. SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM? • Hibernate? © Mesan AS
    11. 11. SQL• Hvordan jobber vi med RDBMS på best mulig måte?• JDBC?• ORM? • Hibernate? • Anorm? Mapper? Record? © Mesan AS
    12. 12. ScalaQuery © Mesan AS
    13. 13. ScalaQueryA type-safe database API for Scala © Mesan AS
    14. 14. ScalaQueryA type-safe database API for Scala © Mesan AS
    15. 15. En enkel domenemodell «enumeration» Artist Genre Album name : String Rock 1 biography : Text name : String Pop * Classic mainGenre : Genre release : Date Blues founded : Date rating : Option[Int] Rap split : Option[Date] 1 HipHop Alternative * * * Song name : String Person duration : Int firstname : String trackNumber : Int lastname : String biography : Text © Mesan AS
    16. 16. Koble til en database • Med javax.sql.DataSourcedef myDs : DataSource = {...}val db = Database.forDataSource(myDs) © Mesan AS
    17. 17. Koble til en database• Alternativt © Mesan AS
    18. 18. Koble til en database • AlternativtDatabase.forName("jdbc/my_ds") //JNDIDatabase.forURL("jdbc:h2:test") © Mesan AS
    19. 19. Gjøre noe med databasen val db = {...} db withSession { do_something() }import Database.threadLocalSession © Mesan AS
    20. 20. StaticQueryHåndkodet SQL mot databasen © Mesan AS
    21. 21. Spørringerval q = StaticQuery[Int] + "select count(id) from Artists"val count = q.first() © Mesan AS
    22. 22. Spørringerval q = StaticQuery[Int, (Int, String)] + "select id, name from Artists where id = ?"val (id,name) = q(1001).firstval artist : (Int, String) = q(1001).first © Mesan AS
    23. 23. Mapping av resultatcase class Artist(id:Int, name:String)val q = StaticQuery.query[Int, (Int, String)]( "select id, name from Artists where id = ?")val qMapped = q.mapResult[Artist]({ case (a, b) => Artist(a, b) })var a:Artist = qMapped(1001).first() © Mesan AS
    24. 24. Implisitt mapping avcase class Artist(id:Int, name:String)implicit val artMapper = GetResult( (r: PositionedResult) => new Artist(r<<, r<<))val q = StaticQuery.query[Int, Art]( "select id, name from Artists where id = ?")val a:Artist = q(1001).first © Mesan AS
    25. 25. Insert / Updateimport org.scalaquery.simple.StaticQuery._val q = query[(String, String), Int]( "insert into Artists(name, biography) "+ "values (?, ?)")val q2 = q("Seigmen", "")q2.execute() © Mesan AS
    26. 26. ScalaQuery © Mesan AS
    27. 27. ScalaQueryPå tide å få noe igjen? Hva om ... © Mesan AS
    28. 28. En enkel domenemodell «enumeration» Artist Genre Album name : String Rock 1 biography : Text name : String Pop * Classic mainGenre : Genre release : Date Blues founded : Date rating : Option[Int] Rap split : Option[Date] 1 HipHop Alternative * * * Song name : String Person duration : Int firstname : String trackNumber : Int lastname : String biography : Text © Mesan AS
    29. 29. Mapping til en tabellobject Artists extends Table[ (Int, String, String, Genre.Genre, Date, Option[Date]) ]("ARTISTS") { ...} Artist name : String biography : Text mainGenre : Genre founded : Date © Mesan AS split : Option[Date]
    30. 30. Mapping til en tabellobject Artists extends Table (...) { def id = column[Int]("ID", O PrimaryKey) def name = column[String]("NAME") def biography = column[String]("BIOGRAPHY") def maingenre = column[Genre.Genre]("MAINGENRE") def founded = column[Date]("FOUNDED") def split = column[Option[Date]]("SPLIT")} Artist name : String biography : Text mainGenre : Genre founded : Date © Mesan AS split : Option[Date]
    31. 31. Mapping til en tabellobject Artists extends Table (...) { ... def * = id ~ name ~ biography ~ maingenre ~ founded ~ split def i = name ~ biography ~ maingenre ~ founded ~ split} Artist name : String biography : Text mainGenre : Genre founded : Date © Mesan AS split : Option[Date]
    32. 32. Mapping med case-klassecase class Artist( id:Int,name:String, bio:String, mainGenre:Genre.Genre, founded:Date, split:Option[Date])object Artists extends Table[Artist]("ARTISTS") { def * = id ~ .. ~ split <> (Artist, Artist.unapply _)} Artist name : String biography : Text mainGenre : Genre founded : Date © Mesan AS split : Option[Date]
    33. 33. Bruke egne typer column[Genre.Genre]("MAINGENRE") object Genre extends Enumeration { type Genre = Value «enumeration» Genre val Rock = Value(1) Rock Pop Classic ... Blues Rap HipHop Alternative val Alternative = Value(7) }implicit val genreMapper = MappedTypeMapper.base[Genre.Genre, Int]( _.id, Genre(_)) © Mesan AS
    34. 34. Bruke egne typer column[Duration]("DURATION")case class Duration(mins:Int, secs:Int)implicit object durationMapper extends MappedTypeMapper[Duration, Int] with BaseTypeMapper[Duration] with NumericTypeMapper { def map(dur: Duration) = dur.mins * 60 + dur.secs def comap(secs: Int) = Duration(secs / 60, secs % 60)} © Mesan AS
    35. 35. Inserts val i: Int = Artists.i.insert( ("Seigmen", "", Genre.Rock, date("1989-12-27"), Some(date("2008-06-22")))) // i is number of rows affectedval artists : List[(...)] = ...val i = Artists.i.insertAll(artists :_*)// i is Option[Int] - num affected © Mesan AS
    36. 36. Enkle spørringerdef findArtist(id:Int) : Option[(...)] = { val q = Artists.createFinderBy(_.id) q(id).firstOption} © Mesan AS
    37. 37. Enkle spørringerdef findArtist(id:Int) : Option[(...)] = { val q = Artists.createFinderBy(_.id) q(id).firstOption}def highRatedAlbums : List[...] = { val q = Albums.filter(_.rating === (Six:Rating)) q.list}def unRatedAlbums : List[...] = { val q = Albums.filter(_.rating isNull) q.list} © Mesan AS
    38. 38. Bruk av spørringerval resList = q.listval resOption = q.firstOptionval res = q.first © Mesan AS
    39. 39. Mer generelle spørringerval q1 = Artists.filter(_.maingenre === Genre.Rock) © Mesan AS
    40. 40. Mer generelle spørringerval q1 = Artists.filter(_.maingenre === Genre.Rock)val q = for { a <- Artists if a.maingenre === Genre.Rock} yield a © Mesan AS
    41. 41. Generell spørring val aQuery = for { x1 <- generator x2 <- generator ... xN <- generator guard } yield projection © Mesan AS
    42. 42. Parametrisertval qArtist = for { n <- Parameters[String] a <- Artists if a.name === n} yield a.id ~ a.name © Mesan AS
    43. 43. Parametrisertval qArtist = for { n <- Parameters[String] a <- Artists if a.name === n} yield a.id ~ a.nameval qTool = qArtist("Tool")val (id, name) = qTool.first © Mesan AS
    44. 44. Spørringer• Er lazy• Er immutable • Dele og gjenbruke • Byggeklosser © Mesan AS
    45. 45. Spørringer • Er lazy • Er immutable • Dele og gjenbruke • Byggeklosserval q1 = for (a <- Artists) yield aval q2 = for (a <- q1) yield a.id ~ a.nameval q3 = q2.take(10).drop(50) © Mesan AS
    46. 46. Updateval q = for { a <- Artists if a.id === 1001} yield a.nameq.update("updated") // num affected © Mesan AS
    47. 47. Deleteval q = for { a <- Albums if a.id === 1001} yield aq.delete © Mesan AS
    48. 48. Relasjoner /object Albums extends Table[(...)]("ALBUMS") { def artist_id = column[Int]("ARTIST_ID") def artist = foreignKey("albums_artists_fk", artist_id, Artists)(_.id) def * = id ~ name ~ release ~ rating ~ artist_id} Artist Album name : String 1 biography : Text name : String * mainGenre : Genre release : Date founded : Date rating : Option[Int] split : Option[Date] © Mesan AS
    49. 49. Joins Artist val q = for { Album name : String 1 biography : Text name : String * mainGenre : Genre release : Date al <- Albums founded : Date split : Option[Date] rating : Option[Int] a <- Artists if al.artist_id === a.id } yield a.name ~ al.name val q = for { al <- Albums a <- al.artist } yield a.name ~ al.nameval q = for { (al, a) <- Albums innerJoin Artists on (_.artist_id is _.id)} yield a.name ~ al.name © Mesan AS
    50. 50. Veien videre? ScalaQuery => SLICKScala Language Integrated © Mesan AS
    51. 51. SLICK• Generiskrammeverk for spørringer mot data• Ulike backends • SQL, NoSQL, json, WebServices, XML ...• Nærmere “vanlig” Scala-kode, backend som scala Collection © Mesan AS
    52. 52. Q&A© Mesan AS
    53. 53. Q&A© Mesan AS
    54. 54. takk for meg tmo@mesan.no @ovstetungithub.com/ovstetun/scala-persistence © Mesan AS
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×