AnsibleでDockerとかしたいのにdocker-pyに苦しめられた話
はい。タイトル通りです。
ansibleとはpythonで動いてるけどpython書かなくてもいい不思議な何かという認識。
で、ansibleからdockerコンテナー立ち上げるときのレシピがこちら。
--- - name: Run CentOS container docker: image: "centos:centos6" name: sample001 tty: yes net: host docker_api_version: 1.18
net=host
はネット設定はデフォルト不可だよというエラーメッセージ用、
docker_api_version=1.18
は本番で動いてるdockerのバージョン違うよ用です。
なのですが、これを実行してもdocker-py
が見つからないよ系エラーが出るのです。
ということでローカルでpip install docker-py
したりしてみたのですが、
これが一向に消えてなくならない。
virtualenvがダメなのかもとか悩んでいろいろググったり試したりした結果・・・
docker-pyは設定先の環境のデフォルトpythonに必要でした!!
はい。ローカルに入っていようが関係なかったのです。
よって、必要なのは設定先ホストでのpip install
。
これもansibleに書いてしまいます。
--- - name: Install docker-py become: yes become_method: sudo become_user: root pip: name: "docker-py" version: 1.7.1 state: present
ansibleの恒等性とかを考えると、state=latest
とどっちがいいのかわかりません。
sudoはたぶん必要。と信じている。
このためにはサーバーにもpipが入っていないといけないので、 それはサーバーのディストリビューションに合わせてって感じになるのかと。
私からは以上です。
GolangでShift_JIS(Windows31J)のファイルを読み込み
たどり着くまで時間がかかったのでメモ。
文字コードを意識しないファイルの読み込み
つまりはUTF-8のファイル。BOMはどうなんだろう?(試していない)
os.Openとbufio.NewReaderで行ごとに読み込める。
注意点: 読み込み完了時はerror
にio.EOFが入る。
package main import ( "bufio" "fmt" "io" "os" ) func main() { path := "/path/to/your/file" fp, err := os.Open(path) if err != nil { panic(err) } defer fp.Close() reader := bufio.NewReader(decoder.Reader(fp)) for { line, _, err := reader.ReadLine() if err == io.EOF { break } else if err != nil { panic(err) } fmt.Println(string(line)) } }
文字コードを考慮する。
とりあえずgolang decode
とかでググってみるとencodingパッケージが出てくる。
どうやらDecoder.ReaderでラップしたReaderが作れそう。
じゃあDecoderってどうやって作るの?と探したところ、japaneseパッケージにShiftJIS
を発見。
こいつがencoding.Encoding型なので、NewDecoder
メソッドを持っているらしい。
とりあえずjapanese
パッケージをゲット
go get golang.org/x/text/encoding/japanese
package main import ( "bufio" "fmt" "golang.org/x/text/encoding/japanese" "io" "os" ) func main() { path := "/path/to/your/file" fp, err := os.Open(path) if err != nil { panic(err) } defer fp.Close() decoder := japanese.ShiftJIS.NewDecoder() reader := bufio.NewReader(decoder.Reader(fp)) for { line, _, err := reader.ReadLine() if err == io.EOF { break } else if err != nil { panic(err) } fmt.Println(string(line)) } }
bufio.NewReader
に変換する前にデコードをはさめばOK
わかれば簡単。
ScalaでゆるふあにDB接続
この記事はScala Advent Calendar 2015 12日目です。
昨日は同じく私による今日から始めるScalaプログラミングでした。
前置き
私はアプリケーションにSQLを自分で書きたい派です。
参考: ScalaでSQLが書きたいんだ!!
なので積極的に自分で書けるライブラリーが好きです。
- DBに直接繋いで、取得結果や処理速度などを調整するクエリーを書く。
- 出来上がったクエリーを作成するためのScalaコードを書く。
こんな風に作業したいのです。
doobie or not DB
ということでdoobieです。
doobieによるシンプルなDBアクセスコードは以下のような感じです。
import doobie.imports._ case class User(id: String, password: String, email: Option[String]) object User { def byId(id: String): ConnectionIO[Option[User]] = sql"SELECT id, password, email FROM users WHERE id = ${id}".query[User].option }
呼び出す側はこちら
import doobie.imports._ import scalaz.effect.IO val xa = DriverManagerTransactor[IO]( "com.mysql.jdbc.Driver", "jdbc:mysql://example.com:3306/example", "user", "password" ) val a: ConnectionIO[Option[User]] = User.byId("kazzna") val b: IO[Option[User]] = a.transact(xa) val c: Option[User] = b.unsafePerformIO
これの素晴らしいところは、接続情報がxa
にまとめられていて、それを明示的に渡すということですね。
ちなみにDriverManagerTransactor
の型引数はscalaz.Catchable
を要求してきたりするので、
IO
以外ではscalaz.concurrent.Task
ぐらいしか使える型を知りません。
(きっとガチ勢がコメントしてくれるはず・・・)
テストを書いてみる
最初に書いた通り、SQLが正しいことは確認してからScalaコードを書きたいので、 ユニットテストでDBになんて繋ぎたくないんですね。
ユニットテストで確認するのは「使用したいSQLが出力されているか」までで、 外部との接続はもうちょっと結合度の高いテストでやりたいわけです。
ですが世間一般のライブラリーはいつの間にかDB接続が暗黙的に渡されていたりして、 テストしようと思うと色々なテクニック(モックとか)を使わないと難しかったりします。
ところがこのdoobieはゆるふあ仕様で、それが簡単にできるのです!!!
val a = User.byId("kazzna") // ConnectionIO[Option[User]] val b = a.transK[IO] // Kleisli[IO, java.sql.Connection, Option[User]]
Kleisli[M[_], A, B]
とはゆるふあに言えばA => M[B]
です。
なのでこの場合はb: java.sql.Connection => IO[Option[User]]
ですね。
つまりjava.sql.Connection
を渡せばテストできるわけです。
このinterfaceを実装しましょう。
import java.sql._ import org.scalatest._ class QueryChecker(sql: String, params: Map[String, Any], result: ResultSet) extends Connection with Matches { override def prepareStatement(s: String): PreparedStatement = new PreparedStatement { s should ===(sql) override def setString(i: Int, s: String): Unit = { params(i) should ===(s) } override def executeQuery(): ResultSet = result // override def ... = ??? を必要なだけ書く } // override def ... = ??? を必要なだけ書く } class DummyResultSet(v: List[Map[Int, Any]]) extends ResultSet { var rowIndex = -1 override def next(): Boolean = { rowIndex = rowIndex + 1 rowIndex < v.length } override def getString(i: Int): String = v(rowIndex)(i).asInstanceOf[String] // override def ... = ??? を必要なだけ書く }
気を付けるべきことは、import java.sql._
でjava.sql.Array
がimportされるため、
scala.Array[A]
がArray
と書けないことです。
scala.Array
と全部ちゃんと書く必要があります。もしくは別名import。
あと、closeとかもoverrideしないとランタイムエラーが出ると思いますので、 エラーが出たところから修正していきましょう。
なお、このあたりのコードはJava用なのでmutableに書いたほうが楽だと思われます。
import org.scalatest._ class UserSpec extends FlatSpec with Matches { "Sql" should "be checked by test Connection" in { val id = "kazzna" val query = "SELECT id, password, email FROM users WHERE id = ?" val map = Map(1 -> id, 2 -> "pass", 3 -> "email@example.jp") val expected = Some(User(map(1), map(2), Some(map(3)))) val a = User.byId(id).transK[IO] val b = new QueryChecker(query, Map(1 -> id), new DummyResultSet(Seq(map))) val actual = a(b).unsafePerformIO actual should ===(expected) } }
これでDB接続情報を一度も書かずにユニットテストができました!!簡単!!
例によって例の如くQueryにはCypherを使用していますが、 一応動くサンプルをgithubにあげておきました。
最後に: 教えて怖い人!
ConnectionIO
をOptionT[ConnectionIO, A]
やEitherT[ConnectionIO, String, A]
なんかにして、
2つ3つ組み合わせて途中で失敗したら実行をやめるようなqueryを書くときに型引数つらいのですが、
なんとかなる方法はありませんか?
コメントお待ちしております(>﹏﹏<);;
以上でScala Advent Calendar 2015 12日目は終了です。
お付き合いいただきありがとうございます。
明日はOE_uiaさんによる「Scala AndroidでかDeepLearning的な何か」です。
レベルが高そうですが、楽しみです。
今日から始めるScalaプログラミング!!
この記事はScala Advent Calendar 11日目です。
昨日はdakatsukaさんによるScalaでLuaスクリプトを動かして遊ぶでした。
Luaでしたね!!
ゲーム業界すごいですね!
さて、Scala Advent Calendarですが、まだまだ空きがあります。
難しいことを書かなきゃならないという空気を吹き飛ばすため、
Scalaをやったことのない人向けの記事を書くことによってハードルを下げます。
窓口が広いほど学びも増えるはずです!!
ということで本日はScalaを始めるための環境づくりです。
インストールせずに試す!!
オンラインならIDEONE!
左下のChoose LanguageでothersのところにScalaがあります。
ライブラリーを使わないような入門書のコードなどは、ここで入力して試せますね。
もちろんLuaもあるのでLet's challenge!!
ローカルにScalaコーディング環境を構築する!!
ここからの説明は一番初心者向けということで、 Windows 10ユーザーを想定して進めます。
その他のOSの方はbrewなりportageなり環境にあったものをご使用ください。
Javaのインストール
ScalaはJava VM上で動く言語です。
そのためまずはJavaのインストールが必要です。
JavaにはJavaで作られたプログラムを動かすためのJRE
(Java Runtime Edition)と、
Javaでプログラムを作るためのJDK
(Java Development Kit)があります。
今回はプログラミングを行うのでJDK
ですね。
JDK
にはJRE
が含まれていますので、作ることも動かすことも可能です。
では、「JDK ダウンロード」などで検索してJavaダウンロードページにたどり着いてください。
プログラミングではGoogle力が試されることがよくありますので、
できる限り自力でたどり着くことが大切です。
今回ダウンロードするのはJava SE
(Standard Edition)のJDK
です。
いろいろなJavaが出てきてもう挫折しそうですよね。
細かい名前は覚えなくてもあまりScalaには関係ありません。
さて、ダウンロードページにたどり着くと、さらに多数の選択肢が出て来ます。
今回は最新版(数字が最も大きいもの)を導入します。
Java SE Development Kit 8u66
ですね。
直接Java言語でプログラミングする予定はないので、DemosやSamplesはいらないでしょう。
ライセンスに同意しろと書かれているので、きちんとライセンスを読んだ上で、
同意できるならAccept License Agreement
を選択します。
その下に並んでいるOSの一覧から、自分のOSを選択します。
WindowsにはWindows X86
とWindows x64
がありますが、
自分のOSにあった方を選択してください。
x86かx64かの確認方法
- Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
- 「システム」が開くので、真ん中ぐらいにある「システムの種類」を確認します。
- ここが「32ビット...」なら
x86
、「64ビット...」ならx64
です。 - その他だった場合は自分でググってください。初心者用ではありません。
Edgeだと、ダウンロードが完了したらそのまま実行が選べます。
インストールは何も考えずすべて「次へ」で大丈夫です。
インストールが終わったら、環境変数Path
にコマンドを追加します。
環境変数の編集はRapid Environment Editorというソフトが使いやすいらしいです。
使ったことはありませんが。
ここでは通常のWindowsの機能でPathを追加する方法を記述しておきます。
既にユーザー環境変数にPath
が存在する場合は、この記事の下の方にある「パスに追加」を見てください。
パスを設定
- Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
- 「システム」が開くので、左端にある「システムの詳細設定」を選択します。
- 「システムのプロパティ」が開くので、詳細設定タブを選択します。
- 一番下の「環境変数」をクリックします。
- 上段の「ユーザー環境変数」の「新規」をクリックします。
- 変数名に「Path」、変数値に先ほどインストールしたJDKのパスを設定します。
(インストール時にすべて「次へ」を選んでいれば「C:\Program Files\Java\jdk1.8.0_66\bin」です。) - 順番にOKを押してウィンドウを閉じます。
インストールが完了したら、コマンドプロンプトを起動してインストールが成功したことを確認しましょう。
後からやると、どこで失敗したのかわからなくてリカバリーが大変です。
スタートメニューからコマンドプロンプトを起動します。
(同じくマークを右クリック -> コマンドプロンプト(C))
すると、下記のような表示の黒い画面が表示されるはずです。
C:\Users\kazzna>
kazznaの部分はログインしているユーザーのユーザー名になっているはずです。
この部分は勝手に出てくるので、>
より後ろを入力してエンターを押すと入力した内容が実行されます。
さて、インストール成功かどうかの確認です。
こういう場合、普通はversionオプションを使用します。
java
ではなくjavac
なことに注意してください。
C:\Users\kazzna> javac -version javac 1.8.0_66
version番号が表示されれば成功です。
versionオプションは「バージョン番号を表示して終了する」という動作をするプログラムがほとんどなので、 インストールされているかどうかを悪影響なく確認できます。
自分がプログラムを作るときもそういう風にするといいと思います。
javac -version
を実行してもバージョンが表示されずエラーメッセージが出たら?
Javaのインストールの初めからやり直すしかありません。
Activatorのインストール
Scalaでよく使われるツールにsbt
があります。
sbt
を使うと、ライブラリーのインストールやコンパイル・テストなどが簡単にできます。
今回はsbt
にいろいろな機能を追加したActivator
というツールを使用します。
Activator
は内部にsbt
を使用している(らしい)ので、
sbt
でできることはすべてActivator
でできるはずです。
まずは先程と同様に「sbt activator ダウンロード」等で検索して、 Activatorのダウンロードページにたどり着きましょう。
ここでDOWNLOADを選べばWindowsではzipファイルがダウンロードされるはずです。
この記事を書いていて初めて知りましたが、sbt
の500倍ぐらいのサイズですね。
何が入ってるんだろう???
これをどこか好きな場所に展開してください。
「どこか」と言われても初心者は困るでしょうから、
決められない人はコマンドプロンプトの>
より左に書かれているフォルダに展開してください。
展開したら、activator-dist-1.3.7
というフォルダができるはずです。
後ろの番号はバージョン番号なので、もしかしたら新しいバージョンになっているかもしれませんが。
フォルダの中にactivator.bat
が入っていることを確認してください。
このフォルダのパスを環境変数に追加します。
パスに追加
- Windowsのタスクバーの左端「Windowsマーク」を右クリックし、「システム(Y)」を選択します。
- 「システム」が開くので、左端にある「システムの詳細設定」を選択します。
- 「システムのプロパティ」が開くので、詳細設定タブを選択します。
- 一番下の「環境変数」をクリックします。
- 上段の「ユーザー環境変数」にある「Path」をクリックして選択します。
- 「編集」を押すと新規作成と同じようなウィンドウが開きます。
- 既に入っている変数値の末尾にセミコロン「;」を追加した後、
activator.bat
があるフォルダのフルパスを追加します。
(ユーザー名に注意して「C:\Users\kazzna\activator-dist-1.3.7」みたいなのを入れてください。) - 順番にOKを押してウィンドウを閉じます。
コマンドプロンプトを一度閉じて、もう一度開きなおしてください。
そして、以下のコマンドを実行し、Activator
がインストールできたことを確認します。
C:\Users\kazzna> activator --version ~~ もしかしたら何行かのメッセージ ~~ sbt launcher version 0.13.8
バージョンが表示されれば成功です。
Activatorを使ってみよう!!
早速Activator
を使用してみましょう。
まずは作業用フォルダを作成します。
C:\Users\kazzna> mkdir activatorwork C:\Users\kazzna> cd activatorwork C:\Users\kazzna\activatorwork>
最初のコマンドmkdir
(make directory)でactivatorwork
というフォルダをC:\Users\kazzna
に作成しました。
次のコマンドcd
(change directory)で、直下に作成したactivatorwork
フォルダに移動しています。
3行目で左側のフォルダ名が変わっていますね。ここが現在いるフォルダです。
では、まずactivator new フォルダ名
で新しいプロジェクト用フォルダを作ってみましょう。
ここではフォルダ名はactivatortest
とします。
C:\Users\kazzna\activatorwork> activator new activatortest ~~ 何行かのメッセージ ~~ Browse the list of templates: http://typesafe.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates) >
activator new
を実行すると、どのテンプレートを使用するか確認されます。
テンプレート一覧をダウンロードするため、少し時間がかかるかもしれません。
tab
を押すと全てのテンプレートの一覧が表示され、名前か番号を入力すると次に進みます。
今回は4
と入力してminimal-scala
を使用しましょう。
> 4 OK, application "activatortest" is being created using the "minimal-scala" template. To run "activatortest" from the command line, "cd activatortest" then: /home/kazzna/tmp/activatortest/activator run To run the test for "activatortest" from the command line, "cd activatortest" then: /home/kazzna/tmp/activatortest/activator test To run the Activator UI for "activatortest" from the command line, "cd activatortest" then: /home/kazzna/tmp/activatortest/activator ui C:\Users\kazzna\activatorwork>
これでactivatorwork
フォルダにactivatortest
フォルダーが作成されました。
cd
コマンドで移動してください。
C:\Users\kazzna\activatorwork> cd activatortest C:\Users\kazzna\activatorwork\activatortest>
ここからはコマンドプロンプトはこのまま開いたままで、エクスプローラーで作業しましょう。
コマンドプロンプトが得意な方はこのまま作業していただいても構いません。
エクスプローラーを開いたら、アドレスバーにコマンドプロンプトの>
より左の部分を貼り付けてください。
ちなみに、コマンドプロンプトからのコピーは
- 右クリック -> 範囲指定
- 左ドラッグで文字を反転
- キーボードでエンターキーをたーんっ!
です。ご注意ください。
フォルダを開くと、ここにもactivator.bat
などがあるのがわかりますね。
Activator
をインストールしていない人でもプロジェクト途中から参加できるように、なのでしょうか?
ファイルがおっきいので、ここのactivator
から始まるやつは全部消してOKだと思います。
さて、この中身の説明です。
build.sbt
sbtの設定ファイルです。ここにいろいろ書くことでライブラリーやコンパイルオプションなどを変更できます。project
このフォルダの中にsbt自身の設定やsbt用のプラグインの設定を書きます。
今回の記事では触りません。src
この中に自分で作るプログラムのソースコードを置きます。
Activator
がコンパイルしてくれます。src
の中には以下のようなフォルダがあります。
src
のmain
にあるHelloworld.scala
をメモ帳などで開けばもうコーディングが可能ですね。
さて、Activator
を使ってコンパイルしてみましょう。
コマンドプロンプトに戻ります。
C:\Users\kazzna\activatorwork\activatortest> activator compile ~~ 何行か表示 ~~ [success] Total time: 124 s, completed 2015/12/11 1:01:27
初回の起動のみ、いろいろなファイルをダウンロードしてくるので時間がかかると思われます。
次は実行です。
C:\Users\kazzna\activatorwork\activatortest> activator run ~~ 何行か表示 ~~ [info] Running com.example.Hello Hello, world! [success] Total time: 0 s, completed 2015/12/11 1:02:18
同様にテストを実行。
C:\Users\kazzna\activatorwork\activatortest> activator test ~~ 何行か表示 ~~ [info] HelloSpec: [info] Hello [info] - should have tests [info] Run completed in 375 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. [success] Total time: 6 s, completed 2015/12/11 1:02:54
ライブラリーを使う
ライブラリーを使いたいときはbuild.sbt
を編集します。
たとえば、MySQLへ接続するためのmysql-connector-javaを入れたいときは、`以下の記述を追加します。
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.37"
Scalaでjsonを扱うためのjson4sならこんな感じです。
libraryDependencies += "org.json4s" %% "json4s-native" % "3.3.0"
Scalaのライブラリーは%%
、Javaのライブラリーは%
です。
なぜそうなってるのかは気になったらググってください。
このlibraryDependencies
に追加したライブラリーは、
ローカルに無ければ次回のコンパイル時などに自動的にダウンロードされます。
他にもいろいろ機能がありますので、「sbt 使い方」で検索してください。
出てきたコマンドのsbt
をそのままactivator
に変えると動くはずです。
IDEを使ってみよう!
さて、ここまでの内容で既に書いて・コンパイルして・テストして・実行はできるわけですが、 最後にIDEをひとつご紹介しておきます。
有料のUltimateと無料のCommunityエディションがありますが、趣味で使う分にはCommunityで十分です。
仕事で使う場合はライセンスを確認してください。
このIDEA
(アイディア)さん、
なんと先ほどActivator
で作ったプロジェクトをそのまま読み込んで作業できるのです。
設定したライブラリーなども自動で取得してくれます。
sbt-idea
なんていうsbtプラグインもありますが、使わなくても動くので使っていません。
詳しいインストールなどについてはサムライズムさんのブログなどをご参照ください。
Scala Advent Calendar 11日目は以上です。
お付き合いいただき、ありがとうございました。
これを見て「この記事よりかはいいものを書けるぜ!」と思ったあなた!
今すぐカレンダーの空きを埋めるのです!!Qiita版も空きがありますです!!
明日も2日連続で私による「いちばんゆるふあななにかを」です。
まだ何を書くのかを決めていませんが、とにかく「ゆるふあ」に行きます!
まだ決まってないので遅い時間になるかもです。。。すみません。
ScalaでSQLが書きたいんだ!!
DSLとかOR Mapperとかじゃなくて、SQLが直接書きたいんだ!!
嘘です。タイトル詐欺です。
最近neo4jというグラフ指向データベースがお気に入りでして、 アクセス用のクエリとしてCypherという言語を使います。
基本はHTTP+JSONでRESTにアクセスできるのですが、Java用にneo4j-jdbcというライブラリがあり、これを使ってアクセスしようと思うわけです。
そうすると、当然SQLではないのでDSLのSQL自動生成とかは使えず、直接SQL(本当はCypher)を書ける機能が望まれるわけです。
neo4jのダウンロード
neo4jは全部Javaで出来ているらしいので、あなたとJavaで検索してJavaをインストールしてください。
その後、neo4j公式サイトから無料版をダウンロードしてきます。
適当な場所に展開して、bin/neo4j status
みたいな感じで実行するとlocalhost:7474
でhttpを待ち受けてくれるようになります。
まずはブラウザでhttp://localhost:7474
に繋いでパスワード変更をしましょう。
初期状態のユーザーはneo4j
、パスワードも同じくneo4j
ですが、1度入力するとパスワード変更を要求されます。
ログインするとダッシュボードのような画面が表示され、 この画面からサンプルDBみたいなのの作り方やヘルプなどが見られるので始めは適当に触ってみるのがよいと思います。
仮データの登録
neo4jの画面の上部からCypherが入力できるので、データを登録してみましょう。
CREATE (p :Person{name: "kazzna", password: "some-password"}), (b :Blog{name: "kazzna's blog", url: "http://kazzna.hatenablog.com/"}), (p)-[:WRITES]->(b) RETURN p, b
p
, b
が変数ですね。
細かい説明はしませんが、:Person
型のノードと:Blog
型のノードを1個ずつ作って、作った物を取得しています。
ついでにせっかくですのですてにゃんあたりを追加しておきましょう。
CREATE (s :Person{name: "stefafan"}), (sb :Blog{name: "すてにゃんのガチ勢日記", url: "http://stefafafan.hatenablog.com/"}), (s)-[:WRITES]->(sb) WITH s, sb MATCH (k :Person{name: "kazzna"}), (kb :Blog{name: "kazzna's blog"}) CREATE (s)-[:READS]->(kb), (k)-[:READS]->(sb) RETURN s, k, sb, kb
kazznaはstefafafanのブログを読んで、stefafafanはkazznaのブログを読む、と。
:Person
のpassword
が無いのが特徴ですね。
Scalaから取得しよう!!
sbtは使える前提で話を進めますので、sbtって何?って人はtypesafe activatorでググってください。
で、以下のコマンド中のsbt
をactivator
に置き換えれば多分大丈夫です。
まずbuild.sbt
ファイルの設定。
name := "test" version := "0.0.1" lazy val root = (project in file(".")) scalaVersion := "2.11.7" resolvers ++= Seq( "neo4j-public" at "http://m2.neo4j.org/content/groups/public", "jitpack" at "https://jitpack.io" ) libraryDependencies ++= Seq( "org.scalikejdbc" %% "scalikejdbc" % "2.3.0", "com.github.kazzna" % "neo4j-jdbc" % "2.2-SNAPSHOT_1", "ch.qos.logback" % "logback-classic" % "1.1.3" )
大体こんな感じ。
resolversを2つ追加しないといけないのは理由があって、
公式のneo4j-jdbcを使うだけなら1番上だけでいいのですが、
現在公式の最新版ではScalikeJDBCなどが自動で生成してくれる?
を使ったPreparedStatementに対応していないのです。
なのでとりあえず?
の自動で対応した形式に置き換える対応を行った自作版を使います。
JitPackという不思議な力を借りて、githubから自動で依存関係ライブラリーを作り出してもらいます。
(mavenのローカルリリースは使い方が分からなくて出来ませんでした。)
公式にはPull Requestがマージされたので、次回のバージョン(2.2系?)のリリースから使えるようになるはずです。
後は普通のSQLの時と同様ですね。sbt console
して
scala> import scalikejdbc._ import scalikejdbc._ scala> case class Blog(name: String, url: String) defined class Blog scala> :paste // Entering paste mode (ctrl-D to finish) case class Person( name: String, password: Option[String], blog: Option[Blog] ) object Person extends SQLSyntaxSupport[Person] { def apply(rs: WrappedResultSet): Person = Person( rs.string("person.name"), rs.stringOpt("person.password"), rs.stringOpt("blog.name").flatMap { n => rs.stringOpt("blog.url").map(u => Blog(n, u)) }) } // Exiting paste mode, now interpreting. defined class Person defined object Person scala> Class.forName("org.neo4j.jdbc.Driver") res0: Class[_] = class org.neo4j.jdbc.Driver scala> ConnectionPool.singleton("jdbc:neo4j://localhost:7474/", "neo4j", "password") 14:09:20.332 [run-main-0] DEBUG scalikejdbc.ConnectionPool$ - Registered connection pool : ConnectionPool(url:jdbc:neo4j://localhost:7474/, user:neo4j) using factory : <default> 14:09:20.338 [run-main-0] DEBUG scalikejdbc.ConnectionPool$ - Registered singleton connection pool : ConnectionPool(url:jdbc:neo4j://localhost:7474/, user:neo4j) scala> implicit val session = AutoSession session: scalikejdbc.AutoSession.type = AutoSession scala> val name = "kazzna" name: String = kazzna scala> val k = sql"MATCH (person :Person{name: ${name}}) WITH person OPTIONAL MATCH (person)-[:WRITES]->(blog) RETURN person.name, person.password, blog.name, blog.url".map(rs => Person(rs)).single.apply() 14:14:33.949 [run-main-0] DEBUG s.StatementExecutor$$anon$1 - SQL execution completed // ScalikeJDBCの長いトレース k: Option[Person] = Some(Person(kazzna,Some(some-password),Some(Blog(kazzna's blog,http://kazzna.hatenablog.com/))))
とりあえず普通に使えそうですね。
気付いたことと言えば、Cypherは更新+取得という文が書けるのですが、
それらはJDBCではupdateとしてしか発行できない為に戻り値は取れないようです。
(queryで発行するとreadonlyだよって怒られます。)
もう少し使ってみて、問題点が出ればまたプルリク投げようかなあと言う感じですね。
みなさんもぜひグラフDB使いましょう。
あ、今回は取り上げてないけれど、実際にはちゃんとインデックス貼りましょうね?
インデックスはほぼRDBと同じ感覚で張れば問題ないので。
Optionがモナドだったなんて・・・orz
いやね、Scalaの話なんですけどね、何の話かってね、Option型がOption("a")
とかってやって生成できるの。。。
> val a = "abc" a: String = abc > val o = Option(a) o: Option[String] = Some(abc)
今までずっとSome(a)
かNone
でしかOption生成できないと思っていた自分が恥ずかしくて(><;;
いや、ね、Monadには単位元というかreturn
?pure
?point
?
とにかくscalaのapply
に当たる何かがあることが定義上必要なんですよ。
つまり絶対Option(???)
で何か生成できるはずなのに、なぜか出来ないって思いこんで居たっていう。。。
で、なんでこんな話をしているかというと、Javaのライブラリを使う時のnull
対策。
> val a: String = null a: String = null > val o = Option(a) o: Option[String] = None
この通り、null
の値の変数をOptionにapplyするとちゃんとNone
を返してくれる!!!
つい先日apache poiのためのscalaを(spoiwoは微妙に古いので)自作していたんだけど、
これが結構null
が返ってくる。
その時書いてたコードがこちら
def getRow(idx: Int)(sh: Sheet): Option[Row] = { val r = sh.getRow(idx) if (r == null) None else Some(r) }
これ、全部Optionのapllyでいいじゃんっていう・・・
是非これからやる人は読みやすい方を使ってください。。。
WindowsでGoのクロスコンパイル環境構築(Go Ver 1.5専用)
さすがはWindows!ひと手間かけたおいしさだぜ!!
経過をメモっているので、最後だけ読めば事足りるよ!!
参考にしたのはこのあたり
Go のクロスコンパイル環境構築 - Qiita
Windows7 64bit版でGo言語のクロスコンパイルを試す - taknb2nchのメモ
どうして試行錯誤時にずっと見てたページって再度ググると全然出てこないんだろう?
なんか英語のall.bashを実行してとかそういうページをずっと見ながらやってたんだけど、
見つからないのでリンクを貼れない。公式っぽいページ。
前提
なのでcgoと呼ばれるCで作られたと思わしきgoは使えません。
前作業
Go1.5をインストロールします。
golang downloadってbingに入力すれば、msiみたいなのを入手できます。
適当にC:\Go
とかに入れます。たぶんデフォルトでそうなってたから。
環境変数としては、GOROOT=C:\Go
がセットされている状態になっていることを確認してください。
Goのコンパイヨ
クロヌコンパイヨに使用するコマンド自体はGOOS=[OS名] GOARCH=[ARCH名] go ~
と簡単なのですが、
この使用したいGOOSとGOARCHの組み合わせ毎にGOそのものをコンパイヨしておく必要があります。
以後の記述が面倒なので、GOOS=darwin
, GOARCH=amd64
に限定して進めます。
コンパイヨはGOROOT\src
フォルダーに移動して、以下のコマンドを実行!!
GOOS=darwin GOARCH=amd64 make.bash
すると、たとえbashがある環境でもWindowsではmake.bat使えよって怒られるので、 コマンドプヨンプヨを開いて実行します。
SET GOOS=darwin SET GOARCH=amd64 make.bat
はい。3行です。1行では実行できません。
上記コマンドを実行すると、BootStrap用のGOがないよと怒られます。
なんか設定がないと、%UserProfile%\Go1.4
をBootStrapのrootと認識するようです。
GOROOT_BOOTSTRAPの設定
これは今からコンパイヨしようとしているGoをコンパイヨするためのGoなので、
もう1個Goの塊が必要?なのです。
SET GOROOT_BOOTSTRAP=%GOROOT%
としても動くのかは確認していません。
1.4を落としてくるのも面倒なので、C:\Go
を丸々コピーしてC:\GoBoot
を作ります。
そして、GOOROOT_BOOTSTRAP
を設定して実行!!
SET GOOS=darwin SET GOARCH=amd64 XCOPY /S /E /F /G /H /R /K /Y C:\Go C:\GoBoot SET GOROOT_BOOTSTRAP=C:\GoBoot make.bat
GOOS
とかは設定済みであれば再度設定する必要はありません。
これでできるかと思いきや、gccがないからcgoが作れないよ!!
と怒られます。
CGOを作らない
作れないなら作らなきゃいいじゃない!!ということで、
CGO_ENABLED
を0に設定します。
SET GOOS=darwin SET GOARCH=amd64 XCOPY /S /E /F /G /H /R /K /Y C:\Go C:\GoBoot SET GOROOT_BOOTSTRAP=C:\GoBoot SET CGO_ENABLED=0 make.bat
あ、同じく一度やったやつは再実行しなくて大丈夫です。
これでコンパイヨに成功するはず!!
少なくともうちではしました。
これで
SET GOOS=darwin SET GOARCH=amd64 go build hello.go
とかが可能になります。
ちなみにマックは高いので持ってません。
おまけ
なぜか頑張ってコマンヨプヨンプヨで実行したけど、 よくよく考えればgoをやっているみんなはgit for Windowsとか入れているはずなので、 git bash使って以下の処理でいいような気がする。
cp -r C:\Go C:\GoBoot GOOS=darwin GOARCH=amd64 GOROOT_BOOTSTRAP=C:\GoBoot CGO_ENABLED=0 make.bat
試してないのでうまく動かないかもしれないけど。
goコマンド実行時も、SET GOOS=???
とか実行してしまうと元に戻さないといけないので、
bashで1行で書いたほうが良さげです。
あ、GoBootはいらなくなったら消す方がいいと思う。 お好みで。