Skip to content

Commit 9caaae7

Browse files
committed
Merge pull request #2 from typesafehub/wip/slick-2.0
slick 2.0.0
2 parents 4fec250 + bac7db6 commit 9caaae7

8 files changed

Lines changed: 468 additions & 219 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
/project/activator-*
77
/logs/
88
/RUNNING_PID
9+
*.iml

build.sbt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ version := "1.0"
44

55
scalaVersion := "2.10.2"
66

7+
mainClass in Compile := Some("HelloSlick")
8+
79
libraryDependencies ++= List(
8-
"com.typesafe.slick" %% "slick" % "1.0.1",
10+
"com.typesafe.slick" %% "slick" % "2.0.0",
911
"org.slf4j" % "slf4j-nop" % "1.6.4",
10-
"com.h2database" % "h2" % "1.3.166"
12+
"com.h2database" % "h2" % "1.3.170",
13+
"org.scalatest" %% "scalatest" % "2.0"
1114
)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import scala.slick.driver.H2Driver.simple._
2+
3+
object CaseClassMapping extends App {
4+
5+
// the base query for the Users table
6+
val users = TableQuery[Users]
7+
8+
Database.forURL("jdbc:h2:mem:hello", driver = "org.h2.Driver").withSession { implicit session =>
9+
10+
// create the schema
11+
users.ddl.create
12+
13+
// insert two User instances
14+
users += User("John Doe")
15+
users += User("Fred Smith")
16+
17+
// print the users (select * from USERS)
18+
println(users.list)
19+
}
20+
21+
}
22+
23+
case class User(name: String, id: Option[Int] = None)
24+
25+
class Users(tag: Tag) extends Table[User](tag, "USERS") {
26+
// Auto Increment the id primary key column
27+
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
28+
// The name can't be null
29+
def name = column[String]("NAME", O.NotNull)
30+
// the * projection (e.g. select * ...) auto-transform the tupled column values to / from a User
31+
def * = (name, id.?) <> (User.tupled, User.unapply)
32+
}

src/main/scala/Hello.scala

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/main/scala/HelloSlick.scala

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import scala.slick.driver.H2Driver.simple._
2+
3+
// The main application
4+
object HelloSlick extends App {
5+
6+
// The query interface for the Suppliers table
7+
val suppliers: TableQuery[Suppliers] = TableQuery[Suppliers]
8+
9+
// the query interface for the Coffees table
10+
val coffees: TableQuery[Coffees] = TableQuery[Coffees]
11+
12+
// Create a connection (called a "session") to an in-memory H2 database
13+
Database.forURL("jdbc:h2:mem:hello", driver = "org.h2.Driver").withSession { implicit session =>
14+
15+
// Create the schema by combining the DDLs for the Suppliers and Coffees tables using the query interfaces
16+
(suppliers.ddl ++ coffees.ddl).create
17+
18+
19+
/* Create / Insert */
20+
21+
// Insert some suppliers
22+
suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199")
23+
suppliers += (49, "Superior Coffee", "1 Party Place", "Mendocino", "CA", "95460")
24+
suppliers += (150, "The High Ground", "100 Coffee Lane", "Meadows", "CA", "93966")
25+
26+
// Insert some coffees (using JDBC's batch insert feature)
27+
val coffeesInsertResult: Option[Int] = coffees ++= Seq (
28+
("Colombian", 101, 7.99, 0, 0),
29+
("French_Roast", 49, 8.99, 0, 0),
30+
("Espresso", 150, 9.99, 0, 0),
31+
("Colombian_Decaf", 101, 8.99, 0, 0),
32+
("French_Roast_Decaf", 49, 9.99, 0, 0)
33+
)
34+
35+
val allSuppliers: List[(Int, String, String, String, String, String)] = suppliers.list
36+
37+
// Print the number of rows inserted
38+
coffeesInsertResult foreach (numRows => println(s"Inserted $numRows rows into the Coffees table"))
39+
40+
41+
/* Read / Query / Select */
42+
43+
// Print the SQL for the Coffees query
44+
println("Generated SQL for base Coffees query:\n" + coffees.selectStatement)
45+
46+
// Query the Coffees table using a foreach and print each row
47+
coffees foreach { case (name, supID, price, sales, total) =>
48+
println(" " + name + "\t" + supID + "\t" + price + "\t" + sales + "\t" + total)
49+
}
50+
51+
52+
/* Filtering / Where */
53+
54+
// Construct a query where the price of Coffees is > 9.0
55+
val filterQuery: Query[Coffees, (String, Int, Double, Int, Int)] = coffees.filter(_.price > 9.0)
56+
57+
println("Generated SQL for filter query:\n" + filterQuery.selectStatement)
58+
59+
// Execute the query
60+
println(filterQuery.list)
61+
62+
63+
/* Update */
64+
65+
// Construct an update query with the sales column being the one to update
66+
val updateQuery: Query[Column[Int], Int] = coffees.map(_.sales)
67+
68+
// Print the SQL for the Coffees update query
69+
println("Generated SQL for Coffees update:\n" + updateQuery.updateStatement)
70+
71+
// Perform the update
72+
val numUpdatedRows = updateQuery.update(1)
73+
74+
println(s"Updated $numUpdatedRows rows")
75+
76+
77+
/* Delete */
78+
79+
// Construct a delete query that deletes coffees with a price less than 8.0
80+
val deleteQuery: Query[Coffees,(String, Int, Double, Int, Int)] = coffees.filter(_.price < 8.0)
81+
82+
// Print the SQL for the Coffees delete query
83+
println("Generated SQL for Coffees delete:\n" + deleteQuery.deleteStatement)
84+
85+
// Perform the delete
86+
val numDeletedRows = deleteQuery.delete
87+
88+
println(s"Deleted $numDeletedRows rows")
89+
90+
91+
/* Selecting Specific Columns */
92+
93+
// Construct a new coffees query that just selects the name
94+
val justNameQuery: Query[Column[String], String] = coffees.map(_.name)
95+
96+
println("Generated SQL for query returning just the name:\n" + justNameQuery.selectStatement)
97+
98+
// Execute the query
99+
println(justNameQuery.list)
100+
101+
102+
/* Sorting / Order By */
103+
104+
val sortByPriceQuery: Query[Coffees, (String, Int, Double, Int, Int)] = coffees.sortBy(_.price)
105+
106+
println("Generated SQL for query sorted by price:\n" + sortByPriceQuery.selectStatement)
107+
108+
// Execute the query
109+
println(sortByPriceQuery.list)
110+
111+
112+
/* Query Composition */
113+
114+
val composedQuery: Query[Column[String], String] = coffees.sortBy(_.name).take(3).filter(_.price > 9.0).map(_.name)
115+
116+
println("Generated SQL for composed query:\n" + composedQuery.selectStatement)
117+
118+
// Execute the composed query
119+
println(composedQuery.list)
120+
121+
122+
/* Joins */
123+
124+
// Join the tables using the relationship defined in the Coffees table
125+
val joinQuery: Query[(Column[String], Column[String]), (String, String)] = for {
126+
c <- coffees if c.price > 9.0
127+
s <- c.supplier
128+
} yield (c.name, s.name)
129+
130+
println("Generated SQL for the join query:\n" + joinQuery.selectStatement)
131+
132+
// Print the rows which contain the coffee name and the supplier name
133+
println(joinQuery.list)
134+
135+
136+
/* Computed Values */
137+
138+
// Create a new computed column that calculates the max price
139+
val maxPriceColumn: Column[Option[Double]] = coffees.map(_.price).max
140+
141+
println("Generated SQL for max price column:\n" + maxPriceColumn.selectStatement)
142+
143+
// Execute the computed value query
144+
println(maxPriceColumn.run)
145+
146+
147+
/* Manual SQL / String Interpolation */
148+
149+
// Required import for the sql interpolator
150+
import scala.slick.jdbc.StaticQuery.interpolation
151+
152+
// A value to insert into the statement
153+
val state = "CA"
154+
155+
// Construct a SQL statement manually with an interpolated value
156+
val plainQuery = sql"select SUP_NAME from SUPPLIERS where STATE = $state".as[String]
157+
158+
println("Generated SQL for plain query:\n" + plainQuery.getStatement)
159+
160+
// Execute the query
161+
println(plainQuery.list)
162+
163+
}
164+
}

src/main/scala/Tables.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import scala.slick.driver.H2Driver.simple._
2+
import scala.slick.lifted.{ProvenShape, ForeignKeyQuery}
3+
4+
// A Suppliers table with 6 columns: id, name, street, city, state, zip
5+
class Suppliers(tag: Tag) extends Table[(Int, String, String, String, String, String)](tag, "SUPPLIERS") {
6+
def id: Column[Int] = column[Int]("SUP_ID", O.PrimaryKey) // This is the primary key column
7+
def name: Column[String] = column[String]("SUP_NAME")
8+
def street: Column[String] = column[String]("STREET")
9+
def city: Column[String] = column[String]("CITY")
10+
def state: Column[String] = column[String]("STATE")
11+
def zip: Column[String] = column[String]("ZIP")
12+
13+
// Every table needs a * projection with the same type as the table's type parameter
14+
def * : ProvenShape[(Int, String, String, String, String, String)] = (id, name, street, city, state, zip)
15+
}
16+
17+
// A Coffees table with 5 columns: name, supplier id, price, sales, total
18+
class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
19+
def name: Column[String] = column[String]("COF_NAME", O.PrimaryKey)
20+
def supID: Column[Int] = column[Int]("SUP_ID")
21+
def price: Column[Double] = column[Double]("PRICE")
22+
def sales: Column[Int] = column[Int]("SALES")
23+
def total: Column[Int] = column[Int]("TOTAL")
24+
25+
def * : ProvenShape[(String, Int, Double, Int, Int)] = (name, supID, price, sales, total)
26+
27+
// A reified foreign key relation that can be navigated to create a join
28+
def supplier: ForeignKeyQuery[Suppliers, (Int, String, String, String, String, String)] =
29+
foreignKey("SUP_FK", supID, TableQuery[Suppliers])(_.id)
30+
}

src/test/scala/TablesSuite.scala

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import org.scalatest._
2+
import scala.slick.driver.H2Driver.simple._
3+
import scala.slick.jdbc.meta._
4+
5+
6+
class TablesSuite extends FunSuite with BeforeAndAfter {
7+
8+
val suppliers = TableQuery[Suppliers]
9+
val coffees = TableQuery[Coffees]
10+
11+
implicit var session: Session = _
12+
13+
def createSchema() = (suppliers.ddl ++ coffees.ddl).create
14+
15+
def insertSupplier(): Int = suppliers += (101, "Acme, Inc.", "99 Market Street", "Groundsville", "CA", "95199")
16+
17+
before {
18+
session = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver").createSession()
19+
}
20+
21+
test("Creating the Schema works") {
22+
createSchema()
23+
24+
val tables = MTable.getTables().list()
25+
26+
assert(tables.size == 2)
27+
assert(tables.count(_.name.name.equalsIgnoreCase("suppliers")) == 1)
28+
assert(tables.count(_.name.name.equalsIgnoreCase("coffees")) == 1)
29+
}
30+
31+
test("Inserting a Supplier works") {
32+
createSchema()
33+
34+
val insertCount = insertSupplier()
35+
assert(insertCount == 1)
36+
}
37+
38+
test("Query Suppliers works") {
39+
createSchema()
40+
insertSupplier()
41+
val results = suppliers.list()
42+
assert(results.size == 1)
43+
assert(results.head._1 == 101)
44+
}
45+
46+
after {
47+
session.close()
48+
}
49+
50+
}

0 commit comments

Comments
 (0)