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.