2015年6月29日月曜日

Pythonのsqlacodegenが便利です

SQLAlchemyのモデルクラスをDBから作ってくれる


PythonのORMでSQLAlchemyが好きな私ですが、最近のmigrationツールを使えなくなってきたお年寄りなので、

「テーブルから簡単にクラスを作ってくれるツールってないのか...」

と思いつつ、探していたら、sqlacodegenっていうのを見つけました、これSQLAlchemy用のORMクラスをデータベースから作成してくれるツールでシンプルでいけてる

インストール


まずはインストール、とりあえず適当にgentooのebuildを作っておきましたので、gentoo貴族はlaymanで入れて見てください。そのたのディストリビューションなかたはpipで入れて見てください。

karky7 ~ # layman -s karky7
...
...
karky7 ~ # emerge -pv sqlacodegen
...
Calculating dependencies... done!
[ebuild  N    ~] dev-python/inflect-0.2.5::karky7  PYTHON_TARGETS="python2_7 python3_3" 0 KiB
[ebuild  N    ~] dev-python/sqlacodegen-1.1.6::karky7  PYTHON_TARGETS="python2_7 python3_3 -python3_4" 0 KiB
..
..
karky7 ~ # emerge sqlacodegen

使ってみる


シェルからこんな感じで直接データベースを見にいかせるとモデルを全部吐いてくる
cuomo@karky7 ~ $ sqlacodegen mysql://root@localhost/SAMPLEDB
# coding: utf-8
from sqlalchemy import BigInteger, Column, DateTime, ForeignKey, Text
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()
metadata = Base.metadata


class BlogPost(Base):
    __tablename__ = 'BlogPost'

    id = Column(BigInteger, primary_key=True)
    title = Column(Text, nullable=False)
    authorId = Column(ForeignKey(u'Person.id'), nullable=False, index=True)

    Person = relationship(u'Person')


class Person(Base):
    __tablename__ = 'Person'

    id = Column(BigInteger, primary_key=True)
    name = Column(Text, nullable=False)
    age = Column(BigInteger)
    regdate = Column(DateTime)

その他のオプションはこんな感じ--tables [テーブル名]で関連するテーブルだけ吐いてきたり、いろいろできる。

cuomo@karky7 ~ $ sqlacodegen --help
usage: sqlacodegen [-h] [--version] [--schema SCHEMA] [--tables TABLES]
                   [--noviews] [--noindexes] [--noconstraints] [--nojoined]
                   [--noinflect] [--noclasses] [--outfile OUTFILE]
                   [url]

Generates SQLAlchemy model code from an existing database.

positional arguments:
  url                SQLAlchemy url to the database

optional arguments:
  -h, --help         show this help message and exit
  --version          print the version number and exit
  --schema SCHEMA    load tables from an alternate schema
  --tables TABLES    tables to process (comma-separated, default: all)
  --noviews          ignore views
  --noindexes        ignore indexes
  --noconstraints    ignore constraints
  --nojoined         don't autodetect joined table inheritance
  --noinflect        don't try to convert tables names to singular form
  --noclasses        don't generate classes, only tables
  --outfile OUTFILE  file to write output to (default: stdout)

最近、WAFへバンドルされているマイグレーションツールがいっぱいありますが、ちょっと使うには色々と覚える必要があるのでちょっと面倒くさい。
でもこのツールは、必要最低限でやりたいことがhelpを見るだけでできちゃうのが凄くいい。
SQLALchemy専用ですが、私はSQLAlchemy以外は使わないのでこれでいい、ちょっと注意点なんですが、テーブルのコメントなどにutf-8以外の文字コードを含んでいると、Unicodeエラーになってしまうので、その場合はALTER TABLEなどでコメントを削除するか、utf-8で入れ直すかしてみて下さい。

2015年6月23日火曜日

Persistentがまともに動きません

SelectOneManyとかもうないのか...


二日酔いが続く中、Database.Persist.Query.Join (SelectOneMany (..), selectOneMany)のあたりの関数がごっそりなくなっていて、嗚咽を模様した今日この頃です。

この辺の記事(「Yesod Web Framework SQL Join」)がそれっぽいようなことを書いてあるような気配がするのですが、英語も読む気力がないので、どなたか訳してくれないでしょうか...Orz

そんなことはいいとして、適当に書き換えてみました、データベースに入っているデータを単純に読み込むだけですが

データはこんな感じ
cuomo@karky7 ~ $ mysql -u root SAMPLEDB
Reading table information for completion of table and column names
...
...
mysql> SELECT * FROM Person;
+----+-------------------+------+
| id | name              | age  |
+----+-------------------+------+
| 11 | Kazuto Ando       |   40 |
| 12 | Yoshirou Dorumaki |   41 |
+----+-------------------+------+
2 rows in set (0.00 sec)

mysql> 
で、haskellのコード、Persistent MySQLを利用しています

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
import Database.Persist
import Database.Persist.MySQL
import Database.Persist.TH
import Data.Int
import Control.Monad.Logger (runNoLoggingT, MonadLogger)
import Control.Monad.IO.Class
import Control.Monad.Trans.Control (MonadBaseControl)

share [mkPersist sqlSettings] [persistUpperCase|
Person
    name String
    age Int Maybe
    deriving(Show)
BlogPost
    title String
    authorId PersonId
    deriving(Show)
|]

main :: IO ()
main = do
  person <- getPerson 11
  case person of
    Just p -> dispPerson (personName p) (personAge p)
    Nothing -> putStrLn "Nothing"

dispPerson :: String -> Maybe Int -> IO ()
dispPerson name (Just age) = putStrLn $ name ++ "\n" ++ show(age)
dispPerson name Nothing = putStrLn name

getPerson :: (MonadBaseControl IO m,
                        MonadIO m) => Int64 -> m (Maybe Person)
getPerson n = runNoLoggingT $ getConn $ runSqlConn $ do
   get (toSqlKey n)


getConn :: (MonadBaseControl IO m,
            MonadIO m,
            MonadLogger m) => (SqlBackend -> m a) -> m a
getConn = withMySQLConn getConnection

getConnection :: ConnectInfo
getConnection = ConnectInfo {
    connectHost = "localhost",
    connectPort = 3306,
    connectUser = "root",
    connectPassword = "",
    connectDatabase = "SAMPLEDB",
    connectOptions = [],
    connectPath = "",
    connectSSL = Nothing
}

そしたら、11番目の「かずと」を抜いてみる、最近、プロマネ的な仕事をこなしているっぽい、出世したらしい
*Main> :load "/home/cuomo/Code/yesod/Persistent/PersistMySQL.hs"
[1 of 1] Compiling Main       ( /home/cuomo/Code/yesod/Persistent/PersistMySQL.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
Kazuto Ando
40
*Main>
こんだけです、気持ちが悪いので止めておきます...


2015年6月22日月曜日

二日酔い

健康診断が控えた今日この頃、「二日酔い」という状態に陥りました。

しかし、今朝はいい天気です。

健康診断は、さらに高得点を叩き出すような気がします、皆さんも飲みすぎにはご注意下さい。