2019年3月31日日曜日

persistentとsequence

Persistentでsequenceの扱い

Persistentからデータベースにテーブルやらを作成すると、自動でidと言う名前でサロゲートキーが生成される。 これなら簡単にinsertできる、insertしたエンティティの自動採番されたidを返してくる。
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
|]
...
...
    uid <- insert $ Person "Mac" $ Just 20
...
これはこれでいいのですが、既にシーケンスとかあって、それから採番している場合、モデルの書き方が変わってちょっと面倒くさくなる。
こんな感じ...
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
NiceGuy
    niceGuyId Int sqltype=bigint default=nextval('nice_guy_id_seq')
    name Text
    age Int
    authorizedDate Day Maybe sqltype=date
    regTime UTCTime sqltype=timestamptz
    Primary niceGuyId
    deriving Show
NiceGuyPet
    name Text
    niceGuyId NiceGuyId
    deriving Show

insertのときniceGuyNiceGuyIdにIntを要求されて「ウゼェー」ってなる

シーケンスを手動でとる


小一時間ほどPersistentまわりを調べたのですがあまりいいやり方が見つからなかったので適当に解決した
getNiceGuySeq :: MonadIO m => ReaderT SqlBackend m [Single Int]
getNiceGuySeq = rawSql "select nextval('nice_guy_id_seq')" []
Singleの中にシーケンスが入って返ってくる
動かした後のデータベースの中身はこちら
$ stack run
Migrating: CREATe TABLE "nice_guy"( PRIMARY KEY ("nice_guy_id"),"nice_guy_id" bigint NOT NULL DEFAULT nextval('nice_guy_id_seq'),"name" VARCHAR NOT NULL,"age" INT8 NOT NULL,"authorized_date" date NULL,"reg_time" timestamptz NOT NULL)
Migrating: CREATe TABLE "nice_guy_pet"("id" SERIAL8  PRIMARY KEY UNIQUE,"name" VARCHAR NOT NULL,"nice_guy_id" INT8 NOT NULL)
Migrating: ALTER TABLE "nice_guy_pet" ADD CONSTRAINT "nice_guy_pet_nice_guy_id_fkey" FOREIGN KEY("nice_guy_id") REFERENCES "nice_guy"("nice_guy_id")
insert nice_guy__id: NiceGuyKey {unNiceGuyKey = 1} / nice_guy_pet_id: NiceGuyPetKey {unNiceGuyPetKey = SqlBackendKey {unSqlBackendKey = 1}}
insert nice_guy__id: NiceGuyKey {unNiceGuyKey = 2} / nice_guy_pet_id: NiceGuyPetKey {unNiceGuyPetKey = SqlBackendKey {unSqlBackendKey = 2}}
insert nice_guy__id: NiceGuyKey {unNiceGuyKey = 3} / nice_guy_pet_id: NiceGuyPetKey {unNiceGuyPetKey = SqlBackendKey {unSqlBackendKey = 3}}

$ psql -U sample sampledb
psql (9.6.12)
Type "help" for help.

sampledb=>
sampledb=> \d
                List of relations
 Schema |        Name         |   Type   | Owner
--------+---------------------+----------+--------
 public | nice_guy            | table    | sample
 public | nice_guy_id_seq     | sequence | sample
 public | nice_guy_pet        | table    | sample
 public | nice_guy_pet_id_seq | sequence | sample
(4 rows)

sampledb=> select * from nice_guy;
 nice_guy_id |    name    | age | authorized_date |           reg_time
-------------+------------+-----+-----------------+-------------------------------
           1 | 玉輿平八郎 |  55 | 2019-03-31      | 2019-03-31 14:11:05.500591+09
           2 | 骨川筋太郎 |  47 | 2019-03-31      | 2019-03-31 14:11:05.517138+09
           3 | 裏筋太郎   |  75 | 2019-03-31      | 2019-03-31 14:11:05.525973+09
(3 rows)

sampledb=> select * from nice_guy_pet;
 id |   name   | nice_guy_id
----+----------+-------------
  1 | モッコ   |           1
  2 | めん     |           2
  3 | スージー |           3
(3 rows)
こんな感じ
全部のサンプルコードはgithubへあげておきます、興味のある方はどうぞ。

empty yoshidaとPersistent物語はこちら

もうちょい綺麗なやり方あんのかなぁ...