From 67c0fd3dfb0dd3e38d0a7cab209a99dfed5808a3 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Thu, 16 Oct 2008 23:44:48 +0000 Subject: [PATCH] - Added query keys to WebGUI::Crud. - WebGUI::Crud can now automatically resolve differences between its definition and the table schema. --- docs/changelog/7.x.x.txt | 3 ++ lib/WebGUI/Crud.pm | 68 ++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 55cb9eef4..984fc3beb 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -3,6 +3,9 @@ - Added Guid form control. - Moved Asset ID and Class Name fields to the Meta tab of all assets. - Made Classname from control a subclass of ReadOnly. + - Added query keys to WebGUI::Crud. + - WebGUI::Crud can now automatically resolve differences between its + definition and the table schema. - Fixed a limit bug in the asset discovery service. 7.6.1 diff --git a/lib/WebGUI/Crud.pm b/lib/WebGUI/Crud.pm index aab665d1c..217c9b07b 100644 --- a/lib/WebGUI/Crud.pm +++ b/lib/WebGUI/Crud.pm @@ -22,6 +22,7 @@ use JSON; use Tie::IxHash; use WebGUI::DateTime; use WebGUI::Exception; +use WebGUI::Utility; private objectData => my %objectData; @@ -198,6 +199,7 @@ sub crud_createTable { my $db = $session->db; my $dbh = $db->dbh; my $tableName = $class->crud_getTableName($session); + $class->crud_dropTable($session); $db->write('create table '.$dbh->quote_identifier($tableName).' ( '.$dbh->quote_identifier($class->crud_getTableKey($session)).' varchar(22) binary not null primary key, sequenceNumber int not null default 1, @@ -207,7 +209,7 @@ sub crud_createTable { $class->crud_updateTable($session); my $sequenceKey = $class->crud_getSequenceKey($session); if ($sequenceKey) { - $db->write('alter table '.dbh->quote_identifier($tableName).' + $db->write('alter table '.$dbh->quote_identifier($tableName).' add index '.$dbh->quote_identifier($sequenceKey).' ('.$dbh->quote_identifier($sequenceKey).')'); } return 1; @@ -250,6 +252,11 @@ properties is a hash reference tied to IxHash so that it maintains its order. It defaultValue => undef, serialize => 0, }, + presidentUserId => { + fieldType => 'guid', + defaultValue => undef, + isQueryKey => 1, + } } The properties of each field can be any property associated with a WebGUI::Form::Control. There are two special properties as well. They are fieldType and serialize. @@ -258,6 +265,8 @@ fieldType is the WebGUI::Form::Control type that you wish to associate with this serialize tells WebGUI::Crud to automatically serialize this field in a JSON wrapper before storing it to the database, and to convert it back to it's native structure upon retrieving it from the database. This is useful if you wish to persist hash references or array references. +isQueryKey tells WebGUI::Crud that the field should be marked as 'non null' in the table and then adds an index of the same name to the table to make searching on the field faster. B Don't use this if the field is already a sequenceKey. If it's a sequence key then it will automatically be indexed. + =cut sub crud_definition { @@ -294,7 +303,7 @@ sub crud_dropTable { } my $db = $session->db; my $dbh = $db->dbh; - $db->write("drop table ".$dbh->quote_identifier($class->crud_getTableName($session))); + $db->write("drop table if exists ".$dbh->quote_identifier($class->crud_getTableName($session))); return 1; } @@ -385,8 +394,6 @@ sub crud_getTableKey { A management class method that tries to resolve the differences between the database table and the definition. Returns 1 on success. -B This works perfectly for adding new fields, but is not perfect at making changes to fields. For that reason we recommend you write your own upgrade scripts when making database changes rather than relying upon this API at this time. - =head3 session A reference to a WebGUI::Session. @@ -406,12 +413,14 @@ sub crud_updateTable { my %tableFields = (); my $sth = $db->read("DESCRIBE ".$tableName); my $tableKey = $class->crud_getTableKey($session); - while (my ($col, $type) = $sth->array) { - next if ($col eq $tableKey); - next if ($col eq 'lastUpdated'); - next if ($col eq 'dateCreated'); - next if ($col eq 'sequenceNumber'); - $tableFields{$col} = $type; + while (my ($col, $type, $null, $key, $default) = $sth->array) { + next if (isIn($col, $tableKey, 'lastUpdated', 'dateCreated','sequenceNumber')); + $tableFields{$col} = { + type => $type, + null => $null, + key => $key, + default => $default, + }; } # update existing and create new fields @@ -419,21 +428,46 @@ sub crud_updateTable { foreach my $property (keys %{$properties}) { my $control = WebGUI::Form::DynamicField->new( $session, %{ $properties->{ $property } }); my $fieldType = $control->getDatabaseFieldType; + my $isKey = $properties->{$property}{isQueryKey}; + my $defaultValue = $properties->{$property}{defaultValue}; + my $notNullClause = ($isKey || $defaultValue ne "") ? "not null" : ""; + my $defaultClause = "default ".$dbh->quote($defaultValue) if ($defaultValue ne ""); if (exists $tableFields{$property}) { - ### have to figure out field type matching - #unless ($fieldType eq $tableFields{$property}) { - # $db->write("alter table $tableName change column ".$dbh->quote_identifier($property)." ".$dbh->quote_identifier($property)." $fieldType"); - #} - delete $tableFields{$property}; + my $changed = 0; + + # parse database table field type + $tableFields{$property}{type} =~ m/^(\w+)(\([\d\s,]+\))?$/; + my ($tableFieldType, $tableFieldLength) = ($1, $2); + + # parse form field type + $fieldType =~ m/^(\w+)(\([\d\s,]+\))?\s*(binary)?$/; + my ($formFieldType, $formFieldLength) = ($1, $2); + + # compare table parts to definition + $changed = 1 if ($tableFieldType ne $formFieldType); + $changed = 1 if ($tableFieldLength ne $formFieldLength); + $changed = 1 if ($tableFields{$property}{null} eq "YES" && $isKey); + $changed = 1 if ($tableFields{$property}{default} ne $defaultValue); + + # modify if necessary + if ($changed) { + $db->write("alter table $tableName change column ".$dbh->quote_identifier($property)." ".$dbh->quote_identifier($property)." $fieldType $notNullClause $defaultClause"); + } } else { - $db->write("alter table $tableName add column ".$dbh->quote_identifier($property)." $fieldType"); - delete $tableFields{$property}; + $db->write("alter table $tableName add column ".$dbh->quote_identifier($property)." $fieldType $notNullClause $defaultClause"); } + if ($isKey) { + $db->write("alter table $tableName add index ".$dbh->quote_identifier($property)." (".$dbh->quote_identifier($property).")"); + } + delete $tableFields{$property}; } # delete fields that are no longer in the definition foreach my $property (keys %tableFields) { + if ($tableFields{$property}{key}) { + $db->write("alter table $tableName drop index ".$dbh->quote_identifier($property)); + } $db->write("alter table $tableName drop column ".$dbh->quote_identifier($property)); } return 1;