Permalink
Browse files

Added support for loading data from Sqlite3 databases.

  • Loading branch information...
1 parent ae5c461 commit 18c2e1d7a3104901b7409baf52f51732d330fe95 @sigurdmeldgaard sigurdmeldgaard committed Sep 20, 2010
Showing with 53 additions and 7 deletions.
  1. +1 −0 Yst/Build.hs
  2. +20 −4 Yst/Data.hs
  3. +27 −0 Yst/Sqlite3.hs
  4. +1 −0 Yst/Types.hs
  5. +4 −3 yst.cabal
View
1 Yst/Build.hs
@@ -51,6 +51,7 @@ dependencies site url =
TemplateFile f -> stripStExt f <.> "st"
SourceFile f -> f
fileFromSpec (DataFromFile f _) = Just f
+ fileFromSpec (DataFromSqlite3 f _ _) = Just f
fileFromSpec _ = Nothing
dataFiles = map (dataDir site </>) $ mapMaybe (\(_,s) -> fileFromSpec s) $ pageData page
in indexFile site : layout : srcdir : (requires ++ dataFiles)
View
24 Yst/Data.hs
@@ -23,6 +23,7 @@ import Yst.Types
import Yst.Util
import Yst.Yaml
import Yst.CSV
+import Yst.Sqlite3 (readSqlite3)
import Control.Monad
import Data.Char
import Data.Maybe (fromMaybe)
@@ -35,6 +36,10 @@ getData site (DataFromFile file opts) = do
raw <- catch (readDataFile $ dataDir site </> file)
(\e -> errorExit 15 ("Error reading data from " ++ file ++ ": " ++ show e) >> return undefined)
return $ foldl applyDataOption raw opts
+getData site (DataFromSqlite3 database query opts) = do
+ raw <- catch (readSqlite3 (dataDir site </> database) query)
+ (\e -> errorExit 15 ("Error reading Sqlite3 database from " ++ database ++ ": " ++ show e) >> return undefined)
+ return $ foldl applyDataOption raw opts
getData _ (DataConstant n) = return n
readDataFile :: FilePath -> IO Node
@@ -100,18 +105,20 @@ reverseIfDescending Descending GT = LT
parseDataField :: Node -> DataSpec
parseDataField n@(NString s) = case parse pDataField s s of
- Right (f,opts) -> DataFromFile f opts
+ Right (f, Nothing, opts) -> DataFromFile f opts
+ Right (f, Just query, opts) -> DataFromSqlite3 f query opts
Left err -> if "from" `isPrefixOf` (dropWhile isSpace $ map toLower s)
then error $ "Error parsing data field: " ++ show err
else DataConstant n
parseDataField n = DataConstant n
-pDataField :: GenParser Char st ([Char], [DataOption])
+pDataField :: GenParser Char st (String, Maybe String,[DataOption])
pDataField = do
spaces
pString "from"
pSpace
- fname <- pIdentifier <?> "name of YAML or CSV file"
+ fname <- pIdentifier <?> "name of YAML, CSV or SQLite3 file"
+ query <- (optionMaybe $ pQuery) <?> "a SQL query"
opts <- many $ (pOptWhere <?> "where [CONDITION]")
<|> (pOptLimit <?> "limit [NUMBER]")
<|> (pOptOrderBy <?> "order by [CONDITION]")
@@ -120,7 +127,7 @@ pDataField = do
optional $ char ';'
spaces
eof
- return (fname, opts)
+ return (fname, query, opts)
pIdentifier :: GenParser Char st [Char]
pIdentifier = spaces >> (pQuoted '\'' <|> pQuoted '"' <|> many (noneOf " \t\n<>=;,'\""))
@@ -140,6 +147,15 @@ pQuoted delim = try $ do
char delim
return res
+pQuery :: GenParser Char st String
+pQuery = try $ do
+ optional $ oneOf ",;"
+ spaces
+ pString "query"
+ pSpace
+ res <- pQuoted '"'
+ return res
+
pOptLimit :: GenParser Char st DataOption
pOptLimit = try $ do
optional $ oneOf ",;"
View
27 Yst/Sqlite3.hs
@@ -0,0 +1,27 @@
+module Yst.Sqlite3 (readSqlite3)
+where
+
+import Database.HDBC
+import Database.HDBC.Sqlite3
+import Data.Maybe
+import Yst.Types
+import Yst.Util (parseAsDate)
+
+readSqlite3 :: FilePath -> String -> IO Node
+readSqlite3 filename query = do
+ conn <- connectSqlite3 filename
+ stmt <- prepare conn query
+ execute stmt []
+ records <- sFetchAllRows' stmt
+ fieldNames <- getColumnNames stmt
+ disconnect conn
+
+ return $ NList $ map (NMap .
+ (zip fieldNames) .
+ (map (fieldToNode . fromMaybe ""))) records
+
+fieldToNode :: String -> Node
+fieldToNode s =
+ case parseAsDate s of
+ Nothing -> NString s
+ Just d -> NDate d
View
1 Yst/Types.hs
@@ -75,6 +75,7 @@ instance Ord Node where
data DataSpec = DataConstant Node
| DataFromFile FilePath [DataOption]
+ | DataFromSqlite3 FilePath String [DataOption]
deriving (Show, Read, Eq)
data DataOption = OrderBy [(String, SortDirection)]
View
7 yst.cabal
@@ -7,7 +7,8 @@ synopsis: Builds a static website from templates and data in YAML or
CSV files.
description: `yst` is a tool for generating a static website
by filling string templates with data taken from
- YAML text files (or, alternatively, CSV files).
+ YAML text files (or, alternatively, CSV files or
+ from a Sqlite3 database).
This approach combines the speed, security, and
ease of deployment of a static website with the
flexibility and maintainability of a dynamic site
@@ -46,11 +47,11 @@ Executable yst
hs-source-dirs: .
main-is: yst.hs
other-modules: Yst.Types, Yst.Yaml, Yst.Util, Yst.Data, Yst.Config,
- Yst.Render, Yst.Build, Yst.CSV
+ Yst.Render, Yst.Build, Yst.CSV, Yst.Sqlite3
build-depends: base >=3 && < 5, HStringTemplate >= 0.6.1, HsSyck, csv,
filepath, containers, directory, utf8-string, time,
old-locale, old-time, parsec, xhtml, pandoc, bytestring,
- split
+ split, HDBC, HDBC-sqlite3
extensions: CPP
if impl(ghc >= 6.12)
ghc-options: -Wall -threaded -fno-warn-orphans -fno-warn-unused-do-bind

0 comments on commit 18c2e1d

Please sign in to comment.