NAME

Meerkat::Role::Document - Enhances a Moose object with Meerkat methods and metadata

VERSION

version 0.016

SYNOPSIS

Your model class:

package My::Model::Person;

use Moose;

with 'Meerkat::Role::Document';

has name => (
    is       => 'ro',
    isa      => 'Str',
    required => 1,
);

has likes => (
    is      => 'ro',
    isa     => 'Num',
    default => 0,
);

has tags => (
    is      => 'ro',
    isa     => 'ArrayRef',
    default => sub { [] },
);

1;

In your code:

use Meerkat;

my $meerkat = Meerkat->new(
    model_namespace => "My::Model",
    database_name => "test"
);

my $person = $meerkat->collection("Person"); # My::Model::Person

# create a document
my $obj = $person->create( name => "Larry" );

# change document in the database and update object
$obj->update_set( name => "Moe" );
$obj->update_inc( likes => 1 );
$obj->update_push( tags => qw/cool hot trendy/ );

# get any other updates from the database
$obj->sync;

# delete it
$obj->remove;

DESCRIPTION

This role enhances a Moose class with attributes and methods needed to operate in tandem with a Meerkat::Collection.

The resulting object is a projection of the document state in the database. Update methods change the state atomically in the database and synchronize the object with the new state in the database (potentially including other changes from other sources).

Consuming the role

When you apply this role to your Moose class, it provides and manages the _id attribute for you. This attribute is meant to be public, but keeps the leading underscore for consistency with MongoDB classes.

The attributes you define should be read-only. Modifying attributes directly in the object will not be reflected in the database and will be lost the next time you synchronize.

Objects are serialized with MooseX::Storage. Any attributes that should not be serialized must have the DoNotSerialize trait:

has 'expensive' => (
    traits => [ 'DoNotSerialize' ],
    is     => 'lazy',
    isa    => 'HeavyObject',
);

Attributes with embedded objects are not well supported. See the Meerkat::Cookbook for more.

Working with objects

Create objects from an associated Meerkat::Collection, not with new.

my $obj = $person->create( %attributes );

That will construct the object, instantiate all lazy attributes (except those marked DoNoSerialize) and store the new document into the database.

Then, use the various update methods to modify state if you need to. Use sync to refresh the object with any remote changes from the database.

METHODS

new

Don't call this directly! Create objects through the Meerkat::Collection or they won't be added to the database.

my $obj = $person->create( name => "Joe" );

update

$obj->update( { '$set' => { 'name' => "Moe" } } );

Executes a MongoDB update command on the associated document and updates the object's attributes. You must only use MongoDB update operators to modify the document's fields.

Returns true if the updates are applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed; subsequent update, sync or remove calls will do nothing and return false.

This command is intended for custom updates with unusual logic or operators. Many typical updates can be accomplished with the update_* methods described below.

For all update methods, you can use a MongoDB nested field label to modify values deep into a data structure. For example parents.father refers to $obj->parents->{father}.

update_set

$obj->update_set( name => "Luke Skywalker" );

Sets a field to a value. This is the MongoDB $set operator.

The field must be undefined or else the existing value and the new value must be of similar types (e.g. scalar or array or hash). For the purpose of this check, an object (e.g. a DateTime) is treated (opaquely) as a scalar value. If the types do not match, an error will be thrown.

Note this means that you can't set a defined value to undefined. To remove a field entirely, see "update_clear". If you need to make other structural changes, do it manually with the "update" method.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_inc

$obj->update_inc( likes => 1 );
$obj->update_inc( likes => -1 );

Increments a field by a positive or negative value. This is the MongoDB $inc operator. The field must be undefined or a numeric scalar value or an error will be thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_push

$obj->update_push( tags => qw/cool hot trendy/ );

Pushes values onto an array reference field. This is the MongoDB $push operator. The field must be undefined or an array reference or an error is thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_add

$obj->update_add( tags => qw/cool hot trendy/ );

Pushes values onto an array reference field, but only if they do not already exist in the array. This is the MongoDB $addToSet operator. The field must be undefined or an array reference or an error is thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_pop

$obj->update_pop( 'tags' );

Removes a value from the end of the array. This is the MongoDB $pop operator with a direction of "1". The field must be undefined or an array reference or an error is thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_shift

$obj->update_shift( 'tags' );

Removes a value from the front of the array. This is the MongoDB $pop operator with a direction of "-1". The field must be undefined or an array reference or an error is thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_remove

$obj->update_remove( tags => qw/cool hot/ );

Removes a list of values from the array. This is the MongoDB $pullAll operator. The field must be undefined or an array reference or an error is thrown.

Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

update_clear

$obj->update_clear( 'tags' );

Removes a field from a document. This is the MongoDB $unset operator. Returns true if the update is applied and synchronized. If the document has been removed, the method returns false and the object is marked as removed.

Be sure not to clear any required fields.

sync

$obj->sync;

Updates object attributes from the database. Returns true if synced. If the document has been removed, the method returns false and the object is marked as removed; subsequent update, sync or remove calls will do nothing and return false.

remove

$obj->remove;

Removes the associated document from the database. The object is marked as removed; subsequent update, sync or remove calls will do nothing and return false.

is_removed

if ( $obj->is_removed ) { ... }

Returns true or false indicating whether the associated document was removed from the database.

reinsert

$obj->reinsert;
$obj->reinsert( force => 1 );

Reinserts a removed document. If the force option is true, then it will be reinserted even if the document has not been removed, overwriting any existing document in the database. Returns false if the document is not removed (unless the force option is true). Returns true if the document has been reinserted.

_indexes

$class->_indexes;

Returns an empty list. If you want to define indexes for use with the ensure_indexes method of Meerkat::Collection, create your own _indexes method that returns a list of array references. The array references can have an optional initial hash reference of indexing options, followed by ordered key & value pairs in the usual MongoDB way.

You must provide index fields in an array reference because Perl hashes are not ordered and a compound index requires an order.

For example:

sub _indexes {
    return (
        [ { unique => 1 }, name => 1 ],
        [ name => 1, zip_code => 1 ]
        [ likes => -1 ],
        [ location => '2dsphere' ],
    );
}

See the Meerkat::Cookbook for more information.

_deep_field

my $value = $obj->_deep_field( "parents.father" ); # hash key
my $value = $obj->_deep_field( "tags.0" );         # array index

Retrieves a field deep in the object's data structure using MongoDB's dot notation. Returns undef if the field does not exist. Throws an error if the dot notation would do an illegal dereference.

This is far less efficient than accessing an attribute and dereferencing directly. It is used internally for validation of update_* field arguments.

AUTHOR

David Golden <dagolden@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2013 by David Golden.

This is free software, licensed under:

The Apache License, Version 2.0, January 2004