将Json值列表注入HashMap

时间:2016-10-27 19:56:44

标签: haskell yesod

我有Product引用Store模型。 我希望/stores/1的响应返回一个也包含引用产品的JSON。类似的东西:

{
  data: {
    storeName: "Store1",
    id: 1
    products: {
       { productName : "Product1",  productPrice: 10},
       { productName : "Product2",  productPrice: 100},
    }
  }
}

我目前仍然坚持使用Yesod处理程序,将产品注入到正确的位置。

getStoreR :: StoreId -> Handler Value
getStoreR storeId = do
    store <- runDB $ get404 storeId

    products <- runDB $ selectList [StoreId ==. storeId] []
    let productsJson = [entityIdToJSON (Entity k r) | Entity k r <- products]

    let storeJson = entityIdToJSON (Entity storeId store)

    -- Inject productsJson under "products" property fails
    let storeJsonWithProducts = HM.insert "products" productsJson storeJson

    return $ object ["data" .= storeJsonWithProducts]

失败了:

Couldn't match expected type ‘HM.HashMap k0 [Value]’
            with actual type ‘Value’
Relevant bindings include
  storeJsonWithProducts :: HM.HashMap k0 [Value]
    (bound at Main.hs:80:9)
In the third argument of ‘HM.insert’, namely ‘storeJson’
In the expression: HM.insert "products" productsJson storeJson

(顺便说一下,我用here创建了一个单独的文件应用程序)

1 个答案:

答案 0 :(得分:1)

HashMap.insert的类型为k -> v -> HashMap k v -> HashMap k v。您的storeJson不是HashMap,而是Value - 使用Object :: HashMap Text Value -> Value构造函数创建的v ~ Value。这意味着~(如果您不熟悉,可以将productsJson视为类型相等)。但是,这是一个问题,因为Value不是[Value],而是HashMap

因此,要解决您的问题,您需要:

  1. storeJson中提取let storeHM = case storeJson of Object h -> h

    storeJson

    当然,您应该确保正确处理其他构造函数,因为如果Object未构造productJson,这将会崩溃。

  2. Value转换为ValueArray :: Vector Value -> Value的一个构造函数为Vector Value,您可以使用[Value]Data.Vector.fromList获得import qualified Data.Vector as V [...] let productsValue = Array (V.fromList productsJson)

    productsValue
  3. 最后,将storeHM插入HashMap let storeHMWithProducts = HM.insert "products" productsValue storeHM

    object
  4. 然后,您可以继续操作,使用storeHMWithProductsValue再次转换为JSON return $ object ["data" .= storeHMWithProducts]

    Private Sub Form_Open(Cancel As Integer)
    Dim strMyDir As String
    Dim intPos As Integer
    Dim rst As dao.Recordset
    Dim strSQL As String
    Dim rstWhatsNew As dao.Recordset
    
    DoCmd.ShowToolbar "Database", acToolbarNo
    DoCmd.ShowToolbar "Toolbox", acToolbarNo
    DoCmd.ShowToolbar "Form View", acToolbarNo
    
    If Application.GetOption("ShowWindowsInTaskbar") = -1 Then
        Application.SetOption "ShowWindowsInTaskbar", 0
    End If
    
    
    If DLookup("Locked", "luLockOut") <> 0 Then
        MsgBox "Database is being worked on.  Please try back in a couple minutes.", vbInformation, " "
        DoCmd.Quit
    Else
        strSQL = "Select * From tblLastLogins Where UserName = '" & GetCurrentUserName() & "'"