The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Elastic::Model::Scope - Keeps objects alive and connected

VERSION

version 0.52

DESCRIPTION

Elastic::Model::Scope is an optional in-memory cache, which serves three purposes:

  • Keep weak-ref Elastic::Doc attributes alive

  • Reuse Elastic::Doc objects as singletons.

  • Multiple scopes allow you to have multiple versions of Elastic::Doc objects live at the same time.

See Elastic::Manual::Scoping for a fuller discussion of when and how to use scoping.

ATTRIBUTES

parent

The parent scope of this scope, or UNDEF.

METHODS

The logic used in scopes is best explained by the examples below:

get_object()

    $obj = $scope->get_object($domain_name, $uid);

When calling "get()" in Elastic::Model::Domain or "get_doc()" in Elastic::Model::Role::Model to retrieve an object from Elasticsearch, we first check to see if we can return the object from our in-memory cache by calling "get_object()":

Getting an object that exists in the current scope

If an object with the same namespace_name/type/id exists in the CURRENT scope (and its version is as least as high as the requested version, if any) then we return the SAME object.

    $scope = $model->new_scope;
    $one   = $domain->get( user => 123 );
    $two   = $domain->get( user => 123 );

    print $one->name;
    # Clint

    $two->name('John');

    print $one->name;
    # John

    print refaddr($one) == refaddr($two) ? 'TRUE' : 'FALSE';
    # TRUE

Getting an object that exists in a parent scope

If an object with the same domain_name/type/id exists in the PARENT scope (and its version is as least as high as the requested version, if any) then we return a CLONE of the object. (Note: we clone the original object as it was when loaded from Elasticsearch. Any unsaved changes are ignored.)

    $scope_1 = $model->new_scope;
    $one     = $domain->get( user => 123 );

    print $one->name;
    # Clint

    $one->name('John');

    $scope_2 = $model->new_scope;
    $two     = $domain->get( user => 123 );

    print $two->name;
    # Clint

    print refaddr($one) == refaddr($two) ? 'TRUE' : 'FALSE';
    # FALSE

Otherwise the calling method will fetch the object from Elasticsearch itself, and store it in the current scope.

Getting an object that has been deleted

If the object exists in the same scope or a parent scope, but it is an Elastic::Model::Deleted object, then we return undef.

store_object()

    $object = $scope->store_object($ns_name, $object);

When we load a object that doesn't exist in the current scope or in any of its parents, or we create-a-new or update-an-existing object via "save()" in Elastic::Model::Role::Doc, we also store it in the current scope via "store_object()".

    $scope_1 = $model->new_scope;
    $one     = $domain->get( user => 123 );

    print $one->name;
    # Clint

    $scope_2 = $model->new_scope;
    $two     = $domain->get( user => 123 );

    print $two->name;
    # Clint

    print refaddr($one) == refaddr($two) ? 'TRUE' : 'FALSE';
    # FALSE

Storing an object in a new scope

Now we update the $one object, while $scope_2 is current, and save it:

    $one->name('John');
    $one->save;

Object $one is now in $scope_1 AND $scope_2.

    $three   = $domain->get( user => 123 );

    print $three->name;
    # John

    print refaddr($one) == refaddr($three) ? 'TRUE' : 'FALSE';
    # TRUE

Object $two still exists, and is still kept alive, but will no longer be returned from $scope_2.

    print $two->name;
    # Clint

delete_object()

    $scope->delete_object( $ns_name, $uid );

When calling "delete_doc()" in Elastic::Model::Role::Model, "delete_doc()" in Elastic::Model::Domain or "delete()" in Elastic::Model::Role::Doc we check to see if an object with the same UID (namespace_name/type/id) exists in the current scope.

If it does, we rebless it into Elastic::Model::Deleted. Otherwise, we create a new Elastic::Model::Deleted object with the $uid and store that in the current scope.

Deleting an object which exists in the current scope

    $scope_1 = $model->new_scope;
    $one     = $domain->get( user => 1 );

    $domain->delete (user => 1 );

    print $domain->isa('Elastic::Model::Deleted') ? 'TRUE' : 'FALSE';
    # TRUE

    print $one->name;                        # Throws an error,

Deleting an object which doesn't exist in the current scope

    $scope_1 = $model->new_scope;
    $one     = $domain->get( user => 1 );

    $scope_2 = $model->new_scope;

    $domain->delete( user => 1);

    $two     = $domain->get( user => 1 );    # Throws an error

    print $one->name;
    # Clint

    undef $scope_2;
    $two     = $domain->get( user => 1 );

    print refaddr($one) == refaddr($two) ? 'TRUE' : 'FALSE';
    # TRUE

But, calling delete() on an object which isn't in the current scope still affects that object:

    $scope_1 = $model->new_scope;
    $one     = $domain->get( user => 1 );

    $scope_2 = $model->new_scope;

    $one->delete;

    print $one->name;                        # Throws an error

AUTHOR

Clinton Gormley <drtech@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by Clinton Gormley.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.