I'm starting develop with Play 2.2.1 and Scala 2.10.2. I'm developing a CRUD application. I'm following a example from book "Play for Scala: Covers 2", but I've a problem.
In these book there is this code in model
import play.api.Play.current
import play.api.db.DB
def getAll: List[Product] = DB.withConnection { implicit connection =>
sql().map
( row =>
Product(row[Long]("id"), row[Long]("ean"), row[String]("name"), row[String]("description"))
).toList
}
But when I try run it, I recieve this error:
value map is not a member of anorm.SqlQuery
Why doesn't function .map?
Thanks you!
SqlQuery doesn't have a map function. I'm not sure how the example in the book is supposed to look, but I'm a little wary of it if it's using that clunky syntax for anorm. I think it should always be preferred to use result set parsers defined separately from the function itself--as you'll be able to reuse them elsewhere.
import anorm._
import anorm.SqlParser._
import play.api.Play.current
import play.api.db.DB
case class Product(id: Long, ean: Long, name: String, description: String)
object Product {
/** Describes how to transform a result row to a `Product`. */
val parser: RowParser[Product] = {
get[Long]("products.id") ~
get[Long]("products.ean") ~
get[String]("products.name") ~
get[String]("products.description") map {
case id ~ ean ~ name ~ description => Product(id, ean, name, description)
}
def getAll: List[Product] = {
DB.withConnection { implicit connection =>
SQL("SELECT * FROM products").as(parser *)
}
}
}
I've made the assumption that your table is named products. It's best to use the full column names in parsers (products.id instead of id), as if later you need to combine parsers (using joined results), then anorm won't get confused from multiple tables using a similar column name like id. The getAll function now looks so much cleaner, and we can re-use the parser for other functions:
def getById(id: Long): Option[Product] = {
DB.withConnection{ implicit connection =>
SQL("SELECT * FROM products WHERE id = {id}")
.on("id" -> id)
.as(parser.singleOpt)
}
}
In the tutorial it is mentioned that,
Before we can get any results, we have to create a query. With Anorm, you call
anorm.SQL with your query as a String parameter:
import anorm.SQL
import anorm.SqlQuery
val sql: SqlQuery = SQL("select * from products order by name asc")
Is this missing from your code?.
SqlQuery is being made private (pending PR), so it should not be used directly. In place SQL("...") or SQL"..." functions can be used, in a safer way.
Best
Related
I would like to be able to insert a value into a table into r2dbc using the #Query designation (as opposed to the built in save function. However I don't know what the return type is for the SQL statement. I've tried String, Book, List<Book> Unit, and Void.
I have two types of errors. When I try and use a Book return value (assuming that the SQL statement will return the value of the inserted row) I get -
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
If I attempt to use a string I get the following. Apparently String return types are not compatible with r2dbc. There is a springboot persistable package (import org.springframework.data.domain.Persistable) which I've attempted to return a Persistable<String>, but that has not worked.
org.springframework.data.mapping.MappingException:
Couldn't find PersistentEntity for type class java.lang.String!
What I think is happening is that what is being returned is attempting to write to an index of some type that is neither a Book value, String, or some nullable type - ie the SQL message that is returned in a standard mysql interface OK, 1 row inserted into Booksor some such. I don't care about the insert value, but I can't call the function without knowing what that is so I can assign a type.
Here is what I have so far. Another question that came up while I've been working on this - is it possible to call a functions return type? I found this abstract class definition here https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-callable/return-type.html but no pragmatic examples so far. Thanks for the help~
package platypus.bookstore.repos.books
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.kotlin.CoroutineCrudRepository;
import org.springframework.data.r2dbc.repository.Query
import org.springframework.data.repository.query.Param
import platypus.bookstore.classes.db.books.Books
import platypus.bookstore.classes.general.ResultString
import org.springframework.stereotype.Repository
#Repository
interface BookRepository : CoroutineCrudRepository<Books, Long> {
#Query("""
INSERT INTO BOOKS (title, subtitle, publisher, currentcopyright, authorbio, synopsis, isbn)
values (:title, :subtitle, :publisher, :currentcopyright, :authorbio, :synopsis, :isbn);
""")
suspend fun addBook(title: String, subtitle: String, publisher: String,
currentcopyright: String, authorbio: String, synopsis: String, isbn: String
):???RETURNTYPE???
#Query("""
select * from books
""")
suspend fun findBooks():List<Books>
}
EDIT - I have a working implementation with a save function which I've now confirmed, so this isn't a huge deal. But...I think that this should be looked into and either fixed or more documentation available. I don't like having to rely on "magic" in order to make a simple SQL query into a database. Thanks!
SOLVED! - Thanks to Mark over at the spring-data-r2dbc github (https://github.com/spring-projects/spring-data-r2dbc/issues/618#event-4981291976) this issue has been solved. Here is the implementation for anyone that encounters a similar issue.
Basically you just have to use the #Modifying tag to write raw SQL -
Calling from the controller -
suspend fun addBook(book: Books):List<Books>{
println("addBooks")
// bookRepo.save(book);
bookRepo.saveabook(
book.title, book.subtitle, book.publisher,
book.currentcopyright, book.bookedition,
book.uniqueid, book.authorbio, book.synopsis, book.isbn
)
var bookList:List<Books> = findBooks()
return bookList;
}
Inside the repository -
import org.springframework.data.r2dbc.repository.Query
import org.springframework.data.r2dbc.repository.Modifying
#Repository
interface BookRepository : CoroutineCrudRepository<Books, Long> {
// The result of a modifying query can be:
// Void (or Kotlin Unit) to discard update count and await completion.
// Integer or another numeric type emitting the affected rows count.
// Boolean to emit whether at least one row was updated.
#Modifying
#Query(
"""
insert into books (title, subtitle, publisher, currentcopyright, bookedition, uniqueid, authorbio, synopsis, isbn) values (:title, :subtitle, :publisher, :currentcopyright, :bookedition, :uniqueid, :authorbio, :synopsis, :isbn)
""")
suspend fun saveabook(title:String, subtitle:String, publisher:String, currentcopyright:String, bookedition:String, uniqueid:String, authorbio:String, synopsis:String, isbn:String):Void
#Query("""
select * from books
""")
suspend fun findBooks():List<Books>
}
I want to create some new number types that like DspReal for dsptools, such as DspPosit and DspQuire. DspPosit bases on posit which I have some Java code, and DspQuire bases on quire which is a kind of accumulator for posit. Because I just want to simulation now, so I have write many ScalaBlackBox for their operation like DspReal. However, I found that ScalaBlackBox can't construct sequential logic. For example, current output of the quire accumulator depends on it's input and last output. But ScalaBlackBox can't get the value of the output. In addition, step(n) also influences the output. Because accumulator will read its input per clock cycle.
I found some system problems of treadle. First, the function of ScalaBlackBox, twoOp and oneOp and so on, will be called many times. I don't know why. Second, step(n) is the function of PeekPokeTester, which can't be access by ScalaBlackBox. Third, I try to read current output but system gives errors.
trait DspBlackBlackBoxImpl extends BlackBoxImplementation with ScalaBlackBox
abstract class DspQuireAccumulator extends DspBlackBlackBoxImpl {
lazy val accValue = Quire32() // initial value
/**
* sub-classes must implement this two argument function
*
* #param posit accumulate element
* #return quire operation result
*/
def accOp(posit: Posit32): Unit
def outputDependencies(outputName: String): Seq[(String)] = {
outputName match {
case "out" => Seq("in") // Seq("out", "in") gives errors
case _ => Seq.empty
}
}
def cycle(): Unit = {}
def execute(inputValues: Seq[Concrete], tpe: Type, outputName: String): Concrete = {
val arg1 :: _ = inputValues
val positArg = Posit32(arg1.value)
accOp(positArg)
val result = quire32ToBigInt(accValue)
ConcreteSInt(result, DspQuire.underlyingWidth, arg1.poisoned).asUInt
}
def getOutput(inputValues: Seq[BigInt], tpe: Type, outputName: String): BigInt = {
val arg1 :: _ = inputValues
val positArg = Posit32(arg1)
accOp(positArg)
quire32ToBigInt(accValue)
}
}
class DspQuireAddAcc(val name: String) extends DspQuireAccumulator {
def accOp(posit: Posit32): Unit = accValue += posit
}
class QuireBlackboxAccOperand extends BlackBox {
val io = IO(new Bundle() {
val in = Input(UInt(DspPosit.underlyingWidth.W))
val out = Output(UInt(DspQuire.underlyingWidth.W))
})
}
class BBQAddAcc extends QuireBlackboxAccOperand
class TreadleDspQuireFactory extends ScalaBlackBoxFactory {
def createInstance(instanceName: String, blackBoxName: String): Option[ScalaBlackBox] = {
blackBoxName match {
case "BBQAddAcc" => Some(add(new DspQuireAddAcc(instanceName)))
...
accOp will be called many times. So, if I want to accumulate List(1, 2, 3), the result maybe 0 + 1 + 1 + 2 + 2 + ...
And peek function will call accOp one time again, this makes me confused also.
I believe most of your problems at this point are caused by mixing two different approaches. I think you should not be using BlackBoxImplmentation because it is an older scheme used in with the firrtl-interpreter. Just use the ScalaBlackBox and implement the methods as described in the wiki page Black Boxes and Treadle and shown in the TreadleTest BlackBoxWithState.
Don't use outputDependencies, and instead specify any dependencies between inputs and outputs with with getDependencies. inputChanged will be called whenever an input IO is changed. So in that method you want to record or update the internal state of your black box. clockChange will be called whenever a clock is changed and will provide the transition information so you can decide what happens then. Treadle will call getOutput whenever it needs that output of your black box, since you will not have used outputDependencies you can ignore the inputs and just provide the output value depending on your internal state.
I am still trying to reproduce a running version of your code here but it will be a little time for me to put it together, if you can try my suggestions above and let me know how it goes that would be helpful. I am interested in making this feature of Treadle better and easier to use so all feedback is appreciated.
I have two sql statements to be executed with a validity check. My need is that I execute the 1st query and store the response in one object and check the object is empty or not and execute the second query if it is not empty.
So, I have tried something like
In rolerepository.scala=>
override val allQuery = s"""
select UserRoles.* from
(select CASE rbac.roleTypeID
ELSE rbac.name JOIN dirNetworkInfo ni
ON UserRoles.PersonID = ni.PersonID
where ni.Loginname = {loginName}
and UserRoles.roleName in ( 'Business User ','Administrator')"""
(This is just some sample of the query - it is not fully written here.)
Then I map it to an object with model class written outside
override def map2Object(implicit map: Map[String, Any]):
HierarchyEntryBillingRoleCheck = {
HierarchyEntryBillingRoleCheck(str("roleName"), oint("PersonID")) }
Then I have written the getall method to execute the query
override def getAll(implicit loginName: String):
Future[Seq[HierarchyEntryBillingRoleCheck]] = {
doQueryIgnoreRowErrors(allQuery, "loginName" -> loginName) }
Then I have written the method to check whether the response from the 1st sql is empty or not. This is were I'm stuck and not able to proceed further.
def method1()= {
val getallresponse = HierarchyEntryBillingRoleCheck
getallresponse.toString
if (getallresponse != " ")
billingMonthCheckRepository.getrepo()
}
I am getting an error (type mismatch) in last closing brace and I don't know what other logic can be used here.
Can any one of you please explain and give me some solution for this?
And i also tried to use for loop in controller but not getting how to do that.
i tried ->
def getAll(implicit queryParams: QueryParams,
billingMonthmodel:Seq[HierarchyEntryBillingRoleCheck]):
Action[AnyContent] = securityService.authenticate() { implicit request
=> withErrorRecovery { req =>
toJson {
repository.getAll(request.user.loginName)
for {
rolenamecheck <- billingMonthmodel
}yield rolenamecheck
}}}}
You don't say which db access method you are using. (I'm assuming anorm). One way of approaching this is:
Create a case class matching your table
Create a parser matching your case class
use Option (or Either) to return a row for a specific set of parameters
For example, perhaps you have:
case class UserRole (id:Int, loginName:String, roleName:String)
And then
object UserRole {
val sqlFields = "ur.id, ur.loginName, ur.roleName"
val userRoleParser = {
get[Int]("id") ~
get[String]("loginName") ~
get[String]("roleName") map {
case id ~ loginName ~ roleName => {
UserRole(id, loginName, roleName)
}
}
}
...
The parser maps the row to your case class. The next step is creating either single row methods like findById or findByLoginName and multi-row methods, perhaps allForRoleName or other generic filter methods. In your case there might (assuming a single role per loginName) be something like:
def findByLoginName(loginName:String):Option[UserRole) = DB.withConnection { implicit c =>
SQL(s"select $sqlFields from userRoles ur ...")
.on('loginName -> loginName)
.as(userRoleParser.singleOpt)
}
The .as(parser... is key. Typically, you'll need at least:
as(parser.singleOpt) which returns an Option of your case class
as(parser *) which returns a List of your case class (you'll need this if multiple roles could exist for a login
as(scalar[Long].singleOpt) which returns an Option[Long] and which is handy for returning counts or exists values
Then, to eventually return to your question a little more directly, you can call your find method, and if it returns something, continue with the second method call, perhaps like this:
val userRole = findByLoginName(loginName)
if (userRole.isDefined)
billingMonthCheckRepository.getrepo()
or, a little more idiomatically
findByLoginName(loginName).map { userRole =>
billingMonthCheckRepository.getrepo()
...
I've shown the find method returning an Option, but in reality we find it more useful to return an Either[String,(your case class)], and then the string contains the reason for failure. Either is cool.
On my version of play (2.3.x), the imports for the above are:
import play.api.db._
import play.api.Play.current
import anorm._
import anorm.SqlParser._
You're going to be doing this sort of thing a lot so worth finding a set of patterns that works for you.
WOW I don't know what's happening with the formatting here, I am really attempting to use the code formatter on the toolbar but I don't know why it won't format it, even when pressed multiple times. I invite the community to edit my code formatting because I can't figure it out. Apologies to OP.
Because I find Play's documentation to be very tough to trudge through if you're unfamiliar with it, I won't just leave a link to it only.
You have to inject an instance of your database into your controller. This will then give it to you as a global variable:
#Singleton
class LoginRegController #Inject()(**myDB: Database**, cc: ControllerComponents ) {
// do stuff
}
But, it's bad practice to actually use this connection within the controller, because the JDBC is a blocking operation, so you need to create a Model which takes the db as a parameter to a method. Don't set the constructor of the object to take the DB and store it as a field. For some reason this creates connection leaks and the connections won't release when they are done with your query. Not sure why, but that's how it is.
Create a Model object that you will use to execute your query. Instead of passing the DB through the object's constructor, pass it through the method you will create:
object DBChecker {
def attemptLogin(db:Database, password:String): String = {
}}
In your method, use the method .withConnection { conn => to access your JDBC connection. So, something like this:
object DBChecker {
def attemptLogin(db:Database, password:String):String = {
var username: String = ""
db.withConnection{ conn =>
val query:String = s"SELECT uploaded_by, date_added FROM tableName where PASSWORD = $password ;"
val stmt = conn.createStatement()
val qryResult:ResultSet = stmt.executeQuery(query)
// then iterate over your ResultSet to get the results from the query
if (qryResult.next()) {
userName = qryResult.getString("uploaded_by")
}
}
}
return username
}
// but note, please look into the use of PreparedStatement objects, doing it this way leaves you vulnerable to SQL injection.
In your Controller, as long as you import the object, you can then call that object's methods from your controller you made in Step 1.
import com.path.to.object.DBChecker
#Singleton
class LoginRegController #Inject()(myDB: Database, cc: ControllerComponents ) { def attemptLogin(pass:String) = Action {
implicit request: Request[AnyContent] => {
val result:String = DbChecker.attemptLogin(pass)
// do your work with the results here
}
Let's say If I have 2 Schema below.Both of them are in a same MySQL server.
master
base
The problem is I can't use more than 2 schema actions in a single Database run.
If I execute such plain sql queries via sql, It works without any problem.
def fooAction(name: String) = {
sql"""
SELECT AGE FROM MASTER.FOO_TABLE WHERE NAME = $name
""".as[String].head
}
def barAction(id: String) = {
sql"""
SELECT BAZ FROM BASE.BAR_TABLE WHERE ID = $id
""".as[String].head
}
def execute = {
//It doesn't matter which Db I use in here But Let's say this baseDb is pointing to BASE schema.
baseDb.run(for{
foo <- fooAction("sample")
bar <- barAction("sample")
} yield foo + bar)
}
But the case of code blow doesn't
class FooTableDAO #Inject() (#NamedDatabase("master") protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
import dbConfig.driver.api._
val table = TableQuery[FooTable]
def fooAction(name: String) = table.filter{_.name == name}.map{_.age}.result.head
}
class BarTableDAO #Inject() (#NamedDatabase("base") protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile] {
import dbConfig.driver.api._
val table = TableQuery[BarTable]
def fooAction(id: String) = table.filter{_.id == id}.map{_.baz}.result.head
}
def execute = {
//com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'BASE.FOO_TABLE' doesn't exist
baseDb.run(for{
foo <- fooTableDAO.fooAction("sample")
bar <- barTableDAO.barAction("sample")
} yield foo + bar)
}
Since baseDb is pointing to BASE schema, It tries to find FOO_TABLE in MASTER schema. All What I want slick to do is use different schema for each query but I couldn't find the way.
Currently I do DBIO.from(db.run(**)) if another schema action is needed in a for-comprehension of DBIO action or execute each actions via run and wrap them with EitherT which is scala library named cats's monad transformer for Either to keep using for-comprehension.
Is there any way to handle more than 2 schemas in a single DBIO Action except using plain text query?
Thanks in advance.
I think (though I am not an MySQL expert) you mean schema, not a database. At least this is what I see from your SQL samples.
Can't you just use schema attribute in your Slick table mappings? Here you have complete answer for using different schemas: https://stackoverflow.com/a/41090987/2239369
Here is the relevant piece of code:
class StudentTable(tag: Tag) extends Table[Student](tag, _schemaName = Option("database2"), "STUDENT") {
...
}
(notice _schemaName attribute).
With this in mind answer to this part of the question:
Is there any way to handle more than 2 schemas in a single DBIO Action except using plain text query?
is: Yes you can.
I'm implementing an actor-based app in scala and I'm trying to be able to pass functions between the actors for them to be processed only when some message is received by the actor.
import actors.Actor
import java.util.Random
import scala.Numeric._
import Implicits._
class Constant(val n:Number) extends Actor{
def act(){
loop{
receive{
case "value" => reply( {n} )
}
}
}
}
class Arithmetic[T: Numeric](A: ()=>T, B: ()=>T) extends Actor{
def act(){
receive{
case "sum" => reply ( A() + B() )
/* case "mul" => reply ( A * B )
*/
}
}
}
object Main extends App{
val c5 = new Constant(5)
c5.start
val a = new Arithmetic({c5 !! "value"}, {c5!!"value"} )
a.start
println(a!?"sum")
println(a!?"mul")
}
In the example code above I would expect the output to be both 5+5 and 5*5. The issue is that reply is not a typed function and as such I'm unable to have the operator (+,*) to operate over the result from A and B.
Can you provide any help on how to better design/implement such system?
Edit: Code updated to better reflect the problem. Error in:
error: could not find implicit value for evidence parameter of type Numeric[Any]
val a = new Arithmetic({c5 !! "value"}, {c5!!"value"} )
I need to be able to pass the function to be evaluated in the actor whenever I call it. This example uses static values but I'll bu using dynamic values in the future, so, passing the value won't solve the problem. Also, I would like to receive different var types (Int/Long/Double) and still be able to use the same code.
The error: Error in: error: could not find implicit value for evidence parameter of type Numeric[Any]. The definition of !!:
def !! (msg: Any): Future[Any]
So the T that Arithmetic is getting is Any. There truly isn't a Numeric[Any].
I'm pretty sure that is not your problem. First, A and B are functions, and functions don't have + or *. If you called A() and B(), then you might stand a chance... except for the fact that they are java.lang.Number, which also does not have + or * (or any other method you'd expect it to have).
Basically, there's no "Number" type that is a superclass or interface of all numbers for the simple reason that Java doesn't have it. There's a lot of questions touching this subject on Stack Overflow, including some of my own very first questions about Scala -- investigate scala.math.Numeric, which is the best approximation for the moment.
Method vs Function and lack of parenthesis
Methods and functions are different things -- see tons of related questions here, and the rule regarding dropping parenthesis is different as well. I'll let REPL speak for me:
scala> def f: () => Int = () => 5
f: () => Int
scala> def g(): Int = 5
g: ()Int
scala> f
res2: () => Int = <function0>
scala> f()
res3: Int = 5
scala> g
res4: Int = 5
scala> g()
res5: Int = 5