2015-05-02 2 views
2

Я довольно новичок в Haskell и экспериментировал с Yesod уже около недели. Я пытаюсь подключиться к существующей базе данных, которая имеет составной первичный ключ в sqlite. Мне удалось заставить код работать с Database.Persist.Sqlite в качестве отдельного приложения.Композитный первичный ключ в Yesod

Вот код, который работает как отдельное приложение с использованием persistent-sqlite.

{-# LANGUAGE EmptyDataDecls    #-} 
{-# LANGUAGE FlexibleContexts   #-} 
{-# LANGUAGE GADTs      #-} 
{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
{-# LANGUAGE MultiParamTypeClasses  #-} 
{-# LANGUAGE OverloadedStrings   #-} 
{-# LANGUAGE QuasiQuotes    #-} 
{-# LANGUAGE TemplateHaskell   #-} 
{-# LANGUAGE TypeFamilies    #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE DeriveGeneriC#-} 
import   Control.Monad.IO.Class (liftIO) 
import   Database.Persist 
import   Database.Persist.Sqlite 
import   Database.Persist.TH 
import   System.Environment 
import   Data.Text (Text,pack) 
import   Data.Time (UTCTime) 

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase| 
    Movie 
    title Text maxlen=20 
    year Int maxlen=11 
    genre Text Maybe maxlen=128 
    mpaa Text Maybe maxlen=16 
    director Text Maybe maxlen=128 
    actors Text Maybe maxlen=512 
    description Text Maybe maxlen=512 
    path Text Maybe maxlen=128 
    codec Text Maybe maxlen=32 
    length Int Maybe maxlen=11 
    poster Text Maybe maxlen=128 
    added UTCTime default=CURRENT_TIMESTAMP 
    Primary title year 
    deriving Show 
|] 

main :: IO() 
main = do 
    (path:args) <- getArgs 
    movies <- runSqlite (pack path) $ do 
    runMigration migrateAll 
    selectList [] [Desc MovieTitle] 

    mapM_ print movies 

Это своего рода надуманный пример, но он иллюстрирует мою мысль. Я хотел бы иметь составной первичный ключ, который состоит из title и year. Все компилируется отлично, и таблица создается с помощью схемы, которая мне нужна. Когда я пытаюсь использовать тип Movie, как определено выше в моем Йесод применении с persistent-sqlite, я получаю ошибку следующие во время компиляции

Foundation.hs:35:1: 
    No instance for (PathPiece MovieId) 
     arising from a use of ‘toPathPiece’ 
    In the first argument of ‘(:)’, namely ‘(toPathPiece dyn_apvA)’ 
    In the second argument of ‘(:)’, namely 
     ‘((toPathPiece dyn_apvA) : [])’ 
    In the expression: 
     ((Data.Text.pack "entry") : ((toPathPiece dyn_apvA) : [])) 

Foundation.hs:35:1: 
    No instance for (PathPiece MovieId) 
     arising from a use of ‘fromPathPiece’ 
    In the expression: fromPathPiece 
    In the pattern: fromPathPiece -> Just dyn_apwt 
    In the pattern: (:) (fromPathPiece -> Just dyn_apwt) [] 

Я застрял в этой точке и не смог продолжить игру самостоятельно. Я попытался выполнить поиск, но я могу найти только рабочий пример составных первичных ключей без использования Yesod. У меня такое ощущение, что это можно сделать, поскольку составной первичный ключ использует только persistent-sqlite работ.

Вот как Movie тип определен в config/models

Movie 
    title Text maxlen=20 
    year Int maxlen=11 
    genre Text Maybe maxlen=128 
    mpaa Text Maybe maxlen=16 
    director Text Maybe maxlen=128 
    actors Text Maybe maxlen=512 
    description Text Maybe maxlen=512 
    path Text Maybe maxlen=128 
    codec Text Maybe maxlen=32 
    length Int Maybe maxlen=11 
    poster Text Maybe maxlen=128 
    added UTCTime default=CURRENT_TIMESTAMP 
    Primary title year 
    deriving 

ответ

2

Я на самом деле не используется Основной особенностью составного ключа сам, но эта ошибка имеет смысл для меня. Нет очевидной сериализации для Text для произвольных составных клавиш, и поэтому постоянная не генерирует ее для вас. Если вы хотите использовать MovieId внутри своих URL-адресов, вам нужно вручную определить экземпляр PathPiece, который представляет собой всего лишь пару функций для преобразования в и от Text.