Skip to content

Slick 2.0.xをPlay! framework2.2から使う

Slick 2.0.xをPlay! framework2.2から使う published on Slick 2.0.xをPlay! framework2.2から使う へのコメントはまだありません

はじめに

タイトルにPlayも含めてるけど、今回のエントリーは主にSlick 2.0.xの話。

そして、最初に一言言わせて欲しい。Slickのドキュメントは分かりにくい or 不十分。ただ、「お前が貢献しろよ」、という真っ当な指摘が来そうなので、これに関してはあまり深入りはしない。

まずは今回の目的を。

目的・ゴール

簡単に今回の目標を書いておく。

  • Play! framework 2.2.xで、Slickを使ってDBにアクセスする。
  • DBのスキーマからコードを自動生成する機能を使う。

後者に関してだけど、DBのテーブルは生のSQLを使うことが多いので、あると非常に便利。幸い、Slickにはコード自動生成の機能があるので、それを使う。

ScalaのDB library

本題に入る前に、今回のエントリーの背景を少し。

今実験的に動いているプロジェクトでは、前回のプロジェクトと同じくPlay! 2.2を使うことにした。慣れてるし。でも、せっかくだし何か新しいことも試さないと、ということで、DBライブラリーは今まで使ったこと無いSlickを使うことにした。

今まではSquerylScalikeJDBCを使った事があって、どちらにも大きな不満はそれほどなかった。実際、両方共いいライブラリだと思う。後から出てきたScalikeJDBCの方が設計は綺麗だと思うけど。

その他、Play!の場合Anormという選択肢もあるけど、知り合いの信頼の置ける開発者から「論外」みたいな話を聞いたことがあるし、ドキュメントを見る限り基本的というか低レベルなので、あまり開発効率向上にはつながらなさそう、ということで除外。

環境

さて、本エントリーの環境。

  • Play! framework 2.2.2
  • play-slick 0.6.0.1 (Play!でSlickを使うためのプラグイン)
  • Slick 2.0.0 (play-slickのバージョンによって使えるSlickのバージョンが異なる)

以下、本題。

Continue reading Slick 2.0.xをPlay! framework2.2から使う

SquerylでPostgreSQLのgeometry関連関数を使う

SquerylでPostgreSQLのgeometry関連関数を使う published on SquerylでPostgreSQLのgeometry関連関数を使う への1件のコメント

以前別ブログで、Squerylで最初からは用意されていない集計関数(median)を実装する、というエントリを書いた。今回はそれと似た内容で、PostgreSQLの位置情報の関数をSquerylで使えるようにしてみる。

Squeryl 0.9.5-6

距離を調べるSQL

今回使いたいのは、2点間の距離を調べる <-> という関数。例えば、以下のクエリーのように、ある位置(36.726637,139.526557)から3000m以内にある点のうち、距離が近い順に30件取得したいとする。これをSquerylを使って実現したい。

SELECT p.*, (p.latlng <-> POINT(36.726637,139.526557)) * 111000 as l
FROM place p
WHERE (p.latlng <-> POINT(36.726637,139.526557)) < 3000.0 / 111000.0
ORDER BY p.latlng <-> POINT(36.726637,139.526557)
LIMIT 30

Continue reading SquerylでPostgreSQLのgeometry関連関数を使う

Play! frameworkのテンプレートでパターンマッチを使う方法

Play! frameworkのテンプレートでパターンマッチを使う方法 published on Play! frameworkのテンプレートでパターンマッチを使う方法 へのコメントはまだありません

Play!のテンプレートは型安全だし、中でScalaが使えるのでそこそこ便利なんだけど、スペースの有無でコンパイルが通らなかったりとか、色々面倒な部分も。

特にパターンマッチを使いたかったのに、なかなかうまく行かなくて色々試行錯誤した。

結論から言うと、以下のように改行を入れるとOKだった(公式サイトのTemplateのuse caseのページより引用)。

@level match {

  case "success" => {
    <p class="success">
      @body("green")
    </p>
  }

  case "warning" => {
    <p class="warning">
      @body("orange")
    </p>
  }

  case "error" => {
    <p class="error">
      @body("red")
    </p>
  }

}

環境:Play! framework 2.2

Play! frameworkでモバイルサイトを作る

Play! frameworkでモバイルサイトを作る published on Play! frameworkでモバイルサイトを作る へのコメントはまだありません

冬休みの宿題ということで、前からぼちぼち作っているサイトのモバイル版を作ろうと思った。モバイル向けの部分はjQuery Mobileを使うことにした(これに関しては別エントリーで)。

環境

  • Play! framework 2.2

(主に)3種類の選択肢

desktopとmobile (smart phone)の両方に対応したサイトを作る場合、主に以下の3通りがある。

  1. 同じURL。User-Agentで判断して異なるHTML、CSS、JavaScriptを返す。
  2. 異なるURL。(www.example.com と m.example.com など)
  3. 同じURL。レスポンシブデザイン。

(3は今の自分がやるには面倒なのでとりあえず除外するとして)、どれがいいんだろう?と思ってちょっとググってみたところ、Googleのこんなページが見つかった。

正直、ユーザーにとっては同じURLだろうと異なるURLだろうとそんな気にしないだろうから(自動的にリダイレクトしてくれれば)、SEOという観点は重要かなと思った。

で、結論として1番の同じURL、異なるコンテンツ、という方式を選ぶことにした。

Continue reading Play! frameworkでモバイルサイトを作る

Play! framework 2.1 → 2.2に上げた

Play! framework 2.1 → 2.2に上げた published on Play! framework 2.1 → 2.2に上げた への1件のコメント

正月休みを利用して、Play! framework 2.1のプロジェクトを2.2にした。あ、皆様あけましておめでとうございます。

結論から言っちゃうと、Play 2.2 Migration Guideに書いてある情報で大体網羅されていた。

Play自体のアップグレード

Migration Guide通り、Build.scalaとか修正すればOK。最新バージョンは2.2.1なので、ドキュメントに2.2.0って書いてある所は、2.2.1と置き換えて読めばOK。

サードパーティライブラリのアップグレード

Playのプラグインとかライブラリでは、Play 2.1.xの人はバージョンMを、Play 2.2.xの人はバージョンNを使ってくれ、っていうパターンのものが結構ある。

そういったライブラリとかのバージョンを正しいものに変更せずにビルドしようとすると、以下の様なエラーが出た。

[error] Modules were resolved with conflicting cross-version suffixes in {file:/Users/kazu/Documents/workspace/projectfoo/}projectfoo:
[error]    org.scala-stm:scala-stm _2.10, _2.10.0
[trace] Stack trace suppressed: run last projectfoo/*:update for the full output.
[error] (projectfoo/*:update) Conflicting cross-version suffixes in: org.scala-stm:scala-stm
[error] Total time: 0 s, completed Jan 1, 2014 12:31:37 AM

個人的に使っていて、バージョン変更する必要があったのはこの辺。

ソースの変更

自分が必要となったところだけ記載。

Result -> SimpleResult

これもMigration Guideに書いてあるけど、play.api.mvc.Resultはdeprecatedになった。

play2-auth関連のコードも修正が必要。具体的にはAuthConfigImpleの各メソッドのシグニチャーを変更すればOK。

Jackson

パッケージ名が変わってる。org.codehaus.jackson → com.fasterxml.jackson

その他(追記)

evolutionsが再実行されそうに

開発環境で起動したら、evolutionsでかなり昔まで戻ってから再実行されそうになった。例えば、現在の最新が50.sqlだとして、20.sqlまでDownが実行され、その後再度20〜50.sqlのUpが実行されそうになった。

原因は、20.sql を適用した後に、20.sql をいじった為だと思う。ただ、Play 2.1の時には、適用済みの古いスクリプトを修正してもそこまで巻き戻らなかったんだけど、Play 2.2で若干仕組みが変わったらしい。詳しくはこちらを参照。

対策として、新しいまっさらなDBを作ってそこでevolutionsを実行し、その後play_evolutionsテーブルから必要なエントリーを元のDBに移し替えること。

specs2関連

以前は以下のようなのがOKだったが、

listOfStrings must contain("A", "B") //A, Bが両方含まれていないとダメ
listOfStrings must not contain("C", "D") // C, Dのどっちかでも含まれていたらダメ

以下のように書き換えないとダメだった。specs2のバージョンは一緒なのに何でだろう。Scalaのバージョンが変わったからかな?

listOfStrings must contain(allOf("A", "B")) //A, Bが両方含まれていないとダメ
listOfStrings must not contain("C")
listOfStrings must not contain("D")

最後に

Play 2.0 → 2.1の時よりは楽だった気がする。あの時はJson周りとか結構変更になったし。

現状、コンパイル通っただけで、まだあんまりテストしてないので、何かあれば追記予定。

ScalaのFutureがブロックする?(深く調べてない)

ScalaのFutureがブロックする?(深く調べてない) published on ScalaのFutureがブロックする?(深く調べてない) への3件のコメント

ScalaのFutureで(あるいはPlay?)で処理がブロックされてしまう現象があった。

環境

  • Scala 2.10.1
  • Play 2.1.3
  • (Playのモデルクラスを使っているだけで、scalaコマンドから起動されるバッチ処理)

簡略化するとこんなコード(実際はもっと分割されてるし、whileじゃなくてtailrecだけど)。

import scala.concurrent.Await
import scala.concurrent.duration._
import play.api.libs.concurrent.Execution.Implicits._
 
for {
  photo <- listOfPhotos
} yield {
  // downloadはサードパーティライブラリのメソッドで
  // Future[java.io.File]を返す
  val fut = photo.download map { file =>
    Logger.debug("start!") //ここまでは実行される。
    // SomeApi.postFileの挙動は、responseが返るまでブロックする。
    // しかし、↓が実行されない
    SomeApi.postFile(file) map { jobId =>
      var complete = false
      var result = None
      while (!complete) {
        Thread.sleep(5000)
        val job = SomeApi.getJob(jobId)
        if (job.isComplete()) {
          complete = true
          result = job.getResult()
          // resultに対して処理
        }
      }
    }
  }
  try {
    Await.result(fut, 120 seconds)
  } catch {
    case e: Exception => Logger.error(e.getMessage())
  }
}

Continue reading ScalaのFutureがブロックする?(深く調べてない)

Play! framework 2.xでJSONを扱う方法をいくつか

Play! framework 2.xでJSONを扱う方法をいくつか published on Play! framework 2.xでJSONを扱う方法をいくつか へのコメントはまだありません

Webサイト作ってると、JSONを扱うことが多い。なので、Play! frameworkで、ScalaのオブジェクトからJSON文字列に、あるいはその逆をやりたいよね、と(特に前者)。

そんな今回はObject -> JSONの方法をいくつかまとめてみた。

環境は Play 2.1.1。そのうち2.2にアップグレードしようと思うけど。

ちなみに Scala Advent Calendar 2013 の 12日目の記事ですら。

Continue reading Play! framework 2.xでJSONを扱う方法をいくつか

Cache play already exists

Cache play already exists published on Cache play already exists へのコメントはまだありません

バッチからPlay.startを実行するとエラー

こちらを参考に、play frameworkで作ったwebサイトのバックグラウンド用タスクを作成し実行した。それに関しては別途エントリーを書くとして、以下のようにPlay.startを実行すると、

    Play.start(new DefaultApplication(new java.io.File("."), cl, None, Mode.Prod))

その時に以下の様なエラーが出た。

Continue reading Cache play already exists

SquerylでORDER BY NULLS FIRST (又はLAST)を実行するには

SquerylでORDER BY NULLS FIRST (又はLAST)を実行するには published on SquerylでORDER BY NULLS FIRST (又はLAST)を実行するには へのコメントはまだありません

本記事は、MLで質問して返ってきた内容をまとめただけ。

ORDER BYを指定した時のNULLの扱い

SQLでORDER BYを指定した時、その列にNULLがあった場合、その行はどこに来るのか?デフォルトだと「最小の値」として処理されるんだけど、いくつかのDBMSではNULLS FIRSTあるいはNULLS LAST句を付けることによってその動作を制御することが出来る。

SquerylでNULLS FIRST/LASTを扱うには

以下の様なのを作って、

import org.squeryl.dsl.ast.{FunctionNode, ExpressionNode}
import org.squeryl.internals.StatementWriter

object OrderBy {
  def nullsLast(col: ExpressionNode) = new FunctionNode("", None, Seq(col)) {
    override def doWrite(sw: StatementWriter) = {
      col.write(sw)
      sw.write(" nulls last")
    }
  }

  def nullsFirst(col: ExpressionNode) = new FunctionNode("", None, Seq(col)) {
    override def doWrite(sw: StatementWriter) = {
      col.write(sw)
      sw.write(" nulls first")
    }
  }
}

後は、クエリーを組み立てる所で以下のようにするだけ。

import com.example.OrderBy.nullsLast
// ...
        orderBy(nullsLast(someColumn) desc))

分かってしまえば簡単だった。

Lift CSS SelectorとAjax

Lift CSS SelectorとAjax published on Lift CSS SelectorとAjax へのコメントはまだありません

相変わらずボチボチLiftを触ってる。Lift 2.2 M1から入った便利な機能として、CSS Selectorがある。詳しくはWikiの該当のエントリを見てもらうとして、それとAjaxを組み合わせる方法。

■環境

Lift 2.2

■やりたい事

<form>タグを使った例はSimply Liftの4.8に載っているんだけど、普通のボタン(ajaxButton)を使いたかった。

DBのテーブルよりデータを取得して、HTMLの表にして出力。各行についているボタンをクリックすると、その行のデータに対する何らかの処理が行われるようにしたい。

結論から言うと簡単。

Continue reading Lift CSS SelectorとAjax