DBIx-NoSQL-Store-Manager
view release on metacpan or search on metacpan
lib/DBIx/NoSQL/Store/Manager/StoreModel.pm view on Meta::CPAN
use experimental 'signatures';
has store_model => (
is => 'ro',
isa => 'Str',
required => 1,
predicate => 'has_store_model',
);
has cascade_model => (
is => 'ro',
isa => 'Bool',
default => sub { 0 },
);
has cascade_save => (
is => 'ro',
isa => 'Bool',
lazy => 1,
default => sub { $_[0]->cascade_model },
);
has cascade_delete => (
is => 'ro',
isa => 'Bool',
lazy => 1,
default => sub { $_[0]->cascade_model },
);
use Types::Standard qw/ InstanceOf Str HashRef ArrayRef ConsumerOf /;
before _process_options => sub ( $meta, $name, $options ) {
my $type = InstanceOf[ $options->{store_model } ] | Str | HashRef;
if ( grep { $_ eq 'Moose::Meta::Attribute::Native::Trait::Array' } @{ $options->{traits} || [] } ) {
$type = 'ArrayRef';
}
$options->{isa} ||= $type;
lib/DBIx/NoSQL/Store/Manager/StoreModel.pm view on Meta::CPAN
my $array_context = grep { $_ eq 'Moose::Meta::Attribute::Native::Trait::Array' } @{ $attr->applied_traits };
my $reader = $attr->get_read_method;
# class that has the attribute
my $main_class = $attr->associated_class;
$main_class->add_before_method_modifier( delete => sub ( $self, @) {
my $obj = $self->$reader or return;
$_->delete for $array_context ? @$obj : $obj;
}) if $attr->cascade_delete;
$main_class->add_before_method_modifier( $attr->get_read_method => sub ( $self, @rest ) {
return if @rest;
my $value = $attr->get_value( $self );
return unless grep { defined $_ and not blessed $_ } $array_context ? @$value : $value;
if( $array_context ) {
$attr->set_raw_value( $self, [ map {
$attr->_expand_to_object( $_, $self ) } @$value ] );
lib/DBIx/NoSQL/Store/Manager/StoreModel.pm view on Meta::CPAN
my $packed = $orig->($self);
my $val = $self->$reader;
if ( $val ) {
$packed->{ $attr->name } = $array_context ? [
map { $_->store_key } @$val
] : $val->store_key;
}
return $packed;
} );
if( $attr->cascade_save ) {
$main_class->add_before_method_modifier( 'save' => sub ( $self, $store=undef ) {
# TODO bug if we remove the value altogether
my $value = $self->$reader or return;
if ( $attr->cascade_delete ) {
my $priors = eval { $self->store_db->get( $self->store_model, $self->store_key )->$reader };
if ( $array_context ) {
my %priors = map { $_->store_key => $_ } @$priors;
for ( @$value ) {
delete $priors{ $_->store_key };
}
$_->delete for values %priors;
}
else {
lib/DBIx/NoSQL/Store/Manager/StoreModel.pm view on Meta::CPAN
version 1.0.0
=head1 SYNOPSIS
package Blog::Model::Entry;
has author => (
traits => [ 'StoreModel' ],
store_model => 'Blog::Model::Author',
cascade_save => 1,
cascade_delete => 0,
is => 'rw',
);
=head1 DESCRIPTION
I<DBIx::NoSQL::Store::Manager::StoreModel> (also aliased to I<StoreModel>)
This trait ties the value of the attribute to a model of the store.
The value of the attribute can be set via either a model object, a hashref, or
lib/DBIx/NoSQL/Store/Manager/StoreModel.pm view on Meta::CPAN
a collection of objects. The same logic applies as above, only wrapped in an arrayref.
=head1 ATTRIBUTES
=head2 store_model => $model_class
Required. Takes in the model associated with the target attribute.
Will automatically populate the C<isa> attribute to
C<$model_class|Str_HashRef>.
=head2 cascade_model => $boolean
Sets the default of C<cascade_save> and C<cascade_delete>.
Defaults to C<false>.
=head2 cascade_save => $boolean
If C<true> the object associated with the attribute is automatically saved
to the store when the main object is C<save()>d.
=head2 cascade_delete => $boolean
If C<true>, deletes the attribute object (if there is any)
from the store when the main object is C<delete()>d.
If both C<cascade_delete> and C<cascade_save> are C<true>,
then when saving the main object, if the attribute object has been
modified, its previous value will be deleted from the store.
# assuming the author attribute has `cascade_model => 1`...
my $blog_entry = $store->create( 'Entry',
author => Blog::Model::Author->new(
name => 'yanick',
bio => 'necrohacker',
),
);
# store now has yanick as an author
t/lib/Blog/Model/Entry2.pm view on Meta::CPAN
with 'DBIx::NoSQL::Store::Manager::Model';
has url => (
traits => [ 'StoreKey' ],
is => 'ro',
required => 1,
);
has author => (
traits => [ 'StoreModel' ],
cascade_model => 1,
store_model => 'Blog::Model::Author',
is => 'rw',
);
has tags => (
traits => [ 'Array', 'StoreModel' ],
cascade_save => 1,
store_model => 'Blog::Model::Tag',
is => 'ro',
default => sub { [] },
);
__PACKAGE__->meta->make_immutable;
1;
t/model-attribute.t view on Meta::CPAN
cmp_deeply $entry->pack => superhashof({
__CLASS__ => 'Blog::Model::Entry',
url => '/first',
author => 'yanick',
});
is $store->create( 'Entry', url => '/first', author => 'yanick' )->author->bio
=> 'necrohacker', 'expansion happens';
subtest 'cascade_save' => sub {
$store->create( Entry => (
url => '/second', author => Blog::Model::Author->new(
name => 'bob',
),
));
ok !$store->get( 'Author' => 'bob' ), "author is not auto-saved";
$store->create( Entry2 => (
url => '/second', author => Blog::Model::Author->new(
name => 'bob',
),
));
ok $store->get( 'Author' => 'bob' ), "author is auto-saved";
};
subtest 'cascade_delete' => sub {
my $author = $store->create( Author => ( name => 'charles', bio => 'foo' ) );
my $entry = $store->create( Entry => (
url => '/third', author => $author
) );
ok $store->get( 'Entry' => '/third' ), "entry is there";
$entry->delete;
( run in 0.646 second using v1.01-cache-2.11-cpan-26ccb49234f )