Slick(2)3 Working Types

Slick(2)3 Working Types
1. Lifted Embedding

The name Lifted Embedding refers to the fact that you are not working with Standard Scala types, but with types that are lifted into a scala.sclick.liftted.Req type constructor.
var l: Lit[Coffee] *
val l2 = l.filter(_.price > 8.0).map(_.name)      

=>

object Coffees extends Table[(String, Int, Double, Int, Int)]("COFFEES"){
     …snip….
}

val q = Query(Coffees)
val q2 = q.filter(_.price > 8.0).map(_.name)
              Rep[Double]   Rep[Double]   Rep[String]

Tables
Defined a table at first.

Mapped Tables
..snip…

Constraints
foreignKey

object Suppliers extends Table[(Int, String, String, String,String, String)]("SUPPLIERS"){
     def id = column[Int]("SUP_ID", O.PrimaryKey)
     …snip...
}

object Coffees extends Table[(String, Int, Double, Int, Int)]("COFFEES"){
     def supID = column[Int]("SUP_ID")
     …snip…
     def supplier = foreignKey("SUP_FK", supID, Suppliers)(_.id)
}

A primary key constraint can be defined in a similar fashion by adding a method that calls primaryKey.

Object A extends Table[(Int, Int)]("a") {
     def k1 = column[Int]("k1")
     def k2 = column[Int]("k2")
    
     def * = k1 ~ k2
     def pk = primaryKey("pk_a",(k1, k2))
}

Object A extends Table[(Int, Int)]("a") {
     def k1 = column[Int]("k1")
     def k2 = column[Int]("k2")
     def * = k1 ~ k2
     def idx = index("idx_a", (k1, k2), unique=true)
}

Data Definition Language(DDL)
DDL statements for a table can be created with its ddl method. We can create and drop table with this function.
val ddl = Coffees.ddl ++ Suppliers.ddl
db withSession {
     ddl.create
     …snip…
     ddl.drop
}

We can see the SQL with these statements>
    ddl.createStatements.foreach(println)
    ddl.dropStatements.foreach(println)

Output:
create table "SUPPLIERS" ("SUP_ID" INTEGER NOT NULL PRIMARY KEY,"SUP_NAME" VARCHAR NOT NULL,"STREET" VARCHAR NOT NULL,"CITY" VARCHAR NOT NULL,"STATE" VARCHAR NOT NULL,"ZIP" VARCHAR NOT NULL)
create table "COFFEES" ("COF_NAME" VARCHAR NOT NULL PRIMARY KEY,"SUP_ID" INTEGER NOT NULL,"PRICE" DOUBLE NOT NULL,"SALES" INTEGER NOT NULL,"TOTAL" INTEGER NOT NULL)
alter table "COFFEES" add constraint "SUP_FK" foreign key("SUP_ID") references "SUPPLIERS"("SUP_ID") on update NO ACTION on delete NO ACTION
alter table "COFFEES" drop constraint "SUP_FK"
drop table "SUPPLIERS"
drop table "COFFEES"

Expressions
…snip…

2. Direct Embedding
we did not use that in my project.

3. Plain SQL Queries
First of all the imports are different.
import scala.slick.session.Database
import Database.threadLocalSession
import scala.slick.jdbc.{GetResult, StaticQuery => Q}

Import scala.slick.jdbc.GetResult and import scala.sclick.jdbc.StaticQuery for Q.

The most important class for Plain SQL queries is scala.slick.jdbc.StaticQuery which gets imported as Q for more convenient use.
// Case classes for our data
case class Supplier(id: Int, name: String, street: String, city: String, state: String, zip: String)
case class Coffee(name: String, supID: Int, price: Double, sales: Int, total: Int)

DDL/DML Statements

  Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
    // Create the tables, including primary and foreign keys
    Q.updateNA("create table suppliers(" +
      "id int not null primary key, " +
      "name varchar not null, " +
      "street varchar not null, " +
      "city varchar not null, " +
      "state varchar not null, " +
      "zip varchar not null)").execute
    Q.updateNA("create table coffees(" +
      "name varchar not null, " +
      "sup_id int not null, " +
      "price double not null, " +
      "sales int not null, " +
      "total int not null, " +
      "foreign key(sup_id) references suppliers(id))").execute
           …snip…
  }

Q.u is StaticQuery.updateNA("")
// Insert some suppliers
(Q.u + "insert into suppliers values(101, 'Acme, Inc.', '99 Market Street', 'Groundsville', 'CA', '95199')").execute
(Q.u + "insert into suppliers values(49, 'Superior Coffee', '1 Party Place', 'Mendocino', 'CA', '95460')").execute
(Q.u + "insert into suppliers values(150, 'The High Ground', '100 Coffee Lane', 'Meadows', 'CA', '93966')").execute

We can use the special concatenation operator +? to add a bind variable to a query string.
    def insert(c: Coffee) = (Q.u + "insert into coffees values (" +? c.name +
      "," +? c.supID + "," +? c.price + "," +? c.sales + "," +? c.total + ")").execute

    // Insert some coffees
    Seq(
      Coffee("Colombian", 101, 7.99, 0, 0),
      Coffee("French_Roast", 49, 8.99, 0, 0),
      Coffee("Espresso", 150, 9.99, 0, 0),
      Coffee("Colombian_Decaf", 101, 8.99, 0, 0),
      Coffee("French_Roast_Decaf", 49, 9.99, 0, 0)).foreach(insert)

Query Statements
// Result set getters
implicit val getSupplierResult = GetResult(r => Supplier(r.nextInt, r.nextString, r.nextString,
    r.nextString, r.nextString, r.nextString))
implicit val getCoffeeResult = GetResult(r => Coffee(r.<<, r.<<, r.<<, r.<<, r.<<))

println("Coffees:")
Q.queryNA[Coffee]("select * from coffees") foreach { c =>
      println("  " + c.name + "\t" + c.supID + "\t" + c.price + "\t" + c.sales + "\t" + c.total)
}

There are predefined GetResult implicates for the standard JDBC types.
The first one uses the explicit PositionedResult methods nextInt and nextString Int or String.
The second one uses the shortcut method << which returns a value of whatever type is expected at this place.

query which takes two type parameters, one for the query parameters and one for the results set rows. Similarly for update and updateNA.
    println("Manual join:")
    val q2 = Q.query[Double, (String, String)]("""
      select c.name, s.name
      from coffees c, suppliers s
      where c.price < ? and s.id = c.sup_id
    """)
    // This time we read the result set into a List
    val l2 = q2.list(9.0)
    for (t <- l2) println("  " + t._1 + " supplied by " + t._2)

    valsupplierById = Q[Int, Supplier] + "select * from suppliers where id = ?"
    println("Supplier #49: " + supplierById(49).first)

String Interpolation
import Q.interpolation
    def coffeeByName(name: String) = sql"select * from coffees where name = $name".as[Coffee]
    println("Coffee Colombian: " + coffeeByName("Colombian").first.name)
    println("Coffee Colombian: " + coffeeByName("Colombian").firstOption)

sqlu seems to sql and update the table.
    def deleteCoffee(name: String) = sqlu"delete from coffees where name = $name".first
    val rows = deleteCoffee("Colombian")
    println(s"Deleted $rows rows")
    println("Coffee Colombian: " + coffeeByName("Colombian").firstOption)

References:
http://slick.typesafe.com/doc/0.11.2/index.html
http://slick.typesafe.com/doc/0.11.2/lifted-embedding.html
http://slick.typesafe.com/doc/0.11.2/direct-embedding.html
http://slick.typesafe.com/doc/0.11.2/sql.html

你可能感兴趣的:(type)