packages feed

roguestar-gl-0.2.1: src/Tables.lhs

\section{Tables}

\begin{code}
module Tables
    (RoguestarTable(..),
     TableDataFormat(..),
     tableSelect,
     tableSelectFormatted,
     tableLookup,
     tableLookupInteger)
    where

import Data.List
import Data.Maybe
import RSAGL.Time
import Control.Monad
import RSAGL.AbstractVector
\end{code}

\texttt{RoguestarTable} is a crude implementation of a relational data table that is used to represent information that has been sent to us from roguestar-engine.

\begin{code}
data RoguestarTable = RoguestarTable { table_created :: Time, table_name, table_id :: String, table_header :: [String], table_data :: [[String]] }
		      deriving (Eq,Show)
\end{code}

\texttt{tableSelect} selects rows from a table, like the SQL select statement.
For example: \texttt{tableSelect people ["name","sex","phone-number"] = [["bob","male","123-4567"],["susan","female","987-6543"]]}
If a given header is not in the table, it lists \texttt{"???"} as the value.

There is a guarantee that all select functions will return results in the same order.

\begin{code}
tableSelect :: RoguestarTable -> [String] -> [[String]]
tableSelect table headers = let header_indices = map (\x -> elemIndex x $ table_header table) headers
				in map (rowSelect header_indices) $ table_data table

rowSelect :: [Maybe Int] -> [String] -> [String]
rowSelect (Nothing:more) row = "???" : rowSelect more row
rowSelect (Just x:more) row = (row !! x) : rowSelect more row
rowSelect [] _ = []
\end{code}

\texttt{tableSelectFormatted} allows Selection of arbitrary strings and integers.

\begin{code}
tableSelectFormatted :: RoguestarTable -> [TableDataFormat String String] -> [[TableDataFormat String Integer]]
tableSelectFormatted table headers = map (toFormat headers) $ tableSelect table (map toString headers)
\end{code}

\texttt{tableLookup table ("name","phone-number") "bob"} yields Bob's phone number, or nothing if "bob" isn't in the table.

\begin{code}
tableLookup :: RoguestarTable -> (String,String) -> String -> Maybe String
tableLookup table (k,v) x = fmap (!! 1) $ find ((== x) . head) $ tableSelect table [k,v]
\end{code}

\texttt{tableLookupInteger} works as \texttt{tableLookup}, but answers an \texttt{Integer}.

\begin{code}
tableLookupInteger :: RoguestarTable -> (String,String) -> String -> Maybe Integer
tableLookupInteger table headers x = tableLookup table headers x >>= readInteger
\end{code}

\subsection{Formatting Arbitrary Table Elements}

\begin{code}
data TableDataFormat s n = TDString s
                         | TDNumber n

readInteger :: String -> Maybe Integer
readInteger = listToMaybe . map fst . reads

toString :: TableDataFormat String String -> String
toString (TDString str) = str
toString (TDNumber str) = str

toFormat :: [TableDataFormat a b] -> [String] -> [TableDataFormat String Integer]
toFormat headers row = zipWith toFormat_ headers row
    where toFormat_ (TDString {}) str = TDString str
          toFormat_ (TDNumber {}) str = maybe (TDString str) TDNumber $ readInteger str
\end{code}