-----------------------------------------------------------------------------
-- |
-- Copyright : (c) Keith Sheppard 2009
-- License : GPL3 or greater
-- Maintainer : keithshep@gmail.com
-- Stability : experimental
-- Portability : portable
--
-- Main entry point for the TxtSushi SQL command line
--
-----------------------------------------------------------------------------
import Data.List
import qualified Data.Map as Map
import System.Environment
import System.Exit
import System.IO
import Text.ParserCombinators.Parsec
import TxtSushi.IO
import TxtSushi.SQLExecution
import TxtSushi.SQLParser
import TxtSushi.Transform
import Util.CommandLineArgument
import Util.IOUtil
helpOption = OptionDescription {
isRequired = False,
optionFlag = "-help",
argumentNames = [],
minArgumentCount = 0,
argumentCountIsFixed = True}
tableDefOption = OptionDescription {
isRequired = False,
optionFlag = "-table",
argumentNames = ["CSV-file-name", "table-name"],
minArgumentCount = 2,
argumentCountIsFixed = True}
turtleSqlOpts = [helpOption, tableDefOption]
sqlCmdLine = CommandLineDescription {
options = turtleSqlOpts,
minTailArgumentCount = 1,
tailArgumentNames = ["SQL-select-statement"],
tailArgumentCountIsFixed = True}
validateTableNames :: [String] -> [String] -> Bool
validateTableNames [] _ = True
validateTableNames (argTblHead:argTblTail) selectTbls =
if argTblHead `elem` selectTbls then
validateTableNames argTblTail selectTbls
else
error $ "The given table name \"" ++ argTblHead ++
"\" does not appear in the SELECT statement"
tableArgsToMap [] = Map.empty
tableArgsToMap (currTableArgs:tailTableArgs) =
case currTableArgs of
[fileName, tableName] ->
Map.insert fileName tableName (tableArgsToMap tailTableArgs)
otherwise ->
error $ "the \"" ++ (optionFlag tableDefOption) ++
"\" option should have exactly two arguments"
unwrapMapList [] = return []
unwrapMapList ((key, value):mapTail) = do
unwrappedValue <- value
unwrappedTail <- unwrapMapList mapTail
return $ (key, unwrappedValue):unwrappedTail
printUsage progName =
putStrLn $ "Usage: " ++ progName ++ " " ++ formatCommandLine sqlCmdLine
main = do
args <- getArgs
progName <- getProgName
let (argMap, argTail) = extractCommandLineArguments sqlCmdLine args
showHelp = Map.member helpOption argMap || length argTail /= 1
parseOutcome = parse parseSelectStatement "" (head argTail)
if showHelp then printUsage progName else
case parseOutcome of
Left err -> print err
Right selectStmt ->
let
-- create a table file map from the user args
tableArgs = Map.findWithDefault [] tableDefOption argMap
tableArgMap = tableArgsToMap tableArgs
-- get a default table to file map from the select statement
selectTblNames = allMaybeTableNames (maybeFromTable selectStmt)
defaultTblMap = Map.fromList (zip selectTblNames selectTblNames)
-- join the two with arg values taking precidence over
-- the default values
finalTblFileMap = tableArgMap `Map.union` defaultTblMap
in
-- turn the files into strings
if validateTableNames (Map.keys tableArgMap) selectTblNames
then do
let contentsMap = Map.map getContentsFromFileOrStdin finalTblFileMap
unwrappedContents <- unwrapMapList $ Map.toList contentsMap
let unwrappedContentsMap = Map.fromList unwrappedContents
textTableMap = Map.map (parseTable csvFormat) unwrappedContentsMap
dbTableMap = Map.mapWithKey textTableToDatabaseTable textTableMap
selectedDbTable = select selectStmt dbTableMap
selectedTxtTable = databaseTableToTextTable selectedDbTable
putStr $ formatTable csvFormat selectedTxtTable
else
exitFailure