Where can I find the scaladocs for scala-play? I'd like to pull off
something like this:
def count(jid:String):Int = SQL(
"""
select count(abu.created)
from ActiveBridgeUser as abu
join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
where pbu.jid={jid}
"""
).on("jid" -> jid).collect { case Row(total:Int) => total }
but without api docs I cannot figure out where to proceed with "Error
raised is : value collect is not a member of
play.db.anorm.SimpleSql[play.db.anorm.Row]"
--
Brian L. Troutwine
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
On Mon, Jun 6, 2011 at 12:00 AM, Sadek Drobi <sadek...@gmail.com> wrote:
> def count(jid:String):Int = SQL(
> """
> select count(abu.created)
> from ActiveBridgeUser as abu
> join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
> where pbu.jid={jid}
> """
> ).on("jid" -> jid).as(scalar[Int])
This results in a runtime error:
java.lang.RuntimeException: TypeDoesNotMatch(int and class java.lang.Long)
at scala.Predef$.error(Predef.scala:58)
at play.db.anorm.Sql$.as(Anorm.scala:984)
at play.db.anorm.Sql$class.as(Anorm.scala:919)
at play.db.anorm.SimpleSql.as(Anorm.scala:829)
at models.BridgeUser$.count(models.scala:57)
at ModelCrudTests$$anonfun$1.apply$mcV$sp(Tests.scala:22)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at org.scalatest.FlatSpec$$anon$2.apply(FlatSpec.scala:2563)
at org.scalatest.Suite$class.withFixture(Suite.scala:1509)
at ModelCrudTests.withFixture(Tests.scala:8)
at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2560)
at ModelCrudTests.org$scalatest$BeforeAndAfterEach$$super$runTest(Tests.scala:8)
at org.scalatest.BeforeAndAfterEach$class.runTest(BeforeAndAfterEach.scala:167)
at ModelCrudTests.runTest(Tests.scala:8)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2485)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2474)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
at org.scalatest.FlatSpec$class.org$scalatest$FlatSpec$$runTestsInBranch(FlatSpec.scala:2473)
at org.scalatest.FlatSpec$class.runTests(FlatSpec.scala:2687)
at ModelCrudTests.runTests(Tests.scala:8)
at org.scalatest.Suite$class.run(Suite.scala:1804)
at ModelCrudTests.org$scalatest$FlatSpec$$super$run(Tests.scala:8)
at org.scalatest.FlatSpec$class.run(FlatSpec.scala:2758)
at ModelCrudTests.run(Tests.scala:8)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:59)
at org.scalatest.tools.ScalaTestRunner$.run(ScalaTestRunner.scala:58)
at org.scalatest.tools.ScalaTestRunner$.runSuiteClass(ScalaTestRunner.scala:17)
at play.scalasupport.ScalaPlugin.runTest(ScalaPlugin.scala:91)
at play.plugins.PluginCollection.runTest(PluginCollection.java:628)
at play.test.TestEngine.run(TestEngine.java:94)
at controllers.TestRunner.run(TestRunner.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:475)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:220)
at play.Invoker$Invocation.run(Invoker.java:265)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:200)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
> Or
> def count(jid:String):Int = SQL(
> """
> select count(abu.created)
> from ActiveBridgeUser as abu
> join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
> where pbu.jid={jid}
> """
> ).on("jid" -> jid).apply().collect{ case Row(total:Int) => total }
This results in: "type mismatch; found :
scala.collection.immutable.Stream[Int] required: Int" Changing the
last line to:
).on("jid" -> jid).apply().collect{ case Row(total:Int) => total }.head
results in:
java.util.NoSuchElementException: head of empty stream
at scala.collection.immutable.Stream$Empty$.head(Stream.scala:506)
at scala.collection.immutable.Stream$Empty$.head(Stream.scala:504)
at models.BridgeUser$.count(models.scala:57)
at ModelCrudTests$$anonfun$1.apply$mcV$sp(Tests.scala:22)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at org.scalatest.FlatSpec$$anon$2.apply(FlatSpec.scala:2563)
at org.scalatest.Suite$class.withFixture(Suite.scala:1509)
at ModelCrudTests.withFixture(Tests.scala:8)
at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2560)
at ModelCrudTests.org$scalatest$BeforeAndAfterEach$$super$runTest(Tests.scala:8)
at org.scalatest.BeforeAndAfterEach$class.runTest(BeforeAndAfterEach.scala:167)
at ModelCrudTests.runTest(Tests.scala:8)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2485)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2474)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
at org.scalatest.FlatSpec$class.org$scalatest$FlatSpec$$runTestsInBranch(FlatSpec.scala:2473)
at org.scalatest.FlatSpec$class.runTests(FlatSpec.scala:2687)
at ModelCrudTests.runTests(Tests.scala:8)
at org.scalatest.Suite$class.run(Suite.scala:1804)
at ModelCrudTests.org$scalatest$FlatSpec$$super$run(Tests.scala:8)
at org.scalatest.FlatSpec$class.run(FlatSpec.scala:2758)
at ModelCrudTests.run(Tests.scala:8)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:59)
at org.scalatest.tools.ScalaTestRunner$.run(ScalaTestRunner.scala:58)
at org.scalatest.tools.ScalaTestRunner$.runSuiteClass(ScalaTestRunner.scala:17)
at play.scalasupport.ScalaPlugin.runTest(ScalaPlugin.scala:91)
at play.plugins.PluginCollection.runTest(PluginCollection.java:628)
at play.test.TestEngine.run(TestEngine.java:94)
at controllers.TestRunner.run(TestRunner.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:475)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:220)
at play.Invoker$Invocation.run(Invoker.java:265)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:200)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
My Play! version: 1.2.2RC1
My Scala-Play: 0.9.1
--
Brian L. Troutwine
Ah, more to the point, why is this a runtime error and not a
compilation error is Play is to be more strict in numeric casting than
Scala? See that:
scala> val twoL:Long = 2
twoL: Long = 2
scala> val twoI:Int = 2
twoI: Int = 2
scala> twoL == twoI
res1: Boolean = true
(Sorry, bungled the sending of my last email.)
I think it's clear that I can avoid the error by requesting Longs
instead, but that I have to when I've requested a scalar[Int] and had
this code compile seems to indicate more a bug in Anorm than in my
thinking, no?
--
Brian L. Troutwine
That the database interaction is impure is orthogonal to an issue of
types: Play is missing out on the ability to make a valid, implicit
conversion. Clearly if I had issued scalar[String] I would deserve my
runtime exception. Not so, I assert, with scalar[Int] on a Long
return. If we look at scalar:
https://github.com/playframework/play-scala/blob/master/src/play/db/anorm/Anorm.scala#L315
You'll note that at #L321 it makes the correct conversation. The use
of Manifest >:> #L320 is the problem: Manifest[Int] is _isomorphic_ to
Manifest[Long] as Long is convertible to Int. It would be better to
define this function:
def orthoganol[S,T](l:Manifest[S], r:Manifest[T]):Boolean = {
try {
l.erasure.asInstanceOf[T]
true
} catch {
case e:java.lang.ClassCastException => false
}
}
And change #L321 to read
if ( orthoganol(m, TypeWrangler.javaType(a.asInstanceOf[AnyRef].getClass) ))
so that the full capability of asInstanceOf were made available.
Renaming 'orthoganol' as an infix '>%>' on ClassManifest would look
rather nicer.
The widths are wrong, yes, but I think that's beside the issue: Play
is missing the opportunity to make type conversions requested by the
user. Maybe I know my database better than you and the width of the
returned Long will always fit inside of an Int, which I want to
express as a type. If your aim is to restrict conversions in which
information might be lost, doing so implicitly is not the best way to
do so. Or consider if I were using my PhoneNumber library[1] to
convert strings that I knew were valid US phone numbers into
us.troutwine.phonenumber.USPhoneNumber instances. This latter fails
because of the use of asInstanceOf: though an implicit casts exists
between String and USPhoneNumber scala's runtime system is
side-stepped and cannot make the valid conversion. To use Scala's
conversion ability #L321 should be changed to
Right(a:T)
unless I am much mistaken.
[1] https://github.com/blt/PhoneNumber
On Mon, Jun 6, 2011 at 11:31 AM, Sadek Drobi <sadek...@gmail.com> wrote:The widths are wrong, yes, but I think that's beside the issue: Play
> Converting a long to int is not valid and especially unsafe.
is missing the opportunity to make type conversions requested by the
user. Maybe I know my database better than you and the width of the
returned Long will always fit inside of an Int, which I want to
express as a type. If your aim is to restrict conversions in which
information might be lost, doing so implicitly is not the best way to
do so. Or consider if I were using my PhoneNumber library[1] to
convert strings that I knew were valid US phone numbers into
us.troutwine.phonenumber.USPhoneNumber instances. This latter fails
because of the use of asInstanceOf: though an implicit casts exists
between String and USPhoneNumber scala's runtime system is
side-stepped and cannot make the valid conversion. To use Scala's
conversion ability #L321 should be changed to
Right(a:T)
unless I am much mistaken.
I cede that converting a Long to a less wide type can cause problems:
I did not contest this. You will also note that I specifically defined
the overflow problem as nil: without Dependent Typing Scala users must
known the range of numeric values to be converted. I defined a
hypothetical in which the conversion is valid, in which scalar
incorrectly restricts my knowledgeable action as a user; this was
ignored. My contention is that scalar is unable to make valid
conversions _requested by the user_. I further illustrated this with a
String to USPhoneNumber conversion: you ignored this. In it's current
state Anorm catches some bugs _only incidentally_. This is a
misfeature in that Anorm refuses to make valid conversions. That
Long->Int is possible at runtime and performs no value checking is a
historical curiosity and beside my point. (If Anorm _really_ were
written with runtime width safety in mind it would not return the
finite Long but, rather, scala.math.BigInt. You will note that _this_
conversion is also not possible with scalar. I digress.)
I will enumerate again:
* Anorm's scalar breaks type parameter semantics by failing to make
valid conversions from the underlying type.
* That scalar is unable to make some invalid numeric conversions is
not a feature.
* The Scala type system lacks dependent types: scalar is
accidentally disallowing some conversions that a dependent types would
fix.
Finally, if I have to perform an explicit conversion on the return
from scalar I must know what types scalar _will_ return from the
underlying database connection. As there is no restriction on the T
accepted by scalar I must discover this accidentally: the type-system
is subverted by allowing a general T at compile-time when the authors
had a more restricted type S in mind. Consistent with my semantics
violation assertion, why even bother with scalar? If I _know_ that all
strings coming out of a query will be valid USPhoneNumbers, what sense
does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?
> Sadek
ColumnTo? The only documentation I have is here:
http://scala.playframework.org/documentation/scala-0.9.1/anorm#UsingtheParsercombinatorAPI
ColumnTo is not mentioned there, I'm afraid.
>>
>> In it's current
>> state Anorm catches some bugs _only incidentally_. This is a
>> misfeature in that Anorm refuses to make valid conversions. That
>> Long->Int is possible at runtime and performs no value checking is a
>> historical curiosity and beside my point. (If Anorm _really_ were
>> written with runtime width safety in mind it would not return the
>> finite Long but, rather, scala.math.BigInt. You will note that _this_
>> conversion is also not possible with scalar. I digress.)
>>
>
> I don't agree. Even if I agree about scalar, other parsers are very
> extensible and you can easily adapt them to your own types. If there is a
> thing that can be improved then it should be an access to lower level
> resultset without passing and being constrained by JDBC cooked up
> ResultSetMetaData. That is certainly a place I am willing to improve.
Perhaps part of our communication problem is that, given the
documentation available, I do not know what scalar is _intended_ to
do. Reading the source code I have an idea of what it does, but that's
not always a clear way to get at the author's hopes. Especially when
the source code is not commented.
>>
>> I will enumerate again:
>>
>> * Anorm's scalar breaks type parameter semantics by failing to make
>> valid conversions from the underlying type.
>
> Again, that is the case of scalar but not any of the other parsers.
This must be an issue of documentation. What is the aim of scalar?
From it's name I assume it holds only a single type, but to what end I
do not know.
>>
>> * That scalar is unable to make some invalid numeric conversions is
>> not a feature.
>
> Correct, I will fix it and it will have a default behavior not to do invalid
> conversion and you can override that then exactly like now for 'get' Parser.
The get parser? Also, how will you define valid and invalid conversions?
>>
>> * The Scala type system lacks dependent types: scalar is
>> accidentally disallowing some conversions that a dependent types would
>> fix.
>>
> I doubt dependent types would save anything here. If one execution of the
> query returns a 'correct' Int doesn't mean the category of the result is
> Int.
Sure it would. Force scalar to produce the widest dependent numerical
type internally, have the compiler complain if the user attempts to
cast to a less-wide type. Or, alternatively, issue a runtime error on
implicit conversion if the less-wide type will not contain the value:
clearer error message, you maintain the current runtime checking and
you paper over the defects in Java's numeric type hierarchy.
>>
>> Finally, if I have to perform an explicit conversion on the return
>> from scalar I must know what types scalar _will_ return from the
>> underlying database connection. As there is no restriction on the T
>> accepted by scalar I must discover this accidentally: the type-system
>> is subverted by allowing a general T at compile-time when the authors
>> had a more restricted type S in mind. Consistent with my semantics
>> violation assertion, why even bother with scalar? If I _know_ that all
>> strings coming out of a query will be valid USPhoneNumbers, what sense
>> does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?
>
> Again the problem with scalar. 'get' puts a restriction on allowed T which
> is the implementation of ColumnTo[T]
I see neither 'get' nor ColumnTo in the available documentation.
Additionally, it seems that no API reference is available.
> Sadek
I cede that converting a Long to a less wide type can cause problems:
I did not contest this. You will also note that I specifically defined
the overflow problem as nil: without Dependent Typing Scala users must
known the range of numeric values to be converted. I defined a
hypothetical in which the conversion is valid, in which scalar
incorrectly restricts my knowledgeable action as a user; this was
ignored. My contention is that scalar is unable to make valid
conversions _requested by the user_. I further illustrated this with a
String to USPhoneNumber conversion: you ignored this.
In it's current
state Anorm catches some bugs _only incidentally_. This is a
misfeature in that Anorm refuses to make valid conversions. That
Long->Int is possible at runtime and performs no value checking is a
historical curiosity and beside my point. (If Anorm _really_ were
written with runtime width safety in mind it would not return the
finite Long but, rather, scala.math.BigInt. You will note that _this_
conversion is also not possible with scalar. I digress.)
I will enumerate again:
* Anorm's scalar breaks type parameter semantics by failing to make
valid conversions from the underlying type.
* That scalar is unable to make some invalid numeric conversions is
not a feature.
* The Scala type system lacks dependent types: scalar is
accidentally disallowing some conversions that a dependent types would
fix.
Finally, if I have to perform an explicit conversion on the return
from scalar I must know what types scalar _will_ return from the
underlying database connection. As there is no restriction on the T
accepted by scalar I must discover this accidentally: the type-system
is subverted by allowing a general T at compile-time when the authors
had a more restricted type S in mind. Consistent with my semantics
violation assertion, why even bother with scalar? If I _know_ that all
strings coming out of a query will be valid USPhoneNumbers, what sense
does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?
> --
> You received this message because you are subscribed to the Google Groups
> "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to
> play-framewor...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/play-framework?hl=en.
>
--
Brian L. Troutwine
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
On Mon, Jun 6, 2011 at 3:04 PM, Sadek Drobi <sadek...@gmail.com> wrote:ColumnTo? The only documentation I have is here:
>>
>>
>> I cede that converting a Long to a less wide type can cause problems:
>
> It was confusing as an argument.
>
>>
>> I did not contest this. You will also note that I specifically defined
>> the overflow problem as nil: without Dependent Typing Scala users must
>> known the range of numeric values to be converted. I defined a
>> hypothetical in which the conversion is valid, in which scalar
>> incorrectly restricts my knowledgeable action as a user; this was
>> ignored. My contention is that scalar is unable to make valid
>> conversions _requested by the user_. I further illustrated this with a
>> String to USPhoneNumber conversion: you ignored this.
>
> You are right, I was arguing having in mind ColumnTo together with other
> extensible parsers (like get). scalar is not extensible in the same way and
> certainly should improve. It should rather integrate a mechanism similar to
> ColumnTo that would allow you to extend to read things your way. Take a look
> at get parser and you'll see what I mean.
http://scala.playframework.org/documentation/scala-0.9.1/anorm#UsingtheParsercombinatorAPI
ColumnTo is not mentioned there, I'm afraid.
Perhaps part of our communication problem is that, given the
>>
>> In it's current
>> state Anorm catches some bugs _only incidentally_. This is a
>> misfeature in that Anorm refuses to make valid conversions. That
>> Long->Int is possible at runtime and performs no value checking is a
>> historical curiosity and beside my point. (If Anorm _really_ were
>> written with runtime width safety in mind it would not return the
>> finite Long but, rather, scala.math.BigInt. You will note that _this_
>> conversion is also not possible with scalar. I digress.)
>>
>
> I don't agree. Even if I agree about scalar, other parsers are very
> extensible and you can easily adapt them to your own types. If there is a
> thing that can be improved then it should be an access to lower level
> resultset without passing and being constrained by JDBC cooked up
> ResultSetMetaData. That is certainly a place I am willing to improve.
documentation available, I do not know what scalar is _intended_ to
do. Reading the source code I have an idea of what it does, but that's
not always a clear way to get at the author's hopes. Especially when
the source code is not commented.