Tuesday, November 13, 2018

Fixing Homebrew Linking Issues

If you get in Homebrew:
Error: An unexpected error occurred during the `brew link` step
The formula built, but is not symlinked into /usr/local
Permission denied @ dir_s_mkdir - /usr/local/XXX

Then run the following to resolve:
sudo chown -R $(whoami) $(brew --prefix)/*
sudo install -d -o $(whoami) -g admin /usr/local/XXX

And either run brew again to install or brew link (whatever package that had the problem)

Tuesday, August 30, 2016

Dependancy Injection and Anorm

Moving from Play Framework 2.4.x to 2.5.x requires to drop global variables. Specifically in this case play.api.Play.current and play.api.db.DB.

Most of my models using Anorm have a simple form:
case class Model(id:Long, name:String, …)

case object Model {
  val model=get[Long]("id")~get[String]("name")~ … map {
    case id~name~ … => Model(id, name, …)
  }
  def findById(id:Long):Option[Model]=DB.withConnection { implicit c=>
    SQL"SELECT * FROM models WHERE modelId=$id".as(model*).headOption
  }
}

In 2.5.x, DB is now deprecated. It is recommended to use dependancy injection.
Here's a minimum to support 2.5.x:
1. Instead of changing much (such as not using a case object), change DB to implicit.
    def findById(id:Long)(implicit db:Database):Option[Model]=db.withConnection { implicit c=>
       SQL"SELECT * FROM models WHERE modelId=$id".as(model*).headOption
    }  

2. For every controller using models, add @Inject()(db: Database), e.g., 
       class Application @Inject()(db: Database) extends Controller {
          implicit val dbImplicitVal=db

3. For every AKKA actor using models, add (db:Database), e.g., 
      class Logger(db:Database) extends Actor {
     and by calling props with a valid database when requesting an actor, e.g., 
       val logger=actorSystem.actorOf(Props(new Logger(db)))

Simple and minimal.





Sunday, December 27, 2015

Simulate location routes when debugging in Xcode

If you want to simulate a route when debugging in Xcode, you'll need to create a gpx file add it to your Xcode project and then choose it when you run your app.

The hardest part is to create a gpx file. Xcode requires gpx files to be in a specific format.
So first create a gpx format by one of the available online map services. I used Graphhopper with satisfactory results (https://graphhopper.com/maps/).
Next, translate the resulting file to a format that Xcode will understand using the tool gpsbabel (on the Mac gpsbabel can be easily installed using homebrew).

gpsbabel -i gpx -f input.gpx -x transform,wpt=trk -o gpx -F output.gpx

And that's it.

Friday, August 7, 2015

Some tips and tricks when doing TDD with SBT (and Play Framework)

If you are doing any TDD with SBT or Play Framework, here are a few tips and tricks to make you happy.
  1. Choose the right command tool to run your tests: 
    •  test       - runs all tests.
    •  testOnly   - runs only one test (e.g. testOnly test1) or wild card specific tests (e.g. testOnly test1*).
    •  testQuick  - runs only the tests that haven't run yet or failed ones. Can be limited to a specific test scope with a wild card (e.g. testQuick test1*).
  2. Since you are going run these command many many times, add the following shortcuts in build.sbt:
    •  to  for testOnly - addCommandAlias("to", "testOnly")
    •  tq  for testQuick - addCommandAlias("tq", "testQuick")
  3. Divide your tests into groups/folders. E.g., have a folder for unit tests in folder "unit" and run those test with  to unit.* .


Saturday, July 4, 2015

Want to have different Java versions on the same Mac: jenv to the rescue

With the introduction of Play Framework 2.4.x, Play doesn't support Java 1.6 anymore. Because some applications running on the Mac require to run only with Java 1.6, there need to be some kind of a hybrid environment. jenv configuration utility to the rescue.


  • Prerequisites - Apple's Java (https://support.apple.com/downloads/java), brew (http://brew.sh/) and brew-cask (http://caskroom.io/)
  • Install Java - brew cask install java
  • Install jenv - brew install jenv & echo 'if which jenv > /dev/null; then eval "$(jenv init -)"; fi' >> ~/.bash_profile
  • Configure jenv - jenv add [JDK Folder], e.g., jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
  • Configure per Folder - jenv local [Java Version], e.g., jenv local oracle64-1.8.0.45

Monday, April 6, 2015

Play Framework, Anorm, Postgres and JSON

With the release of Postgres 9.4, JSON has become a first class citizen. JSON objects inside the DB can be indexed and searched as can regular columns in a relational DB.


If you are using Play Framework with Anorm then JSON with Postgres support doesn't come out of the box. On the bright side, it doesn't take much to make it work.


The examples below have been tested with Play Framework 2.3.7, Postgres 9.4.1 and Postgres JDBC Driver 9.4-1201.


Let's say we have a table in the DB of the following:

CREATE TABLE json_store (
   id serial PRIMARY KEY,
   data json
);
 
And here's some regular Scala code with Anorm:

import anorm.SqlParser._
import anorm._
import play.api.db.DB
import play.api.libs.json.JsValue
import play.api.Play.current

case class JsonData(id:Long, data:JsValue)

object JsonData {
 val jsonData=get[Long]("id")~get[JsValue]("data") map {
   case id~data=> JsonData(id, data)
 }

 def insert(data:JsValue):Option[Long]=DB.withConnection { implicit c=>
   SQL"INSERT INTO json_store (data) VALUES ($data)".executeInsert()
 }

 def findById(jsonId:Long):Option[JsonData]=DB.withConnection { implicit c=>
   SQL"SELECT * FROM object_store WHERE id=$jsonId".as(jsonData*).headOption
 }
}


This doesn't compile with 2 errors:

[error]  could not find implicit value for parameter extractor: anorm.Column[play.api.libs.json.JsValue]
[error]  val jsonData=get[Long]("id")~get[JsValue]("data") map {
[error]                                        ^

and

[error]  type mismatch;
[error]  found   : play.api.libs.json.JsValue
[error]  required: anorm.ParameterValue
[error]     SQL"INSERT INTO json_store (data) VALUES ($data)".executeInsert()


To fix the 1st error, we'll add an implicit that will transform a json into a string and inject it into the SQL statement:

implicit object jsonToStatement extends ToStatement[JsValue] {
 def set(s: PreparedStatement, i: Int, json: JsValue):Unit=s.setString(i, Json.stringify(json))
}

implicit object jsonToStatement extends ToStatement[JsValue] {
def set(s: PreparedStatement, i: Int, json: JsValue):Unit={
  val jsonObject=new org.postgresql.util.PGobject()  
jsonObject.setType("json")
jsonObject.setValue(Json.stringify(json)) s.setObject(i, jsonObject)
}
}


And for the 2nd error, we'll add an implicit that will transform a PGobject into JsValue:

implicit val columnToJsValue:Column[JsValue]=anorm.Column.nonNull[JsValue] { (value, meta) =>
 val MetaDataItem(qualified, nullable, clazz)=meta
 value match {
   case json:org.postgresql.util.PGobject=> Right(Json.parse(json.getValue))
   case _=> Left(TypeDoesNotMatch(s"Cannot convert $value: ${value.asInstanceOf[AnyRef].getClass} to Json for column $qualified"))
 }
}



So now everything compiles, but we do have a runtime error:
[error]    PSQLException: : ERROR: column "data" is of type json but expression is of type character varying


To overcome, we'll add the following cast:
CREATE CAST (VARCHAR AS JSON) WITHOUT FUNCTION AS IMPLICIT;

And that's all you need for adding JSON support in Play Framework with Anorm.