将 Json 个值的列表注入 HashMap

Inject a list of Json Values into a HashMap

我有一个 Product 引用了一个 Store 模型。 我想要 /stores/1 对 return 的响应 JSON 也有参考产品。类似于:

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

我目前正忙于将产品注入正确的位置。

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 创建了一个单文件应用程序)

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

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

  1. storeJson中提取HashMap

    let storeHM = case storeJson of
                    Object h -> h
    

    当然,您应该确保正确处理此处的其他构造函数,因为如果 storeJson 不是用 Object 构造的,这将崩溃。

  2. productJson 转换为 ValueValue 的构造函数之一是 Array :: Vector Value -> Value,您可以使用 Data.Vector.fromList:

    [Value] 获得 Vector Value
    import qualified Data.Vector as V
    [...]
    let productsValue = Array (V.fromList productsJson)
    
  3. 最后,将productsValue插入storeHM HashMap:

    let storeHMWithProducts = HM.insert "products" productsValue storeHM
    

然后您可以像以前一样继续操作,再次使用 objectstoreHMWithProducts 转换为 JSON Value

return $ object ["data" .= storeHMWithProducts]