diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 6c49f363b..a1dcbd50d 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -5,6 +5,8 @@ head tags. - fixed #10322: Dataform: wrong attr on script tag - fixed #10336: postReceivedTemplateId not corrected in upgrade_7.6.0-7.6.1 (Jukka Raimovaara / Axxion Oy) + - fixed: Crud handling of Form fields with database types that cannot have default values. + - fixed: Crud serialization. 7.7.5 - Adding StoryManager. diff --git a/lib/WebGUI/Crud.pm b/lib/WebGUI/Crud.pm index c75268496..94009180a 100644 --- a/lib/WebGUI/Crud.pm +++ b/lib/WebGUI/Crud.pm @@ -20,11 +20,11 @@ use strict; use Class::InsideOut qw(readonly private id register); use JSON; use Tie::IxHash; +use Clone qw/clone/; use WebGUI::DateTime; use WebGUI::Exception; use WebGUI::Utility; - private objectData => my %objectData; readonly session => my %session; @@ -438,8 +438,14 @@ sub crud_updateTable { my $fieldType = $control->getDatabaseFieldType; my $isKey = $properties->{$property}{isQueryKey}; my $defaultValue = $properties->{$property}{defaultValue}; + if ($properties->{$property}{serialize}) { + $defaultValue = JSON->new->canonical->encode($defaultValue); + } my $notNullClause = ($isKey || $defaultValue ne "") ? "not null" : ""; - my $defaultClause = "default ".$dbh->quote($defaultValue) if ($defaultValue ne ""); + my $defaultClause = ''; + if ($fieldType !~ /(?:text|blob)$/i) { + $defaultClause = "default ".$dbh->quote($defaultValue) if ($defaultValue ne ""); + } if (exists $tableFields{$property}) { my $changed = 0; @@ -549,12 +555,11 @@ sub get { # return a specific property if (defined $name) { - return $objectData{id $self}{$name}; + return clone $objectData{id $self}{$name}; } # return a copy of all properties - my %copy = %{$objectData{id $self}}; - return \%copy; + return clone $objectData{id $self}; } #------------------------------------------------------------------- @@ -920,9 +925,11 @@ B As part of it's validation mechanisms, update() will delete any elem sub update { my ($self, $data) = @_; + my $session = $self->session; # validate incoming data - my $properties = $self->crud_getProperties($self->session); + my $properties = $self->crud_getProperties($session); + my $dbData = { $self->crud_getTableKey($session) => $self->getId }; foreach my $property (keys %{$data}) { # don't save fields that aren't part of our definition @@ -937,20 +944,23 @@ sub update { } # serialize if needed - if ($properties->{$property}{serialize} && $data->{property} ne "") { - $data->{property} = JSON->new->canonical->encode($data->{property}); + if ($properties->{$property}{serialize} && $data->{$property} ne "") { + $dbData->{$property} = JSON->new->canonical->encode($data->{$property}); } + else { + $dbData->{$property} = $data->{$property}; + } } # set last updated - $data->{lastUpdated} ||= WebGUI::DateTime->new($self->session, time())->toDatabase; + $data->{lastUpdated} ||= WebGUI::DateTime->new($session, time())->toDatabase; # update memory my $refId = id $self; %{$objectData{$refId}} = (%{$objectData{$refId}}, %{$data}); # update the database - $self->session->db->setRow($self->crud_getTableName($self->session), $self->crud_getTableKey($self->session), $objectData{$refId}); + $session->db->setRow($self->crud_getTableName($session), $self->crud_getTableKey($session), $dbData); return 1; } diff --git a/t/Crud/serialize.t b/t/Crud/serialize.t new file mode 100644 index 000000000..b94b8535b --- /dev/null +++ b/t/Crud/serialize.t @@ -0,0 +1,122 @@ +# vim:syntax=perl +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2009 Plain Black Corporation. +#------------------------------------------------------------------- +# Please read the legal notices (docs/legal.txt) and the license +# (docs/license.txt) that came with this distribution before using +# this software. +#------------------------------------------------------------------ +# http://www.plainblack.com info@plainblack.com +#------------------------------------------------------------------ + +# Tests WebGUI::Crud + + +use FindBin; +use strict; +use lib "$FindBin::Bin/../lib"; +use Test::More; +use Test::Deep; +use JSON; +use WebGUI::Test; # Must use this before any other WebGUI modules +use WebGUI::Session; + +#---------------------------------------------------------------------------- +# Init +my $session = WebGUI::Test->session; + +#---------------------------------------------------------------------------- +# Tests + +plan tests => 10; # Increment this number for each test you create + +#---------------------------------------------------------------------------- +use_ok('WebGUI::Serialize'); + +WebGUI::Serialize->crud_createTable($session); + +my $cereal = WebGUI::Serialize->create($session); +isa_ok($cereal, 'WebGUI::Serialize'); +cmp_deeply( + $cereal->get, + { + someName => 'someName', + jsonField => [], + dateCreated => ignore(), + lastUpdated => ignore(), + sequenceNumber => ignore(), + serializeId => ignore(), + }, + 'object contains data structure in the jsonField, not JSON' +); + +my $expectedJson = $session->db->quickScalar('select jsonField from crudSerialize where serializeId=?', [ $cereal->getId]); +is ($expectedJson, '[]', 'json stored in the db'); + +$cereal->update({someName => 'Raisin Bran'}); +my $name = $session->db->quickScalar('select someName from crudSerialize where serializeId=?', [ $cereal->getId]); +is($cereal->get('someName'), 'Raisin Bran', 'sparse object update works'); +is($name, 'Raisin Bran', 'sparse update to db works'); + +$cereal->update({jsonField => [ { sugarContent => 50, averageNutrition => 3, foodColoring => 15,} ], }); +cmp_deeply( + $cereal->get('jsonField'), + [ + { + sugarContent => 50, + averageNutrition => 3, + foodColoring => 15, + }, + ], + 'update/get work on json field' +); + +my $json = $session->db->quickScalar('select jsonField from crudSerialize where serializeId=?', [ $cereal->getId]); +my $dbData = from_json($json); +cmp_deeply( + $dbData, + [ + { + sugarContent => 50, + averageNutrition => 3, + foodColoring => 15, + }, + ], + 'correct JSON data stored into db' +); + +my $cereal2 = WebGUI::Serialize->new($session, $cereal->getId); +cmp_deeply( + $cereal2->get('jsonField'), + [ + { + sugarContent => 50, + averageNutrition => 3, + foodColoring => 15, + }, + ], + 'new: deserialized data correctly' +); + +my $objData = $cereal->get('jsonField'); +$objData->[0]->{fiber} = 0; +cmp_deeply( + $cereal->get('jsonField'), + [ + { + sugarContent => 50, + averageNutrition => 3, + foodColoring => 15, + }, + ], + 'get: returns safe references' +); + +#---------------------------------------------------------------------------- +# Cleanup +END { + +WebGUI::Serialize->crud_dropTable($session); + +} +#vim:ft=perl