DBIC_TRACE=1のときに発行されるsqlにどこで発行されたクエリか追記する
package DBIx::Class::Storage::Statistics::Caller; use strict; use warnings; use base qw/ DBIx::Class::Storage::Statistics /; sub query_start { my ($self, $string, @bind) = @_; my $caller_sub_name = $self->_get_non_dbic_caller; my $message = "[$caller_sub_name] $string: ".join(', ', @bind)."\n"; if(defined($self->callback)) { $string =~ m/^(\w+)/; $self->callback->($1, $message); return; } $self->print($message); } sub _get_non_dbic_caller { my ($self) = @_; my $get_sub_name = sub { for my $n ( 0..20 ) { my ($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($n); return $subroutine if $subroutine =~ s{^AppName::}{}; }; return ''; }; return $get_sub_name->(); } 1;
使いたいときに
$schema->storage->debugobj( DBIx::Class::Storage::Statistics::Caller->new );
する。
callerをとってくる部分はもっとうまくかけるにおいがぷんぷんする。
あと、上のやつとは全然関係ないけど、最近Arkアプリの起動は
perl boot_app_server_fcgi.pl >> ~/tmp/app/fcgi.log 2>&1 >> /dev/stdin 2>&1 | grep SELECT >> ~/tmp/app/fcgi-select.log
みたいに起動して、
M-x tail-log-file ~/tmp/app/fcgi.log してる。
してる。
zshとかきちんと理解してないので勘で書いて、あ、動いた。みたいな感じ。
Emacsでlogを見るようにすると、anything-c-moccur とか使えて便利な事がおおい。
あと、sqlとかそのまま実行できて、それもたのしい。
tail-log-fileの定義は以下のような感じ
(defun tail-log-file (file) (interactive "f") (let* ((log-file (expand-file-name file)) (buffer-name (concat "*" log-file "*"))) (with-current-buffer (get-buffer-create buffer-name) (set-buffer buffer-name) (setq auto-window-vscroll t) (fundamental-mode) (start-process "tail" buffer-name "tail" "-f" log-file) ) (switch-to-buffer buffer-name)))
rails.elを参考にしました。
今日は、海の家でタイ料理を食べながらおビールを飲みました。
ですが、気温が高かったからか、僕のビールがすぐに蒸発してしまう不思議な現象に見舞われたため、沢山ビールを注文することになってしまいました。
不思議でしたが、楽しいお酒が沢山飲めて本当に幸せでした。しあわせ、しあわせ。
SQL扱うのに便利な関数とか、プレースホルダーを埋める関数とか
Arkのログ、DBIC_TRACE=1 の時に出るやつをごニョゴニョしたいと思って。いろいろやってみた。
SELECT * FROM user me WHERE ( ( me.id = ? AND deleted = ? ) ): '4', '0'
を選択して、
M-x sql-fill-placeholders
すると、kill-ring に
SELECT * FROM user me WHERE ( ( me.id = '4' AND deleted = '0' ) );
が入っている状態になる。埋め込まれている。そのまま実行できるはず。
以下は、応用。
SELECT * FROM user me WHERE ( ( me.id = ? AND deleted = ? ) ): '4', '0'
を選択して、
C-u M-x sql-fill-placeholders-and-send
で EXPLAIN をつけてSQLバッファで実行。
以外と便利。
落ち着いたらゆっくり書きたい。
(defun sql-fill-params (q los) (assert (stringp q)) (assert (and (listp los) (stringp (car-safe los)))) (with-temp-buffer (insert q) (goto-char (point-min)) (dolist (s los) (re-search-forward (rx "?")) (replace-match s nil t nil)) (buffer-substring-no-properties (point-min) (point-max)))) (defun sql-fill-placeholders-parse-param-str (param-str) (let ((params (split-string param-str "," t))) (mapcar (lambda (s) (replace-regexp-in-string "[ \t\n]*$" "" (replace-regexp-in-string "^[ \t\n]*" "" s))) params))) (defun sql-fill-placeholders-from-string (str) (when (string-match (rx (* space) (group (* (not (any ":")))) ":" (* space) (group (* print)) eol) str) (let ((query (match-string-no-properties 1 str)) (param-str (match-string-no-properties 2 str))) (cond ;; no placeholder ((not (string-match (rx "?") query)) query) (t (let ((params (sql-fill-placeholders-parse-param-str param-str))) (sql-fill-params query params))))))) (defun sql-fill-placeholders-make-executable-sql (start end) (let ((sql (sql-fill-placeholders-from-string (buffer-substring-no-properties start end)))) (concat sql ";"))) (defun sql-fill-placeholders (start end) (interactive "r") (let ((sql (sql-fill-placeholders-make-executable-sql start end))) (kill-new sql))) (defun sql-fill-placeholders-and-send (start end) (interactive "r") (assert (buffer-live-p (get-buffer sql-buffer))) (let* ((sql (sql-fill-placeholders-make-executable-sql start end)) (sql (if current-prefix-arg (concat "EXPLAIN " sql) sql))) (with-current-buffer sql-buffer (sql-send-string sql))))
Emacsに選択してる範囲を読んでもらう
say コマンドがインストールされている場合のお話です。
(defun say-on-region (&optional start end) (interactive "r") (unless (executable-find "say") (error "say command is not installed!!")) (shell-command-on-region start end "say"))
読んで欲しいところをリージョン選択しながら M-x say-on-region で話し始めます。
endless eight onichan Daisuki dogura magura
もうお好きなのをどうぞ!!
自分の中のビールの部分がお届けしました。おやすみなさい。
List::Util::first の返り値でハマったのでメモ
use Test::Base qw(no_plan); use Test::Exception; use List::Util qw(first); use Perl6::Say; my $arr = [ { id => 1, name => 'aaa' }, { id => 2, name => 'bbb' }, ]; my $is_ccc = sub { $_->{name} eq 'ccc' }; lives_ok( sub { map { say $_->name } first { $is_ccc->($_) } @$arr; }, 'first' ); # => died: Can't call method "name" on an undefined value at -e line 20. lives_ok( sub { map { say $_->name } grep { $is_ccc->($_) } @$arr; }, 'grep' ); # => ok.
原因は、
first { $is_ccc->($_) } @$arr;
が
(undef)
を返すからだと思われる。
podにはこうかかれている。
This function could be implemented using C<reduce> like this $foo = reduce { defined($a) ? $a : wanted($b) ? $b : undef } undef, @list
ちょっとずつ前にすすんでる気がする!!。
デフォルト設定の semantic が semantic.cache を各ディレクトリに作ってアレなときにすべき設定
semanticdb-default-save-directory にディレクトリを設定してあげると、そこにキャッシュを作るようになります。
(setq semanticdb-default-save-directory "~/.emacs.d/")
また、 semanticdb-default-file-name を変更するとキャッシュファイルの名前を変更する事もできます。
これらの変数は、cedet/semantic/semanticdb-file.el で定義されています。
M-x custom-group semanticdb
でもOKです!!
Lingua::JA::Regular::Unicode をつかって全角カナを半角カナに変換する
全角と半角が混在していて、アレだったのですが、以下のコードで一発でした。
"、。" 等の文字も変換されて問題ない状況でした。
use Lingua::JA::Regular::Unicode; sub z2h { katakana_z2h($_[0]) } $_->update({ name => z2h($_->name), description => z2h($_->description) }) for ( $schema->resultset('Spec')->all );
もし管理画面とにらめっこしながら手作業で直していたとしたら、電脳コイルを見る時間が取れませんでした。
最高です。素晴らしすぎます。tokuhiromさんに感謝!!
tokuhirom++
(incf tokuhirom)
DBIC勉強しつつ、SQL書き方ドリル読んだメモ -2-
p175〜 相関副問い合わせ。
SELECT p.ProductName, s1.Quantity, s1.saledate FROM Sales AS s1 JOIN Products AS p ON p.ProductID = s1.ProductID WHERE s1.Quantity > ( SELECT AVG(s2.Quantity) FROM Sales AS s2 WHERE s2.ProductID = s1.ProductID ) ;
my $avg = $schema->resultset('Sales')->get_column('Quantity')->func('AVG'); $schema->resultset('Sales')->search( { 'me.Quantity' => {'>' => $avg}, }, { select => [qw/ Products.productname me.saledate /], as => [qw/ name saledate/], join => [qw/ Products /], order_by => \'Products.productid ASC, me.saledate DESC', } );