Anorm 2.3 multi-value parameter: required anorm.NamedParameter
Asked Answered
W

1

1

Using scala 2.11.1 on play framework 2.3.

Because Anorm didn't support multi-value parameters in previous versions I used David's workaround. Anorm now supports multi-value parameters and I started removing the workaround and using Anorm multi-value parameters.

The example [sic] mentioned:

// With default formatting (", " as separator)
SQL("SELECT * FROM Test WHERE cat IN ({categories})").
  on('categories -> Seq("a", "b", "c")
// -> SELECT * FROM Test WHERE cat IN ('a', 'b', 'c')

Yet my code:

val names = List("Able", "Baker", "Charlie") // Passed as a parameter to my method!
val result =
  SQL( """
    SELECT city
    FROM addresses
    WHERE name IN ({names});
  """ ).on( 'names -> names ).as( scalar[String] * )

gives me this error:

type mismatch;
 found   : (Symbol, List[String])
 required: anorm.NamedParameter

or

type mismatch;
 found   : (Symbol, scala.collection.immutable.Seq[String])
 required: anorm.NamedParameter

depending if i try a list or sequence (or one of the suggestions to map it).

I'm no expert, by far, and I think it's missing some implicit conversion? Clueless to find out how/what/where. Tips/suggestions/solutions welcome!

Whet answered 5/8, 2014 at 14:0 Comment(0)
A
0

Looking at Anorm document, you will see there is no multi-value example using List. Indeed that's on purpose as instance of NamedParameter is implemented only for Seq[T].

Just updating your code to val names = Seq("Able", "Baker", "Charlie") make it valid (and compiles).

I would suggest to edit your code using Anorm interpolation:

val result = 
  SQL"SELECT city FROM addresses WHERE name IN ($names)" as scalar[String].*

// OR (if names won't change):
val result = SQL"""SELECT city FROM addresses
    WHERE name IN (${Seq("Able", "Baker", "Charlie")})""".
  as(scalar[String].*)

EDIT: See changes in Anorm https://github.com/playframework/playframework/pull/3257 (supports List)

Atingle answered 5/8, 2014 at 14:55 Comment(4)
Afraid that didn't fix it. See my error, i already tried a Seq. Something i noticed: an example Seq(A,B,C) works, but if it isn't defined on forehand it doesn't. I get the parameter as a List and a toSeq didn't work. It seems that while typing this, I might have found the solution: val names:Seq[String] = theList.toSeq (have to add the :Seq[String]. Will edit again if that fixed it.Plaster
Which code do you try with Seq? Have you tried pasted samples? I can confirm you that all given examples are working with Anorm 2.3. What's important that is that the visible type of multivalue passed as parameter must be Seq[String]. If you let val seq = List("a", "b"), yes seq is instance of Seq, but visible type is List, and implicit (typeclass) there is not defined for S <: Seq[T] but strictly for Seq[T].Atingle
From the original question: found: (Symbol, scala.collection.immutable.Seq[String]). That was because I tried converting my passed parameter List to a Seq. val seq = List("a", "b").toSeq. That gave me the error. I changed that to: val seq: Seq[String] = List("a", "b").toSeq and it worked! So i guess that was my error. Assuming the List[String] .toSeq would give me a Seq[String]. (Don't know much about S<:Set[T] I'm afraid. Will look it up. Is that the visible type?) Re: tried the pasted samples: they worked, that's how i noticed the difference between the List.toSeq and a Seq("a","b").Plaster
That's not because you see scala.collection.immutable.Seq in to debug that the visible type is Seq. It's List, as List keep string representation from its parent (.toString). As said, instance of NamedParameter is defined only for Seq[T], which means your multivalue need to be declared as a Seq[T], not a List[T] even if List[T] is a kind of Seq[T]: with this implicit resolution inheritance is not followed (on purpose). Would you mind accepting the answer, as it fixes the original question. Best regards.Atingle

© 2022 - 2024 — McMap. All rights reserved.