Giter VIP home page Giter VIP logo

slickless's Introduction

slickless

Build Status codecov Join the chat at https://gitter.im/underscoreio/slickless

Shapeless HList support for Slick.

by Richard Dallaway, Miles Sabin, and Dave Gurnell.

Copyright 2015-2019 Underscore Consulting LLP. Licensed Apache 2.

Versions

Scala Slick Slickless
2.13 3.3 Maven Central
2.12 3.3 Maven Central
2.12 3.2 0.3.3
2.11 3.1 0.3.0

Getting Started

Grab the code by adding the following to your build.sbt:

libraryDependencies ++= Seq(
  "com.typesafe.slick" %% "slick"     % "3.3.2",
  "com.chuusai"        %% "shapeless" % "2.3.3",
  "io.underscore"      %% "slickless" % "<<VERSION>>"
)

Synopsis

Import Slick, shapeless, and slickless, and you should be able to define Tables on any shapeless HList type:

import slick.jdbc.H2Profile.api._
import shapeless.{ HList, ::, HNil }
import slickless._

class Users(tag: Tag) extends Table[Long :: String :: HNil](tag, "users") {
  def id    = column[Long]( "id", O.PrimaryKey, O.AutoInc )
  def email = column[String]("email")

  def * = id :: email :: HNil
}

lazy val users = TableQuery[Users]

If you want to map your HList to a case class (i.e. you have a case class that has more than 22 fields and you are using slickless to bypass this limit), you can do the following

import slick.jdbc.H2Profile.api._
import shapeless.{ HList, ::, HNil, Generic }
import slickless._

case class User(id: Long, email: String)

class Users(tag: Tag) extends Table[User](tag, "users") {
  def id    = column[Long]( "id", O.PrimaryKey, O.AutoInc )
  def email = column[String]("email")

  def * = (id :: email :: HNil).mappedWith(Generic[User])
}

lazy val users = TableQuery[Users]

Notes

Compile time

Due to this issue, if you accidentally make a mapping which is incorrect, the Scala compiler can take a huge amount of time to report an error. If your slickless project is taking an insanely long amount of time to compile (more than a couple of minutes), try to make sure you have the mapping correct before using <>.

Build example without default resolvers

If you need to add resolvers into your build, here's an example:

resolvers += "Maven Central" at "https://repo1.maven.org/maven2/"

resolvers += Resolver.sonatypeRepo("releases")

resolvers += Resolver.sonatypeRepo("snapshots")

libraryDependencies ++= Seq(
  "com.typesafe.slick" %% "slick"     % "3.2.1",
  "com.chuusai"        %% "shapeless" % "2.3.3",
  "io.underscore"      %% "slickless" % "0.3.3"
)

Publishing

We use the sbt-pgp plugin and the sbt-sonatype plugin to publish to Maven Central.

Publish sequence could be:

sbt> set pgpPassphrase := Some(Array('s','e','c','r','3','t'))
sbt> set publishTo := sonatypePublishTo.value
sbt> +publishSigned
sbt> sonatypeRelease

slickless's People

Contributors

d6y avatar danielasfregola avatar davegurnell avatar gitter-badger avatar jorokr21 avatar nigewarren avatar oker1 avatar scala-steward avatar taig avatar travisbrown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slickless's Issues

java.lang.StackOverflowError

When compiling my project with sbt sometimes I get this. I realize that this may be a shot in the dark but I don't experience any similar issues with my other Scala projects where I use Slick. I'm just curious if anyone has had this issue and can advice on what the root cause may be.

I'm using "com.typesafe.slick" %% "slick" % "3.0.1", "com.chuusai" %% "shapeless" % "2.2.5", "io.underscore" %% "slickless" % "0.1.1". I'm modelling a table with 59 columns.

Please ask questions if you need more info. Much appreciated!

table with 144 columns inevitably causes a stackoverflowerror when compiling

I've isolated the cause of my stackoverflow error to the def * method that chains all 144 columns using the slickless "::" class.

aka:

def * = ( col1 :: col2 :: col3 :: .... col143 :: col144 :: HNil).mappedWith(Generic[MyCaseClass])

There should be an alternative way to constuct the * def that doesn't involve the mass recursion? After all this is the "BigData" solution to the 22 constructor limit in scala case classes / tuples.

Support for Slick 3.4.0-M1

I am currently working on a project that makes extensive use of Slickless 0.3.6 with Slick 3.3.3. That project wants to move to Scala 2.13 and has some strict compiler flags set that will fail because of the code emitted by slick

See also slick/slick#2121 and slick/slick#2054

They seem to be addressed in release 3.4.0-M1. Unfortunately I can't move to that since slickless depends on 3.3

Do you plan of supporting the 3.4 series?

"No matching Shape found" error introduced in 0.3.3

I was recently upgrading our dependencies, and ran across the following issue when attempting to migrate past slickless 0.3.2:

[error] C:\build\public\slickless\src\test\scala\slickless\NestedSpec.scala:22:73: No matching Shape found.
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your * projection,
[error]  you use an unsupported type in a Query (e.g. scala List),
[error]  or you forgot to import a driver api into scope.
[error]   Required level: L
[error]      Source type: slick.lifted.Rep[Long] :: slick.lifted.MappedProjection[NestedSpec.this.Department,(Long, String)] :: slick.lifted.MappedProjection[NestedSpec.this.Department,(Long, String)] :: slick.lifted.Rep[String] :: shapeless.HNil
[error]    Unpacked type: this.Repr
[error]      Packed type: P
[error]     def * = (id :: department :: department :: email :: HNil).mappedWith(Generic[Employee])
[error]                                                                         ^
[error] one error found

While it is not exactly a real-world scenario, you can replicate the issue by making the following changes on the latest master branch (8e324ee):

jmaki@jmaki-pc /build/public/slickless
$ git diff
diff --git a/src/test/scala/slickless/NestedSpec.scala b/src/test/scala/slickless/NestedSpec.scala
index 5e750b9..6b45ad5 100644
--- a/src/test/scala/slickless/NestedSpec.scala
+++ b/src/test/scala/slickless/NestedSpec.scala
@@ -9,7 +9,7 @@ class NestedSpec extends Spec {

   case class Department(id: Long, city: String)

-  case class Employee(id: Long, dept: Department, email: String)
+  case class Employee(id: Long, dept1: Department, dept2: Department, email: String)

   class Employees(tag: Tag) extends Table[Employee](tag, "emps") {
     def id             = column[Long]("id", O.PrimaryKey, O.AutoInc)
@@ -19,7 +19,7 @@ class NestedSpec extends Spec {

     def department = (departmentId, departmentCity).mapTo[Department]

-    def * = (id :: department :: email :: HNil).mappedWith(Generic[Employee])
+    def * = (id :: department :: department :: email :: HNil).mappedWith(Generic[Employee])
   }

   lazy val emps = TableQuery[Employees]
@@ -28,7 +28,7 @@ class NestedSpec extends Spec {
     "should support inserts and selects" in {
       val db = Database.forConfig("h2")

-      val emp = Employee(1L, Department(42L, "Brighton"), "[email protected]")
+      val emp = Employee(1L, Department(42L, "Brighton"), Department(42L, "Brighton"), "[email protected]")

       val action = for {
         _   <- emps.schema.create

If feasible, it's technically possible to work around this by using mapTo instead of mappedWith but this approach does not work well when using case classes with custom companion objects since you likely have to define tupled inside these companion objects.

MappedWith Not Working

  • I am trying to create a table using a case class with 24 columns and therefore using HList as mentioned
    here
  • However, in the def * method, when i try to use mappedWith, intelliJ gives me an error:

Screen Shot 2020-06-23 at 4 17 26 PM

* My clase class:

Screen Shot 2020-06-23 at 4 17 58 PM

* `def *` method:

Screen Shot 2020-06-23 at 4 21 11 PM

* build.sbt:

Screen Shot 2020-06-23 at 4 22 05 PM

Alternative to tails?

Hello,

I recently ran in the tuple problem of Slick and stumbled across this neat library. I made it work with my 53 columns - all good. My question is - is there a better way to access a specific column in the class other this?

val id = ltm.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail
            .tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail.tail
            .tail.tail.tail.head

It seems kind of ridiculous :D

I know I'm constructing a list but it takes me quite a while to pinpoint my column just by the type.

Support for extensible records

I've been playing around with slickless for the past few days. I'm particularly interested in getting extensible records to work with slick. A "record projection" would be a nice feature IMHO. Either by providing a RecordShape or by a MappedProjection.

class Users(tag: Tag) extends Table[Long :: String :: HNil](tag, "users") {
  def id    = column[Long]( "id", O.PrimaryKey, O.AutoInc )
  def email = column[String]("email")

  def * = ('id ->> id) :: ('email ->> email) :: HNil    // support by RecordShape
  // or
  def * = (id :: email :: HNil).mappedWithRecord('id :: 'email :: HNil)  // support by MappedProjection
}

As I just started my journey with shapeless, I could not get any of these two approaches to work. The closest I could come up with is a non working MappedProjection:

def mappedWithRecord[R <: HList : ClassTag, U <: HList, K <: HList](keys: K)
  (implicit
    shape: Shape[_ <: FlatShapeLevel, T, U, _]) =
  new MappedProjection[R, U](
    shape.toNode(hlist),
    MappedScalaType.Mapper(
      ((f: HList) => f.zipWithKeys(keys)).asInstanceOf[Any => Any], // compiler error: could not find implicit value for parameter withKeys: shapeless.ops.hlist.ZipWithKeys[K,shapeless.HList]

      ((g: HList) => ???).asInstanceOf[Any => Any],
      None
    ),
    implicitly[ClassTag[R]]
  )
}

So basically my two questions are:

  1. Would it even be possible to provide a RecordShape? Unfortunately I could not even figure out where to start...
  2. Why can't the compile find the implicit parameter withKeys in the code above? What am I missing?

Question for the forked repo.

Forked slickless to scalax/slickless and will only released Scala 2 version for self project compat.

  1. Scala 3 will only have a simple
package object slickless exntends AnyRef
  1. Will push to maven repo as "net.scalax" %% "slickless" % version.

Anything I must take care about the Apache License?

class > 22 fields stops compiling

Trying to compile the following code with slickless never finishes compilation:

import slick.driver.SQLiteDriver.api._
import shapeless.{::, HNil}

object DataHolder2 {
  lazy val tradeConfirmationTable = TableQuery[TradeConfirmationTable]

  class TradeConfirmationTable(tag: Tag) extends Table[String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: String :: HNil](tag, "trade.confirmation") {
    def accountId = column[String]("accountId")
    def acctAlias = column[String]("acctAlias")
    def symbol = column[String]("symbol")
    def description = column[String]("description")
    def assetCategory = column[String]("assetCategory")
    def multiplier = column[String]("multiplier")
    def currency = column[String]("currency")
    def tradeDate = column[String]("tradeDate")
    def dateTime = column[String]("dateTime")
    def orderType = column[String]("orderType")
    def buySell = column[String]("buySell")
    def quantity = column[String]("quantity")
    def price = column[String]("price")
    def amount = column[String]("amount")
    def commission = column[String]("commission")
    def exchange = column[String]("exchange")
    def model = column[String]("model")
    def conid = column[String]("conid")
    def securityID = column[String]("securityID")
    def securityIDType = column[String]("securityIDType")
    def cusip = column[String]("cusip")
    def isin = column[String]("isin")
    def underlyingConid = column[String]("underlyingConid")
    def underlyingSymbol = column[String]("underlyingSymbol")
    def issuer = column[String]("issuer")
    def strike = column[String]("strike")
    def expiry = column[String]("expiry")
    def putCall = column[String]("putCall")
    def transactionType = column[String]("transactionType")
    def tradeID = column[String]("tradeID")
    def orderID = column[String]("orderID")
    def execID = column[String]("execID")
    def brokerageOrderID = column[String]("brokerageOrderID")
    def orderReference = column[String]("orderReference")
    def volatilityOrderLink = column[String]("volatilityOrderLink")
    def clearingFirmID = column[String]("clearingFirmID")
    def origTradePrice = column[String]("origTradePrice")
    def origTradeDate = column[String]("origTradeDate")
    def origTradeID = column[String]("origTradeID")
    def orderTime = column[String]("orderTime")
    def reportDate = column[String]("reportDate")
    def settleDate = column[String]("settleDate")
    def proceeds = column[String]("proceeds")
    def brokerExecutionCommission = column[String]("brokerExecutionCommission")
    def brokerClearingCommission = column[String]("brokerClearingCommission")
    def thirdPartyExecutionCommission = column[String]("thirdPartyExecutionCommission")
    def thirdPartyClearingCommission = column[String]("thirdPartyClearingCommission")
    def thirdPartyRegulatoryCommission = column[String]("thirdPartyRegulatoryCommission")
    def otherCommission = column[String]("otherCommission")
    def commissionCurrency = column[String]("commissionCurrency")
    def tax = column[String]("tax")
    def code = column[String]("code")
    def levelOfDetail = column[String]("levelOfDetail")
    def traderID = column[String]("traderID")
    def isAPIOrder = column[String]("isAPIOrder")
    def allocatedTo = column[String]("allocatedTo")

    def * = accountId :: acctAlias :: symbol :: description :: assetCategory :: multiplier :: currency :: tradeDate :: dateTime :: orderType :: buySell :: quantity :: price :: amount :: commission :: exchange :: model :: conid :: securityID :: securityIDType :: cusip :: isin :: underlyingConid :: underlyingSymbol :: issuer :: strike :: expiry :: putCall :: transactionType :: tradeID :: orderID :: execID :: brokerageOrderID :: orderReference :: volatilityOrderLink :: clearingFirmID :: origTradePrice :: origTradeDate :: origTradeID :: orderTime :: reportDate :: settleDate :: proceeds :: brokerExecutionCommission :: brokerClearingCommission :: thirdPartyExecutionCommission :: thirdPartyClearingCommission :: thirdPartyRegulatoryCommission :: otherCommission :: commissionCurrency :: tax :: code :: levelOfDetail :: traderID :: isAPIOrder :: allocatedTo :: HNil

    val pk = primaryKey("trade.confirmation_pkey", accountId :: orderID :: execID :: HNil)
  }
}

Make slick and shapeless a runtime dependency

The project build depends on slick and shapeless, naturally. But should they be run-time dependencies to allow the end user to make minor version changes?

Not sure what the best practice is here. For example, as of right now while I'm writing this issue, we've published slickless for Slick 3.2.0-M2. If I want to use this with 3.2.0 final I see:

[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn] 	* com.typesafe.slick:slick_2.12:3.2.0-M2 -> 3.2.0
[warn] Run 'evicted' to see detailed eviction warnings

I think we can mark these lines as % runtime (or something like that):

https://github.com/underscoreio/slickless/blob/master/build.sbt#L21-L22

I'll do that, unless anyone wants to point to th error of my ways :-)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.