데이터베이스에 저장된 데이터를 기반으로 Database.Esqueleto
쿼리를 동적으로 만들려고합니다 (아래 코드의 DynamicQuery Database.Persist
엔티티 참조). 아래의 코드는 컴파일되지만 반복되는 정의 (텍스트 필드 유형의 경우 op
, 날짜 필드 유형의 경우 op2
및 Bool
필드 유형의 경우 op3
)로 인해 매우 우아하지 않습니다.Database.Esqueleto SQL 연산자를 동적으로 선택하십시오.
expr
의 정의에서 모든 경우에 사용할 수있는 op
과 유사한 더 일반적인 기능을 작성할 수 있습니까?
test.hs:68:46:
Couldn't match expected type `Text' with actual type `Day'
Expected type: EntityField (ItemGeneric backend0) Text
Actual type: EntityField (ItemGeneric backend0) Day
In the second argument of `(^.)', namely `ItemInserted'
In the first argument of `op', namely `(mp ^. ItemInserted)'
코드 조각은 다음과 같습니다 : op2
는 다음과 같은 오류 메시지가 결과를 사용하는 날의 필드 종류에 op
을 다시 시도
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
import Database.Esqueleto
import Database.Esqueleto.Internal.Sql
import Data.Time.Calendar
import Data.Text (Text)
import qualified Data.Text as T
import Database.Persist.TH
import Database.Persist.Sqlite hiding ((==.), (!=.), (>=.), (<=.))
import Control.Monad.IO.Class (liftIO)
import Enums
{- enumerated field types have to be in a separate module due to GHC
-- stage restriction. Enums.hs contains the following definitions:
{-# LANGUAGE TemplateHaskell #-}
module Enums where
import Database.Persist.TH
data DynField = DynFieldName | DynFieldInserted | DynFieldActive deriving (Eq, Read, Show)
derivePersistField "DynField"
data SqlBinOp = SqlBinOpLike | SqlBinOpLtEq | SqlBinOpGtEq | SqlBinOpNotEq | SqlBinOpEq deriving (Eq, Read, Show)
derivePersistField "SqlBinOp"
-}
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
DynamicQuery
field DynField
op SqlBinOp
value Text
Item
name Text
inserted Day
active Bool
|]
safeRead :: forall a. Read a => Text -> Maybe a
safeRead s = case (reads $ T.unpack s) of
[(v,_)] -> Just v
_ -> Nothing
getItems dc = do
select $ from $ \mp -> do
where_ $ expr mp
return $ mp ^. ItemId
where
value = dynamicQueryValue dc
boolValue = case safeRead value of
Just b -> b
Nothing -> False
dateValue = case safeRead value of
Just dt -> dt
Nothing -> fromGregorian 1900 1 1
expr = \mp -> case dynamicQueryField dc of
DynFieldName -> (mp ^. ItemName) `op` val value
DynFieldInserted -> (mp ^. ItemInserted) `op2` val dateValue
DynFieldActive -> (mp ^. ItemActive) `op3` val boolValue
op = case dynamicQueryOp dc of
SqlBinOpEq -> (==.)
SqlBinOpNotEq -> (!=.)
SqlBinOpGtEq -> (>=.)
SqlBinOpLtEq -> (<=.)
SqlBinOpLike -> unsafeSqlBinOp " ILIKE "
op2 = case dynamicQueryOp dc of
SqlBinOpEq -> (==.)
SqlBinOpNotEq -> (!=.)
SqlBinOpGtEq -> (>=.)
SqlBinOpLtEq -> (<=.)
SqlBinOpLike -> unsafeSqlBinOp " ILIKE "
op3 = case dynamicQueryOp dc of
SqlBinOpEq -> (==.)
SqlBinOpNotEq -> (!=.)
SqlBinOpGtEq -> (>=.)
SqlBinOpLtEq -> (<=.)
SqlBinOpLike -> unsafeSqlBinOp " ILIKE "
main = runSqlite ":memory:" $ do
runMigration migrateAll
_ <- insert $ Item "item 1" (fromGregorian 2014 2 11) True
_ <- insert $ Item "item 2" (fromGregorian 2014 2 12) False
let dc = DynamicQuery DynFieldName SqlBinOpEq "item 1"
items <- getItems dc
liftIO $ print items
@ KarthikVU, 오늘 귀하의 수정 사항을 검토했습니다 ... 내가 본 것들 중 * 모든 것에 대해 추가 한 '* 작은 변경 사항'보다 편집에 대한 더 정확한 설명을 제공해주십시오. – Sheridan