Lift, Squeryl and relationships

221 views
Skip to first unread message

Nolan Darilek

unread,
Oct 20, 2011, 12:19:52 PM10/20/11
to Lift
I'm struggling to define a one-to-many relationship in Squeryl using
Record. I have the following Model trait:

import squerylrecord.RecordTypeMode._
import org.squeryl._
import annotations.Column

trait Model[OwnerType <: Record[OwnerType] with KeyedEntity[String]]
extends KeyedEntity[String] {
self: OwnerType =>

def table: Table[OwnerType]

@Column(name="id")
object _id extends StringField(this.asInstanceOf[OwnerType], 36) {
override def defaultValue = newID
}
def id = _id.is
def id_=(i:String) = _id(i)

protected def newID = UUID.randomUUID.toString

object practiceID extends StringField(this.asInstanceOf[OwnerType], 36) {
override def defaultValue = model.practice.is.map(_.id).openOr("")
}

def save = {
if(isPersisted)
table.update(this)
else
table.insert(this)
true
}

def delete_! = table.delete(id)

def apply(id:String) = {
table.lookup(id)
}

def list = table.toList

}

And the following definitions in my schema:

val appointmentTypes = table[AppointmentType]("appointment_types")

val practices = table[Practice]("practices")
val practiceToAppointmentTypes = oneToManyRelation(practices,
appointmentTypes).via((p, u) => p.id === u.practiceID.is)

I've tried many permutations: p._id, p._id.is, u.practiceID,
u.practiceID.is, but I always get this error. RecordTypeMode._ is
imported into the schema.

11:17:37.068 [pool-8-thread-2] ERROR
n.liftweb.http.provider.HTTPProvider - Failed to Boot! Your application
may not run properly
java.lang.ExceptionInInitializerError: null
at bootstrap.liftweb.Boot$$anonfun$boot$4.apply(Boot.scala:44)
~[classes/:na]
at bootstrap.liftweb.Boot$$anonfun$boot$4.apply(Boot.scala:44)
~[classes/:na]
at net.liftweb.db.DB$$anonfun$use$1.apply(DB.scala:639)
~[lift-db_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.util.DynoVar$class.run(ThreadGlobal.scala:95)
~[lift-util_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.db.DB$currentConn$.run(DB.scala:626)
~[lift-db_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.db.DB$class.use(DB.scala:636)
~[lift-db_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.db.DB$$anon$1.use(DB.scala:38)
~[lift-db_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at bootstrap.liftweb.Boot.boot(Boot.scala:44) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
~[na:1.6.0_22]
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
~[na:1.6.0_22]
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
~[na:1.6.0_22]
at java.lang.reflect.Method.invoke(Method.java:616) ~[na:1.6.0_22]
at
net.liftweb.util.ClassHelpers$$anonfun$createInvoker$1.apply(ClassHelpers.scala:361)
~[lift-util_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
net.liftweb.util.ClassHelpers$$anonfun$createInvoker$1.apply(ClassHelpers.scala:359)
~[lift-util_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
net.liftweb.http.DefaultBootstrap$$anonfun$boot$1.apply(LiftRules.scala:1838)
~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
net.liftweb.http.DefaultBootstrap$$anonfun$boot$1.apply(LiftRules.scala:1838)
~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.common.Full.map(Box.scala:491)
~[lift-common_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.http.DefaultBootstrap$.boot(LiftRules.scala:1838)
~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
net.liftweb.http.provider.HTTPProvider$class.bootLift(HTTPProvider.scala:88)
~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.http.LiftFilter.bootLift(LiftServlet.scala:757)
[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
net.liftweb.http.provider.servlet.ServletFilterProvider$class.init(ServletFilterProvider.scala:40)
[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at net.liftweb.http.LiftFilter.init(LiftServlet.scala:757)
[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
org.eclipse.jetty.servlet.FilterHolder.doStart(FilterHolder.java:99)
[jetty-servlet-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
[jetty-util-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:740)
[jetty-servlet-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:245)
[jetty-servlet-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1158)
[jetty-webapp-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:588)
[jetty-server-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:436)
[jetty-webapp-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
[jetty-util-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:226)
[jetty-server-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:164)
[jetty-server-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
[jetty-util-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95)
[jetty-server-7.3.0.v20110203.jar:7.3.0.v20110203]
at org.eclipse.jetty.server.Server.doStart(Server.java:258)
[jetty-server-7.3.0.v20110203.jar:7.3.0.v20110203]
at
org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
[jetty-util-7.3.0.v20110203.jar:7.3.0.v20110203]
at com.github.siasia.Jetty7Runner.start(JettyRunner.scala:72)
[xsbt-web-plugin_2.9.1-0.11.0-0.2.3.jar:0.11.0-0.2.3]
at
com.github.siasia.Container$$anonfun$containerSettings$6.apply(Container.scala:59)
[xsbt-web-plugin_2.9.1-0.11.0-0.2.3.jar:0.11.0-0.2.3]
at
com.github.siasia.Container$$anonfun$containerSettings$6.apply(Container.scala:58)
[xsbt-web-plugin_2.9.1-0.11.0-0.2.3.jar:0.11.0-0.2.3]
at sbt.Scoped$$anonfun$hf6$1.apply(Structure.scala:463)
[main_2.9.1-0.11.0.jar:na]
at sbt.Scoped$$anonfun$hf6$1.apply(Structure.scala:463)
[main_2.9.1-0.11.0.jar:na]
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:41)
[scala-library.jar:na]
at
sbt.Scoped$Reduced$$anonfun$combine$1$$anonfun$apply$9.apply(Structure.scala:271)
[main_2.9.1-0.11.0.jar:na]
at
sbt.Scoped$Reduced$$anonfun$combine$1$$anonfun$apply$9.apply(Structure.scala:271)
[main_2.9.1-0.11.0.jar:na]
at
sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
[collections_2.9.1-0.11.0.jar:na]
at sbt.std.Transform$$anon$5.work(System.scala:67)
[task-system_2.9.1-0.11.0.jar:na]
at
sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:221)
[tasks_2.9.1-0.11.0.jar:na]
at
sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:221)
[tasks_2.9.1-0.11.0.jar:na]
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:13)
[control_2.9.1-0.11.0.jar:na]
at sbt.Execute.work(Execute.scala:227) [tasks_2.9.1-0.11.0.jar:na]
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:221)
[tasks_2.9.1-0.11.0.jar:na]
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:221)
[tasks_2.9.1-0.11.0.jar:na]
at
sbt.CompletionService$$anon$1$$anon$2.call(CompletionService.scala:26)
[tasks_2.9.1-0.11.0.jar:na]
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
[na:1.6.0_22]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
[na:1.6.0_22]
at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
[na:1.6.0_22]
at
java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
[na:1.6.0_22]
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
[na:1.6.0_22]
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
[na:1.6.0_22]
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
[na:1.6.0_22]
at java.lang.Thread.run(Thread.java:679) [na:1.6.0_22]
Caused by: java.lang.RuntimeException: left side of assignment
''ConstantExpressionNode:c0eb3ac2-41c7-404d-a0e9-2ba9c4fbb14f' is
invalid, make sure statement uses *only* closure argument.
at
org.squeryl.dsl.ast.TypedExpressionNode$class._fieldMetaData(ExpressionNode.scala:287)
~[squeryl_2.9.1-0.9.4.jar:na]
at
net.liftweb.squerylrecord.RecordTypeMode$$anon$12._fieldMetaData(RecordTypeMode.scala:78)
~[lift-squeryl-record_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
at
org.squeryl.dsl.QueryDsl$class.org$squeryl$dsl$QueryDsl$$_splitEquality(QueryDsl.scala:614)
~[squeryl_2.9.1-0.9.4.jar:na]
at
org.squeryl.dsl.QueryDsl$OneToManyRelationImpl.<init>(QueryDsl.scala:553) ~[squeryl_2.9.1-0.9.4.jar:na]

at
org.squeryl.dsl.QueryDsl$OneToManyRelationBuilder.via(QueryDsl.scala:525) ~[squeryl_2.9.1-0.9.4.jar:na]

at code.model.schema$.<init>(Schema.scala:20) ~[classes/:na]
at code.model.schema$.<clinit>(Schema.scala) ~[classes/:na]
... 61 common frames omitted
Caused by: java.lang.ClassCastException:
net.liftweb.squerylrecord.RecordTypeMode$$anon$12 cannot be cast to
org.squeryl.dsl.ast.SelectElementReference
at
org.squeryl.dsl.ast.TypedExpressionNode$class._fieldMetaData(ExpressionNode.scala:283)
~[squeryl_2.9.1-0.9.4.jar:na]
... 67 common frames omitted


Thoughts?

David Whittaker

unread,
Oct 20, 2011, 1:02:56 PM10/20/11
to lif...@googlegroups.com
Nolan,

Please post a sample to github, http://www.assembla.com/spaces/liftweb/wiki/Posting_example_code, and I'll take a look.

-Dave


--
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

Nolan Darilek

unread,
Oct 20, 2011, 1:34:06 PM10/20/11
to lif...@googlegroups.com
Done. I'm one of those weirdos who doesn't use Git or Github. If the requirement that the sample must be a github project is a hard one then I can do that, but I exported the following zip from my Fossil repository:

http://dl.dropbox.com/u/147071/sample.zip

~container:start aughta cause the error. The entire setup is in boot.scala.

Thanks.

David Whittaker

unread,
Oct 20, 2011, 3:09:22 PM10/20/11
to lif...@googlegroups.com
Nolan,

Ok, we've got a couple of problems here.  The first is that with squeryl-record you don't use KeyedEntity, you use KeyedRecord instead.  KeyedRecord will require you to implement a field named "idField" instead of _id but you can always add def _id = idField if you'd like and you can change the column name with the @Column(name = "xxx") annotation.

The second problem is that squeryl-record doesn't seem to be properly handling field of the form:

 object fieldName extends StringField(this)

That is a bug and I'd appreciate it if you could create a ticket http://www.assembla.com/spaces/liftweb/wiki/Creating_tickets so I don't forget to look into it.  For the time being, you can work around it with:

lazy val fieldName = new StringField(this)

P.S. While grabbing your source from DB was not a big deal, it's nice to be able to fork the repo and then push my fixes back so you can see exactly what I did to get it to compile.

-Dave

Nolan Darilek

unread,
Oct 20, 2011, 4:14:54 PM10/20/11
to lif...@googlegroups.com
Ticket created:

https://www.assembla.com/spaces/liftweb/tickets/1134-squeryl-record-doesn-t-honor-stringfields-as-objects

Thanks! Is it possible to search on fields defined as vals rather than as objects? I'm getting failures when I try:

where(_.idField === idParam)

Also, it might be nice to add lookup/delete functions to KeyedRecord as exist in KeyedEntity, since that seems like a common enough use case.

Thanks.

David Whittaker

unread,
Oct 20, 2011, 4:40:53 PM10/20/11
to lif...@googlegroups.com
Ticket created:

https://www.assembla.com/spaces/liftweb/tickets/1134-squeryl-record-doesn-t-honor-stringfields-as-objects

Thanks! Is it possible to search on fields defined as vals rather than as objects? I'm getting failures when I try:

where(_.idField === idParam)

What types are involved here?  What error are you getting?  Or does it just not find anything?
 

Also, it might be nice to add lookup/delete functions to KeyedRecord as exist in KeyedEntity, since that seems like a common enough use case.


Actually, Squeryl's KeyedEntity trait doesn't provide lookup/delete methods: http://squeryl.org/api/index.html#org.squeryl.KeyedEntity.  Was that what you meant?

Nolan Darilek

unread,
Oct 21, 2011, 12:43:31 PM10/21/11
to lif...@googlegroups.com
OK, it seems that I've figured out the issue. There seemed to be a few classes of the same name at various places, and I was unknowingly pulling in the wrong ones. The problem was complicated by the fact that I'm not starting from a fresh codebase and building up, but rather switching an existing and mostly working codebase over from MongoDB to Squeryl. So I was learning to swim by diving into the deep end and fighting a strong current, not by playing around in the kid pool. :)

Thanks for the help.
Thanks.
-Dave

   at net.liftweb.http.DefaultBootstrap$$anonfun$boot$1.apply(LiftRules.scala:1838)~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]

   at net.liftweb.common.Full.map(Box.scala:491) ~[lift-common_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
   at net.liftweb.http.DefaultBootstrap$.boot(LiftRules.scala:1838) ~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
   at net.liftweb.http.provider.HTTPProvider$class.bootLift(HTTPProvider.scala:88)~[lift-webkit_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]
   at net.liftweb.squerylrecord.RecordTypeMode$$anon$12._fieldMetaData(RecordTypeMode.scala:78)~[lift-squeryl-record_2.9.1-2.4-SNAPSHOT.jar:2.4-SNAPSHOT]

Olek Swirski

unread,
Nov 21, 2011, 12:42:28 PM11/21/11
to Lift
hi, I'm one of these lift newbies, very eager to see ProtoUser working
with squeryl.
you certainly have my moral support :-)

On Oct 21, 5:43 pm, Nolan Darilek <no...@thewordnerd.info> wrote:
> OK, it seems that I've figured out the issue. There seemed to be a few
> classes of the same name at various places, and I was unknowingly
> pulling in the wrong ones. The problem was complicated by the fact that
> I'm not starting from a fresh codebase and building up, but rather
> switching an existing and mostly working codebase over from MongoDB to
> Squeryl. So I was learning to swim by diving into the deep end and
> fighting a strong current, not by playing around in the kid pool. :)
>
> Thanks for the help.
>
> On 10/20/2011 03:40 PM, David Whittaker wrote:
>
> >     Ticket created:
>

> >    https://www.assembla.com/spaces/liftweb/tickets/1134-squeryl-record-d...


>
> >     Thanks! Is it possible to search on fields defined as vals rather
> >     than as objects? I'm getting failures when I try:
>
> >     where(_.idField === idParam)
>
> > What types are involved here?  What error are you getting?  Or does it
> > just not find anything?
>
> >     Also, it might be nice to add lookup/delete functions to
> >     KeyedRecord as exist in KeyedEntity, since that seems like a
> >     common enough use case.
>
> > Actually, Squeryl's KeyedEntity trait doesn't provide lookup/delete
> > methods:http://squeryl.org/api/index.html#org.squeryl.KeyedEntity.
> >  Was that what you meant?
>
> >     Thanks.
>
> >     On 10/20/2011 02:09 PM, David Whittaker wrote:
> >>     Nolan,
>
> >>     Ok, we've got a couple of problems here.  The first is that with
> >>     squeryl-record you don't use KeyedEntity, you use KeyedRecord
> >>     instead.  KeyedRecord will require you to implement a field named
> >>     "idField" instead of _id but you can always add def _id = idField
> >>     if you'd like and you can change the column name with the
> >>     @Column(name = "xxx") annotation.
>
> >>     The second problem is that squeryl-record doesn't seem to be
> >>     properly handling field of the form:
>
> >>      object fieldName extends StringField(this)
>
> >>     That is a bug and I'd appreciate it if you could create a ticket

> >>    http://www.assembla.com/spaces/liftweb/wiki/Creating_ticketsso I


> >>     don't forget to look into it.  For the time being, you can work
> >>     around it with:
>
> >>     lazy val fieldName = new StringField(this)
>
> >>     P.S. While grabbing your source from DB was not a big deal, it's
> >>     nice to be able to fork the repo and then push my fixes back so
> >>     you can see exactly what I did to get it to compile.
>
> >>     -Dave
>
> >>     On Thu, Oct 20, 2011 at 1:34 PM, Nolan Darilek

> >>     <no...@thewordnerd.info <mailto:no...@thewordnerd.info>> wrote:
>
> >>         Done. I'm one of those weirdos who doesn't use Git or Github.
> >>         If the requirement that the sample must be a github project
> >>         is a hard one then I can do that, but I exported the
> >>         following zip from my Fossil repository:
>
> >>        http://dl.dropbox.com/u/147071/sample.zip
>
> >>         ~container:start aughta cause the error. The entire setup is
> >>         in boot.scala.
>
> >>         Thanks.
>
> >>         On 10/20/2011 12:02 PM, David Whittaker wrote:
> >>>         Nolan,
>
> >>>         Please post a sample to github,
> >>>        http://www.assembla.com/spaces/liftweb/wiki/Posting_example_code,
> >>>         and I'll take a look.
>
> >>>         -Dave
>
> >>>         On Thu, Oct 20, 2011 at 12:19 PM, Nolan Darilek

> >>>         <no...@thewordnerd.info <mailto:no...@thewordnerd.info>> wrote:
>
> >>>             I'm struggling to define a one-to-many relationship in
> >>>             Squeryl using Record. I have the following Model trait:
>
> >>>             import squerylrecord.RecordTypeMode._
> >>>             import org.squeryl._
> >>>             import annotations.Column
>
> >>>             trait Model[OwnerType <: Record[OwnerType] with
> >>>             KeyedEntity[String]] extends KeyedEntity[String] {
> >>>              self: OwnerType =>
>
> >>>              def table: Table[OwnerType]
>
> >>>              @Column(name="id")
> >>>              object _id extends
> >>>             StringField(this.asInstanceOf[OwnerType], 36) {
> >>>                override def defaultValue = newID
> >>>              }

> >>>              def id = _id.is <http://id.is>


> >>>              def id_=(i:String) = _id(i)
>
> >>>              protected def newID = UUID.randomUUID.toString
>
> >>>              object practiceID extends
> >>>             StringField(this.asInstanceOf[OwnerType], 36) {
> >>>                override def defaultValue =
> >>>             model.practice.is.map(_.id).openOr("")
> >>>              }
>
> >>>              def save = {
> >>>                if(isPersisted)
> >>>                  table.update(this)
> >>>                else
> >>>                  table.insert(this)
> >>>                true
> >>>              }
>
> >>>              def delete_! = table.delete(id)
>
> >>>              def apply(id:String) = {
> >>>                table.lookup(id)
> >>>              }
>
> >>>              def list = table.toList
>
> >>>             }
>
> >>>             And the following definitions in my  schema:
>
> >>>              val appointmentTypes =
> >>>             table[AppointmentType]("appointment_types")
>
> >>>              val practices = table[Practice]("practices")
> >>>              val practiceToAppointmentTypes =
> >>>             oneToManyRelation(practices, appointmentTypes).via((p,

> >>>             u) => p.id <http://p.id> === u.practiceID.is
> >>>             <http://u.practiceID.is>)


>
> >>>             I've tried many permutations: p._id, p._id.is

> >>>             <http://id.is>, u.practiceID, u.practiceID.is
> >>>             <http://u.practiceID.is>, but I always get this error.

> >>>             <http://class.org>$squeryl$dsl$QueryDsl$$_splitEquality(QueryDsl.scala:614)

Olek Swirski

unread,
Nov 21, 2011, 1:15:27 PM11/21/11
to Lift
I mean in general some form of user entity scaffolding.

> ...
>
> read more »

Reply all
Reply to author
Forward
0 new messages