content: -- Copyright (c) 2017 Uber Technologies, Inc.
  --
  -- Permission is hereby granted, free of charge, to any person obtaining a copy
  -- of this software and associated documentation files (the "Software"), to deal
  -- in the Software without restriction, including without limitation the rights
  -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  -- copies of the Software, and to permit persons to whom the Software is
  -- furnished to do so, subject to the following conditions:
  --
  -- The above copyright notice and this permission notice shall be included in
  -- all copies or substantial portions of the Software.
  --
  -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  -- THE SOFTWARE.
  
  module Database.Sql.Vertica.Parser.IngestionOptions where
  
  import Database.Sql.Info
  import Database.Sql.Helpers
  
  import Database.Sql.Vertica.Parser.Internal
  import Database.Sql.Position
  
  import qualified Database.Sql.Vertica.Parser.Token as Tok
  import Database.Sql.Vertica.Parser.Shared
  
  import           Text.Parsec ( choice
                               , option, optional
                               , sepBy, sepBy1, (<|>))
  
  
  ingestionColumnListP :: Parser Range -> Parser Range
  ingestionColumnListP exprP = do
      s <- Tok.openP
      _ <- columnSpecP `sepBy1` Tok.commaP
      e <- Tok.closeP
      return $ s <> e
    where
      columnSpecP = do
          (_, s) <- Tok.columnNameP
          e <- consumeOrderedOptions s $
              [ Tok.asP >> exprP
              , delimiterAsP
              , enclosedByP
              , Tok.enforceLengthP
              , escapeFormatP
              , fillerP
              , columnStorageFormatP
              , nullAsP
              , trimByteP
              ]
          return $ s <> e
  
  ingestionColumnOptionP :: Parser Range
  ingestionColumnOptionP = do
      s <- Tok.columnP
      _ <- Tok.optionP
      _ <- Tok.openP
      _ <- optionSpecP `sepBy1` Tok.commaP
      e <- Tok.closeP
      return $ s <> e
    where
      optionSpecP = do
          (_, s) <- Tok.columnNameP
          consumeOrderedOptions s $
              [ delimiterAsP
              , enclosedByP
              , Tok.enforceLengthP
              , escapeFormatP
              , columnStorageFormatP
              , nullAsP
              , trimByteP
              ]
  
  fileStorageFormatP :: Parser Range
  fileStorageFormatP = choice $
      [ do
           r <- Tok.nativeP
           option r (snd <$> Tok.varCharP)
      , do
           s <- Tok.fixedWidthP
           _ <- Tok.colSizesP
           _ <- Tok.openP
           _ <- Tok.numberP `sepBy1` Tok.commaP
           e <- Tok.closeP
           return $ s <> e
      , Tok.orcP
      , Tok.parquetP
      ]
  
  abortOnErrorP :: Parser Range
  abortOnErrorP = Tok.abortP >> Tok.onP >> Tok.errorP
  
  delimiterAsP :: Parser Range
  delimiterAsP = Tok.delimiterP >> optional Tok.asP >> snd <$> Tok.stringP
  
  enclosedByP :: Parser Range
  enclosedByP = Tok.enclosedP >> optional Tok.byP >> snd <$> Tok.stringP
  
  errorToleranceP :: Parser Range
  errorToleranceP = Tok.errorP >> Tok.toleranceP
  
  escapeFormatP :: Parser Range
  escapeFormatP = choice $
      [ Tok.escapeP >> Tok.asP >> snd <$> Tok.stringP
      , Tok.noP >> Tok.escapeP
      ]
  
  exceptionsOnNodeP :: Parser Range
  exceptionsOnNodeP = do
      s <- Tok.exceptionsP
      e <- snd <$> Tok.stringP
      let onNodeP = Tok.onP >> snd <$> Tok.nodeNameP
      e' <- option e $ last <$> (onNodeP `sepBy1` Tok.commaP)
      return $ s <> e'
  
  fileFilterP :: Parser Range
  fileFilterP = do
      s <- Tok.filterP
      _ <- Tok.functionNameP
      _ <- Tok.openP
      let argP = do
              _ <- Tok.paramNameP
              _ <- Tok.equalP
              getInfo <$> constantP
      _ <- argP `sepBy` Tok.commaP
      e <- Tok.closeP
      return $ s <> e
  
  fileParserP :: Parser Range
  fileParserP = do
      s <- Tok.parserP
      _ <- Tok.functionNameP
      _ <- Tok.openP
      let argP = do
              _ <- Tok.paramNameP
              _ <- Tok.equalP
              snd <$> Tok.parserNameP
      _ <- argP `sepBy` Tok.commaP
      e <- Tok.closeP
      return $ s <> e
  
  fileSourceP :: Parser Range
  fileSourceP = do
      s <- Tok.sourceP
      _ <- Tok.functionNameP
      _ <- Tok.openP
      let argP = do
              _ <- Tok.paramNameP
              _ <- Tok.equalP
              snd <$> Tok.stringP
      _ <- argP `sepBy` Tok.commaP
      e <- Tok.closeP
      return $ s <> e
  
  fillerP :: Parser Range
  fillerP = Tok.fillerP >> getInfo <$> dataTypeP
  
  columnStorageFormatP :: Parser Range
  columnStorageFormatP = Tok.formatP >> snd <$> Tok.stringP
  
  noCommitP :: Parser Range
  noCommitP = Tok.noP >> Tok.commitP
  
  nullAsP :: Parser Range
  nullAsP = Tok.nullP >> optional Tok.asP >> snd <$> Tok.stringP
  
  recordTerminatorP :: Parser Range
  recordTerminatorP = Tok.recordP >> Tok.terminatorP >> snd <$> Tok.stringP
  
  rejectedDataOnNodeP :: Parser Range
  rejectedDataOnNodeP = do
      s <- Tok.rejectedP
      _ <- Tok.dataP
      e <- choice $
          [ do
              e' <- snd <$> Tok.stringP
              let onNodeP = Tok.onP >> snd <$> Tok.nodeNameP
              option e' $ last <$> (onNodeP `sepBy1` Tok.commaP)
          , do
              _ <- Tok.asP
              _ <- Tok.tableP
              getInfo <$> tableNameP
          ]
      return $ s <> e
  
  rejectMaxP :: Parser Range
  rejectMaxP = Tok.rejectMaxP >> snd <$> Tok.numberP
  
  skipBytesP :: Parser Range
  skipBytesP = Tok.skipP >> Tok.bytesP >> snd <$> Tok.numberP
  
  skipRecordsP :: Parser Range
  skipRecordsP = Tok.skipP >> snd <$> Tok.numberP
  
  streamNameP :: Parser Range
  streamNameP = Tok.streamP >> Tok.nameP >> snd <$> Tok.stringP
  
  trailingNullColsP :: Parser Range
  trailingNullColsP = Tok.trailingP >> Tok.nullColsP
  
  trimByteP :: Parser Range
  trimByteP = Tok.trimP >> snd <$> Tok.stringP
  
  compressionP :: Parser Range
  compressionP = choice $
      [ Tok.bzipP
      , Tok.gzipP
      , Tok.lzoP
      , Tok.uncompressedP
      ]
  
  loadMethodP :: Parser Range
  loadMethodP = Tok.autoP <|> Tok.directP <|> Tok.trickleP
  