File:  [LON-CAPA] / loncom / metadata_database / LONCAPA / lonmetadata.pm
Revision 1.2: download - view: text, annotated - select for diffs
Mon Jan 12 21:32:20 2004 UTC (20 years, 6 months ago) by matthew
Branches: MAIN
CVS tags: HEAD
Implement store_metadata.  lookup_metadata is not tested in the least.

    1: # The LearningOnline Network with CAPA
    2: #
    3: # $Id: lonmetadata.pm,v 1.2 2004/01/12 21:32:20 matthew Exp $
    4: #
    5: # Copyright Michigan State University Board of Trustees
    6: #
    7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    8: #
    9: # LON-CAPA is free software; you can redistribute it and/or modify
   10: # it under the terms of the GNU General Public License as published by
   11: # the Free Software Foundation; either version 2 of the License, or
   12: # (at your option) any later version.
   13: #
   14: # LON-CAPA is distributed in the hope that it will be useful,
   15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17: # GNU General Public License for more details.
   18: #
   19: # You should have received a copy of the GNU General Public License
   20: # along with LON-CAPA; if not, write to the Free Software
   21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22: #
   23: # /home/httpd/html/adm/gpl.txt
   24: #
   25: # http://www.lon-capa.org/
   26: #
   27: ######################################################################
   28: 
   29: package LONCAPA::lonmetadata;
   30: 
   31: use strict;
   32: use DBI;
   33: 
   34: ######################################################################
   35: ######################################################################
   36: 
   37: =pod 
   38: 
   39: =head1 Name
   40: 
   41: lonmetadata
   42: 
   43: =head1 Synopsis
   44: 
   45: lonmetadata holds a description of the metadata table and provides
   46: wrappers for the storage and retrieval of metadata to/from the database.
   47: 
   48: =head1 Description
   49: 
   50: =head1 Methods
   51: 
   52: =over 4
   53: 
   54: =cut
   55: 
   56: ######################################################################
   57: ######################################################################
   58: 
   59: =pod
   60: 
   61: =item Old table creation command
   62: 
   63: CREATE TABLE IF NOT EXISTS metadata 
   64: (title TEXT, 
   65: author TEXT, 
   66: subject TEXT, 
   67: url TEXT, 
   68: keywords TEXT, 
   69: version TEXT, 
   70: notes TEXT, 
   71: abstract TEXT, 
   72: mime TEXT, 
   73: language TEXT, 
   74: creationdate DATETIME, 
   75: lastrevisiondate DATETIME, 
   76: owner TEXT, 
   77: copyright TEXT, 
   78: 
   79: FULLTEXT idx_title (title), 
   80: FULLTEXT idx_author (author), 
   81: FULLTEXT idx_subject (subject), 
   82: FULLTEXT idx_url (url), 
   83: FULLTEXT idx_keywords (keywords), 
   84: FULLTEXT idx_version (version), 
   85: FULLTEXT idx_notes (notes), 
   86: FULLTEXT idx_abstract (abstract), 
   87: FULLTEXT idx_mime (mime), 
   88: FULLTEXT idx_language (language),
   89: FULLTEXT idx_owner (owner), 
   90: FULLTEXT idx_copyright (copyright)) 
   91: 
   92: TYPE=MYISAM;
   93: 
   94: =cut
   95: 
   96: ######################################################################
   97: ######################################################################
   98: my @Metadata_Table_Description = 
   99:     (
  100:      { name => 'title',     type=>'TEXT'},
  101:      { name => 'author',    type=>'TEXT'},
  102:      { name => 'subject',   type=>'TEXT'},
  103:      { name => 'url',       type=>'TEXT', restrictions => 'NOT NULL' },
  104:      { name => 'keywords',  type=>'TEXT'},
  105:      { name => 'version',   type=>'TEXT'},
  106:      { name => 'notes',     type=>'TEXT'},
  107:      { name => 'abstract',  type=>'TEXT'},
  108:      { name => 'mime',      type=>'TEXT'},
  109:      { name => 'language',  type=>'TEXT'},
  110:      { name => 'creationdate',     type=>'DATETIME'},
  111:      { name => 'lastrevisiondate', type=>'DATETIME'},
  112:      { name => 'owner',     type=>'TEXT'},
  113:      { name => 'copyright', type=>'TEXT'}, 
  114:       #--------------------------------------------------
  115:      { name => 'dependencies',   type=>'TEXT'},
  116:      { name => 'modifyinguser',  type=>'TEXT'},
  117:      { name => 'authorspace',    type=>'TEXT'},
  118:      { name => 'lowestgradelevel',  type=>'INT'},
  119:      { name => 'highestgradelevel', type=>'INT'},
  120:      { name => 'standards',      type=>'TEXT'},
  121:      { name => 'count',          type=>'INT'},
  122:      { name => 'course',         type=>'INT'},
  123:      { name => 'course_list',    type=>'TEXT'},
  124:      { name => 'goto',           type=>'INT'},
  125:      { name => 'goto_list',      type=>'TEXT'},
  126:      { name => 'comefrom',       type=>'INT'},
  127:      { name => 'comefrom_list',  type=>'TEXT'},
  128:      { name => 'sequsage',       type=>'INT'},
  129:      { name => 'sequsage_list',  type=>'TEXT'},
  130:      { name => 'stdno',          type=>'INT'},
  131:      { name => 'stdno_list',     type=>'TEXT'},
  132:      { name => 'avetries',       type=>'FLOAT'},
  133:      { name => 'avetries_list',  type=>'TEXT'},
  134:      { name => 'difficulty',     type=>'FLOAT'},
  135:      { name => 'difficulty_list',type=>'TEXT'},
  136:      { name => 'clear',          type=>'FLOAT'},
  137:      { name => 'technical',      type=>'FLOAT'},
  138:      { name => 'correct',        type=>'FLOAT'},
  139:      { name => 'helpful',        type=>'FLOAT'},
  140:      { name => 'depth',          type=>'FLOAT'},
  141:      { name => 'hostname',       type=> 'TEXT'},
  142:      #--------------------------------------------------
  143:      );
  144: 
  145: my @Fulltext_indicies = qw/
  146:     title
  147:     author
  148:     subject
  149:     url
  150:     keywords
  151:     version
  152:     notes
  153:     abstract
  154:     mime
  155:     language
  156:     owner
  157:     copyright/;
  158: 
  159: ######################################################################
  160: ######################################################################
  161: 
  162: =pod
  163: 
  164: =item &describe_metadata_storage
  165: 
  166: Input: None
  167: 
  168: Returns: An array of hash references describing the columns and indicies
  169: of the metadata table(s).
  170: 
  171: =cut
  172: 
  173: ######################################################################
  174: ######################################################################
  175: sub describe_metadata_storage { 
  176:     return (\@Metadata_Table_Description,\@Fulltext_indicies);
  177: }
  178: 
  179: ######################################################################
  180: ######################################################################
  181: 
  182: =pod
  183: 
  184: =item create_metadata_storage()
  185: 
  186: Inputs: None
  187: 
  188: Returns: A perl string which, when executed by MySQL, will cause the
  189: metadata storage to be initialized.
  190: 
  191: =cut
  192: 
  193: ######################################################################
  194: ######################################################################
  195: sub create_metadata_storage { 
  196:     my $tablename = 'metadata';
  197:     my $request = "CREATE TABLE IF NOT EXISTS ".$tablename." ";
  198:     #
  199:     # Process the columns  (this code is stolen from lonmysql.pm)
  200:     my @Columns;
  201:     my $col_des; # mysql column description
  202:     foreach my $coldata (@Metadata_Table_Description) {
  203:         my $column = $coldata->{'name'};
  204:         $col_des = '';
  205:         if (lc($coldata->{'type'}) =~ /(enum|set)/) { # 'enum' or 'set'
  206:             $col_des.=$column." ".$coldata->{'type'}."('".
  207:                 join("', '",@{$coldata->{'values'}})."')";
  208:         } else {
  209:             $col_des.=$column." ".$coldata->{'type'};
  210:             if (exists($coldata->{'size'})) {
  211:                 $col_des.="(".$coldata->{'size'}.")";
  212:             }
  213:         }
  214:         # Modifiers
  215:         if (exists($coldata->{'restrictions'})){
  216:             $col_des.=" ".$coldata->{'restrictions'};
  217:         }
  218:         if (exists($coldata->{'default'})) {
  219:             $col_des.=" DEFAULT '".$coldata->{'default'}."'";
  220:         }
  221:         $col_des.=' AUTO_INCREMENT' if (exists($coldata->{'auto_inc'}) &&
  222:                                         ($coldata->{'auto_inc'} eq 'yes'));
  223:         $col_des.=' PRIMARY KEY'    if (exists($coldata->{'primary_key'}) &&
  224:                                         ($coldata->{'primary_key'} eq 'yes'));
  225:     } continue {
  226:         # skip blank items.
  227:         push (@Columns,$col_des) if ($col_des ne '');
  228:     }
  229:     foreach my $colname (@Fulltext_indicies) {
  230:         my $text = 'FULLTEXT idx_'.$colname.' ('.$colname.')';
  231:         push (@Columns,$text);
  232:     }
  233:     $request .= "(".join(", ",@Columns).") ";
  234:     return $request;
  235: }
  236: 
  237: ######################################################################
  238: ######################################################################
  239: 
  240: =pod
  241: 
  242: =item store_metadata()
  243: 
  244: Inputs: database handle ($dbh) and a hash or hash reference containing the 
  245: metadata for a single resource.
  246: 
  247: Returns: 1 on success, 0 on failure to store.
  248: 
  249: =cut
  250: 
  251: ######################################################################
  252: ######################################################################
  253: {
  254:     ##
  255:     ##  WARNING: The following cleverness may cause trouble in cases where
  256:     ##  the dbi connection is dropped and recreated - a stale statement
  257:     ##  handler may linger around and cause trouble.
  258:     ##
  259:     ##  In most scripts, this will work fine.  If the dbi is going to be
  260:     ##  dropped and (possibly) later recreated, call &clear_sth.  Yes it
  261:     ##  is annoying but $sth appearantly does not have a link back to the 
  262:     ##  $dbh, so we can't check our validity.
  263:     ##
  264:     my $sth = undef;
  265: 
  266: sub create_statement_handler {
  267:     my $dbh = shift();
  268:     my $request = 'INSERT INTO metadata VALUES(';
  269:     foreach (@Metadata_Table_Description) {
  270:         $request .= '?,';
  271:     }
  272:     chop $request;
  273:     $request.= ')';
  274:     $sth = $dbh->prepare($request);
  275:     return;
  276: }
  277: 
  278: sub clear_sth { $sth=undef; }
  279: 
  280: sub store_metadata {
  281:     my $dbh = shift();
  282:     my $errors = '';
  283:     if (! defined($sth)) {
  284:         &create_statement_handler($dbh);
  285:     }
  286:     my $successcount = 0;
  287:     while (my $mdata = shift()) {
  288:         next if (ref($mdata) ne "HASH");
  289:         my @MData;
  290:         foreach my $field (@Metadata_Table_Description) {
  291:             if (exists($mdata->{$field->{'name'}})) {
  292:                 push(@MData,$mdata->{$field->{'name'}});
  293:             } else {
  294:                 push(@MData,undef);
  295:             }
  296:         }
  297:         $sth->execute(@MData);
  298:         if (! $sth->err) {
  299:             $successcount++;
  300:         } else {
  301:             $errors = join(',',$errors,$sth->errstr);
  302:         }
  303:     }
  304:     if (wantarray()) {
  305:         return ($successcount,$errors);
  306:     } else {
  307:         return $successcount;
  308:     }
  309: }
  310: 
  311: }
  312: 
  313: ######################################################################
  314: ######################################################################
  315: 
  316: =pod
  317: 
  318: =item lookup_metadata()
  319: 
  320: Inputs: database handle ($dbh) and a hash or hash reference containing 
  321: metadata which will be used for a search.
  322: 
  323: Returns: scalar with error string on failure, array reference on success.
  324: The array reference is the same one returned by $sth->fetchall_arrayref().
  325: 
  326: =cut
  327: 
  328: ######################################################################
  329: ######################################################################
  330: sub lookup_metadata {
  331:     my ($dbh,$condition,$fetchparameter) = @_;
  332:     my $error;
  333:     my $returnvalue=[];
  334:     my $request = 'SELECT * FROM metadata';
  335:     if (defined($condition)) {
  336:         $request .= ' WHERE '.$condition;
  337:     }
  338:     my $sth = $dbh->prepare($request);
  339:     if ($sth->err) {
  340:         $error = $sth->errstr;
  341:     }
  342:     if (! $error) {
  343:         $sth->execute();
  344:         if ($sth->err) {
  345:             $error = $sth->errstr;
  346:         } else {
  347:             $returnvalue = $sth->fetchall_arrayref($fetchparameter);
  348:             if ($sth->err) {
  349:                 $error = $sth->errstr;
  350:             }
  351:         }
  352:     }
  353:     return ($error,$returnvalue);
  354: }
  355: 
  356: ######################################################################
  357: ######################################################################
  358: 
  359: =pod
  360: 
  361: =item delete_metadata()
  362: 
  363: 
  364: 
  365: =cut
  366: 
  367: ######################################################################
  368: ######################################################################
  369: sub delete_metadata {}
  370: 
  371: ######################################################################
  372: ######################################################################
  373: 
  374: 1;
  375: 
  376: __END__;
  377: 
  378: =pod
  379: 
  380: =back
  381: 
  382: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>