Skip to content
This repository
Browse code

More documentation

  • Loading branch information...
commit be1c55ef8a8144a4dbcf6c892306fe18b830905b 1 parent 2ef90ba
Stefan Zeiger authored August 15, 2012
120  src/sphinx/code/LiftedEmbedding.scala
... ...
@@ -0,0 +1,120 @@
  1
+package scala.slick.docsnippets
  2
+
  3
+import scala.slick.driver.H2Driver.simple._
  4
+import Database.threadLocalSession
  5
+
  6
+class LiftedEmbedding {
  7
+
  8
+//#foreignkey
  9
+  object Suppliers extends Table[(Int, String, String, String, String, String)]("SUPPLIERS") {
  10
+    def id = column[Int]("SUP_ID", O.PrimaryKey)
  11
+    //...
  12
+//#foreignkey
  13
+    def name = column[String]("SUP_NAME")
  14
+    def street = column[String]("STREET")
  15
+    def city = column[String]("CITY")
  16
+    def state = column[String]("STATE")
  17
+    def zip = column[String]("ZIP")
  18
+    // Every table needs a * projection with the same type as the table's type parameter
  19
+    def * = id ~ name ~ street ~ city ~ state ~ zip
  20
+//#foreignkey
  21
+  }
  22
+
  23
+//#foreignkey
  24
+//#tabledef
  25
+//#reptypes
  26
+//#foreignkey
  27
+  object Coffees extends Table[(String, Int, Double, Int, Int)]("COFFEES") {
  28
+//#foreignkey
  29
+    def name = column[String]("COF_NAME", O.PrimaryKey)
  30
+//#reptypes
  31
+//#foreignkey
  32
+    def supID = column[Int]("SUP_ID")
  33
+//#foreignkey
  34
+//#reptypes
  35
+    def price = column[Double]("PRICE")
  36
+//#foreignkey
  37
+//#tabledef
  38
+    //...
  39
+//#tabledef
  40
+//#foreignkey
  41
+//#reptypes
  42
+    def sales = column[Int]("SALES")
  43
+    def total = column[Int]("TOTAL")
  44
+    def * = name ~ supID ~ price ~ sales ~ total
  45
+//#tabledef
  46
+//#foreignkeynav
  47
+//#foreignkey
  48
+    def supplier = foreignKey("SUP_FK", supID, Suppliers)(_.id)
  49
+//#foreignkey
  50
+    def supplier2 = Suppliers.where(_.id === supID)
  51
+//#foreignkeynav
  52
+//#foreignkey
  53
+//#tabledef
  54
+//#reptypes
  55
+  }
  56
+//#foreignkey
  57
+//#reptypes
  58
+//#tabledef
  59
+
  60
+//#plaintypes
  61
+  case class Coffee(name: String, price: Double)
  62
+  val l: List[Coffee] = //...
  63
+//#plaintypes
  64
+    Nil
  65
+//#plaintypes
  66
+  val l2 = l.filter(_.price > 8.0).map(_.name)
  67
+  //                  ^       ^          ^
  68
+  //                  Double  Double     String
  69
+//#plaintypes
  70
+
  71
+//#reptypes
  72
+  val q = Query(Coffees)
  73
+  val q2 = q.filter(_.price > 8.0).map(_.name)
  74
+  //                  ^       ^          ^
  75
+  //          Rep[Double]  Rep[Double]  Rep[String]
  76
+//#reptypes
  77
+
  78
+//#mappedtable
  79
+  case class User(id: Option[Int], first: String, last: String)
  80
+
  81
+  object Users extends Table[User]("users") {
  82
+    def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  83
+    def first = column[String]("first")
  84
+    def last = column[String]("last")
  85
+    def * = id.? ~ first ~ last <> (User, User.unapply _)
  86
+  }
  87
+//#mappedtable
  88
+
  89
+//#index
  90
+//#primarykey
  91
+  object A extends Table[(Int, Int)]("a") {
  92
+    def k1 = column[Int]("k1")
  93
+    def k2 = column[Int]("k2")
  94
+    def * = k1 ~ k2
  95
+//#index
  96
+    def pk = primaryKey("pk_a", (k1, k2))
  97
+//#primarykey
  98
+//#index
  99
+    def idx = index("idx_a", (k1, k2), unique = true)
  100
+//#primarykey
  101
+  }
  102
+//#primarykey
  103
+//#index
  104
+
  105
+  val db: Database = null
  106
+//#ddl
  107
+  val ddl = Coffees.ddl ++ Suppliers.ddl
  108
+  db withSession {
  109
+    ddl.create
  110
+    //...
  111
+    ddl.drop
  112
+  }
  113
+//#ddl
  114
+
  115
+//#ddl2
  116
+  ddl.createStatements.foreach(println)
  117
+  ddl.dropStatements.foreach(println)
  118
+//#ddl2
  119
+  
  120
+}
1  src/sphinx/index.rst
Source Rendered
@@ -42,5 +42,6 @@ Table of Contents
42 42
    :maxdepth: 4
43 43
    
44 44
    gettingstarted
  45
+   lifted-embedding
45 46
    direct-embedding
46 47
    sql
212  src/sphinx/lifted-embedding.rst
Source Rendered
... ...
@@ -1,4 +1,214 @@
1 1
 Lifted Embedding
2 2
 ================
3 3
 
4  
-tbd
  4
+The *lifted embedding* is the standard API for type-safe queries and updates
  5
+in Slick. Please see :doc:`gettingstarted` for an introduction. This chapter
  6
+describes the available features in more detail.
  7
+
  8
+The name *Lifted Embedding* refers to the fact that you are not working with
  9
+standard Scala types (as in the :doc:`direct embedding <direct-embedding>`)
  10
+but with types that are *lifted* into a the ``scala.slick.lifted.Rep`` type
  11
+constructor. This becomes clear when you compare the types of a simple
  12
+Scala collections example
  13
+
  14
+.. includecode:: code/LiftedEmbedding.scala#plaintypes
  15
+
  16
+... with the types of similar code using the lifted embedding:
  17
+
  18
+.. includecode:: code/LiftedEmbedding.scala#reptypes
  19
+
  20
+All plain types are lifted into ``Rep``. The same is true for the record
  21
+type ``Coffees`` which is a subtype of ``Rep[(String, Int, Double, Int, Int)]``.
  22
+Even the literal ``8.0`` is automatically lifted to a ``Rep[Double]`` by an
  23
+implicit conversion because that is what the ``>`` operator on
  24
+``Rep[Double]`` expects for the right-hand side.
  25
+
  26
+Tables
  27
+------
  28
+
  29
+In order to use the lifted embedding, you need to define ``Table`` objects
  30
+for your database tables:
  31
+
  32
+.. includecode:: code/LiftedEmbedding.scala#tabledef
  33
+
  34
+Note that Slick clones your table objects under the covers, so you should not
  35
+add any extra state to them (extra methods are fine though). Also make sure
  36
+that an actual ``object`` for a table is not defined in a *static* location
  37
+(i.e. at the top level or nested only inside other objects) because this can
  38
+cause problems in certain situations due to an overeager optimization performed
  39
+by scalac. Using a ``val`` for your table (with an anonymous structural type
  40
+or a separate ``class`` definition) is fine everywhere.
  41
+
  42
+All columns are defined through the ``column`` method. Note that they need to
  43
+be defined with ``def`` and not ``val`` due to the cloning. Each column has a
  44
+Scala type and a column name for the database (usually in upper-case). The
  45
+following primitive types are supported out of the box (with certain
  46
+limitations imposed by the individual database drivers):
  47
+
  48
+- Boolean
  49
+- java.sql.Blob
  50
+- Byte
  51
+- Array[Byte]
  52
+- java.sql.Clob
  53
+- java.sql.Date
  54
+- Double
  55
+- Float
  56
+- Int
  57
+- Long
  58
+- Short
  59
+- String
  60
+- java.sql.Time
  61
+- java.sql.Timestamp
  62
+- Unit
  63
+- java.util.UUID
  64
+- BigDecimal
  65
+
  66
+Nullable columns are represented by ``Option[T]`` where ``T`` is one of the
  67
+supported primitive types.
  68
+
  69
+After the column name, you can add optional column options to a ``column``
  70
+definition. The applicable options are available through the table's ``O``
  71
+object. The following ones are defined for ``BasicProfile``:
  72
+
  73
+``NotNull``, ``Nullable``
  74
+   Explicitly mark the column a nullable or non-nullable when creating the
  75
+   DDL statements for the table. Nullability is otherwise determined from the
  76
+   type (Option or non-Option).
  77
+
  78
+``PrimaryKey``
  79
+   Mark the column as a (non-compound) primary key when creating the DDL
  80
+   statements.
  81
+
  82
+``Default[T](defaultValue: T)``
  83
+   Specify a default value for inserting data the table without this column.
  84
+   This information is only used for creating DDL statements so that the
  85
+   database can fill in the missing information.
  86
+
  87
+``DBType(dbType: String)``
  88
+   Use a non-standard database-specific type for the DDL statements (e.g.
  89
+   ``DBType("VARCHAR(20)")`` for a ``String`` column).
  90
+
  91
+``AutoInc``
  92
+   Mark the column as an auto-incrementing key when creating the DDL
  93
+   statements. Unlike the other column options, this one also has a meaning
  94
+   outside of DDL creation: Many databases do not allow non-AutoInc columns to
  95
+   be returned when inserting data (often silently ignoring other columns), so
  96
+   Slick will check if the return column is properly marked as AutoInc where
  97
+   needed.
  98
+
  99
+Every table requires a ``*`` method contatining a default projection.
  100
+This describes what you get back when you return rows (in the form of a
  101
+table object) from a query. Slick's ``*`` projection does not have to match
  102
+the one in the database. You can add new columns (e.g. with computed values)
  103
+or omit some columns as you like. The non-lifted type corresponding to the
  104
+``*`` projection is given as a type parameter to ``Table``. For simple,
  105
+non-mapped tables, this will be a single column type or a tuple of column
  106
+types.
  107
+
  108
+Mapped Tables
  109
+-------------
  110
+
  111
+It is possible to define a mapped table that uses a custom type for its ``*``
  112
+projection by adding a bi-directional mapping with the ``<>`` operator:
  113
+
  114
+.. includecode:: code/LiftedEmbedding.scala#mappedtable
  115
+
  116
+It is optimized for case classes (with a simple ``apply`` method and an
  117
+``unapply`` method that wraps its result in an ``Option``) but there is also
  118
+an overload that operates directly on the mapped types.
  119
+
  120
+Constraints
  121
+-----------
  122
+
  123
+A foreign key constraint can be defined with a table's ``foreignKey`` method.
  124
+It takes a name for the constraint, the local column (or projection, so you
  125
+can define compound foreign keys), the linked table, and a function from that
  126
+table to the corresponding column(s). When creating the DDL statements for the
  127
+table, the foreign key definition is added to it.
  128
+
  129
+.. includecode:: code/LiftedEmbedding.scala#foreignkey
  130
+
  131
+Independent of the actual constraint defined in the database, such a foreign
  132
+key can be used to navigate to the linked data with a *join*. For this
  133
+purpose, it behaves the same as a manually defined utility method for finding
  134
+the joined data:
  135
+
  136
+.. includecode:: code/LiftedEmbedding.scala#foreignkeynav
  137
+
  138
+A primary key constraint can be defined in a similar fashion by adding a
  139
+method that calls ``primaryKey``. This is useful for defining compound
  140
+primary keys (which cannot be done with the ``O.PrimaryKey`` column option):
  141
+
  142
+.. includecode:: code/LiftedEmbedding.scala#primarykey
  143
+
  144
+Other indexes are defined in a similar way with the ``index`` method. They
  145
+are non-unique by default unless you set the ``unique`` parameter:
  146
+
  147
+.. includecode:: code/LiftedEmbedding.scala#index
  148
+
  149
+All constraints are discovered reflectively by searching for methods with
  150
+the appropriate return types which are defined in the table. This behavior
  151
+can be customized by overriding the ``tableConstraints`` method.
  152
+
  153
+Data Definition Language
  154
+------------------------
  155
+
  156
+DDL statements for a table can be created with its ``ddl`` method. Multiple
  157
+``DDL`` objects can be concatenated with ``++`` to get a compound ``DDL``
  158
+object which can create and drop all entities in the correct order, even in
  159
+the presence of cyclic dependencies between tables. The statements are
  160
+executed with the ``create`` and ``drop`` methods:
  161
+
  162
+.. includecode:: code/LiftedEmbedding.scala#ddl
  163
+
  164
+You can use the ``createStatements`` and ``dropStatements`` methods to get
  165
+the SQL code:
  166
+
  167
+.. includecode:: code/LiftedEmbedding.scala#ddl2
  168
+
  169
+Expressions
  170
+-----------
  171
+
  172
+Primitive (non-compound, non-collection) values are representend by type
  173
+``Column[T]`` (a sub-type of ``Rep[R]``) where a ``TypeMapper[T]`` must
  174
+exist. Only some special methods for internal use and those that deal with
  175
+conversions between nullable and non-nullable columns are defined directly in
  176
+the ``Column`` class.
  177
+
  178
+The operators and other methods which are commonly used in the lifted
  179
+embedding are added through implicit conversions defined in
  180
+``ExtensionMethodConversions``. The actual methods can be found in
  181
+the classes ``AnyExtensionMethods``, ``ColumnExtensionMethods``,
  182
+``NumericColumnExtensionMethods``, ``BooleanColumnExtensionMethods`` and
  183
+``StringColumnExtensionMethods``.
  184
+
  185
+Collection values are represented by the ``Query`` class (a ``Rep[Seq[T]]``)
  186
+which contains many standard collection methods like ``flatMap``,
  187
+``filter``, ``take`` and ``groupBy``. Due to the two different component
  188
+types of a ``Query`` (lifted and plain), the signatures for these methods are
  189
+very complex but the semantics are essentially the same as for Scala
  190
+collections.
  191
+
  192
+Additional methods for queries of non-compound values are added via an
  193
+implicit conversion to ``SingleColumnQueryExtensionMethods``.
  194
+
  195
+Joins
  196
+-----
  197
+
  198
+Unions
  199
+------
  200
+
  201
+Aggregation
  202
+-----------
  203
+
  204
+Querying
  205
+--------
  206
+
  207
+Inserting and Updating
  208
+----------------------
  209
+
  210
+Query Templates
  211
+---------------
  212
+
  213
+User-Defined Functions and Types
  214
+--------------------------------

0 notes on commit be1c55e

Please sign in to comment.
Something went wrong with that request. Please try again.