Search code examples
scalaone-to-manysqueryl

Strange result when using squeryl and scala


I'm trying to select the coupled user by getting the correct linkedAccount. The query that is created is correct but when trying to use a property on dbuser e.g dbuser.lastName I get a compile error since dbuser is not of type User but Query1 size=?
It's probably something really simple but I can't figure it out since I'm a scala and squeryl noob!

Why doesn't it return the correct value and what have I done wrong in my query? Also, saving works without any issues.

User:

class User(
            @Column("id") val id: Long,
            @Column("first_name") val firstName : String,
            @Column("last_name") val lastName : String,
            @Column("email") val email : String,
            @Column("email_validated") val emailValidated: Boolean = false,
            @Column("last_login") val lastLogin: Timestamp = null,
            val created: Timestamp,
            val modified: Timestamp,
            val active: Boolean = false
                 ) extends KeyedEntity[Long] {

  lazy val linkedAccounts: OneToMany[LinkedAccount] = AppDB.usersToLinkedAccounts.left(this)
}

LinkedAccount:

class LinkedAccount(
                     @Column("id") val id: Long,
                     @Column("user_id") val userId: Long,
                     @Column("provider_user_id") val providerUserId: String,
                     @Column("salt") val salt: String,
                     @Column("provider_key") val providerKey: String) extends KeyedEntity[Long] {

  lazy val user: ManyToOne[User] = AppDB.usersToLinkedAccounts.right(this)

}

AppDB:

object AppDB extends Schema {
  val users = table[User]("users")
  val linkedAccounts = table[LinkedAccount]("linked_account")
  val usersToLinkedAccounts = oneToManyRelation(users, linkedAccounts).via((u, l) => u.id === l.userId)

def userByLinkedAccount(prodivderKey: String, providerUserId: String) = {
    from(AppDB.users)(u =>
      where(u.id in
        from(AppDB.linkedAccounts)(la =>
          where(la.userId === u.id and la.providerKey === prodivderKey and la.providerUserId === providerUserId)
            select (la.userId)
        )
      )
        select (u)
    )    
  }

The call:

val dbuser = inTransaction {
      val u2 = AppDB.userByLinkedAccount(id.providerId, id.id)
      println(u2.statement)              
    }
     println(dbuser.lastName)

The sql generated

Select
  users10.last_login as users10_last_login,
  users10.email as users10_email,
  users10.modified as users10_modified,
  users10.last_name as users10_last_name,
  users10.first_name as users10_first_name,
  users10.id as users10_id,
  users10.created as users10_created,
  users10.email_validated as users10_email_validated,
  users10.active as users10_active
From
  users users10
Where
  (users10.id in ((Select
     linked_account13.user_id as linked_account13_user_id
   From
     linked_account linked_account13
   Where
     (((linked_account13.user_id = users10.id) and (linked_account13.provider_key = 'facebook')) and (linked_account13.provider_user_id = 'XXXXXXXXXX'))
  ) ))

Solution

  • Ok figured it out. I need to make the call, in this case:

    .headOption
    

    Also fixed the query after some tips from Per

    def userByLinkedAccount(providerKey : String, providerUserId : String) = {
        inTransaction {
          from(AppDB.users, AppDB.linkedAccounts)((u,la) =>
            where (u.id === la.userId and la.providerKey === providerKey and la.providerUserId === providerUserId)
              select(u)
          ).headOption
        }
      }