packages feed

tsvsql (empty) → 0.1.1.0

raw patch · 7 files changed

+190/−0 lines, 7 filesdep +attoparsecdep +basedep +bytestringsetup-changed

Dependencies added: attoparsec, base, bytestring, containers, optparse-applicative, text, unordered-containers

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2014 Daniel Choi++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.
+ Main.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables#-}+module Main where+import Data.Monoid+import qualified Data.Map.Strict as M+import Data.Text (Text)+import qualified Data.Text.Encoding as T (decodeUtf8)+import Data.List (intersperse)+import qualified Data.List +import qualified Data.Text as T+import qualified Data.Text.IO as T+import Data.Maybe (catMaybes)+import Control.Applicative+import Control.Monad (when)+import Data.Attoparsec.Text +import System.Environment (getArgs)+import qualified Options.Applicative as O++data Options = Options {  +      template :: Template+    } deriving Show++data Template = TemplateFile FilePath | TemplateText Text deriving (Show)++parseOpts :: O.Parser Options+parseOpts = Options <$> (tmplText <|> tmplFile)++tmplText = TemplateText . T.pack <$> O.argument O.str (O.metavar "TEMPLATE")+tmplFile = TemplateFile +      <$> O.strOption (O.metavar "FILE" <> O.short 'f' <> O.help "Template file")++opts = O.info (O.helper <*> parseOpts)+          (O.fullDesc +          <> O.progDesc "Inject TSV into SQL template strings" +          <> O.header "tsvsql 0.1.1.0")++main = do+  Options tmpl <- O.execParser opts+  template <- case tmpl of+                  TemplateFile fp -> T.readFile fp+                  TemplateText t -> return t+  xs :: [[Text]] <- fmap (map (T.splitOn "\t") . T.lines) T.getContents +  let chunks :: [TemplateChunk] +      chunks = parseText template+      results = map (evalText chunks) xs+  mapM_ T.putStrLn results++data ValType = String | Bool | Number deriving (Eq, Show)++data TemplateChunk = Pass Text +    | Placeholder Int ValType +    deriving (Show, Eq)++evalText :: [TemplateChunk] -> [Text] -> Text+evalText xs vals = mconcat $ map (evalChunk vals) xs++evalChunk :: [Text] -> TemplateChunk -> Text+evalChunk vs (Pass s) = s+evalChunk vs (Placeholder idx _) | (vs !! idx) == "null" = "NULL"+evalChunk vs (Placeholder idx String) = wrapQuote (vs !! idx)+evalChunk vs (Placeholder idx Number) | (vs !! idx) == "" = "NULL"+                                      | otherwise         = (vs !! idx)+evalChunk vs (Placeholder idx Bool) | (vs !! idx) == "t" = "true"+evalChunk vs (Placeholder idx Bool) | (vs !! idx) == "f" = "false"++wrapQuote x = T.singleton '\'' <> (escapeText x) <> T.singleton '\''++escapeText = T.pack . escapeStringLiteral . T.unpack ++escapeStringLiteral :: String -> String+escapeStringLiteral ('\'':xs) = '\'': ('\'' : escapeStringLiteral xs)+escapeStringLiteral (x:xs) = x : escapeStringLiteral xs+escapeStringLiteral [] = []++parseText :: Text -> [TemplateChunk]+parseText = either error id . parseOnly (many textChunk)++textChunk = placeholderChunk <|> passChunk++placeholderChunk :: Parser TemplateChunk+placeholderChunk = do+    try (char '$')+    idx <- decimal+    type' <- pType+    return $ Placeholder (idx - 1) type'++pType :: Parser ValType+pType = +  (do+    try (char ':') +    (Bool <$ string "bool") <|> (Number <$ string "num"))+  <|> pure String+  +passChunk :: Parser TemplateChunk+passChunk = Pass <$> takeWhile1 (notInClass "$")+++------------------------------------------------------------------------+
+ README view
@@ -0,0 +1,35 @@+tsvsql++Templates TSV values into a SQL template++input.tsv:+apple 1+banana 2++tsvsql $ < input.tsv dist/build/tsvsql/tsvsql 'INSERT into fruits (name, price) VALUES ($1, $2:num);'+INSERT into fruits (name, price) VALUES ('apple', 1);+INSERT into fruits (name, price) VALUES ('banana', 2);+++WARNING: Use single quotes around the SQL template expression so that+Bash does not do interpolation.++'null' text is translated into NULL:++input2.tsv+apple	1+banana	null++tsvsql $ < input2.tsv dist/build/tsvsql/tsvsql 'INSERT into fruits (name, price) VALUES ($1, $2:num);'+INSERT into fruits (name, price) VALUES ('apple', 1);+INSERT into fruits (name, price) VALUES ('banana', NULL);+++The subtitution placeholders are like this:++    $1      # value is a string; the value is quoted and escaped+    $2:num  # value is a number; not quoted+    $3:bool # value is a bool; "t" is true, "f" is false++The placeholders start counting the first TSV value from position 1, not+zero.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ input.tsv view
@@ -0,0 +1,2 @@+apple	1+banana	2
+ input2.tsv view
@@ -0,0 +1,2 @@+apple	1+banana	null
+ tsvsql.cabal view
@@ -0,0 +1,31 @@+-- Initial tsvsql.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                tsvsql+version:             0.1.1.0+synopsis:            Template tsv into SQL+-- description:         +homepage:            https://github.com/danchoi/tsvsql+license:             MIT+license-file:        LICENSE+author:              Daniel Choi+maintainer:          dhchoi@gmail.com+-- copyright:           +category:            Text+build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10++executable tsvsql+  main-is:             Main.hs+  -- other-modules:       +  -- other-extensions:    +  build-depends:       base >=4.6 && <4.8+                     , unordered-containers +                     , containers +                     , text >= 1.1.0.0+                     , bytestring +                     , optparse-applicative+                     , attoparsec+  -- hs-source-dirs:      +  default-language:    Haskell2010