[system] / trunk / webwork2 / lib / WeBWorK / DBv3.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/DBv3.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3017 - (download) (as text) (annotate)
Tue Dec 7 02:42:59 2004 UTC (8 years, 6 months ago) by sh002i
File size: 20075 byte(s)
ordering, normalizers, booleans, documentation. details:

* changed order of table classes so that the has_a() part of a
  relationship occurs before the has_many() part.
* added WeBWorK::DBv3::NormalizerMixin, simiar to Class::Trigger, to
  manage normalizer subroutines for per-column normalization.
* overloaded normalize_column_values to all normalizers for changed
  fields.
* implemented predefined has_a_boolean() normalizer definition.
* defined boolean fields in tables using has_a_boolean().
* added/clarified docs.

still to do:

* add inflators/deflators for durations
* add triggers for setting creation dates

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork2/lib/WeBWorK/DBv3.pm,v 1.2 2004/11/25 05:50:01 sh002i Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 package WeBWorK::DBv3;
   18 use base 'Class::DBI';
   19 use WeBWorK::DBv3::NormalizerMixin;
   20 
   21 =head1 NAME
   22 
   23 WeBWorK::DBv3 - Class::DBI interface to WWDBv3.
   24 
   25 =head1 SYNOPSIS
   26 
   27  use WeBWorK::DBv3;
   28 
   29  my $wwdbv3_settings = {
   30   dsn          => "dbi:mysql:wwdbv3",
   31   user         => "wwdbv3",
   32   pass         => "SeCrEt",
   33   attr         => {  }, # optional
   34   upgrade_lock => "/path/to/wwdbv3_upgrade.lock", # prevent concurrent schema upgrades
   35  };
   36 
   37  WeBWorK::DBv3::init($wwdbv3_settings);
   38 
   39  # --- any time after init() as been called... ---
   40 
   41  my $course = WeBWorK::DBv3::Course->find({name => "Sam's course"})
   42   or die "course not found!";
   43 
   44  my @participants = $course->participants;
   45 
   46  my $participant = WeBWorK::DBv3::Participant->find({login_name => "sam.hathaway"});
   47  $participant->first_name("Sam");
   48  $participant->last_name("Hathaway");
   49  $participant->update;
   50 
   51  my @set_assignments = $participant->set_assignments;
   52 
   53 =head1 DESCRIPTION
   54 
   55 WeBWorK::DBv3 provides a Class::DBI-based interface to the third-generation
   56 WeBWorK database. (WeBWorK::DB provided an interface to the second-generation
   57 database, the first-generation database was that used by WeBWorK 1.x.)
   58 
   59 The database schema is described at
   60 <http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/DatabaseSchemaV3>.
   61 
   62 WeBWorK::DBv3 supports automatic schema upgrades by checking the value of the
   63 C<db_version> record in the C<setting> table and applying SQL deltas to the
   64 database.
   65 
   66 =cut
   67 
   68 use strict;
   69 use warnings;
   70 use vars qw/$dbh $dt_format/;
   71 use DateTime::Format::DBI;
   72 use WeBWorK::DBv3::Utils;
   73 
   74 =head1 INITIALIZATION
   75 
   76 The init($wwdbv3_settings) function allows the user to set up the details of the
   77 database connection at runtime rather than at compile time. This lets us use
   78 values from the WeBWorK::CourseEnvironment (loaded at runtime) in specifying the
   79 database connection.
   80 
   81 $wwdbv3_settings is a reference to a hash containing the following values:
   82 
   83  dsn          => The DBI data source, e.g. "dbi:mysql:wwdbv3"
   84  user         => The user name with which to connect.
   85  pass         => The password to supply to connect.
   86  attr         => A reference to a hash containing DBI attributes.
   87                  See L<DBI> for more information.
   88  upgrade_lock => Path to a file which is flock()'d while performing
   89                  database upgrades.
   90 
   91 =cut
   92 
   93 sub init {
   94   my ($wwdbv3_settings) = @_;
   95 
   96   my $dsn  = $wwdbv3_settings->{dsn};
   97   my $user = $wwdbv3_settings->{user};
   98   my $pass = $wwdbv3_settings->{pass};
   99   my %attr = (
  100     RootClass => "DBIx::ContextualFetch", # this is supposedly important to Class::DBI
  101     RaiseError => 1, # we don't want to have to test return values
  102     %{ $wwdbv3_settings->{attr} }, # allow user-specified attributes to override
  103   );
  104 
  105   $dbh = DBI->connect_cached($dsn, $user, $pass, \%attr);
  106 
  107   $dt_format = new DateTime::Format::DBI($dbh);
  108 
  109   my $lockfile = $wwdbv3_settings->{upgrade_lock};
  110   upgrade_schema($dbh, $lockfile);
  111 }
  112 
  113 # override db_Main to get database handle initialized in init() above. note that
  114 # Class::DBI->connection() is never called.
  115 sub db_Main {
  116   return $dbh;
  117 }
  118 
  119 ################################################################################
  120 
  121 =head1 PUBLIC CLASS::DBI EXTENSIONS
  122 
  123 WeBWorK::DBv3 extends Class::DBI to provide several features useful to users to
  124 the WWDBv3 system.
  125 
  126 =head2 TABLE LOCKING
  127 
  128 When using a table type that doesn't support transactions, we need to be able to
  129 do table-level locks. The currently implementations are from
  130 Class::DBI::Extension and are MySQL-specific.
  131 
  132 =over
  133 
  134 =item lock_table()
  135 
  136 Write-lock the current table.
  137 
  138 =cut
  139 
  140 __PACKAGE__->set_sql(LockTable => "LOCK TABLES %s WRITE");
  141 
  142 sub lock_table {
  143     my $class = shift;
  144     $class->sql_LockTable($class->table)->execute;
  145 }
  146 
  147 =item unlock_table()
  148 
  149 Unlock I<all> locked tables.
  150 
  151 =cut
  152 
  153 __PACKAGE__->set_sql(UnlockTable => "UNLOCK TABLES");
  154 
  155 sub unlock_table {
  156     my $class = shift;
  157     $class->sql_UnlockTable->execute;
  158 }
  159 
  160 =back
  161 
  162 =cut
  163 
  164 ################################################################################
  165 
  166 =head1 INTERNAL IMPROVEMENTS
  167 
  168 WeBWorK::DBv3 extends Class::DBI to provide several features useful in the
  169 definition of table classes.
  170 
  171 =head2 DATETIME SUPPORT
  172 
  173 The method has_a_datetime() has been defined as a shortcut to specifying that a
  174 DATETIME column should be inflated to and deflated from a DateTime.pm object.
  175 
  176  __PACKAGE__->has_a_datetime("open_date");
  177 
  178 =cut
  179 
  180 sub datetime_inflate {
  181   my $dt = $dt_format->parse_datetime($_[0]) or _croak("invalid date: '$_[0]'");
  182   return $dt->set_time_zone("UTC");
  183 }
  184 
  185 sub datetime_deflate {
  186   my $dt = $_[0]->clone->set_time_zone("UTC"); # clone to avoid changing timezone of original object
  187   return $dt_format->format_datetime($dt);
  188 }
  189 
  190 # this declares a column to be of type DateTime and defines inflation/deflation
  191 # subroutines for it
  192 sub has_a_datetime {
  193   my ($class, $field) = @_;
  194   return unless $field;
  195 
  196   $class->has_a(
  197     $field  => "DateTime",
  198     inflate => \&datetime_inflate,
  199     deflate => \&datetime_deflate,
  200   );
  201 }
  202 
  203 =head2 PER-COLUMN NORMALIZATION SUPPORT
  204 
  205 WeBWorK::DBv3 adds per-column normalization support to Class::DBI via
  206 WeBWorK::DBv3::NormalizerMixin. The interface and implementation are similar to
  207 that of Class::DBI triggers (via Class::Trigger).
  208 
  209 To add a normalizer to a field:
  210 
  211  __PACKAGE__->add_normalizer(field => \&normalizer_sub);
  212 
  213 &normalizer_sub takes one argument, the value to be normalized. It should return
  214 the normalized value. For example:
  215 
  216  sub bool_normalizer { $_[0] ? 1 : 0 }
  217  WeBWorK::DBv3::Course->add_normalizer(visible => \&bool_normalizer);
  218 
  219 Like triggers, multiple normalizers can be added for a single field. However,
  220 you cannot specify the order in which they will be run.
  221 
  222 =cut
  223 
  224 sub normalize_column_values {
  225   my ($self, $column_values) = @_;
  226 
  227   my @errors;
  228 
  229   foreach my $column (keys %$column_values) {
  230     #warn "callig normalizers for column '$column'.\n";
  231     eval { $self->call_normalizer($column_values, $column) };
  232     push @errors, $column => $@ if $@;
  233   }
  234 
  235   return unless @errors;
  236   $self->_croak(
  237     "normalize_column_values error: " . join(" ", @errors),
  238     method => "normalize_column_values",
  239     data => { @errors },
  240   );
  241 }
  242 
  243 =head3 PREDEFINED NORMALIZERS
  244 
  245 Several normalizers are conveniently predefined using a syntax similar to that
  246 of has_a() relationship declarations.
  247 
  248 =over
  249 
  250 =item has_a_boolean($field)
  251 
  252 True values will be normalized to C<1>, false values to C<0>.
  253 
  254 =cut
  255 
  256 sub bool_normalizer { $_[0] ? 1 : 0 }
  257 sub has_a_boolean {
  258   my ($class, $field) = @_;
  259   return unless $field;
  260 
  261   $class->add_normalizer($field => \&bool_normalizer);
  262 }
  263 
  264 =back
  265 
  266 =cut
  267 
  268 ################################################################################
  269 # Table classes: each table in the database is a subclass of WeBWorK::DBv3.
  270 # (http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/DatabaseSchemaV3)
  271 #
  272 # These are in the reverse order from the order in DatabaseSchemaV3, to ensure
  273 # that the has_a() part of a relationship occurs before the has_many() part.
  274 #
  275 # From C<Class::DBI/has_many>:
  276 #
  277 # When setting up the relationship we examine the foreign class's has_a()
  278 # declarations to discover which of its columns reference our class. (Note that
  279 # because this happens at compile time, if the foreign class is defined in the
  280 # same file, the class with the has_a() must be defined earlier than the class
  281 # with the has_many(). If the classes are in different files, Class::DBI should
  282 # be able to do the right thing).
  283 ################################################################################
  284 
  285 package WeBWorK::DBv3::ProblemAttempt;
  286 use base 'WeBWorK::DBv3';
  287 
  288 __PACKAGE__->table("problem_attempt");
  289 __PACKAGE__->columns(All => qw/id problem_version creation_date score data/);
  290 
  291 __PACKAGE__->has_a(problem_version => "WeBWorK::DBv3::ProblemVersion");
  292 __PACKAGE__->has_a_datetime("creation_date");
  293 
  294 # FIXME need trigger to set creation_date
  295 
  296 ################################################################################
  297 
  298 package WeBWorK::DBv3::ProblemVersion;
  299 use base 'WeBWorK::DBv3';
  300 
  301 __PACKAGE__->table("problem_version");
  302 __PACKAGE__->columns(All => qw/id set_version problem_assignment creation_date
  303 source_file seed/);
  304 
  305 __PACKAGE__->has_a(set_version => "WeBWorK::DBv3::SetVersion");
  306 __PACKAGE__->has_a(problem_assignment => "WeBWorK::DBv3::ProblemAssignment");
  307 __PACKAGE__->has_a_datetime("creation_date");
  308 
  309 __PACKAGE__->has_many(problem_attempts => "WeBWorK::DBv3::ProblemAttempt");
  310 
  311 # FIXME need trigger to set creation_date
  312 
  313 ################################################################################
  314 
  315 package WeBWorK::DBv3::SetVersion;
  316 use base 'WeBWorK::DBv3';
  317 
  318 __PACKAGE__->table("set_version");
  319 __PACKAGE__->columns(All => qw/id set_assignment problem_order creation_date/);
  320 
  321 __PACKAGE__->has_a(set_assignment => "WeBWorK::DBv3::SetAssignment");
  322 __PACKAGE__->has_a_datetime("creation_date");
  323 
  324 __PACKAGE__->has_many(problem_versions => "WeBWorK::DBv3::ProblemVersion");
  325 
  326 # FIXME need trigger to set creation_date
  327 
  328 sub problem_order_list {
  329   my ($self, @problem_order) = @_;
  330   if (@problem_order) {
  331     return $self->problem_order(join(",", @problem_order));
  332   } else {
  333     return split(",", $self->problem_order);
  334   }
  335 }
  336 
  337 ################################################################################
  338 
  339 package WeBWorK::DBv3::ProblemOverride;
  340 use base 'WeBWorK::DBv3';
  341 
  342 __PACKAGE__->table("problem_override");
  343 __PACKAGE__->columns(All => qw/id abstract_problem section recitation
  344 participant source_type source_file source_group_set_id weight
  345 max_attempts_per_version version_creation_interval versions_per_interval
  346 version_due_date_offset version_answer_date_offset/);
  347 
  348 __PACKAGE__->has_a(abstract_problem => "WeBWorK::DBv3::AbstractProblem");
  349 __PACKAGE__->has_a(section => "WeBWorK::DBv3::Section");
  350 __PACKAGE__->has_a(recitation => "WeBWorK::DBv3::Recitation");
  351 __PACKAGE__->has_a(participant => "WeBWorK::DBv3::Participant");
  352 
  353 # FIXME need to make version_due_date_offset/version_answer_date_offset
  354 # DateTime::Offset objects
  355 
  356 ################################################################################
  357 
  358 package WeBWorK::DBv3::SetOverride;
  359 use base 'WeBWorK::DBv3';
  360 
  361 __PACKAGE__->table("set_override");
  362 __PACKAGE__->columns(All => qw/id abstract_set section recitation participant
  363 set_header hardcopy_header open_date due_date answer_date published
  364 problem_order reorder_type reorder_subset_size atomicity
  365 max_attempts_per_version version_creation_interval versions_per_interval
  366 version_due_date_offset version_answer_date_offset/);
  367 
  368 __PACKAGE__->has_a(abstract_set => "WeBWorK::DBv3::AbstractSet");
  369 __PACKAGE__->has_a(section => "WeBWorK::DBv3::Section");
  370 __PACKAGE__->has_a(recitation => "WeBWorK::DBv3::Recitation");
  371 __PACKAGE__->has_a(participant => "WeBWorK::DBv3::Participant");
  372 
  373 __PACKAGE__->has_a_datetime("open_date");
  374 __PACKAGE__->has_a_datetime("due_date");
  375 __PACKAGE__->has_a_datetime("answer_date");
  376 
  377 # FIXME need to make version_due_date_offset/version_answer_date_offset
  378 # DateTime::Offset objects
  379 
  380 sub problem_order_list {
  381   my ($self, @problem_order) = @_;
  382   if (@problem_order) {
  383     return $self->problem_order(join(",", @problem_order));
  384   } else {
  385     return split(",", $self->problem_order);
  386   }
  387 }
  388 
  389 ################################################################################
  390 
  391 package WeBWorK::DBv3::ProblemAssignment;
  392 use base 'WeBWorK::DBv3';
  393 
  394 __PACKAGE__->table("problem_assignment");
  395 __PACKAGE__->columns(All => qw/id set_assignment abstract_problem source_file/);
  396 
  397 __PACKAGE__->has_a(set_assignment => "WeBWorK::DBv3::SetAssignment");
  398 __PACKAGE__->has_a(abstract_problem => "WeBWorK::DBv3::AbstractProblem");
  399 
  400 __PACKAGE__->has_many(problem_overrides => "WeBWorK::DBv3::ProblemOverride");
  401 __PACKAGE__->has_many(problem_versions => "WeBWorK::DBv3::ProblemVersion");
  402 
  403 ################################################################################
  404 
  405 package WeBWorK::DBv3::SetAssignment;
  406 use base 'WeBWorK::DBv3';
  407 
  408 __PACKAGE__->table("set_assignment");
  409 __PACKAGE__->columns(All => qw/id abstract_set participant problem_order/);
  410 
  411 __PACKAGE__->has_a(abstract_set => "WeBWorK::DBv3::AbstractSet");
  412 __PACKAGE__->has_a(participant => "WeBWorK::DBv3::Participant");
  413 
  414 __PACKAGE__->has_many(problem_assignments => "WeBWorK::DBv3::ProblemAssignment");
  415 __PACKAGE__->has_many(set_overrides => "WeBWorK::DBv3::SetOverride");
  416 __PACKAGE__->has_many(set_versions => "WeBWorK::DBv3::SetVersion");
  417 
  418 sub problem_order_list {
  419   my ($self, @problem_order) = @_;
  420   if (@problem_order) {
  421     return $self->problem_order(join(",", @problem_order));
  422   } else {
  423     return split(",", $self->problem_order);
  424   }
  425 }
  426 
  427 ################################################################################
  428 
  429 package WeBWorK::DBv3::AbstractProblem;
  430 use base 'WeBWorK::DBv3';
  431 
  432 __PACKAGE__->table("abstract_problem");
  433 __PACKAGE__->columns(All => qw/id abstract_set name source_type source_file
  434 source_group_set_id source_group_select_time weight max_attempts_per_version
  435 version_creation_interval versions_per_interval version_due_date_offset
  436 version_answer_date_offset/);
  437 
  438 __PACKAGE__->has_a(abstract_set => "WeBWorK::DBv3::AbstractSet");
  439 
  440 __PACKAGE__->has_many(problem_assignments => "WeBWorK::DBv3::ProblemAssignment");
  441 
  442 # FIXME need to make version_due_date_offset/version_answer_date_offset
  443 # DateTime::Offset objects
  444 
  445 ################################################################################
  446 
  447 package WeBWorK::DBv3::AbstractSet;
  448 use base 'WeBWorK::DBv3';
  449 
  450 __PACKAGE__->table("abstract_set");
  451 __PACKAGE__->columns(All => qw/id course name set_header problem_header
  452 open_date due_date answer_date published problem_order reorder_type
  453 reorder_subset_size reorder_time atomicity max_attempts_per_version
  454 version_creation_interval versions_per_interval version_due_date_offset
  455 version_answer_date_offset/);
  456 
  457 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  458 __PACKAGE__->has_a_datetime("open_date");
  459 __PACKAGE__->has_a_datetime("due_date");
  460 __PACKAGE__->has_a_datetime("answer_date");
  461 __PACKAGE__->has_a_boolean("published");
  462 
  463 __PACKAGE__->has_many(abstract_problems => "WeBWorK::DBv3::AbstractProblem");
  464 __PACKAGE__->has_many(set_assignments => "WeBWorK::DBv3::SetAssignment");
  465 
  466 # FIXME need to make version_due_date_offset/version_answer_date_offset
  467 # DateTime::Offset objects
  468 
  469 sub problem_order_list {
  470   my ($self, @problem_order) = @_;
  471   if (@problem_order) {
  472     return $self->problem_order(join(",", @problem_order));
  473   } else {
  474     return split(",", $self->problem_order);
  475   }
  476 }
  477 
  478 ################################################################################
  479 
  480 package WeBWorK::DBv3::Participant;
  481 use base 'WeBWorK::DBv3';
  482 
  483 __PACKAGE__->table("participant");
  484 __PACKAGE__->columns(All => qw/id course user status role section recitation
  485 last_access comment/);
  486 
  487 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  488 __PACKAGE__->has_a(user => "WeBWorK::DBv3::User");
  489 __PACKAGE__->has_a(status => "WeBWorK::DBv3::Status");
  490 __PACKAGE__->has_a(role => "WeBWorK::DBv3::Role");
  491 __PACKAGE__->has_a(section => "WeBWorK::DBv3::Section");
  492 __PACKAGE__->has_a(recitation => "WeBWorK::DBv3::Recitation");
  493 
  494 __PACKAGE__->has_many(set_assignments => "WeBWorK::DBv3::SetAssignment");
  495 __PACKAGE__->has_many(set_overrides => "WeBWorK::DBv3::SetOverride");
  496 __PACKAGE__->has_many(problem_overrides => "WeBWorK::DBv3::ProblemOverride");
  497 
  498 ################################################################################
  499 
  500 package WeBWorK::DBv3::Recitation;
  501 use base 'WeBWorK::DBv3';
  502 
  503 __PACKAGE__->table("recitation");
  504 __PACKAGE__->columns(All => qw/id course name/);
  505 
  506 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  507 
  508 __PACKAGE__->has_many(participants => "WeBWorK::DBv3::Participant");
  509 __PACKAGE__->has_many(set_overrides => "WeBWorK::DBv3::SetOverride");
  510 __PACKAGE__->has_many(problem_overrides => "WeBWorK::DBv3::ProblemOverride");
  511 
  512 ################################################################################
  513 
  514 package WeBWorK::DBv3::Section;
  515 use base 'WeBWorK::DBv3';
  516 
  517 __PACKAGE__->table("section");
  518 __PACKAGE__->columns(All => qw/id course name/);
  519 
  520 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  521 
  522 __PACKAGE__->has_many(participants => "WeBWorK::DBv3::Participant");
  523 __PACKAGE__->has_many(set_overrides => "WeBWorK::DBv3::SetOverride");
  524 __PACKAGE__->has_many(problem_overrides => "WeBWorK::DBv3::ProblemOverride");
  525 
  526 ################################################################################
  527 
  528 package WeBWorK::DBv3::Role;
  529 use base 'WeBWorK::DBv3';
  530 
  531 __PACKAGE__->table("role");
  532 __PACKAGE__->columns(All => qw/id course name privs/);
  533 
  534 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  535 
  536 __PACKAGE__->has_many(participants => "WeBWorK::DBv3::Participant");
  537 
  538 sub priv_list {
  539   my ($self, @privs) = @_;
  540   if (@privs) {
  541     return $self->privs(join(",", @privs));
  542   } else {
  543     return split(",", $self->privs);
  544   }
  545 }
  546 
  547 ################################################################################
  548 
  549 package WeBWorK::DBv3::Status;
  550 use base 'WeBWorK::DBv3';
  551 
  552 __PACKAGE__->table("status");
  553 __PACKAGE__->columns(All => qw/id course name allow_course_access
  554 include_in_assignment include_in_stats include_in_scoring/);
  555 
  556 __PACKAGE__->has_a(course => "WeBWorK::DBv3::Course");
  557 __PACKAGE__->has_a_boolean("allow_course_access");
  558 __PACKAGE__->has_a_boolean("include_in_assignment");
  559 __PACKAGE__->has_a_boolean("include_in_stats");
  560 __PACKAGE__->has_a_boolean("include_in_scoring");
  561 
  562 __PACKAGE__->has_many(participants => "WeBWorK::DBv3::Participant");
  563 
  564 ################################################################################
  565 
  566 package WeBWorK::DBv3::User;
  567 use base 'WeBWorK::DBv3';
  568 
  569 __PACKAGE__->table("user");
  570 __PACKAGE__->columns(All => qw/id first_name last_name email_address student_id
  571 login_id password display_mode show_old_answers/);
  572 
  573 __PACKAGE__->has_a_boolean("show_old_answers");
  574 
  575 __PACKAGE__->has_many(participants => "WeBWorK::DBv3::Participant");
  576 
  577 ################################################################################
  578 
  579 package WeBWorK::DBv3::Course;
  580 use base 'WeBWorK::DBv3';
  581 
  582 __PACKAGE__->table("course");
  583 __PACKAGE__->columns(All => qw/id name visible locked archived/);
  584 
  585 __PACKAGE__->has_a_boolean("visible");
  586 __PACKAGE__->has_a_boolean("locked");
  587 __PACKAGE__->has_a_boolean("archived");
  588 
  589 __PACKAGE__->has_many(statuses => "WeBWorK::DBv3::Status");
  590 __PACKAGE__->has_many(roles => "WeBWorK::DBv3::Role");
  591 __PACKAGE__->has_many(sections => "WeBWorK::DBv3::Section");
  592 __PACKAGE__->has_many(recitations => "WeBWorK::DBv3::Recitation");
  593 __PACKAGE__->has_many(participants  => "WeBWorK::DBv3::Participant");
  594 __PACKAGE__->has_many(abstract_sets => "WeBWorK::DBv3::AbstractSet");
  595 
  596 ################################################################################
  597 
  598 package WeBWorK::DBv3::EquationCache;
  599 use base 'WeBWorK::DBv3';
  600 
  601 __PACKAGE__->table("equation_cache");
  602 __PACKAGE__->columns(All => qw/id tex width height depth/);
  603 
  604 ################################################################################
  605 
  606 package WeBWorK::DBv3::Setting;
  607 use base 'WeBWorK::DBv3';
  608 
  609 __PACKAGE__->table("setting");
  610 __PACKAGE__->columns(All => qw/name val/);
  611 
  612 ################################################################################
  613 
  614 =head1 AUTHOR
  615 
  616 Written by Sam Hathaway, sh002i (at) math.rochester.edu.
  617 
  618 =cut
  619 
  620 1;
  621 
  622 __END__
  623 

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9