Use method in sql interpolator - sql

Using scala 2.11 and Slick 2.11
In a scala class, I have 2 methods:
getSQL which returns String SQL
getSqlStreamingAction which returns a composed SqlStreamingAction using sql interpolator
The code
def getSQL(id: Int): String = {
var fields_string = "";
for ((k,v) <- field_map) fields_string += k + ", ";
fields_string = fields_string.dropRight(2) // remove last ", "
"SELECT "+ fields_string +" FROM my_table WHERE id = " + id
}
def getSqlStreamingAction (id: Int): SqlStreamingAction[Vector[OtherObject], OtherObject, Effect] = {
val r = GetResult(r => OtherObject(r.<<, r.<<))
// this works
var fields_string = "";
for ((k,v) <- field_map) fields_string += k + ", ";
sql"""SELECT #$fields_string FROM my_table WHERE id = #$id""".as(r)
// But I want to use the method getSQL to retrieve the SQL String
// I imagine something like this, but of course it doesn't work :)
//sql"getSQL($id)".as(r)
I want to have separated methods for unit tests purposes, so I want to use getSQL method for sql interpolator
So, how can I use a method for Slick sql interpolator?
Note: I'm pretty new in Scala

-1 for me.
Solution:
def getSqlStreamingAction (id: Int): SqlStreamingAction[Vector[OtherObject], OtherObject, Effect] = {
val r = GetResult(r => OtherObject(r.<<, r.<<))
var sql_string: String = getSQL(id)
sql"""#$sql_string""".as(r)

Related

How to solve PW Generator can´t handle specific Chars?

I´m new to Kotlin so first I start with a Password Generator. I do use IntelliJIDea
fun main() {
var helper = Int
var counter = 0
val counterOfPwCha = 10
var pwString = ""
val opportunityArray = arrayOf('A','C','a','c','B','b','D','d','E','e','F','f','#','+','*','$','%','&','§','G','g','H','h','I','i','J','j','k','K','1','2','3','4','5','6','7','8','9',
'l','L','M','m','N','n','O','o','P','p','Q','q','R','r','S','s','T','t','U','u','V','v','W','w','Y','y','X','x','Z','z','<','>','|','?','!',)
while (counter <= counterOfPwCha)
{
helper = (0..73).random()
pwString += opportunityArray[helper]
counter++
}
println(pwString)
}
it workes fine, but the output isn´t what I expected.
Example: +3�2L%II>J�
So it cant handle some of my Chars, I can debug it until I know what kind of Char he can´t handle with and delete them from the Array, but they are all some typical PW Chars, so my question is:
How can I let Kotlin know, how to Handle these ASCI2 chars?
Or is it because of the $?
Avoid hardcoded numbers like the "73" in your range, it's way too error prone!
If you still get funny characters, put in some println that shows each character's numeric value so that you can lookup it using "man ascii".
A more Kotlin-like code would be:
fun pwgen() {
val counterOfPwCha = 10
val charset = ('A'..'Z') + ('a'..'z') + ('0'..'9') + listOf('#', '+', '*', '$', '%', '&', '§', '<', '>', '|', '?', '!')
val pwString = (1..counterOfPwCha)
.map {
val randomArrayIndex = charset.indices.random()
charset[randomArrayIndex]
}
.onEach { c -> println("Character $c = " + c.toInt()) }
.joinToString("")
println(pwString)
}
fun main() {
var helper = Int
var counter = 0
val counterOfPwCha = 10
var pwString = ""
val opportunityArray = arrayOf('A','C','a','c','B','b','D','d','E','e','F','f','#','+','*','$','%','&','§','G','g','H','h','I','i','J','j','k','K','1','2','3','4','5','6','7','8','9',
'l','L','M','m','N','n','O','o','P','p','Q','q','R','r','S','s','T','t','U','u','V','v','W','w','Y','y','X','x','Z','z','<','>','|','?','!',)
while (counter <= counterOfPwCha)
{
helper = (0..73).random()
pwString += opportunityArray[helper]
counter++
}
println(pwString)
}

Kotlin - The caracter literal does not conform expect type Int

I'm struggling with types with my program, I've been asked to do it in JS first and it worked fine but now I can't achieve the result.
Do you think I should make another 'algorithm' ? In advance, thank you for your time.
fun main(){
// the idea is to put numbers in a box
// that cant be larger than 10
val data = "12493419133"
var result = data[0]
var currentBox = Character.getNumericValue(data[0])
var i = 1
while(i < data.length){
val currentArticle = Character.getNumericValue(data[i])
currentBox += currentArticle
println(currentBox)
if(currentBox <= 10){
result += Character.getNumericValue(currentArticle)
}else{
result += '/'
//var resultChar = result.toChar()
// result += '/'
currentBox = Character.getNumericValue(currentArticle)
result += currentArticle
}
i++
}
print(result) //should print 124/9/341/91/33
}
The result is actually of a Char type, and the overload operator function + only accepts Int to increment ASCII value to get new Char.
public operator fun plus(other: Int): Char
In idomatic Kotlin way, you can solve your problem:
fun main() {
val data = "12493419133"
var counter = 0
val result = data.asSequence()
.map(Character::getNumericValue)
.map { c ->
counter += c
if (counter <= 10) c.toString() else "/$c".also{ counter = c }
}
.joinToString("") // terminal operation, will trigger the map functions
println(result)
}
Edit: If the data is too large, you may want to use StringBuilder because it doesn't create string every single time the character is iterated, and instead of using a counter of yourself you can use list.fold()
fun main() {
val data = "12493419133"
val sb = StringBuilder()
data.fold(0) { acc, c ->
val num = Character.getNumericValue(c)
val count = num + acc
val ret = if (count > 10) num.also { sb.append('/') } else count
ret.also { sb.append(c) } // `ret` returned to ^fold, next time will be passed as acc
}
println(sb.toString())
}
If you want a result in List<Char> type:
val data = "12493419133"
val result = mutableListOf<Char>()
var sum = 0
data.asSequence().forEach {
val v = Character.getNumericValue(it)
sum += v
if (sum > 10) {
result.add('/')
sum = v
}
result.add(it)
}
println(result.joinToString(""))

kotlin SQLite database always writing default values, never new ones

here is the class I set up for my database. database handler being the inner class.
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.content.ContentValues
import android.util.Log
import java.sql.Date
class Scores {
var id : Int = 0
var dataBaseName = "ScoreDatabase"
var averageTime = 0.0f
val date = Date(System.currentTimeMillis()).toString()
constructor(averageTime:Float) {
this.averageTime = averageTime
Log.d("Poop", averageTime.toString())
}
constructor()
inner class DataBaseHandler(var context:Context, tableName:String): SQLiteOpenHelper(context, dataBaseName, null,1){
val TABLE_NAME = tableName
val COL_ID = "id"
val COL_AVG = "Average_Time"
val COL_DATE = "Date"
override fun onCreate(db: SQLiteDatabase?) {
val createTable = "CREATE TABLE " + TABLE_NAME +" (" +
COL_ID +" INTEGER PRIMARY KEY AUTOINCREMENT," +
COL_AVG + " VARCHAR(256)," +
COL_DATE +" VARCHAR(256)"
db?.execSQL(createTable)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
fun insertData(score: Scores){
val db = this.writableDatabase
var cv = ContentValues()
cv.put(COL_AVG,score.averageTime)
cv.put(COL_DATE,score.date)
var result = db.insert(TABLE_NAME,null,cv)
if(result == -1.toLong())
Log.d("POOP", "fail score table in addition")
else
Log.d("POOP", "Success score table in addition" )
}
fun readData(): MutableList<Scores>{
var list: MutableList<Scores> = ArrayList()
val db = this.readableDatabase
val query = "Select * from $TABLE_NAME"
val result = db.rawQuery(query,null)
if (result.moveToFirst()){
do {
var score = Scores()
var id = result.getString(0).toInt()
var AvgTime = result.getString(1).toFloat()
var date = result.getString(2).toString()
list.add(score)
}while (result.moveToNext())
}
result.close()
db.close()
return list
}
}
}
I tried this where the scores class and the handler were two separate classes, but it generated the same results.
here is how I write to the database (from 4 separate activities. in each activity the tablename is different. in this one for example it is 'additionDataBase')
val scores = Scores("%.3f".format(timeKeeper.averageNumber).toFloat())
val db = scores.DataBaseHandler(context, "additionDataBase")
db.insertData(scores)
and here is how I read from the database which is in a different activity that shows the averageTime from each table. here is the code for one of them
val context: Context? = activity
val adb = Scores().DataBaseHandler(context!!,"additionDataBase")
val data = adb.readData()
TextViewAdScore.text = data[0].averageTime.toString() + " " + data[1].date
I think I am missing something, but I can't seem to find what it is.
so far, no matter how many times I do this. the output is always 0.0f
Look at what you do in readData:
var score = Scores()
var id = result.getString(0).toInt()
var AvgTime = result.getString(1).toFloat()
var date = result.getString(2).toString()
list.add(score)
id, AvgTime, and date are retrieved but not used in any way, so your code is equivalent to just writing list.add(Scores()). (Side note: there's no reason for them to be var, and why the case inconsistency between AvgTime and the rest?)

Squeryl geo queries with a postgres backend?

How can I perform geo queries using Squeryl with a postgres backend? The sort of queries I want to run are "return all users within x kilometres", etc.
If geo queries aren't supported directly/through a plugin, how can I run raw SQL queries? I saw one gist and it looked complicated.
Update
Specifically I want to run the following query:
SELECT events.id, events.name FROM events
WHERE earth_box( {current_user_lat}, {current_user_lng},
{radius_in_metres}) #> ll_to_earth(events.lat, events.lng);
This is taken from http://johanndutoit.net/searching-in-a-radius-using-postgres/
This object should solve your problem.
object object RawSql {
def q(query: String, args: Any*) =
new RawTupleQuery(query, args)
class RawTupleQuery(query: String, args: Seq[Any]) {
private def prep = {
val s = Session.currentSession
val st = s.connection.prepareStatement(query)
def unwrap(o: Any) = o match {
case None => null
case Some(ob) => ob.asInstanceOf[AnyRef]
case null => null
case a#AnyRef => a
case a#_ => a
}
for(z <- args.zipWithIndex) {
st.setObject(z._2 + 1, unwrap(z._1))
}
st
}
def toSeq[A1]()(implicit f1 : TypedExpressionFactory[A1,_]) = {
val st = prep
val rs = st.executeQuery
try {
val ab = new ArrayBuffer[A1]
val m1 = f1.thisMapper.asInstanceOf[PrimitiveJdbcMapper[A1]]
while(rs.next)
ab.append(m1.convertFromJdbc(m1.extractNativeJdbcValue(rs, 1)))
ab
}
finally {
rs.close()
st.close()
}
}
def toTupleSeq[A1,A2]()(implicit f1 : TypedExpressionFactory[A1,_], f2 : TypedExpressionFactory[A2,_]) = {
val st = prep
val rs = st.executeQuery
try {
val ab = new ArrayBuffer[(A1,A2)]
val m1 = f1.thisMapper.asInstanceOf[PrimitiveJdbcMapper[A1]]
val m2 = f2.thisMapper.asInstanceOf[PrimitiveJdbcMapper[A2]]
while(rs.next)
ab.append(
(m1.convertFromJdbc(m1.extractNativeJdbcValue(rs, 1)),
m2.convertFromJdbc(m2.extractNativeJdbcValue(rs, 2))))
ab
}
finally {
rs.close()
st.close()
}
}
}
}
I got from this gist:
https://gist.github.com/max-l/9250053

How to use ScalaQuery to insert a BLOB field?

I used ScalaQuery and Scala.
If I have an Array[Byte] object, how do I insert it into the table?
object TestTable extends BasicTable[Test]("test") {
def id = column[Long]("mid", O.NotNull)
def extInfo = column[Blob]("mbody", O.Nullable)
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Blob)
Can I define the method used def extInfo = column[Array[Byte]]("mbody", O.Nullable), how to operate(UPDATE, INSERT, SELECT) with the BLOB type field?
BTW: no ScalaQuery tag
Since the BLOB field is nullable, I suggest changing its Scala type to Option[Blob], for the following definition:
object TestTable extends Table[Test]("test") {
def id = column[Long]("mid")
def extInfo = column[Option[Blob]]("mbody")
def * = id ~ extInfo <> (Test, Test.unapply _)
}
case class Test(id: Long, extInfo: Option[Blob])
You can use a raw, nullable Blob value if you prefer, but then you need to use orElse(null) on the column to actually get a null value out of it (instead of throwing an Exception):
def * = id ~ extInfo.orElse(null) <> (Test, Test.unapply _)
Now for the actual BLOB handling. Reading is straight-forward: You just get a Blob object in the result which is implemented by the JDBC driver, e.g.:
Query(TestTable) foreach { t =>
println("mid=" + t.id + ", mbody = " +
Option(t.extInfo).map { b => b.getBytes(1, b.length.toInt).mkString })
}
If you want to insert or update data, you need to create your own BLOBs. A suitable implementation for a stand-alone Blob object is provided by JDBC's RowSet feature:
import javax.sql.rowset.serial.SerialBlob
TestTable insert Test(1, null)
TestTable insert Test(2, new SerialBlob(Array[Byte](1,2,3)))
Edit: And here's a TypeMapper[Array[Byte]] for Postgres (whose BLOBs are not yet supported by ScalaQuery):
implicit object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.pos += 1
r.rs.getBytes(r.pos)
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.pos += 1
r.rs.updateBytes(r.pos, v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new SQueryException("Cannot convert BYTEA to literal")
}
I just post an updated code for Scala and SQ, maybe it will save some time for somebody:
object PostgresByteArrayTypeMapper extends
BaseTypeMapper[Array[Byte]] with TypeMapperDelegate[Array[Byte]] {
def apply(p: org.scalaquery.ql.basic.BasicProfile) = this
val zero = new Array[Byte](0)
val sqlType = java.sql.Types.BLOB
override val sqlTypeName = "BYTEA"
def setValue(v: Array[Byte], p: PositionedParameters) {
p.pos += 1
p.ps.setBytes(p.pos, v)
}
def setOption(v: Option[Array[Byte]], p: PositionedParameters) {
p.pos += 1
if(v eq None) p.ps.setBytes(p.pos, null) else p.ps.setBytes(p.pos, v.get)
}
def nextValue(r: PositionedResult) = {
r.nextBytes()
}
def updateValue(v: Array[Byte], r: PositionedResult) {
r.updateBytes(v)
}
override def valueToSQLLiteral(value: Array[Byte]) =
throw new org.scalaquery.SQueryException("Cannot convert BYTEA to literal")
}
and then usage, for example:
...
// defining a column
def content = column[Array[Byte]]("page_Content")(PostgresByteArrayTypeMapper)