packages feed

hasbolt-extras 0.0.1.4 → 0.0.1.5

raw patch · 3 files changed

+37/−46 lines, 3 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Database.Bolt.Extras.DSL.Typed: CypherDSLParams :: CypherDSL a -> CypherDSLParams
+ Database.Bolt.Extras.DSL.Typed: CypherDSLParams :: CypherDSL a -> CypherDSLParams (params :: [(Symbol, Type)]) (a :: Type)
- Database.Bolt.Extras.DSL.Typed: defR :: RelSelector 'Nothing
+ Database.Bolt.Extras.DSL.Typed: defR :: RelSelector 'Nothing
- Database.Bolt.Extras.Graph: relations :: forall n_ache a_achf b_achg b_aloe. Lens (Graph n_ache a_achf b_achg) (Graph n_ache a_achf b_aloe) (Map (n_ache, n_ache) b_achg) (Map (n_ache, n_ache) b_aloe)
+ Database.Bolt.Extras.Graph: relations :: forall n_aa9V a_aa9W b_aa9X b_adZ2. Lens (Graph n_aa9V a_aa9W b_aa9X) (Graph n_aa9V a_aa9W b_adZ2) (Map (n_aa9V, n_aa9V) b_aa9X) (Map (n_aa9V, n_aa9V) b_adZ2)
- Database.Bolt.Extras.Graph: vertices :: forall n_ache a_achf b_achg a_alof. Lens (Graph n_ache a_achf b_achg) (Graph n_ache a_alof b_achg) (Map n_ache a_achf) (Map n_ache a_alof)
+ Database.Bolt.Extras.Graph: vertices :: forall n_aa9V a_aa9W b_aa9X a_adZ3. Lens (Graph n_aa9V a_aa9W b_aa9X) (Graph n_aa9V a_adZ3 b_aa9X) (Map n_aa9V a_aa9W) (Map n_aa9V a_adZ3)

Files

CHANGELOG.md view
@@ -6,6 +6,11 @@  ## [Unreleased] +## [0.0.1.5] - 2020-12-22+### Fixed+- Compatibility of `makeNodeLike` / `makeURelationLike` with `DuplicateRecordFields`, thanks to+  [@oddsome](https://github.com/oddsome), [PR #40](https://github.com/biocad/hasbolt-extras/pull/40).+ ## [0.0.1.4] - 2020-05-27 ### Fixed - Compatibility with GHC-8.10.
hasbolt-extras.cabal view
@@ -1,5 +1,5 @@ name:           hasbolt-extras-version:        0.0.1.4+version:        0.0.1.5 synopsis:       Extras for hasbolt library description:    Extras for hasbolt library homepage:       https://github.com/biocad/hasbolt-extras#readme
src/Database/Bolt/Extras/Template/Internal/Converters.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP             #-} {-# LANGUAGE TemplateHaskell #-}  module Database.Bolt.Extras.Template.Internal.Converters@@ -10,8 +10,6 @@   , makeURelationLikeWith   ) where -import           Control.Lens               (view, _1)-import           Control.Monad              ((>=>)) import           Data.Map.Strict            (fromList, member, notMember, (!)) import           Data.Text                  (Text, pack, unpack) import           Database.Bolt (Node (..), URelationship (..), Value (..))@@ -151,18 +149,18 @@   -- nameBase gives object name without package prefix. `label` is the type name here.   let label = nameBase tyName -  -- collects the names of all fields in the type.-  let dataFields = concatMap (snd . getConsFields) constr+  -- collects names and types of all fields in the type.+  let (dataFields, fieldTypes) = unzip $ concatMap (snd . getConsFields) constr    -- gets data constructor name   let (consName, _) = head $ fmap getConsFields constr -  -- Just a fresh variable. It will be used in labmda abstractions in makeToClause and makeFromClause functions.+  -- Just a fresh variable. It will be used in labmda abstractions in makeFromClause function.   fresh <- newName "x"    -- constructs `bijective` class functions (phi and phiInv – toClause and fromClause correspondingly here).-  toClause   <- makeToClause label dataName fresh dataFields fieldLabelModifier-  fromClause <- makeFromClause label consName fresh dataFields fieldLabelModifier+  toClause   <- makeToClause label dataName consName dataFields fieldLabelModifier+  fromClause <- makeFromClause label consName fresh dataFields fieldTypes fieldLabelModifier    -- function declarations themselves.   let bodyDecl = [FunD classToFun [toClause], FunD classFromFun [fromClause]]@@ -170,14 +168,12 @@   -- Instance declaration itself.   pure [InstanceD Nothing [] (AppT (ConT className) (ConT typeCon)) bodyDecl] ----- | Extract information about type: constructor name and field record names.+-- | Extract information about type: constructor name and field record names with corresponding types. ---getConsFields :: Con -> (Name, [Name])-getConsFields (RecC cName decs)           = (cName, fmap (view _1) decs)+getConsFields :: Con -> (Name, [(Name, Type)])+getConsFields (RecC cName decs)           = (cName, fmap (\(fname, _, ftype) -> (fname, ftype)) decs) getConsFields (ForallC _ _ cons)          = getConsFields cons-getConsFields (RecGadtC (cName:_) decs _) = (cName, fmap (view _1) decs)+getConsFields (RecGadtC (cName:_) decs _) = (cName, fmap (\(fname, _, ftype) -> (fname, ftype)) decs) getConsFields (NormalC cName _)           = (cName, []) getConsFields _                           = error $ $currentLoc ++ "unsupported data declaration." @@ -192,20 +188,20 @@ -- | Describes the body of conversion to target type function. -- makeToClause :: String -> Name -> Name -> [Name] -> (String -> String) -> Q Clause-makeToClause label dataCons varName dataFields fieldLabelModifier-  | null dataFields = pure $ Clause [WildP] (NormalB result) []-  | otherwise       = pure $ Clause [VarP varName] (NormalB result) []+makeToClause label dataCons consName dataFields fieldLabelModifier+  | null dataFields = pure $ Clause [WildP] (NormalB $ result []) []+  | otherwise       = do+    fieldVars <- sequenceQ $ newName "_field" <$ dataFields -- var for each field+    pure $ Clause [recPat fieldVars] (NormalB $ result fieldVars) []   where-    -- apply field record to a data.-    getValue :: Name -> Exp-    getValue name = AppE (VarE name) (VarE varName)+    -- construct record pattern: (Rec {f1 = v1, ... })+    recPat :: [Name] -> Pat+    recPat fieldVars = ParensP $ RecP consName $ zip dataFields $ VarP <$> fieldVars      -- List of values which a data holds.-    -- The same in terms of Haskell :: valuesExp = fmap (\field -> toValue (field x))-    -- `x` is a bounded in pattern match variable (e.g. toNode x = ...). If toNode :: a -> Node, then x :: a, i.e. x is data which we want to convert into Node.-    -- `field` is a field record function.-    valuesExp :: [Exp]-    valuesExp = fmap (AppE (VarE 'toValue) . getValue) dataFields+    -- The same in terms of Haskell :: valuesExp = fmap (\field -> toValue fieldVar)+    valuesExp :: [Name] -> [Exp]+    valuesExp = fmap (AppE (VarE 'toValue) . VarE)      -- Retrieve all field record names from the convertible type.     fieldNames :: [String]@@ -214,14 +210,14 @@     -- List of pairs :: [(key, value)]     -- `key` is field record name.     -- `value` is the data that corresponding field holds.-    pairs :: [Exp]-    pairs = zipWith (\fld val -> tupE' [strToTextE $ fieldLabelModifier fld, val]) fieldNames valuesExp+    pairs :: [Name] -> [Exp]+    pairs = zipWith (\fld val -> tupE' [strToTextE $ fieldLabelModifier fld, val]) fieldNames . valuesExp      -- Map representation:     -- mapE = fromList pairs     -- in terms of Haskell.-    mapE :: Exp-    mapE = AppE (VarE 'fromList) (ListE pairs)+    mapE :: [Name] -> Exp+    mapE vars = AppE (VarE 'fromList) (ListE $ pairs vars)      -- A bit of crutches.     -- The difference between Node and URelationship is in the number of labels they hold.@@ -235,20 +231,14 @@     -- In terms of Haskell:     -- dataCons (fromIntegral dummyId) (fieldFun label) mapE     -- Constructs data with three fields.-    result :: Exp-    result = AppE (AppE (AppE (ConE dataCons) (LitE . IntegerL . fromIntegral $ dummyId)) (fieldFun $ strToTextE label)) mapE+    result :: [Name] -> Exp+    result = AppE (AppE (AppE (ConE dataCons) (LitE . IntegerL . fromIntegral $ dummyId)) (fieldFun $ strToTextE label)) . mapE   -- | Describes the body of conversion from target type function. ---makeFromClause :: String -> Name -> Name -> [Name] -> (String -> String) -> Q Clause-makeFromClause label conName varName dataFields fieldLabelModifier = do--  -- Obtain all data field types.-  -- 'reify' returns 'Q Info', and we are interested in its 'VarI' constructur which provides information about variable: name and type.-  -- To obtain field type, one should get the second field record of VarI.-  fieldTypes <- mapM (reify >=> extractVarType) dataFields-+makeFromClause :: String -> Name -> Name -> [Name] -> [Type] -> (String -> String) -> Q Clause+makeFromClause label conName varName dataFields fieldTypes fieldLabelModifier = do   -- Contains 'True' in each position where 'Maybe a' type occured and 'False' everywhere else.   let maybeFields = fmap isMaybe fieldTypes @@ -288,18 +278,14 @@    -- Kind of this function realization in terms of Haskell:   -- fromNode :: Node -> a-  -- fromNode varName | checkLabels varName [dataLabel] && checkProps varName fieldNames = ConName { foo = bar, baz = quux ...}+  -- fromNode varName | checkLabels varName [dataLabel] && checkProps varName fieldNames = ConName (getProp varName "fieldName1") (getProp varName "fieldName2") ...   --                  | otherwise = unpackError varName (unpack dataLabel)-  let successExp = RecConE conName (zipWith (\f fldName -> (fldName, AppE (AppE (VarE 'getProp) (VarE varName)) f)) maybeNamesE dataFields)+  let successExp = foldl (\a f -> AppE a $ AppE (AppE (VarE 'getProp) (VarE varName)) f) (ConE conName) maybeNamesE   let successCase = (guardSuccess, successExp)   let failCase = (guardFail, failExp)    pure $ Clause [VarP varName] (GuardedB [successCase, failCase]) [] --extractVarType :: Info -> Q Type-extractVarType (VarI _ fieldType _) = pure fieldType-extractVarType _                    = error ($currentLoc ++ "this can not happen.")  -- | Check whether given type is '_ -> Maybe _' -- It pattern matches arrow type applied to any argument ant 'T _' and checks if T is ''Maybe