Elastic-Model

 view release on metacpan or  search on metacpan

lib/Elastic/Model/Role/Model.pm  view on Meta::CPAN

package Elastic::Model::Role::Model;
$Elastic::Model::Role::Model::VERSION = '0.52';
use Moose::Role;
use Carp;
use Elastic::Model::Types qw(ES);
use Search::Elasticsearch 1.20 ();
use Class::Load qw(load_class);
use Moose::Util qw(does_role);
use MooseX::Types::Moose qw(:all);
use Elastic::Model::UID();
use Elastic::Model::Deleted();
use Scalar::Util qw(blessed refaddr weaken);
use List::MoreUtils qw(uniq);
use JSON();
our $JSON = JSON->new->canonical->utf8;

use namespace::autoclean;
my @wrapped_classes = qw(
    domain  namespace      store   view     scope
    results cached_results scrolled_results result  bulk
);

#===================================
sub BUILD {
#===================================
    my $self = shift;
    my $es   = $self->es;
    if ( $es->isa('Search::Elasticsearch::Client::0_90::Direct') ) {
        $self->_set_result_class(
            $self->_wrap_class('Elastic::Model::0_90::Result') );
        $self->_set_store_class(
            $self->_wrap_class('Elastic::Model::0_90::Store') );
    }
    $self->doc_class_wrappers;
    return $self;

}

for my $class (@wrapped_classes) {
#===================================
    has "${class}_class" => (
#===================================
        isa     => Str,
        is      => 'ro',
        lazy    => 1,
        writer  => "_set_${class}_class",
        default => sub { shift->wrap_class($class) }
    );
}

#===================================
has 'typemap' => (
#===================================
    is      => 'ro',
    isa     => Str,
    default => sub { shift->wrap_class('typemap') }
);

#===================================
has [ 'deflators', 'inflators' ] => (
#===================================
    isa     => HashRef,
    is      => 'ro',
    default => sub { {} }
);

#===================================
has 'store' => (
#===================================
    does    => 'Elastic::Model::Role::Store',
    is      => 'ro',
    lazy    => 1,

lib/Elastic/Model/Role/Model.pm  view on Meta::CPAN

    }
    \%domains;
}

#===================================
sub namespace_for_domain {
#===================================
    my ( $self, $domain ) = @_;
    my $ns;
    $ns = $self->_get_domain_namespace($domain) and return $ns;
    $self->clear_domain_namespace;
    $self->_get_domain_namespace($domain)
        or croak "No namespace found for domain ($domain). ";
}

#===================================
sub all_live_indices {
#===================================
    my $self = shift;
    return map { $_->all_live_indices } values %{ $self->namespaces };
}

#===================================
sub wrap_doc_class {
#===================================
    my $self  = shift;
    my $class = shift;

    load_class($class);

    croak "Class ($class) does not do Elastic::Model::Role::Doc. "
        . "Please add : use Elastic::Doc;\n\n"
        unless Moose::Util::does_role( $class, 'Elastic::Model::Role::Doc' );

    $self->_wrap_class($class);
}

#===================================
sub wrap_class {
#===================================
    my $self  = shift;
    my $name  = shift || '';
    my $class = $self->meta->get_class($name)
        or croak "Unknown class for ($name)";

    $self->_wrap_class($class);
}

#===================================
sub _wrap_class {
#===================================
    my $self  = shift;
    my $class = shift;
    load_class($class);

    my $meta
        = Moose::Meta::Class->create(
        Class::MOP::class_of($self)->wrapped_class_name($class),
        superclasses => [$class] );

    weaken( my $weak_model = $self );
    $meta->add_method( model          => sub {$weak_model} );
    $meta->add_method( original_class => sub {$class} );
    $meta->make_immutable;

    return $meta->name;
}

#===================================
sub domain {
#===================================
    my $self = shift;
    my $name = shift or croak "No domain name passed to domain()";
    my $domain;

    $domain = $self->_get_domain($name) and return $domain;
    my $ns = $self->namespace_for_domain($name)
        or croak "Unknown domain name ($name)";

    $domain = $self->domain_class->new(
        name      => $name,
        namespace => $ns
    );
    return $self->_cache_domain( $name => $domain );
}

#===================================
sub view { shift->view_class->new(@_) }
#===================================

#===================================
sub new_scope {
#===================================
    my $self = shift;
    my @args
        = $self->has_current_scope ? ( parent => $self->current_scope ) : ();
    $self->current_scope( $self->scope_class->new(@args) );
}

#===================================
sub detach_scope {
#===================================
    my ( $self, $scope ) = @_;
    my $current = $self->current_scope;
    return unless $current && refaddr($current) eq refaddr($scope);
    my $parent = $scope->parent;
    return $self->clear_current_scope unless $parent;
    $self->current_scope($parent);
}

#===================================
sub get_doc {
#===================================
    my ( $self, %args ) = @_;
    my $uid = $args{uid}
        or croak "No UID passed to get_doc()";

    my $ns     = $self->namespace_for_domain( $uid->index );
    my $scope  = $self->current_scope;
    my $source = $args{source};

lib/Elastic/Model/Role/Model.pm  view on Meta::CPAN

=head1 COMMONLY USED METHODS

=head2 new()

Usually, the only parameter that you need to pass to C<new()> is C<es>,
which contains your L<Search::Elasticsearch> connection.

    $es    = Search::Elasticsearch->new( nodes => 'es1.domain.com:9200' );
    $model = MyApp->new( es => $es );

If the C<es> parameter is omitted, then it will default to a L<Search::Elasticsearch>
connection to C<localhost:9200>.

    $model = MyApp->new();   # localhost:9200

=head2 namespace()

    $namespace = $model->namespace($name);

Returns the L<Elastic::Model::Namespace> instance corresponding to
C<$name>. The namespace must have been configured via
L<Elastic::Model/has_namespace>.

Use a C<$namespace> to create, delete and update
L<indices|Elastic::Manual::Terminology/Index> and
L<index aliases|Elastic::Manual::Terminology/Alias>.

=head2 domain()

    $domain = $model->domain($name);

Returns an L<Elastic::Model::Domain> instance where C<$name> is the name
of an L<index|Elastic::Manual::Terminology/Index> or
L<index alias|Elastic::Manual::Terminology/Alias> (which points at a single
index) and is known to one of the L</namespaces>.

Use a C<$domain> to create, retrieve, update or delete individual
objects/documents.

=head2 view()

    $view = $model->view(%args);

Creates a new L<Elastic::Model::View> instance. Any args are passed on to
L<Elastic::Model::View/"new()">.

Use a C<$view> to query your documents.  Views can be multi-domain and
multi-type.

=head2 new_scope()

    $scope = $model->new_scope();

Creates a new L<Elastic::Model::Scope> instance (in-memory cache). If there is
an existing scope, then the new scope inherits from the existing scope.

    $scope = $model->new_scope();   # scope_1
    $scope = $model->new_scope();   # scope_2, inherits from scope_1
    undef $scope;                   # scope_2 and scope_1 are destroyed

Scopes are optional unless you have attributes which are weakened.

See L<Elastic::Model::Scoping> and L<Elastic::Model::Scope> to read more about
how scopes work.

=head1 OTHER METHODS AND ATTRIBUTES

These methods and attributes, while public, are usually used only by internal
modules. They are documented here for completeness.

=head2 CRUD

=head3 get_doc()

Normally, you want to use L<Elastic::Model::Domain/"get()"> rather than this
method.

    $doc = $model->get_doc(uid => $uid);
    $doc = $model->get_doc(uid => $uid, ignore => 404, ...);

C<get_doc()> tries to retrieve the object corresponding to the
L<$uid|Elastic::Model::UID>, first from the L</current_scope()> (if there is one)
or from any of its parents. Failing that, it tries to retrieve the doc
from the L</store>. If it finds the doc, then
it stores it in the current scope (again, if there is one), otherwise it
throws an error.

C<get_doc()> also accepts an optional C<$source> parameter which is
used internally for inflating search results.
See L<Elastic::Model::Scope> for a more detailed explanation.

Any other args are passed on to L<Elastic::Model::Store/get_doc()>.

=head3 get_doc_source()

    $doc = $model->get_doc_source(uid => $uid);
    $doc = $model->get_doc_source(uid => $uid, ignore => 404, ...);

Calls L<Elastic::Model::Store/"get_doc()"> and returns the raw source hashref
as stored in Elasticsearch for the doc with the corresponding
L<$uid|Elastic::Model::UID>. Throws an error if it doesn't exist.

Any other args are passed on to L<Elastic::Model::Store/get_doc()>.

=head3 doc_exists()

    $bool = $model->doc_exists( uid => $uid, %args );

Calls L<Elastic::Model::Role::Store/doc_exists()> to check whether the doc
exists.

=head3 save_doc()

Normally, you want to use L<Elastic::Model::Role::Doc/"save()"> rather than this
method.

    $doc = $model->save_doc(doc => $doc, %args);

Saves C<$doc> to Elasticsearch by calling
L<Elastic::Model::Store/"index_doc()"> (if the C<$doc> was originally loaded
from Elasticsearch), or L<Elastic::Model::Store/"create_doc()">, which



( run in 1.255 second using v1.01-cache-2.11-cpan-39bf76dae61 )