NAME

WeBWorK::DB - interface with the WeBWorK databases.

SYNOPSIS

 my $db = WeBWorK::DB->new($dbLayout);
 
 my @userIDs = $db->listUsers();
 my $Sam = $db->{user}->{record}->new();
 
 $Sam->user_id("sammy");
 $Sam->first_name("Sam");
 $Sam->last_name("Hathaway");
 # etc.
 
 $db->addUser($User);
 my $Dennis = $db->getUser("dennis");
 $Dennis->status("C");
 $db->putUser->($Dennis);
 
 $db->deleteUser("sammy");

DESCRIPTION

WeBWorK::DB provides a consistent interface to a number of database backends. Access and modification functions are provided for each logical table used by the webwork system. The particular backend (``schema'' and ``driver''), record class, data source, and additional parameters are specified by the hash referenced by $dbLayout, usually taken from the course environment.

ARCHITECTURE

The new database system uses a three-tier architecture to insulate each layer from the adjacent layers.

Top Layer: DB

The top layer of the architecture is the DB module. It provides the methods listed below, and uses schema modules (via tables) to implement those methods.

         / new* list* exists* add* get* get*s put* delete* \          <- api
 +------------------------------------------------------------------+
 |                                DB                                |
 +------------------------------------------------------------------+
  \ password permission key user set set_user problem problem_user /  <- tables

Middle Layer: Schemas

The middle layer of the architecture is provided by one or more schema modules. They are called ``schema'' modules because they control the structure of the data for a table. This includes odd things like the way multiple tables are encoded in a single hash in the WW1Hash schema, and the encoding scheme used.

The schema modules provide an API that matches the requirements of the DB layer, on a per-table basis. Each schema module has a style that determines which drivers it can interface with. For example, WW1Hash is a ``hash'' style schema. SQL is a ``dbi'' style schema.

Examples

Both WeBWorK 1.x and 2.x courses use:

  / password  permission  key \        / user \      <- tables provided
 +-----------------------------+  +----------------+
 |          Auth1Hash          |  | Classlist1Hash |
 +-----------------------------+  +----------------+
             \ hash /                  \ hash /      <- driver style required

WeBWorK 1.x courses also use:

  / set_user problem_user \       / set problem \    
 +-------------------------+  +---------------------+
 |         WW1Hash         |  | GlobalTableEmulator |
 +-------------------------+  +---------------------+
           \ hash /                   \ null /

The GlobalTableEmulator schema emulates the global set and problem tables using data from the set_user and problem_user tables.

WeBWorK 2.x courses also use:

  / set set_user problem problem_user \ 
 +-------------------------------------+
 |               WW2Hash               |
 +-------------------------------------+
                 \ hash /

Bottom Layer: Drivers

Driver modules implement a style for a schema. They provide physical access to a data source containing the data for a table. The style of a driver determines what methods it provides. All drivers provide connect(MODE) and disconnect() methods. A hash style driver provides a hash() method which returns the tied hash. A dbi style driver provides a handle() method which returns the DBI handle.

Examples

  / hash \    / hash \    / hash \  <- style
 +--------+  +--------+  +--------+
 |   DB   |  |  GDBM  |  |   DB3  |
 +--------+  +--------+  +--------+
  / dbi \    / ldap \ 
 +-------+  +--------+
 |  SQL  |  |  LDAP  |
 +-------+  +--------+

Record Types

In %dblayout, each table is assigned a record class, used for passing complete records to and from the database. The default record classes are subclasses of the WeBWorK::DB::Record class, and are named as follows: User, Password, PermissionLevel, Key, Set, UserSet, Problem, UserProblem. In the following documentation, a reference the the record class for a table means the record class currently defined for that table in %dbLayout.

CONSTRUCTOR

new($dbLayout)

The new method creates a DB object and brings up the underlying schema/driver structure according to the hash referenced by $dbLayout.

$dbLayout Format

$dbLayout is a hash reference consisting of items keyed by table names. The value of each item is a reference to a hash containing the following items:

record

The name of a perl module to use for representing the data in a record.

schema

The name of a perl module to use for access to the table.

driver

The name of a perl module to use for access to the data source.

source

The location of the data source that should be used by the driver module. Depending on the driver, this may be a path, a url, or a DBI spec.

params

A reference to a hash containing extra information needed by the schema. Some schemas require parameters, some do not. Consult the documentation for the schema in question.

For each table defined in $dbLayout, new loads the record, schema, and driver modules. It the schema module's tables method lists the current table (or contains the string ``*'') and the output of the schema and driver modules' style methods match, the table is installed. Otherwise, an exception is thrown.

METHODS

General Methods

hashDatabaseOK($fix)

If the schema module in use for the set and problem tables is WeBWorK::DB::Schema::GlobalTableEmulator, the database is checked to make sure that the ``global user'' exists and all sets and problems are assigned to it. If $fix is true, problems found will be fixed: A global user will be created and all sets/problems assigned to it.

A list of values is returned. The first value is a boolean value indicating whether problems remain in the database after hashDatabaseOK() is called. The remaining values are a list of strings indicating the particular ways in which the database is (or was) broken.

Password Methods

newPassword()

Returns a new, empty password object.

listPasswords()

Returns a list of user IDs representing the records in the password table.

addPassword($Password)

$Password is a record object. The password will be added to the password table if a password with the same user ID does not already exist. If one does exist, an exception is thrown. To add a password, a user with a matching user ID must exist in the user table.

getPassword($userID)

If a record with a matching user ID exists, a record object containting that record's data will be returned. If no such record exists, one will be created.

getPasswords(@uesrIDs)

Return a list of password records associated with the user IDs given. If there is no record associated with a given user ID, one will be created.

putPassword($Password)

$Password is a record object. If a password record with the same user ID exists in the password table, the data in the record is replaced with the data in $Password. If a matching password record does not exist, one will be created. (This is different from most other ``put'' methods.)

deletePassword($userID)

If a password record with a user ID matching $userID exists in the password table, it is removed and the method returns a true value. If one does exist, a false value is returned.

Permission Level Methods

newPermissionLevel()

Returns a new, empty permission level object.

listPermissionLevels()

Returns a list of user IDs representing the records in the permission table.

addPermissionLevel($PermissionLevel)

$PermissionLevel is a record object. The permission level will be added to the permission table if a permission level with the same user ID does not already exist. If one does exist, an exception is thrown. To add a permission level, a user with a matching user ID must exist in the user table.

getPermissionLevel($userID)

If a record with a matching user ID exists, a record object containting that record's data will be returned. If no such record exists, one will be created.

getPermissionLevels(@uesrIDs)

Return a list of permission level records associated with the user IDs given. If there is no record associated with a given user ID, one will be created.

putPermissionLevel($PermissionLevel)

$PermissionLevel is a record object. If a permission level record with the same user ID exists in the permission table, the data in the record is replaced with the data in $PermissionLevel. If a matching permission level record does not exist, one will be created. (This is different from most other ``put'' methods.)

deletePermissionLevel($userID)

If a permission level record with a user ID matching $userID exists in the permission table, it is removed and the method returns a true value. If one does exist, a false value is returned.

Key Methods

newKey()

Returns a new, empty key object.

listKeys()

Returns a list of user IDs representing the records in the key table.

addKey($Key)

$Key is a record object. The key will be added to the key table if a key with the same user ID does not already exist. If one does exist, an exception is thrown. To add a key, a user with a matching user ID must exist in the user table.

getKey($userID)

If a record with a matching user ID exists, a record object containting that record's data will be returned. If no such record exists, an undefined value will be returned.

getKeys(@uesrIDs)

Return a list of key records associated with the user IDs given. If there is no record associated with a given user ID, that element of the list will be undefined.

putKey($Key)

$Key is a record object. If a key record with the same user ID exists in the key table, the data in the record is replaced with the data in $Key. If a matching key record does not exist, an exception is thrown.

deleteKey($userID)

If a key record with a user ID matching $userID exists in the key table, it is removed and the method returns a true value. If one does exist, a false value is returned.

User Methods

newUser()

Returns a new, empty user object.

listUsers()

Returns a list of user IDs representing the records in the user table.

addUser($User)

$User is a record object. The user will be added to the user table if a user with the same user ID does not already exist. If one does exist, an exception is thrown.

getUser($userID)

If a record with a matching user ID exists, a record object containting that record's data will be returned. If no such record exists, an undefined value will be returned.

getUsers(@uesrIDs)

Return a list of user records associated with the user IDs given. If there is no record associated with a given user ID, that element of the list will be undefined.

putUser($User)

$User is a record object. If a user record with the same user ID exists in the user table, the data in the record is replaced with the data in $User. If a matching user record does not exist, an exception is thrown.

deleteUser($userID)

If a user record with a user ID matching $userID exists in the user table, it is removed and the method returns a true value. If one does exist, a false value is returned. When a user record is deleted, all records associated with that user are also deleted. This includes the password, permission, and key records, and all user set records for that user.

Global Set Methods

FIXME: write this

newGlobalSet()
listGlobalSets()
addGlobalSet($GlobalSet)
addGlobalSet($setID)
getGlobalSets(@setIDs)

Return a list of global set records associated with the record IDs given. If there is no record associated with a given record ID, that element of the list will be undefined.

addGlobalSet($GlobalSet)
addGlobalSet($setID)

User-Specific Set Methods

FIXME: write this

getUserSets(@userSetIDs)

Return a list of user set records associated with the record IDs given. If there is no record associated with a given record ID, that element of the list will be undefined. @userProblemIDs consists of references to arrays in which the first element is the user_id and the second element is the set_id.

Global Problem Methods

FIXME: write this

getGlobalProblems(@problemIDs)

Return a list of global set records associated with the record IDs given. If there is no record associated with a given record ID, that element of the list will be undefined. @problemIDs consists of references to arrays in which the first element is the set_id, and the second element is the problem_id.

getAllGlobalProblems($setID)

Returns a list of Problem objects representing all the problems in the given global set. When using the WW1Hash/GlobalTableEmulator schemas, this is far more efficient than using listGlobalProblems and getGlobalProblems.

User-Specific Problem Methods

FIXME: write this

getUserProblems(@userProblemIDs)

Return a list of user set records associated with the user IDs given. If there is no record associated with a given user ID, that element of the list will be undefined. @userProblemIDs consists of references to arrays in which the first element is the user_id, the second element is the set_id, and the third element is the problem_id.

getAllUserProblems($userID, $setID)

Returns a list of UserProblem objects representing all the problems in the given set. When using the WW1Hash/GlobalTableEmulator schemas, this is far more efficient than using listUserProblems and getUserProblems.

Set Merging Methods

These functions combine a global set and a user set to create a merged set, which is returned. Any field that is not defined in the user set is taken from the global set. Merged sets have the same type as user sets.

getMergedSet($userID, $setID)

Returns a merged set record associated with the record IDs given. If there is no record associated with a given record ID, the undefined value is returned.

getMegedSets(@userSetIDs)

Return a list of merged set records associated with the record IDs given. If there is no record associated with a given record ID, that element of the list will be undefined. @userSetIDs consists of references to arrays in which the first element is the user_id and the second element is the set_id.

Problem Merging Methods

These functions combine a global problem and a user problem to create a merged problem, which is returned. Any field that is not defined in the user problem is taken from the global problem. Merged problems have the same type as user problems.

getMergedProblem($userID, $setID, $problemID)

Returns a merged problem record associated with the record IDs given. If there is no record associated with a given record ID, the undefined value is returned.

getMergedProblems(@userProblemIDs)

Return a list of merged problem records associated with the record IDs given. If there is no record associated with a given record ID, that element of the list will be undefined. @userProblemIDs consists of references to arrays in which the first element is the user_id, the second element is the set_id, and the third element is the problem_id.

AUTHOR

Written by Sam Hathaway, sh002i (at) math.rochester.edu.