/test/Data/Transform/TwoLevelOrganogramExample.hs

http://2lt.googlecode.com/ · Haskell · 148 lines · 81 code · 24 blank · 43 comment · 4 complexity · 82ef0512d25d8264eca576f5bae1bb04 MD5 · raw file

  1. {-# OPTIONS -fglasgow-exts #-}
  2. -----------------------------------------------------------------------------
  3. -- |
  4. -- Maintainer : joost.visser@di.uminho.pt, alcino@di.uminho.pt
  5. -- Stability : experimental
  6. -- Portability : portable
  7. --
  8. -- Example of format evolution and data mapping, using a
  9. -- recursive datatype for employee hierarchies (organograms).
  10. --
  11. -----------------------------------------------------------------------------
  12. module Data.Transform.TwoLevelOrganogramExample where
  13. import Data.Transform.TwoLevel
  14. import Data.List as List
  15. import Control.Monad
  16. import Data.Map as Map
  17. -----------------------------------------------------------------------------
  18. {- Adapted from the online \emph{.NET Framework Developer's Guide} (\url{http://msdn.microsoft.com/library/}), for representing employee hierarchies.
  19. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  20. <xs:element name="Emp" type="EmployeeType" />
  21. <xs:complexType name="EmployeeType">
  22. <xs:sequence>
  23. <xs:element name="Emp" type="EmployeeType" />
  24. </xs:sequence>
  25. <xs:attribute name="EmployeeID" type="xs:ID" />
  26. <xs:attribute name="FirstName" type="xs:string"/>
  27. <xs:attribute name="LastName" type="xs:string"/>
  28. </xs:complexType>
  29. </xs:schema>
  30. -}
  31. data Emp = Emp EmployeeType deriving (Show,Eq)
  32. data EmployeeType = EmployeeType {
  33. emp_seq :: [EmployeeType],
  34. job :: String,
  35. firstName :: String,
  36. lastName :: String
  37. } deriving (Show,Eq)
  38. -- emp :: Type EmpT
  39. emp = Tag "Emp" employeeType
  40. employeeType = Mu employeeTypeF
  41. employeeTypeF =
  42. ((List . Tag "Emp") :@: ID) :*:
  43. (K $ Tag "job" String) :*:
  44. (K $ Tag "firstName" String) :*:
  45. (K $ Tag "lastName" String)
  46. type EmpT = Mu (
  47. ([] :@: ID) :*:
  48. (K String) :*:
  49. (K String) :*:
  50. (K String)
  51. )
  52. -- | Map nominal type onto a structural one.
  53. emp2fix :: Emp -> EmpT
  54. emp2fix (Emp et) = ana aux et
  55. where
  56. aux (EmployeeType s e f l) = Pair (
  57. Comp (Prelude.map Id s)) (Pair (
  58. Const e) (Pair (
  59. Const f) (
  60. Const l)))
  61. -- The European Commission
  62. -- http://europa.eu.int/comm/commission_barroso/index_en.htm
  63. ec = Emp $ EmployeeType {
  64. emp_seq = [
  65. EmployeeType {
  66. emp_seq = [
  67. EmployeeType [] "Driver" "Asdren" "Juniku",
  68. EmployeeType [] "Head of Cabinet" "Ben" "Smulders"
  69. ],
  70. job = "Competition",
  71. firstName = "Neelie",
  72. lastName = "Kroes"
  73. },
  74. EmployeeType [] "Trade" "Peter" "Mandelson"
  75. ],
  76. job = "President",
  77. firstName = "Durao",
  78. lastName = "Barroso"
  79. }
  80. test = do
  81. -- Map the original format to a database
  82. let (Just vw) = toRDB emp
  83. putStrLn $ showType vw
  84. -- Forward migration
  85. let rdbType = Prod (Prod
  86. Int (
  87. Map Int (Prod (Prod String String) String))) (
  88. Map (Prod Int Int) Int)
  89. unless (showType vw == show rdbType) $ fail "Different type expected"
  90. let (Just ecDB) = forth vw rdbType $ emp2fix ec
  91. putStrLn $ gshow rdbType ecDB
  92. -- Backward migration
  93. let (Just ec') = back vw rdbType ecDB
  94. putStrLn $ gshow emp ec'
  95. unless (gshow emp ec' == gshow emp (emp2fix ec)) $ fail "Original value not recovered"
  96. -- Evolve format to allow several jobs per person.
  97. -- let (Just vw1) = (once (inside "job" allowRep1)) emp
  98. -- putStrLn $ showType vw1
  99. testDyn = do
  100. -- Map the original format to a database
  101. let (Just vw) = toRDB emp
  102. putStrLn $ showType vw
  103. -- Forward migration
  104. putStrLn "Forward migration ..."
  105. let (Just ecRdbDyn) = forthDyn vw $ emp2fix ec
  106. putStrLn $ show ecRdbDyn
  107. putStrLn $ applyDyn gshow ecRdbDyn
  108. -- Backward migration to original format
  109. putStrLn "Backward migration to original format ..."
  110. let (Just ec'') = backDyn vw ecRdbDyn
  111. unless (ec'' == emp2fix ec) $ fail "Original value not recovered"
  112. unless (gshow emp ec'' == gshow emp (emp2fix ec)) $ fail "Original value not recovered"
  113. putStrLn $ gshow emp ec''
  114. -- Backward migration to *different* format
  115. putStrLn "Backward migration to *different* format ..."
  116. let empList = List (Prod (Tag "function" String) (Prod (Tag "first" String) (Tag "last" String)))
  117. -- let (Just vw') = (toRDB >>> (addfield (Map (Prod Int Int) Int) Map.empty) >>> (addfieldl Int (-1))) empList
  118. let (Just vw') = (toRDB >>> (addfieldl Int (-1)) >>> (addfield (Map (Prod Int Int) Int) Map.empty)) empList
  119. putStrLn $ showType vw'
  120. let (Just el) = backDyn vw' ecRdbDyn
  121. putStrLn $ gshow empList el
  122. -----------------------------------------------------------------------------