【问题标题】:Convert value to sql select in Haskell在 Haskell 中将值转换为 sql 选择
【发布时间】:2014-07-09 02:00:19
【问题描述】:

我正在构建一个从 html 表单查询数据库的工具,并且我定义了一个数据类型来捕获表单值。例如:

data BookSearchParams = BookSearchParams
{ Title       :: Maybe Text
  TitleSearchType :: SearchType
, Author      :: Maybe Text
, AuthorSearchType :: SearchType
}

数据库的列表示为数据类型中的字段,我使用 Maybe 因为用户可能会也可能不会在表单中输入该值。 SearchType 字段用于指定完全匹配、正则表达式等。我想把它变成一个 sql select 语句。

在命令式语言中,如果字段被传递,我可以将每个字段添加到字符串中:

if params.title:
    sql += params.title

在 Haskell 中,我可以用很多 case 语句来创建一个具有以下类型的函数:

bookSearchParamsToSql :: BookSearchParams -> Text

但是,这将是一个混乱的功能。这个函数应该怎么写?

【问题讨论】:

    标签: sql haskell


    【解决方案1】:

    我会使用 Monoid 来解决这个问题。

    import Data.Monoid (<>)
    
    titleSQL, authorSQL :: BookSearchParams -> Text
    
    bookSearchSQL p = titleSQL p <> authorSQL p
    

    【讨论】:

      【解决方案2】:

      几周前我问过类似的question,优雅的答案是使用Writer monad。 (事实上​​,这是完全相同的问题:构建 SQL 查询,但我将其转换为更一般的问题)。

      import Control.Monad.Writer hiding (forM_)
      import Data.Foldable
      
      bookSearchSQL :: BookSearchParams -> Text
      bookSearchSQL p = execWriter $ do
          tell "header of the query"
          forM_ (title p) $ \t -> "title = " ++ (show t)
          tell $ "type = " ++ (searchType p)
          forM_ (author p) $ \a -> "author = " ++ (show a)
      

      (我没有检查它是否有效,甚至没有编译)。诀窍是使用Data.Foldable.forM_ 而不是更传统的Control.Monad.forM_。后者将列表作为参数,但可折叠版本采用任何可折叠的,在我们的例子中为Maybe

      请注意,在 lambda 中,ta 不是 Maybe 而是 Text,并且只有在 Maybe 不是 Nothing 时才会调用 lambda。

      【讨论】:

        【解决方案3】:

        如果你想连接所有的Texts,你可以使用:

        (编辑:忘了Text 不是Strings ..)

        import Data.Monoid
        params = ...
        sql = [ s | Just s <- title params ] <>
              [ s | Just s <- author params ] <>
              ...
        

        甚至是类似的东西

        import Data.List (intersperse)
        import Data.Text
        import Data.Monoid
        params = ...
        sql = concat $ Data.List.intersperse " AND "
              [ [ "title='" <> escape s <> "'" | Just s <- title params ]
              , [ "author='" <> escape s <> "'" | Just s <- author params ]
              , ...
              ]
        

        当然,连接字符串来构建 SQL 查询不是很安全(并且可能容易受到注入攻击)。相反,我会看看我们拥有的可以帮助执行此操作的不错的库。我不能推荐任何一个,因为我从未使用过它们:P,但它们确实存在并且看起来不错。

        【讨论】:

          猜你喜欢
          • 2011-02-14
          • 2018-03-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-16
          • 2017-01-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多