Left join problem for SquerylRecord

39 views
Skip to first unread message

Steven Yang

unread,
Dec 20, 2011, 11:27:02 PM12/20/11
to lif...@googlegroups.com
Hi

I think this is a bug or I am missing something on the conversion in SquerylRecord
I want to confirm this before filing a bug.

Here is my sample code

class Fund private() extends Record[Fund] with KeyedRecord[String] {
    
    override def meta = Fund
    override val idField = id
    
    val id = new StringField(this, 8)
    val lcc = new OptionalStringField(this, 8)
  }
  
  object Fund extends Fund with MetaRecord[Fund]
  
  class Lc private() extends Record[Lc] with KeyedRecord[String] {
    
    override def meta = Lc
    override val idField = lcc
    
    val lcc = new StringField(this, 8)
    val name = new StringField(this, 8)
  }
  
  object Lc extends Lc with MetaRecord[Lc]
  
  object TestSchema extends Schema {
    
    val fund = table[Fund]
    val lc = table[Lc]
  }
  
  import TestSchema._
  val d = join(fund, lc.leftOuter)((f, l) => 
    where(f.id === "xxx")
    select(f, l)
    on(f.lcc === l.map(_.lcc)))

This code doesn't compile for the last line
it says 
"type mismatch; 
found : org.squeryl.dsl.StringExpression[String] with net.liftweb.squerylrecord.SquerylRecordNonNumericalExpression[String] 
required: org.squeryl.dsl.NonNumericalExpression[Option[String]]"

However if I change the type of "lcc" to Long then everything works.

I believe it's because for Long the implicit conversion 
implicit def optionLongField2OptionLong(f: Option[TypedField[Long]]) = convertNumericalOption(f, createOutMapperLongTypeOption) 
returns something of SquerylRecordNumericalExpression[Option[LongType]]
However for String type
implicit def optionStringField2OptionString(f: Option[TypedField[String]])
returns something of SquerylRecordNonNumericalExpression[String]

and same goes for other non-numeric types

is this an expected behavior? or a bug?

Thanks

Steven Yang

unread,
Dec 21, 2011, 1:08:26 AM12/21/11
to lif...@googlegroups.com
also I just found out for all the implicits in RecordTypeMode for Calendar
optionDateField2OptionDate
optionDate2ScalarDate
date2ScalarDate
return BooleanExpression in case of None

Ján Raska

unread,
Dec 21, 2011, 3:08:42 AM12/21/11
to lif...@googlegroups.com
Hi Steve,

can you please post an example (https://www.assembla.com/wiki/show/liftweb/Posting_example_code)? I'll have a look at it before confirming a bug. 

Also, please note, that there is a policy (https://www.assembla.com/wiki/show/liftweb/Creating_ticketshttp://www.assembla.com/spaces/liftweb/wiki/Contributing), that non-committer shouldn't create a ticket without being asked by a committer, so until then, please do not create it.

Thanks

Jan


--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Steven Yang

unread,
Dec 21, 2011, 9:00:43 PM12/21/11
to lif...@googlegroups.com
hi

Yes I will not post until confirmed.

My example in the mail is complete and posting directly with proper imports into IDE should result in compilation error.
On this line
" on(f.lcc === l.map(_.lcc)))"

do you still want me to post an example code on github?
if so I will do ASAP

and here is the imports

import net.liftweb.squerylrecord.RecordTypeMode._
import net.liftweb.record.{MetaRecord, Record, Field, OptionalTypedField}
import net.liftweb.record.field._
import net.liftweb.squerylrecord.KeyedRecord
import org.squeryl.Schema

Thanks

Ján Raska

unread,
Dec 22, 2011, 2:27:07 AM12/22/11
to lif...@googlegroups.com
Hi Steve,

yes, please do post an example. All the reasons why we ask for that, instead of posting a code to the list are explained here: https://www.assembla.com/wiki/show/liftweb/Posting_example_code. To summarize it, if any of the community members are going to spend some of their valuable time playing around with your issue, posting a runnable example to github will save some of that time, that is required to setup a project. Also, in case it's not a bug, it allows me to fix your code and publish it back in a way, that you can immediately see what I've changed.

Thanks for understanding that

Jan

Steven Yang

unread,
Dec 22, 2011, 2:48:28 AM12/22/11
to lif...@googlegroups.com
Hi
sorry for asking as i have never post on github before

here is the link 

again first time using github and on a window machine.
dont know if it totally satisfy the Posting_example_code rule
if there is anything i should watch out next time please let me know 

Thanks for helping

by the way my sample doesnt satisfy the "must compile" rule because my question is about not able to compile

Thanks

Steven Yang

unread,
Dec 22, 2011, 2:52:10 AM12/22/11
to lif...@googlegroups.com
By the way, the commented out code in TestModel.scala is the counter part that is written purely with Squeryl and it compiles.
So I assume the same types for Record should work

Thanks

Peter Petersson

unread,
Dec 22, 2011, 4:24:13 AM12/22/11
to lif...@googlegroups.com
Steven
If there is any problem for Jan to build and run your example (I have not checked it out) you can clone my Basic-SquerylRecord-User-Setup example as template, add your example code, rename the project and put it back up on github.
This example includes everything that is needed (including a in memory db setup) and should run out of the box.

https://github.com/karma4u101/Basic-SquerylRecord-User-Setup

best regards
  Peter Petersson

Ján Raška

unread,
Dec 22, 2011, 8:58:36 AM12/22/11
to lif...@googlegroups.com
Thanks Steven, I'll investitate it and let you know. Of course "must compile" point doesn't apply to compilation error issues :)

Jan


Steven Yang

unread,
Dec 22, 2011, 8:34:00 PM12/22/11
to lif...@googlegroups.com
Thanks Jan will wait for you answer

Thanks Peter, the main reason is that I never committed to github before so i am very unfamiliar with the process and how things are done.

Ján Raska

unread,
Dec 26, 2011, 1:52:11 PM12/26/11
to lif...@googlegroups.com
Steven,

first of all, I'm sorry for replying a bit late, but during Christmas I've had some "computer free" time :)

It's quite weird, I don't understand, why optionString2ScalarString returns StringExpression[Option[String]] with SquerylRecordNonNumericalExpression[Option[String]] and optionStringField2OptionString returns StringExpression[String] with SquerylRecordNonNumericalExpression[String], while everything is all right in case of Long, Int and other numeric types. However, there's quite an easy workaround, in your join expression, please use:

on(Some(f.lcc) === l.map(_.lcc)) instead of on(f.lcc === l.map(_.lcc)). This way, optionStringField2OptionString will be used on both sides, thus the code will compile and will work perfectly (I checked my code and found out, I'm using this workaround already :) ).

If you want, feel free to create a ticket and assign it to me, I'll try to dig more deeply into it. You must be a watcher of Lift space to create a ticket.


Dave W., if you're reading this, don't you know if there is a reason, why optionString2ScalarString and optionStringField2OptionString (and similarly methods for other non numerical types) return different types, while appropriate methods for numerical types return same types? If not, then I'll fix it so that both methods return MyTypeExpression[Option[MyType]]. This way, it won't be required to use Some(field) for such joins any more, while at the same time, having Some(field) will continue to work.

Jan

Steven Yang

unread,
Dec 26, 2011, 9:26:11 PM12/26/11
to lif...@googlegroups.com
Hi Jan 
Thanks a lot
I had the same observation. Hope you can sorted it out, and Dave can help out.
here is the ticket

David Whittaker

unread,
Dec 27, 2011, 4:46:40 PM12/27/11
to lif...@googlegroups.com

It's quite weird, I don't understand, why optionString2ScalarString returns StringExpression[Option[String]] with SquerylRecordNonNumericalExpression[Option[String]]

This seems correct, optionString2ScalarString accepts an OptionalTypedField[String] as a parameter and returns an Expression type that reflects the fact that it's optional.
 
and optionStringField2OptionString returns StringExpression[String] with SquerylRecordNonNumericalExpression[String],

If you look at the comment you'll see that this was added for outer joins.  When you do a join(a, b.leftOuter)((a1,b1) => ....)  b1 will be wrapped in an option because you can't guarantee that there will be a "b" for each "a".  I guess that implicit was added so that the on() clause could contain something like a1.id === b1.map(_.aId).  In that case whether the aId field is a MandatoryTypedField or an OptionalTypedField it is going to be wrapped in an Option.  It would probably be more consistent to have two implicits here, one that converts Option[MandatoryTypedField[String]] to StringExpression[String] and one that converts Option[OptionalTypedField[String]] to StringExpression[Option[String]].
 
while everything is all right in case of Long, Int and other numeric types. However, there's quite an easy workaround, in your join expression, please use:

Yeah, this is a bit tricky and applies to non-Record Squeryl as well.  There is an implicit conversion from NumericalExpression[Option[A]] to NumericalExpression[A], but not from NonNumericalExpression[Option[A]] to NonNumericalExpression[A].  This is due to a limitation in the Scala compiler which thinks that the two together are ambiguous.


Dave W., if you're reading this, don't you know if there is a reason, why optionString2ScalarString and optionStringField2OptionString (and similarly methods for other non numerical types) return different types, while appropriate methods for numerical types return same types? If not, then I'll fix it so that both methods return MyTypeExpression[Option[MyType]]. This way, it won't be required to use Some(field) for such joins any more, while at the same time, having Some(field) will continue to work.


Jan, if you are going to make a change I think it would be better to break each optionXXXField method up into 2 methods, one for MandatoryTypedField and one for OptionalTypedField like I outlined above.  When Squeryl 0.9.6 is released (hopefully it will be much faster than 0.9.5) the whole Expression type system will be overhauled so this type of thing should be far easier to deal with, so I'll leave it up to you to decide whether the short term benefit is worth the effort.
Reply all
Reply to author
Forward
0 new messages