From 3a2418d302ee14b9605ebe3013cf417ea5cf0057 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 12 Jun 2014 17:25:44 -0400 Subject: [PATCH] Implement a good deal of the AutoRacingResults (un)pickling. --- src/TSN/XML/AutoRacingResults.hs | 290 +++++++++++++++++++++++++++++-- 1 file changed, 275 insertions(+), 15 deletions(-) diff --git a/src/TSN/XML/AutoRacingResults.hs b/src/TSN/XML/AutoRacingResults.hs index f8221bb..fc19656 100644 --- a/src/TSN/XML/AutoRacingResults.hs +++ b/src/TSN/XML/AutoRacingResults.hs @@ -3,7 +3,6 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} @@ -11,19 +10,21 @@ -- module TSN.XML.AutoRacingResults ( dtd, --- pickle_message, + pickle_message, -- * Tests -- auto_racing_results_tests, -- * WARNING: these are private but exported to silence warnings AutoRacingResultsConstructor(..), - AutoRacingResultsListingConstructor(..) ) --- AutoRacingResultsRaceInformationConstructor(..) ) + AutoRacingResultsListingConstructor(..), + AutoRacingResultsRaceInformationConstructor(..) ) where -- System imports. import Control.Monad ( forM_ ) +import Data.Data ( Data ) import Data.Time ( UTCTime(..) ) import Data.Tuple.Curry ( uncurryN ) +import Data.Typeable ( Typeable ) import Database.Groundhog ( countAll, deleteAll, @@ -40,21 +41,25 @@ import Test.Tasty ( TestTree, testGroup ) import Test.Tasty.HUnit ( (@?=), testCase ) import Text.XML.HXT.Core ( PU, - xp7Tuple, - xp8Tuple, - xp10Tuple, + xp11Tuple, + xp12Tuple, + xp13Tuple, + xpAttr, xpElem, xpInt, xpList, xpOption, + xpPair, + xpPrim, xpText, + xpTriple, xpWrap ) -- Local imports. import TSN.Codegen ( tsn_codegen_config ) import TSN.DbImport ( DbImport(..), ImportResult(..), run_dbmigrate ) -import TSN.Picklers ( xp_date, xp_tba_time, xp_time_stamp ) +import TSN.Picklers ( xp_earnings, xp_racedate, xp_time_stamp ) import TSN.XmlImport ( XmlImport(..), XmlImportFk(..) ) import Xml ( FromXml(..), @@ -84,9 +89,9 @@ data AutoRacingResults = db_heading :: String, db_category :: String, db_sport :: String, - db_title :: String, db_race_id :: Int, db_race_date :: UTCTime, + db_title :: String, db_track_location :: String, db_laps_remaining :: Int, db_checkered_flag :: Bool, @@ -103,14 +108,14 @@ data Message = xml_heading :: String, xml_category :: String, xml_sport :: String, - xml_title :: String, xml_race_id :: Int, xml_race_date :: UTCTime, + xml_title :: String, xml_track_location :: String, xml_laps_remaining :: Int, xml_checkered_flag :: Bool, xml_listings :: [AutoRacingResultsListingXml], --- xml_race_information :: AutoRacingResultsRaceInformation, + xml_race_information :: AutoRacingResultsRaceInformationXml, xml_time_stamp :: UTCTime } deriving (Eq, Show) @@ -134,9 +139,9 @@ instance FromXml Message where db_heading = xml_heading, db_category = xml_category, db_sport = xml_sport, - db_title = xml_title, db_race_id = xml_race_id, db_race_date = xml_race_date, + db_title = xml_title, db_track_location = xml_track_location, db_laps_remaining = xml_laps_remaining, db_checkered_flag = xml_checkered_flag, @@ -166,12 +171,11 @@ data AutoRacingResultsListing = db_points :: Int, db_laps_completed :: Int, db_laps_leading :: Int, - db_status :: Int, + db_status :: Maybe String, db_dnf :: Maybe Bool, db_nc :: Maybe Bool, db_earnings :: Maybe Int } - -- | XML representation of a \ contained within a -- \. -- @@ -186,7 +190,7 @@ data AutoRacingResultsListingXml = xml_points :: Int, xml_laps_completed :: Int, xml_laps_leading :: Int, - xml_status :: Int, + xml_status :: Maybe String, xml_dnf :: Maybe Bool, xml_nc :: Maybe Bool, xml_earnings :: Maybe Int } @@ -234,11 +238,119 @@ instance XmlImportFk AutoRacingResultsListingXml +-- * AutoRacingResultsRaceInformation / AutoRacingResultsRaceInformationXml + +-- | The \ child of \ always +-- contains exactly three fields, so we just embed those three into +-- the 'AutoRacingResultsRaceInformation' type. We (pointlessly) use +-- the \"db_\" prefix since our field namer is going to strip of +-- everything before the first underscore. +-- +data MostLapsLeading = + MostLapsLeading { + db_most_laps_leading_driver_id :: Int, + db_most_laps_leading_driver :: String, + db_most_laps_leading_number_of_laps :: Int } + deriving (Data, Eq, Show, Typeable) + + +-- | Database representation of a \ contained within a +-- \. +-- +data AutoRacingResultsRaceInformation = + AutoRacingResultsRaceInformation { + -- Note the apostrophe to disambiguate it from the + -- AutoRacingResultsListing filed. + db_auto_racing_results_id' :: DefaultKey AutoRacingResults, + db_track_length :: Double, + db_track_length_kph :: Double, + db_laps :: Int, + db_average_speed_mph :: Maybe Double, + db_average_speed_kph :: Maybe Double, + db_average_speed :: Maybe Double, + db_time_of_race :: Maybe String, + db_margin_of_victory :: Maybe String, + db_cautions :: Maybe String, + db_lead_changes :: Maybe String, + db_lap_leaders :: Maybe String, + db_most_laps_leading :: MostLapsLeading } + + +-- | XML representation of a \ contained within a +-- \. +-- +data AutoRacingResultsRaceInformationXml = + AutoRacingResultsRaceInformationXml { + xml_track_length :: Double, + xml_track_length_kph :: Double, + xml_laps :: Int, + xml_average_speed_mph :: Maybe Double, + xml_average_speed_kph :: Maybe Double, + xml_average_speed :: Maybe Double, + xml_time_of_race :: Maybe String, + xml_margin_of_victory :: Maybe String, + xml_cautions :: Maybe String, + xml_lead_changes :: Maybe String, + xml_lap_leaders :: Maybe String, + xml_most_laps_leading :: MostLapsLeading } + deriving (Eq,Show) + + +instance ToDb AutoRacingResultsRaceInformationXml where + -- | The database analogue of an + -- 'AutoRacingResultsRaceInformationXml' is an + -- 'AutoRacingResultsRaceInformation'. + -- + type Db AutoRacingResultsRaceInformationXml = + AutoRacingResultsRaceInformation + +instance FromXmlFk AutoRacingResultsRaceInformationXml where + -- | Each 'AutoRacingResultsRaceInformationXml' is contained in + -- (i.e. has a foreign key to) a 'AutoRacingResults'. + -- + type Parent AutoRacingResultsRaceInformationXml = AutoRacingResults + + -- | To convert an 'AutoRacingResultsRaceInformationXml' to an + -- 'AutoRacingResultsRaceInformartion', we add the foreign key and + -- copy everything else verbatim. + -- + from_xml_fk fk AutoRacingResultsRaceInformationXml{..} = + AutoRacingResultsRaceInformation { + db_auto_racing_results_id' = fk, + db_track_length = xml_track_length, + db_track_length_kph = xml_track_length_kph, + db_laps = xml_laps, + db_average_speed_mph = xml_average_speed_mph, + db_average_speed_kph = xml_average_speed_kph, + db_average_speed = xml_average_speed, + db_time_of_race = xml_time_of_race, + db_margin_of_victory = xml_margin_of_victory, + db_cautions = xml_cautions, + db_lead_changes = xml_lead_changes, + db_lap_leaders = xml_lap_leaders, + db_most_laps_leading = xml_most_laps_leading } + + +-- | This allows us to insert the XML representation +-- 'AutoRacingResultsRaceInformationXml' directly. +-- +instance XmlImportFk AutoRacingResultsRaceInformationXml + + --- --- Database stuff. --- +instance DbImport Message where + dbmigrate _ = + run_dbmigrate $ do + migrate (undefined :: AutoRacingResults) + migrate (undefined :: AutoRacingResultsListing) + migrate (undefined :: AutoRacingResultsRaceInformation) + + dbimport = undefined + mkPersist tsn_codegen_config [groundhog| - entity: AutoRacingResults @@ -260,4 +372,152 @@ mkPersist tsn_codegen_config [groundhog| - name: db_auto_racing_results_id reference: onDelete: cascade + + +- entity: AutoRacingResultsRaceInformation + dbName: auto_racing_results_race_information + constructors: + - name: AutoRacingResultsRaceInformation + fields: + - name: db_auto_racing_results_id' + reference: + onDelete: cascade + - name: db_most_laps_leading + embeddedType: + - {name: most_laps_leading_driver_id, dbName: most_laps_leading_driver_id} + - {name: most_laps_leading_driver, dbName: most_laps_leading_driver} + +- embedded: MostLapsLeading + fields: + - name: db_most_laps_leading_driver_id + dbName: most_laps_leading_driver_id + - name: db_most_laps_leading_driver + dbName: most_laps_leading_driver + - name: db_most_laps_leading_number_of_laps + dbName: most_laps_leading_number_of_laps |] + + +--- +--- Pickling +--- + +pickle_listing :: PU AutoRacingResultsListingXml +pickle_listing = + xpElem "Listing" $ + xpWrap (from_tuple, to_tuple) $ + xp13Tuple (xpElem "FinishPosition" xpInt) + (xpElem "StartingPosition" xpInt) + (xpElem "CarNumber" xpInt) + (xpElem "DriverID" xpInt) + (xpElem "Driver" xpText) + (xpElem "CarMake" xpText) + (xpElem "Points" xpInt) + (xpElem "Laps_Completed" xpInt) + (xpElem "Laps_Leading" xpInt) + (xpElem "Status" $ xpOption xpText) + (xpOption $ xpElem "DNF" xpPrim) + (xpOption $ xpElem "NC" xpPrim) + (xpElem "Earnings" xp_earnings) + where + from_tuple = uncurryN AutoRacingResultsListingXml + to_tuple m = (xml_finish_position m, + xml_starting_position m, + xml_car_number m, + xml_driver_id m, + xml_driver m, + xml_car_make m, + xml_points m, + xml_laps_completed m, + xml_laps_leading m, + xml_status m, + xml_dnf m, + xml_nc m, + xml_earnings m) + + +-- | Pickler for the top-level 'Message'. +pickle_message :: PU Message +pickle_message = + xpElem "message" $ + xpWrap (from_tuple, to_tuple) $ + xp13Tuple (xpElem "XML_File_ID" xpInt) + (xpElem "heading" xpText) + (xpElem "category" xpText) + (xpElem "sport" xpText) + (xpElem "RaceID" xpInt) + (xpElem "RaceDate" xp_racedate) + (xpElem "Title" xpText) + (xpElem "Track_Location" xpText) + (xpElem "Laps_Remaining" xpInt) + (xpElem "Checkered_Flag" xpPrim) + (xpList pickle_listing) + pickle_race_information + (xpElem "time_stamp" xp_time_stamp) + where + from_tuple = uncurryN Message + to_tuple m = (xml_xml_file_id m, + xml_heading m, + xml_category m, + xml_sport m, + xml_race_id m, + xml_race_date m, + xml_title m, + xml_track_location m, + xml_laps_remaining m, + xml_checkered_flag m, + xml_listings m, + xml_race_information m, + xml_time_stamp m) + + +pickle_most_laps_leading :: PU MostLapsLeading +pickle_most_laps_leading = + xpElem "Most_Laps_Leading" $ + xpWrap (from_tuple, to_tuple) $ + xpTriple (xpElem "DriverID" xpInt) + (xpElem "Driver" xpText) + (xpElem "NumberOfLaps" xpInt) + where + from_tuple = uncurryN MostLapsLeading + to_tuple m = (db_most_laps_leading_driver_id m, + db_most_laps_leading_driver m, + db_most_laps_leading_number_of_laps m) + +pickle_race_information :: PU AutoRacingResultsRaceInformationXml +pickle_race_information = + xpElem "Race_Information" $ + xpWrap (from_tuple, to_tuple) $ + xp11Tuple (-- I can't think of another way to get both the + -- TrackLength and its KPH attribute. So we shove them + -- both in a 2-tuple. + xpElem "TrackLength" $ xpPair xpPrim (xpAttr "KPH" xpPrim) ) + (xpElem "Laps" xpInt) + (xpOption $ xpElem "AverageSpeedMPH" xpPrim) + (xpOption $ xpElem "AverageSpeedKPH" xpPrim) + (xpOption $ xpElem "AverageSpeed" xpPrim) + (xpOption $ xpElem "TimeOfRace" xpText) + (xpOption $ xpElem "MarginOfVictory" xpText) + (xpOption $ xpElem "Cautions" xpText) + (xpOption $ xpElem "LeadChanges" xpText) + (xpOption $ xpElem "LapLeaders" xpText) + pickle_most_laps_leading + where + -- Derp. Since the first two are paired, we have to + -- manually unpack the bazillion arguments. + from_tuple ((x1,x2),x3,x4,x5,x6,x7,x8,x9,x10,x11,x12) = + AutoRacingResultsRaceInformationXml + x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 + + -- And here we have to re-pair the first two. + to_tuple m = ((xml_track_length m, xml_track_length_kph m), + xml_laps m, + xml_average_speed_mph m, + xml_average_speed_kph m, + xml_average_speed m, + xml_time_of_race m, + xml_margin_of_victory m, + xml_cautions m, + xml_lead_changes m, + xml_lap_leaders m, + xml_most_laps_leading m) -- 2.43.2