packages feed

thimk-0.3: PCDB.hs

--- Spelling word suggestion tool
--- Copyright © 2008 Bart Massey
--- ALL RIGHTS RESERVED

--- This software is licensed under the "3-clause ('new')
--- BSD License".  Please see the file COPYING provided with
--- this distribution for license terms.

-- |Create and maintain a nonvolatile database of
--  phonetic codes for cheap lookup

module PCDB (DBConnection, filePathOfDB, defaultDictionaryForDB,
             createDB, openDB, matchDB, closeDB)
where

import qualified Control.Exception as C
import Database.SQLite
import System.IO
import Text.PhoneticCode.Soundex
import Text.PhoneticCode.Phonix

import Paths_thimk

filePathOfDB :: IO String
filePathOfDB = getDataFileName "pcdb.sq3"

defaultDictionaryForDB :: String
defaultDictionaryForDB = "/usr/share/dict/words"

showError :: Maybe String -> IO ()
showError Nothing = return ()
showError (Just s) = fail s

--- table schema
cw = Column { colName = "word",
              colType = SQLVarChar 64,
              colClauses = [ PrimaryKey False ] }
cs = Column { colName = "soundex",
              colType = SQLVarChar 16,
              colClauses = [ IsNullable False ] }
cp = Column { colName = "phonix",
              colType = SQLVarChar 16,
              colClauses = [ IsNullable False ] }
tab = Table { tabName = "phonetic_codes",
              tabColumns = [ cw, cs, cp ],
              tabConstraints = [] }

-- |Create and populate the phonetic codes database.
createDB :: String -> IO ()
createDB wfn = do
  dbfn <- filePathOfDB
  db <- openConnection dbfn
  execStatement_ db ("DROP TABLE IF EXISTS " ++ tabName tab ++ ";")
                     >>= showError
  defineTableOpt db True tab >>= showError
  wf <- openFile wfn ReadMode
  hSetEncoding wf utf8
  wc <- hGetContents wf
  let ws = lines wc
  execStatement_ db "BEGIN TRANSACTION;" >>= showError
  mapM_ (codeRow db) (ws `zip` (map (soundex True) ws `zip`
                                map phonix ws))
  execStatement_ db "COMMIT;" >>= showError
  hClose wf
  closeConnection db
    where
      codeRow db (w, (sc, pc)) =
          insertRow db (tabName tab) [(colName cw, w),
                                      (colName cs, sc),
                                      (colName cp, pc)] >>= showError
-- |Database connection.
newtype DBConnection = DBConnection SQLiteHandle

-- |Get a connection to the database.
openDB :: IO (Maybe DBConnection)
openDB = do
  dbfn <- filePathOfDB
  C.catch (do db <- openReadonlyConnection dbfn
              return (Just (DBConnection db)))
          (const (return Nothing) :: C.IOException -> IO (Maybe DBConnection))

-- |Return all the words in the given coding system matching the given code.
matchDB :: DBConnection -> String -> String -> IO [String]
matchDB (DBConnection db) coding code = do
    result <- execParamStatement db
      ("SELECT word FROM phonetic_codes WHERE " ++ coding ++ " = :code ;")
      [(":code", Text code)]
    case result of
      Left msg -> error msg
      Right rows -> return (map (snd . head) . head $ rows)

closeDB :: DBConnection -> IO ()
closeDB (DBConnection db) = closeConnection db