1

I'm implementing a Users table in Slick with a User class that extends SecureSocial's Identity trait. I'm having trouble converting from an optional not-storable-in-database type object to an optional primitive database type.

To refer to: Slick docs, SecureSocial docs (To generate API documentation for SecureSocial, pull from their Github, go into their "module-code" directory, and then run play doc. Then look in the module-code/target/api folder and open up index.html)

What I have

Take this parameter in a User case class:

oAuth1Info: Option[securesocial.core.OAuth1Info]

Where OAuth1Info's new instance constructor in the Scaladoc looks like so:

new OAuth1Info(token: String, secret: String)

Now in my * method (as explained here) :

def * = stuffs ~ oAuth1InfoToken ~ oAuth1InfoToken ~ moreStuff <> 
    ( // the following is the apply method
    { t => User(stuffs, 
        Some(OAuth1Info( (t._9).getOrElse(""), (t._10).getOrElse("")) ), 
        moreStuffs)
    }, // the following is the unapply method
    {
        (r: User) => Some( (r.stuffs, 
            (r.oAuth1Info).getOrElse(None).token , // ERROR
            (r.oAuth1Info).getOrElse(None).secret , // ERROR
            r.moreStuffs) )
    }

What I'm trying to do

Insert in None to the database if oAuth1Info wasn't provided and

Option[securesocial.core.OAuth1Info] = None

Otherwise, take the OAuth1Info object and get the token and secret and store it to their respective columns in my database.

On top of this mapped projection being a 500+ character line, do I need to do some sort of

oAuth1Info match {
    case None: None
    case _: oAuth1Info.token
}

? Can a single-line pattern-matcher be possible? I am so lost in my code at this point...

Thanks for any help


If you'd like to see my full implementation so far...

Scala + Slick + SecureSocial = sadly tl;dr code

I know this code is a wall of text. Multiline Scala code would be awesome here if it exists? Pastebin

Community
  • 1
  • 1
Meredith
  • 3,928
  • 4
  • 33
  • 58

2 Answers2

1

I haven't completely grasped the types in your original question, but the oAuth1Unapply method in your answer can be re-written as

def oAuth1Unapply(smth: Option[securesocial.core.OAuth1Info]): (String, String) =
  smth.map(oa => (oa.token, oa.secret)).getOrElse(("",""))

The map method applies a function to the content of the Option if it is not None, and returns the result as a Some value, or otherwise leaves the result as None.

Kristian Domagala
  • 3,686
  • 20
  • 22
0

I'm silly. I got it.

So I do use a pattern matcher.

def oAuth1Unapply(smth: Option[securesocial.core.OAuth1Info]): (String, String) =  {
    smth match {
          case None => ("", "")
          case _ => (smth.getOrElse(OAuth1Info("","")).token, smth.getOrElse(OAuth1Info("","")).secret)
        }
}

Then I do

val oa1 = oAuth1Unapply(r.oAuth1Info)
def * = stuffs ~ oAuth1InfoToken ~ oAuth1InfoToken ~ moreStuff <> 
( // the following is the apply method
{ t => User(stuffs, 
    Some(OAuth1Info( (t._9).getOrElse(""), (t._10).getOrElse("")) ), 
    moreStuffs)
}, // the following is the unapply method
{
    (r: User) => Some( (r.stuffs, 
        oa1._1, oa2._2
        r.moreStuffs) )
}
Meredith
  • 3,928
  • 4
  • 33
  • 58
  • def * does not compile this way if both stuffs and moreStuff are Projections. You have to use ~: after stuffs. – cvogt Jul 01 '13 at 08:50
  • ? What do you mean by "does not compile this way"? What way? – Meredith Jul 01 '13 at 08:52
  • I've been following the [Slick documentation](http://slick.typesafe.com/doc/1.0.1/lifted-embedding.html#mapped-tables), and that's what they go by... it seems to compile fine for me so far – Meredith Jul 01 '13 at 08:54
  • Always returning Some for OAuth1Info (sometimes with empty String fields) looks suspicious. Why have an Option at all then? Maybe you want this: t._9.map( OAuth1Info( t._9.get, t._10.get ) ). Be aware that this assumes that if _9 is not None, _10 is not None either. You should adapt the code if that assumption does not hold. – cvogt Jul 01 '13 at 08:55
  • Does def * actually look exactly like this in your code "def * = stuffs ~ oAuth1InfoToken ~ oAuth1InfoToken ~ moreStuff" with stuffs and moreStuff being of type Projection (not Column[...])? – cvogt Jul 01 '13 at 08:57
  • Pretty much yes, but with a lot more fields... here's an [ideone of my code](http://ideone.com/60BVHh) – Meredith Jul 01 '13 at 09:01
  • 1
    exactly. with `def stuff = col1 ~ col2; def moreStuff = col4 ~ col5` this works: `def * = stuff ~ col3 ~ col4 ~ col5` but this does not `def * = stuff ~ col3 ~ moreStuff` _(compile error)_. My previous suggestion of using `~:` was wrong by the way. you can't combine two previous projections (`~` operator) into a new one in Slick 1.x. In Slick 2.0 this should be possible. – cvogt Jul 01 '13 at 11:47