--- 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