Module Database.KeyDatabaseSQLite

This module provides a general interface for databases (persistent predicates) where each entry consists of a key and an info part. The key is an integer and the info is arbitrary. All functions are parameterized with a dynamic predicate that takes an integer key as a first parameter.

This module is based on the SQLite database engine. In order to use it you need to have sqlite3 in your PATH environment variable or adjust the value of the constant path<code><a href="#to">to</a></code>sqlite3.

Author: Sebastian Fischer with changes by Michael Hanus

Version: August 2011

Summary of exported operations:

runQ :: Query a -> IO a   
Runs a database query in the IO monad.
transformQ :: (a -> b) -> Query a -> Query b   
Applies a function to the result of a database query.
runT :: Transaction a -> IO (Either a TError)   
Runs a transaction atomically in the IO monad.
runJustT :: Transaction a -> IO a   
Executes a possibly composed transaction on the current state of dynamic predicates as a single transaction.
getDB :: Query a -> Transaction a   
Lifts a database query to the transaction type such that it can be composed with other transactions.
returnT :: a -> Transaction a   
Returns the given value in a transaction that does not access the database.
doneT :: Transaction ()   
Returns the unit value in a transaction that does not access the database.
errorT :: TError -> Transaction a   
Aborts a transaction with an error.
failT :: String -> Transaction a   
Aborts a transaction with a user-defined error message.
(|>>=) :: Transaction a -> (a -> Transaction b) -> Transaction b   
Combines two transactions into a single transaction that executes both in sequence.
(|>>) :: Transaction a -> Transaction b -> Transaction b   
Combines two transactions to execute them in sequence.
sequenceT :: [Transaction a] -> Transaction [a]   
Executes a list of transactions sequentially and computes a list of all results.
sequenceT_ :: [Transaction a] -> Transaction ()   
Executes a list of transactions sequentially, ignoring their results.
mapT :: (a -> Transaction b) -> [a] -> Transaction [b]   
Applies a function that yields transactions to all elements of a list, executes the transaction sequentially, and collects their results.
mapT_ :: (a -> Transaction b) -> [a] -> Transaction ()   
Applies a function that yields transactions to all elements of a list, executes the transactions sequentially, and ignores their results.
persistentSQLite :: String -> String -> [String] -> Int -> a -> Dynamic   
This function is used instead of dynamic or persistent to declare predicates whose facts are stored in an SQLite database.
existsDBKey :: (Int -> a -> Dynamic) -> Int -> Query Bool   
Checks whether the predicate has an entry with the given key.
allDBKeys :: (Int -> a -> Dynamic) -> Query [Int]   
Returns a list of all stored keys.
allDBInfos :: (Int -> a -> Dynamic) -> Query [a]   
Returns a list of all info parts of stored entries.
allDBKeyInfos :: (Int -> a -> Dynamic) -> Query [(Int,a)]   
Returns a list of all stored entries.
(@=) :: Int -> a -> ColVal   
Constructs a value restriction for the column given as first argument
someDBKeys :: (Int -> a -> Dynamic) -> [ColVal] -> Query [Int]   
Returns a list of those stored keys where the corresponding info part matches the gioven value restriction.
someDBInfos :: (Int -> a -> Dynamic) -> [ColVal] -> Query [a]   
Returns a list of those info parts of stored entries that match the given value restrictions for columns.
someDBKeyInfos :: (Int -> a -> Dynamic) -> [ColVal] -> Query [(Int,a)]   
Returns a list of those entries that match the given value restrictions for columns.
someDBKeyProjections :: (Int -> a -> Dynamic) -> [Int] -> [ColVal] -> Query [(Int,b)]   
Returns a list of column projections on those entries that match the given value restrictions for columns.
getDBInfo :: (Int -> a -> Dynamic) -> Int -> Query (Maybe a)   
Queries the information stored under the given key.
getDBInfos :: (Int -> a -> Dynamic) -> [Int] -> Query (Maybe [a])   
Queries the information stored under the given keys.
deleteDBEntry :: (Int -> a -> Dynamic) -> Int -> Transaction ()   
Deletes the information stored under the given key.
deleteDBEntries :: (Int -> a -> Dynamic) -> [Int] -> Transaction ()   
Deletes the information stored under the given keys.
updateDBEntry :: (Int -> a -> Dynamic) -> Int -> a -> Transaction ()   
Updates the information stored under the given key.
newDBEntry :: (Int -> a -> Dynamic) -> a -> Transaction Int   
Stores new information in the database and yields the newly generated key.
newDBKeyEntry :: (Int -> a -> Dynamic) -> Int -> a -> Transaction ()   
Stores a new entry in the database under a given key.
cleanDB :: (Int -> a -> Dynamic) -> Transaction ()   
Deletes all entries from the database associated with a predicate.
closeDBHandles :: IO ()   
Closes all database connections.
showTError :: TError -> String   
Transforms a transaction error into a string.

Exported datatypes:


Query

Queries can read but not write to the database.

Constructors:


Transaction

Transactions can modify the database and are executed atomically.

Constructors:


Dynamic

Result type of database predicates.

Constructors:


Key

The general type of database keys.

Type synonym: Key = Int


KeyPred

Type synonym: KeyPred a = Key -> a -> Dynamic


ColVal

Abstract type for value restrictions

Constructors:


TError

The type of errors that might occur during a transaction.

Constructors:


TErrorKind

The various kinds of transaction errors.

Constructors:

  • KeyNotExistsError :: TErrorKind
  • NoRelationshipError :: TErrorKind
  • DuplicateKeyError :: TErrorKind
  • KeyRequiredError :: TErrorKind
  • UniqueError :: TErrorKind
  • MinError :: TErrorKind
  • MaxError :: TErrorKind
  • UserDefinedError :: TErrorKind
  • ExecutionError :: TErrorKind

Exported operations:

runQ :: Query a -> IO a   

Runs a database query in the IO monad.

Further infos:
  • solution complete, i.e., able to compute all solutions

transformQ :: (a -> b) -> Query a -> Query b   

Applies a function to the result of a database query.

runT :: Transaction a -> IO (Either a TError)   

Runs a transaction atomically in the IO monad.

Transactions are immediate, which means that locks are acquired on all databases as soon as the transaction is started. After one transaction is started, no other database connection will be able to write to the database or start a transaction. Other connections can read the database during a transaction of another process.

The choice to use immediate rather than deferred transactions is conservative. It might also be possible to allow multiple simultaneous transactions that lock tables on the first database access (which is the default in SQLite). However this leads to unpredictable order in which locks are taken when multiple databases are involved. The current implementation fixes the locking order by sorting databases by their name and locking them in order immediately when a transaction begins.

More information on transactions in SQLite is available online.

runJustT :: Transaction a -> IO a   

Executes a possibly composed transaction on the current state of dynamic predicates as a single transaction. Similar to runT but a run-time error is raised if the execution of the transaction fails.

getDB :: Query a -> Transaction a   

Lifts a database query to the transaction type such that it can be composed with other transactions. Run-time errors that occur during the execution of the given query are transformed into transaction errors.

returnT :: a -> Transaction a   

Returns the given value in a transaction that does not access the database.

doneT :: Transaction ()   

Returns the unit value in a transaction that does not access the database. Useful to ignore results when composing transactions.

errorT :: TError -> Transaction a   

Aborts a transaction with an error.

failT :: String -> Transaction a   

Aborts a transaction with a user-defined error message.

(|>>=) :: Transaction a -> (a -> Transaction b) -> Transaction b   

Combines two transactions into a single transaction that executes both in sequence. The first transaction is executed, its result passed to the function which computes the second transaction, which is then executed to compute the final result.

If the first transaction is aborted with an error, the second transaction is not executed.

Further infos:
  • defined as left-associative infix operator with precedence 1

(|>>) :: Transaction a -> Transaction b -> Transaction b   

Combines two transactions to execute them in sequence. The result of the first transaction is ignored.

Further infos:
  • defined as left-associative infix operator with precedence 1

sequenceT :: [Transaction a] -> Transaction [a]   

Executes a list of transactions sequentially and computes a list of all results.

sequenceT_ :: [Transaction a] -> Transaction ()   

Executes a list of transactions sequentially, ignoring their results.

mapT :: (a -> Transaction b) -> [a] -> Transaction [b]   

Applies a function that yields transactions to all elements of a list, executes the transaction sequentially, and collects their results.

mapT_ :: (a -> Transaction b) -> [a] -> Transaction ()   

Applies a function that yields transactions to all elements of a list, executes the transactions sequentially, and ignores their results.

persistentSQLite :: String -> String -> [String] -> Int -> a -> Dynamic   

This function is used instead of dynamic or persistent to declare predicates whose facts are stored in an SQLite database.

If the provided database or the table do not exist they are created automatically when the declared predicate is accessed for the first time.

Multiple column names can be provided if the second argument of the predicate is a tuple with a matching arity. Other record types are not supported. If no column names are provided a table with a single column called info is created. Columns of name rowid are not supported and lead to a run-time error.

Example call:
(persistentSQLite dbFile tableName colNames)
Parameters:
  • dbFile : the name of the associated database file
  • tableName : the name of the associated database table
  • colNames : the column names of the associated database table

existsDBKey :: (Int -> a -> Dynamic) -> Int -> Query Bool   

Checks whether the predicate has an entry with the given key.

allDBKeys :: (Int -> a -> Dynamic) -> Query [Int]   

Returns a list of all stored keys. Do not use this function unless the database is small.

allDBInfos :: (Int -> a -> Dynamic) -> Query [a]   

Returns a list of all info parts of stored entries. Do not use this function unless the database is small.

allDBKeyInfos :: (Int -> a -> Dynamic) -> Query [(Int,a)]   

Returns a list of all stored entries. Do not use this function unless the database is small.

(@=) :: Int -> a -> ColVal   

Constructs a value restriction for the column given as first argument

someDBKeys :: (Int -> a -> Dynamic) -> [ColVal] -> Query [Int]   

Returns a list of those stored keys where the corresponding info part matches the gioven value restriction. Safe to use even on large databases if the number of results is small.

someDBInfos :: (Int -> a -> Dynamic) -> [ColVal] -> Query [a]   

Returns a list of those info parts of stored entries that match the given value restrictions for columns. Safe to use even on large databases if the number of results is small.

someDBKeyInfos :: (Int -> a -> Dynamic) -> [ColVal] -> Query [(Int,a)]   

Returns a list of those entries that match the given value restrictions for columns. Safe to use even on large databases if the number of results is small.

someDBKeyProjections :: (Int -> a -> Dynamic) -> [Int] -> [ColVal] -> Query [(Int,b)]   

Returns a list of column projections on those entries that match the given value restrictions for columns. Safe to use even on large databases if the number of results is small.

getDBInfo :: (Int -> a -> Dynamic) -> Int -> Query (Maybe a)   

Queries the information stored under the given key. Yields Nothing if the given key is not present.

getDBInfos :: (Int -> a -> Dynamic) -> [Int] -> Query (Maybe [a])   

Queries the information stored under the given keys. Yields Nothing if a given key is not present.

deleteDBEntry :: (Int -> a -> Dynamic) -> Int -> Transaction ()   

Deletes the information stored under the given key. If the given key does not exist this transaction is silently ignored and no error is raised.

deleteDBEntries :: (Int -> a -> Dynamic) -> [Int] -> Transaction ()   

Deletes the information stored under the given keys. No error is raised if (some of) the keys do not exist.

updateDBEntry :: (Int -> a -> Dynamic) -> Int -> a -> Transaction ()   

Updates the information stored under the given key. The transaction is aborted with a KeyNotExistsError if the given key is not present in the database.

newDBEntry :: (Int -> a -> Dynamic) -> a -> Transaction Int   

Stores new information in the database and yields the newly generated key.

newDBKeyEntry :: (Int -> a -> Dynamic) -> Int -> a -> Transaction ()   

Stores a new entry in the database under a given key. The transaction fails if the key already exists.

Example call:
(newDBKeyEntry db key info)
Parameters:
  • db : the database (a dynamic predicate)
  • key : the key of the new entry (an integer)
  • info : the information to be stored in the new entry

cleanDB :: (Int -> a -> Dynamic) -> Transaction ()   

Deletes all entries from the database associated with a predicate.

closeDBHandles :: IO ()   

Closes all database connections. Should be called when no more database access will be necessary.

showTError :: TError -> String   

Transforms a transaction error into a string.