From 72b3e389801506290d9637b48cc014d4cd7a7e15 Mon Sep 17 00:00:00 2001 From: Dhananjay Balan Date: Thu, 13 Apr 2023 23:43:39 +0200 Subject: [PATCH] Add an importer binary. --- README.md | 2 +- app/Main.hs | 17 ++--------------- importer/Main.hs | 23 +++++++++++++++++++++++ lib/Config.hs | 28 ++++++++++++++++++++++++++++ lib/Database.hs | 25 +++++++++++++++++++++++++ quotes-api.cabal | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 importer/Main.hs create mode 100644 lib/Database.hs diff --git a/README.md b/README.md index 3aaacec..da71b5c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Personal, bare bones [readwise] alternative. Have - Parsers - [-] Read from kindle - - [ ] Read from readwise + - [x] Read from readwise - [x] Read from KOReader - [x] Minimal API - Expose random-quote API diff --git a/app/Main.hs b/app/Main.hs index 2001d61..9b5ba9c 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -22,6 +22,7 @@ import qualified Parsers.KOReader as KO import qualified Parsers.Readwise as RW import Config import Options.Applicative +import Database data User = User { username :: T.Text @@ -50,16 +51,6 @@ checkBasicAuth user passhash = BasicAuthCheck $ \authData -> _ -> return Unauthorized -initDb :: FilePath -> IO () -initDb dbFile = withConnection dbFile $ \conn -> - execute_ conn - [sql|CREATE TABLE IF NOT EXISTS quotes ( quote text non null - , author text - , title text - , page text - , chapter text - , created_on integer);|] - -- | TODO: readerT server :: FilePath -> Server API server dbf = randomQuote dbf @@ -83,12 +74,8 @@ listQuotes db = liftIO $ withConnection db $ \conn -> query_ conn [sql|SELECT * addKoReader :: FilePath -> KO.KoHighlight -> Handler NoContent addKoReader db hl = do - liftIO $ withConnection db $ \c -> - executeMany c qry qts + liftIO $ insertQts db (KO.parse hl) pure NoContent - where - qry = [sql|INSERT INTO quotes VALUES (?,?,?,?,?,?);|] - qts = KO.parse hl addReadwise :: FilePath -> T.Text -> Handler NoContent addReadwise db hl = do diff --git a/importer/Main.hs b/importer/Main.hs new file mode 100644 index 0000000..12db0fe --- /dev/null +++ b/importer/Main.hs @@ -0,0 +1,23 @@ +module Main where + +import Options.Applicative +import qualified Data.ByteString.Lazy as BSL + +import Config +import Database + +import qualified Parsers.Readwise as RW + +runImporter :: FilePath -> FilePath -> IO () +runImporter db rw = do + x <- BSL.readFile rw + let y = RW.parse x + case y of + Left err -> print err + Right qts -> insertQts db qts + +main :: IO () +main = do + conf <- execParser importerParserOpts + initDb (ioAppDbFile conf) + runImporter (ioAppDbFile conf) (ioReadwiseFile conf) diff --git a/lib/Config.hs b/lib/Config.hs index 4a8c9c3..85ea531 100644 --- a/lib/Config.hs +++ b/lib/Config.hs @@ -2,6 +2,8 @@ module Config ( parserOpts , AppConfig(..) + , importerParserOpts + , ImporterConfig(..) ) where import Options.Applicative @@ -43,3 +45,29 @@ parserOpts = info (appConfig <**> helper) ( fullDesc <> progDesc "Serve Quotes API" <> header "quotes api" ) + +data ImporterConfig = ImporterConfig + { ioAppDbFile :: FilePath + , ioReadwiseFile :: FilePath + } deriving (Show, Eq) + +importerConfig :: Parser ImporterConfig +importerConfig = ImporterConfig + <$> strOption + ( long "dbpath" + <> help "sqlite db file path" + <> showDefault + <> value "quotes.db" + <> metavar "TARGET") + <*> strOption + ( long "readwise" + <> help "readwise export file path" + <> showDefault + <> value "readwise.csv" + <> metavar "RWCSV") + +importerParserOpts :: ParserInfo ImporterConfig +importerParserOpts = info (importerConfig <**> helper) + ( fullDesc + <> progDesc "Import data into db" + <> header "importer API") diff --git a/lib/Database.hs b/lib/Database.hs new file mode 100644 index 0000000..0afde9c --- /dev/null +++ b/lib/Database.hs @@ -0,0 +1,25 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Database where + +import Database.SQLite.Simple.QQ +import Database.SQLite.Simple + +import Api.Types + +initDb :: FilePath -> IO () +initDb dbFile = withConnection dbFile $ \conn -> + execute_ conn + [sql|CREATE TABLE IF NOT EXISTS quotes ( quote text non null + , author text + , title text + , page text + , chapter text + , created_on integer);|] + +insertQts :: FilePath -> [Quote] -> IO () +insertQts db qts = do + withConnection db $ \c -> + executeMany c qry qts + where + qry = [sql|INSERT INTO quotes VALUES (?,?,?,?,?,?);|] diff --git a/quotes-api.cabal b/quotes-api.cabal index a125f5c..5311e7a 100644 --- a/quotes-api.cabal +++ b/quotes-api.cabal @@ -63,6 +63,7 @@ library Parsers.KOReader, Parsers.Readwise, Config, + Database, -- Modules included in this library but not exported. -- other-modules: @@ -124,6 +125,43 @@ executable quotes-api -- Base language which the package is written in. default-language: Haskell2010 + +executable quotes-importer + -- Import common warning flags. + import: warnings + + -- .hs or .lhs file containing the Main module. + main-is: Main.hs + + -- Modules included in this executable, other than Main. + -- other-modules: + + -- LANGUAGE extensions used by modules in this package. + -- other-extensions: + + -- Other library packages from which modules are imported. + build-depends: + base ^>=4.16.3.0, + sqlite-simple ^>=0.4.18.0, + text ^>=1.2.5.0, + servant-server ^>=0.19.1, + wai, + warp, + aeson, + deriving-aeson, + quotes-api, + servant-blaze, + optparse-applicative, + argon2 >= 1.3.0, + text-short, + bytestring, + QuickCheck, + -- Directories containing source files. + hs-source-dirs: importer + + -- Base language which the package is written in. + default-language: Haskell2010 + test-suite quotes-api-test -- Import common warning flags. import: warnings