NAME

DBIx::EAV::ResultSet - Represents a query used for fetching a set of entities.

SYNOPSIS

# resultsets are bound to an entity type
my $cds_rs = $eav->resultset('CD');


# insert CDs
my $cd1 = $cds_rs->insert({ title => 'CD1', tracks => \@tracks });
my $cd2 = $cds_rs->insert({ title => 'CD2', tracks => \@tracks });
my $cd3 = $cds_rs->insert({ title => 'CD3', tracks => \@tracks });

# ... or use populate() to insert many
my (@cds) = $cds_rs->populate(\@cds);


# find all 2015 cds
my @cds = $eav->resultset('CD')->search({ year => 2015 });

foreach my $cd (@cds) {

    printf "CD '%s' has %d tracks.\n",
        $cd->get('title'),
        $cd->get('tracks')->count;
}

# find one
my $cd2 = $cds_rs->search_one({ name => 'CD2' });

# find by related attribute
my $cd2 = $cds_rs->search_one({ 'tracks.title' => 'Some CD2 Track' });

# count
my $top_cds_count = $cds_rs->search({ rating => { '>' => 7 } })->count;


# update

# delete all entities
$cds_rs->delete;      # fast, but doesn't deletes related entities

$cds_rs->delete_all;  # cascade delete all cds and related entities

DESCRIPTION

A ResultSet is an object which stores a set of conditions representing a query. It is the backbone of DBIx::EAV (i.e. the really important/useful bit).

No SQL is executed on the database when a ResultSet is created, it just stores all the conditions needed to create the query.

A basic ResultSet representing the data of an entire table is returned by calling resultset on a DBIx::EAV and passing in a type name.

my $users_rs = $eav->resultset('User');

A new ResultSet is returned from calling "search" on an existing ResultSet. The new one will contain all the conditions of the original, plus any new conditions added in the search call.

A ResultSet also incorporates an implicit iterator. "next" and "reset" can be used to walk through all the entities the ResultSet represents.

The query that the ResultSet represents is only executed against the database when these methods are called: "find", "next", "all", "first", "count".

If a resultset is used in a numeric context it returns the "count". However, if it is used in a boolean context it is always true. So if you want to check if a resultset has any results, you must use if $rs != 0.

METHODS

new_entity

Arguments: \%entity_data
Return Value: $entity

Creates a new entity object of the resultset's type and returns it. The row is not inserted into the database at this point, call "save" in DBIx::EAV::Entity to do that. Calling "in_storage" in DBIx::EAV::Entity will tell you whether the entity object has been inserted or not.

# create a new entity, do some modifications...
my $cd = $eav->resultset('CD')->new_entity({ title  => 'CD1' });
$cd->set('year', 2016);

# now insert it
$cd->save;

insert

Arguments: \%entity_data
Return Value: $entity

Attempt to create a single new entity or a entity with multiple related entities in the type represented by the resultset (and related types). This will not check for duplicate entities before inserting, use "find_or_create" to do that.

To create one entity for this resultset, pass a hashref of key/value pairs representing the attributes of the "type" and the values you wish to store. If the appropriate relationships are set up, you can also pass related data.

To create related entities, pass a hashref of related-object attribute values keyed on the relationship name. If the relationship is of type has_many or many_to_many - pass an arrayref of hashrefs. The process will correctly identify the relationship type and side, and will transparently populate the "entitiy_relationships table". This can be applied recursively, and will work correctly for a structure with an arbitrary depth and width, as long as the relationships actually exists and the correct data has been supplied.

Instead of hashrefs of plain related data (key/value pairs), you may also pass new or inserted objects. New objects (not inserted yet, see "new_entity"), will be inserted into their appropriate types.

Effectively a shortcut for ->new_entity(\%entity_data)->save.

Example of creating a new entity.

my $cd1 = $cds_rs->insert({
    title  => 'CD1',
    year   => 2016
});

Example of creating a new entity and also creating entities in a related has_many resultset. Note Arrayref for tracks.

my $cd1 = $eav->resultset('CD')->insert({
    title  => 'CD1',
    year   => 2016
    tracks => [
        { title => 'Track1', duration => ... },
        { title => 'Track2', duration => ... },
        { title => 'Track3', duration => ... }
    ]
});

Example of passing existing objects as related data.

my @tags = $eav->resultset('Tag')->search(\%where);

my $article = $eav->resultset('Article')->insert({
    title   => 'Some Article',
    content => '...',
    tags    => \@tags
});
WARNING

When subclassing ResultSet never attempt to override this method. Since it is a simple shortcut for $self->new_entity($data)->save, a lot of the internals simply never call it, so your override will be bypassed more often than not. Override either "new" in DBIx::EAV::Entity or "save" in DBIx::EAV::Entity depending on how early in the "insert" process you need to intervene.

populate

Arguments: \@entites
Return Value: @inserted_entities

Shortcut for inserting multiple entities at once. Returns a list of inserted entities.

my @cds = $eav->resultset('CD')->populate([
    { title => 'CD1', ... },
    { title => 'CD2', ... },
    { title => 'CD3', ... }
]);

count

Arguments: \%where, \%options
Return Value: $count

Performs an SQL COUNT with the same query as the resultset was built with to find the number of elements. Passing arguments is equivalent to $rs->search($cond, \%attrs)->count

delete

Arguments: \%where
Return Value: $underlying_storage_rv

Deletes the entities matching \%where condition without fetching them first. This will run faster, at the cost of related entities not being casdade deleted. Call "delete_all" if you want to cascade delete related entities.

When "database_cascade_delete" in DBIx::EAV is enabled, the delete operation is done in a single query. Otherwise one more query is needed for each of the values table and another for the relationship link table.

WARNING

This method requires database support for DELETE ... JOIN. Since the current implementation of DBIx::EAV is only tested against MySQL and SQLite, this method calls "delete_all" if SQLite database is detected.

delete_all

Arguments: \%where, \%options
Return Value: $num_deleted

Fetches all objects and deletes them one at a time via "delete" in DBIx::EAV::Entity. Note that delete_all will cascade delete related entities, while "delete" will not.

QUERY OPTIONS

limit

Value: $rows

Specifies the maximum number of rows for direct retrieval or the number of rows per page if the page option or method is used.

offset

Value: $offset

Specifies the (zero-based) row number for the first row to be returned, or the of the first row of the first page if paging is used.

page

NOT IMPLEMENTED.

group_by

Value: \@columns

A arrayref of columns to group by. Can include columns of joined tables.

group_by => [qw/ column1 column2 ... /]

having

Value: \%condition

The HAVING operator specifies a secondary condition applied to the set after the grouping calculations have been done. In other words it is a constraint just like "QUERY" (and accepting the same SQL::Abstract syntax) applied to the data as it exists after GROUP BY has taken place. Specifying "having" without "group_by" is a logical mistake, and a fatal error on most RDBMS engines. Valid fields for criteria are all known attributes, relationships and related attributes for the type this cursor is bound to.

E.g.

$eav->resultset('CD')->search(undef, {
    '+select' => { count => 'tracks' },              # alias 'count_tracks' created automatically
    group_by  => ['me.id'],
    having    => { count_tracks => { '>' => 5 } }
});

Althought literal SQL is supported, you must know the actual alias and column names used in the generated SQL statement.

having => \[ 'count(cds_link.) >= ?', 100 ]

Set the debug flag to get the SQL statements printed to stderr.

distinct

Value: (0 | 1)

Set to 1 to automatically generate a "group_by" clause based on the selection (including intelligent handling of "order_by" contents). Note that the group criteria calculation takes place over the final selection. This includes any "+columns", "+select" or "order_by" additions in subsequent "search" calls, and standalone columns selected via DBIx::Class::ResultSetColumn ("get_column"). A notable exception are the extra selections specified via "prefetch" - such selections are explicitly excluded from group criteria calculations.

If the cursor also explicitly has a "group_by" attribute, this setting is ignored and an appropriate warning is issued.

subtype_depth

Value: $depth

Specifies how deep in the type hierarchy you want the query to go. By default its 0, and the query is restricted to the type this cursor is bound to. Even though you can use this option to find entities of subtypes, you cannot use the subtypes own attributes in the query. So if you need to do a subtype query, ensure all attributes needed for the query are defined on the parent type.

# Example entity types:
# Product       [attrs: name, price, description]
# HardDrive     [extends: Product] [attrs: rpm, capacity]
# Monitor       [extends: Product] [attrs: resolution, contrast_ratio]
# FancyMonitor  [extends: Monitor] [attrs: fancy_feature]

# this query won't find any HardDrive or Monitor, only Product entities
$eav->resultset('Product')->search({ price => { '<' => 500 } });

# this also finds HardDrive and Monitor entities
$eav->resultset('Product')->search(
    { price => { '<' => 500 } },       # subtype's attributes are not allowed
    { subtype_depth => 1 }
);

# this query also finds FancyMonitor
$eav->resultset('Product')->search(
    \%where,
    { subtype_depth => 2 }
);

prefetch

NOT IMPLEMENTED.

LICENSE

Copyright (C) Carlos Fernando Avila Gratz.

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

AUTHOR

Carlos Fernando Avila Gratz <cafe@kreato.com.br>