Persistence-Entity

 view release on metacpan or  search on metacpan

lib/Persistence/Manual/Relationship.pm  view on Meta::CPAN


    package Department;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'dept';
    column deptno   => has('$.id');
    column dname    => has('$.name');
    to_one 'address' => (
        attribute        =>  has ('$.address', associated_class => 'Address'),
        cascade          => ALL,
        fetch_method     => EAGER,
    );


=item many_to_one

An example of a many-to-one relationship is one between an Employee object
and a Department  object. In this example, each Employee has exactly one Department,
and each Department has many Employees.

lib/Persistence/Manual/Relationship.pm  view on Meta::CPAN

    package Employee;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';
    to_one 'dept' => (
        attribute        =>  has ('$.dept', associated_class => 'Department'),
        cascade          => ALL,
        fetch_method     => EAGER,
    );

    package Department;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'dept';
    column deptno   => has('$.id');
    column dname    => has('$.name');

Note: Bidirectional relationship in this case requires reference on Dept object:

    one_to_many 'emp' => (
        attribute    => has('@.employees' => (associated_class => 'Employee')),
        fetch_method => EAGER,
        cascade      => ALL,
    );


=item one_to_many

An example of a one-to-many relationship is one between a Department object
and Employees  objects. In this example, each Department has  many Employees 
and each Employee has exactly one Department 


    package Department;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'dept';
    column deptno   => has('$.id');
    column dname    => has('$.name');
    one_to_many 'emp' => (
        attribute    => has('@.employees' => (associated_class => 'Employee')),
        fetch_method => EAGER,
        cascade      => ALL,
    );

    package Employee;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';

Note: Bidirectional relationship in this case requires reference on Employee object:

    to_one 'dept' => (
        attribute        =>  has ('$.dept', associated_class => 'Department'),
        cascade          => ALL,
        fetch_method     => EAGER,
    );


=item many_to_many

An example of a mant to mant relationship  is one between an Employee and a Project.
A Employee can be associated to many projects and each Projects has many Employees.
Many to many relationship uses join table.

lib/Persistence/Manual/Relationship.pm  view on Meta::CPAN


    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';

    many_to_many 'project' => (
        attribute        => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
        join_entity_name => 'emp_project',
        fetch_method     => LAZY,
        cascade          => ALL,
    );

    package Project;
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'project';
    column projno => has('$.id');
    column name => has('$.name');

lib/Persistence/Meta/Injection.pm  view on Meta::CPAN

=cut

sub _add_relationship_parameters {
    my ($self, $relationship, $orm) = @_;
    my $attribute = $orm->attribute($relationship->{attribute});
    
    my @result = ($orm->class, $relationship->{name}, attribute => $attribute);
    if (my $fetch_method = $relationship->{fetch_method}) {
        push @result, 'fetch_method' => Persistence::Relationship->$fetch_method();
    }
    if (my $cascade = $relationship->{cascade}) {
        push @result, 'cascade' => Persistence::Relationship->$cascade();
    }
    
    if (my $join_entity = $relationship->{join_entity}) {
        push @result, 'join_entity_name' => $join_entity;
    }
    @result;
}



lib/Persistence/Meta/XML.pm  view on Meta::CPAN

        </to_many_relationships>
    </entity>

    Employee.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <orm entity="emp"  class="Employee" >
        <column name="empno"  attribute="id" />
        <column name="ename"  attribute="name" />
        <column name="job"    attribute="job" />
        <column name="dname"  attribute="dept_name" />
        <to_one_relationship  name="dept" attribute="dept" fetch_method="EAGER" cascade="ALL"/>
    </orm>

    Department.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <orm entity="dept"  class="Department" >
        <column name="deptno" attribute="id" />
        <column name="dname" attribute="name" />
        <column name="loc" attribute="location" />
        <one_to_many_relationship  name="emp" attribute="employees" fetch_method="EAGER" cascade="ALL"/>
    </orm>


    package Employee;
    use Abstract::Meta::Class ':all';

    has '$.id';
    has '$.name';
    has '$.job';
    has '$.dept_name';

lib/Persistence/Meta/XML.pm  view on Meta::CPAN

=item orm_xml_handler

    <!ELEMENT orm (column+, lob+, to_one_relationship*, one_to_many_relationship*, many_to_many_relationship*)
    <!ATTRLIST orm class entity mop_attribute_adapter>
    <!ELEMENT column>
    <!ATTRLIST column name attribute>
    <!ELEMENT lob name attribute fetch_method>
    <!ELEMENT to_one_relationship>
    <!ATTRLIST to_one_relationship name attribute #REQUIRED>
    <!ATTRLIST to_one_relationship fetch_method (LAZY|EAGER) "LAZY">
    <!ATTRLIST to_one_relationship cascade (NONE|ALL|ON_INSERT|ON_UPDATE|ON_DELETE) "NONE">

    <orm entity="emp"  class="Employee" >
        <column name="empno" attribute="id" />
        <column name="ename" attribute="name" />
        <column name="job" attribute="job" />
        <to_one_relationship name="dept" attribute="depts" fetch_method="LAZY" cascade="ALL">
    </orm>

    many_to_many 'project' => (
        attribute        => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
        join_entity_name => 'emp_project',
        fetch_method     => LAZY,
        cascade          => ALL,
    );


=item orm_xml_handler

Retunds xml handlers that will transform the orm xml into Persistence::ORM object

=cut

sub orm_xml_handler {

lib/Persistence/Relationship.pm  view on Meta::CPAN


=item fetch_method

LAZY, EAGER

=cut

has '$.fetch_method' => (default => LAZY);


=item cascade

NONE, ALL ON_UPDATE, ON_DELETE, ON_INSERT

=cut

has '$.cascade' => (default => NONE);


=item orm

=cut

has '$.orm' => (associated_class => 'Persistence::ORM', the_other_end => 'lobs');


=back

lib/Persistence/Relationship.pm  view on Meta::CPAN


=cut

sub insertable_to_many_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next if ref($relation) eq 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_INSERT);
        push @result, $relation;
    }
    @result;
}


=item insertable_to_one_relations

Returns all to one relation where insert applies.

=cut

sub insertable_to_one_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next unless ref($relation) eq 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_INSERT);
        push @result, $relation;
    }
    @result;
}


=item updatable_to_many_relations

Returns all relation where insert applies.

=cut

sub updatable_to_many_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next if ref($relation) eq 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_UPDATE);
        push @result, $relation;
    }
    @result;
}


=item updatable_to_one_relations

Returns all relation where insert applies.

=cut

sub updatable_to_one_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next if ref($relation) ne 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_UPDATE);
        push @result, $relation;
    }
    @result;
}


=item deleteable_to_many_relations

Returns all to many relation where insert applies.

=cut

sub deleteable_to_many_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next if ref($relation) eq 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_DELETE);
        push @result, $relation;
    }
    @result;
}


=item deleteable_to_one_relations

Returns all to one relation where insert applies.

=cut

sub deleteable_to_one_relations {
    my ($class, $obj_class) = @_;
    my $relations = $class->relationships($obj_class) or return;
    my @result;
    foreach my $attribute_name (keys %$relations) {
        my $relation = $relations->{$attribute_name};
        next if ref($relation) ne 'Persistence::Relationship::ToOne';
        my $cascade = $relation->cascade;
        next if($cascade ne ALL && $cascade ne ON_DELETE);
        push @result, $relation;
    }
    @result;
}


=item eager_fetch_relations

=cut

lib/Persistence/Relationship/ManyToMany.pm  view on Meta::CPAN


    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';

    many_to_many 'project' => (
        attribute        => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
        join_entity_name => 'emp_project',
        fetch_method     => LAZY,
        cascade          => ALL,
    );

=head1 DESCRIPTION

Represents many to many relationship.
Supports eager, lazy fetch, cascading operation (inert/update/delete).

=head1 EXPORT

many_to_many by ':all' tag.

lib/Persistence/Relationship/OneToMany.pm  view on Meta::CPAN


    entity 'wsus_user';
    column id => has('$.id');
    column username => has('$.name');
    column password => has('$.password');
    column email => has('$.email');

    one_to_many 'wsus_user_service' => (
        attribute    => has('@.membership' => (associated_class => 'Membership')),
        fetch_method => EAGER,
        cascade      => ALL,
    );

=head1 DESCRIPTION

Represents one to many relationship. Allows cascading operation (inert/update/delete).
Supports eager, lazy fetch, cascading operation (inert/update/delete).

=head1 EXPORT

one_to_many method by ':all' tag.

lib/Persistence/Relationship/OneToMany.pm  view on Meta::CPAN


=item one_to_many

Create a new instance of one to many relation.
Takes associated entity's id as parameters
and list of named parameters for Persistence::Relationship::OneToMany constructor.

    one_to_many 'wsus_user_service' => (
        attribute    => has('@.membership' => (associated_class => 'Membership')),
        fetch_method => EAGER,
        cascade      => ALL,
    );


=cut

sub one_to_many {
    my $package = caller();
    __PACKAGE__->add_relationship($package, @_);
}

lib/Persistence/Relationship/ToOne.pm  view on Meta::CPAN

    use Abstract::Meta::Class ':all';
    use Persistence::Entity ':all';
    use Persistence::ORM ':all';

    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';
    to_one 'dept' => (
        attribute        =>  has ('$.dept', associated_class => 'Department'),
        cascade          => ALL,
        fetch_method     => EAGER,
    );

    package Department;

    use Abstract::Meta::Class ':all';
    use Persistence::Entity ':all';
    use Persistence::ORM ':all';

    entity 'dept';

lib/Persistence/Relationship/ToOne.pm  view on Meta::CPAN


=item to_one

Create a new instance of to one relation.
Takes associated entity's id as parameters
and list of named parameters for Persistence::Relationship::OneToMany constructor.

    one_to_many 'wsus_user_service' => (
        attribute    => has('@.membership' => (associated_class => 'Membership')),
        fetch_method => EAGER,
        cascade      => ALL,
    );


=cut

sub to_one {
    my $package = caller();
    __PACKAGE__->add_relationship($package, @_);
}

t/meta/xml.t  view on Meta::CPAN

    has '$.location';
    has '@.employees' => (associated_class => 'Employee');

    $xml = $meta->orm_xml_handler;
    $meta->injection->  set_entity_manager(Persistence::Entity::Manager->new(name => 'test', connection_name => 'test'));    
        my $xml_content = '<?xml version="1.0" encoding="UTF-8"?>
    <orm entity="emp"  class="Employee" >
        <column name="empno" attribute="id" />
        <column name="ename" attribute="name" />
        <column name="job" attribute="job" />
        <to_one_relationship  name="dept" attribute="dept" fetch_method="LAZY" cascade="ALL"/>
    </orm>
    ';
    
    $xml->parse_string($xml_content);
    $meta->injection->load_persistence_context($meta);
    my $orm = $meta->injection->entity_manager->find_entity_mappings('Employee');
    ::isa_ok($orm, 'Persistence::ORM');
    ::isa_ok($orm->_column('ename'), 'Persistence::Attribute', 'should have ename column mapping');
    ::isa_ok($orm->_column('empno'), 'Persistence::Attribute', 'should have empno column mapping');
    ::isa_ok($orm->_column('job'), 'Persistence::Attribute', 'should have job column mapping');

t/meta/xml/Employee.xml  view on Meta::CPAN

<?xml version="1.0" encoding="UTF-8"?>
<orm entity="emp"  class="Employee" >
    <column name="empno" attribute="id" />
    <column name="ename" attribute="name" />
    <column name="job" attribute="job" />
    <to_one_relationship  name="dept" attribute="dept" fetch_method="LAZY" cascade="ALL"/>
</orm>

t/relationship/many_to_many_relationship.t  view on Meta::CPAN

    
    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';

    many_to_many 'project' => (
        attribute        => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
        join_entity_name => 'emp_project',
        fetch_method     => LAZY,
        cascade          => ALL,
    );
}

{
    package EagerEmployee;
    
    use Abstract::Meta::Class ':all';
    use Persistence::Entity ':all';
    use Persistence::ORM ':all';
    
    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';

    many_to_many 'project' => (
        attribute        => has('%.projects' => (associated_class => 'Project'), index_by => 'name'),
        join_entity_name => 'emp_project',
        fetch_method     => EAGER,
        cascade          => ALL,
    );
}



SKIP: {
    
    ::skip('missing env varaibles DB_TEST_CONNECTION, DB_TEST_USERNAME DB_TEST_PASSWORD', 10)
        unless $ENV{DB_TEST_CONNECTION};

t/relationship/many_to_many_relationship.t  view on Meta::CPAN

        };
        is_deeply($exp_result, $projects, 'should retrieve projects association');
        
    }
    {
        my ($emp) = $entity_manager->find(emp => 'EagerEmployee', name => 'emp2');
        ok( $emp->{'%.projects'}, 'should have projects - eager retrieval');
    }


    #cascade on insert
    {
        my $emp = Employee->new(name => 'Adrian', job => 'Software Engineer');
        $emp->add_projects(
            Project->new(name => 'Identity'),
            Project->new(name => 'project1')
        );
       $entity_manager->insert($emp);
    }
    
    expected_xml_dataset_ok('insert');
 
    xml_dataset_ok('init');
 
     #cascade on update
    {
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        $emp->add_projects(
            Project->new(name => 'Identity'),
        );
        $entity_manager->update($emp);
    }
 
    expected_xml_dataset_ok('update');
    
    xml_dataset_ok('init');
     #cascade on delete
    {
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        $entity_manager->delete($emp);
    }

    expected_xml_dataset_ok('delete');
    
    
}

t/relationship/meta/Department.xml  view on Meta::CPAN

<?xml version="1.0" encoding="UTF-8"?>
<orm entity="dept"  class="Department" >
    <column name="deptno" attribute="id" />
    <column name="dname" attribute="name" />
    <column name="loc" attribute="location" />
    <one_to_many_relationship  name="emp" attribute="employees" fetch_method="EAGER" cascade="ALL"/>
</orm>

t/relationship/meta/Employee.xml  view on Meta::CPAN

<?xml version="1.0" encoding="UTF-8"?>
<orm entity="emp"  class="Employee" >
    <column name="empno"  attribute="id" />
    <column name="ename"  attribute="name" />
    <column name="job"    attribute="job" />
    <column name="dname"  attribute="dept_name" />
    <to_one_relationship  name="dept" attribute="dept" fetch_method="EAGER" cascade="ALL"/>
</orm>

t/relationship/one_to_many_relationship.t  view on Meta::CPAN

    use Persistence::ORM ':all';
    
    entity 'dept';
    column deptno => has('$.id');
    column dname => has('$.name');
    column loc   => has('$.location');
    
    my $relation = one_to_many 'emp' => (
        attribute    => has('@.employees' => (associated_class => 'Employee')),
        fetch_method => EAGER,
        cascade      => ALL,
    );
    ::is_deeply([$class->insertable_to_many_relations('Department')], [$relation], 'should have insertable relations');
    ::is_deeply([$class->updatable_to_many_relations('Department')],  [$relation],  'should have updatable relations');
    ::is_deeply([$class->deleteable_to_many_relations('Department')], [$relation], 'should have deleteable relations');
}


{
    package HODepartment;
    

t/relationship/one_to_many_relationship.t  view on Meta::CPAN

    use Persistence::ORM ':all';

    entity 'dept';
    column deptno => has('$.id');
    column dname => has('$.name');
    column loc => has('$.location');
    
    my $relation = one_to_many 'emp' => (
        attribute    => has('@.employees' => (associated_class => 'Employee', item_accessor => 'employee')),
        fetch_method => LAZY,
        cascade      => ON_INSERT,
        );

    
    ::is_deeply([$class->insertable_to_many_relations('HODepartment')], [$relation], 'should have insertable relations');
    ::ok(! $class->updatable_to_many_relations('HODepartment'), 'should not have updatable relations');
    ::ok(! $class->deleteable_to_many_relations('HODepartment'), 'should not have deleteable relations');
}


SKIP: {

t/relationship/one_to_many_relationship.t  view on Meta::CPAN

                    Employee->new(id => 4, name => 'emp4', job => undef),
                ], 'should lazily retrive relation data');
                $dept->employees;
                is($dept->employee(0), $employees->[0], 'should have the same employee');
                is($fetch_counter, 6, 'should lazily retrive relation data after refresh object');
            }
        }
    }
    
    
    #cascade on insert
    {
        my $dept =  new HODepartment(
            id         => '50',
            name       => 'dept50',
            location   => 'loc50',
            employees => [
                Employee->new(id => 21, name => 'emp21', job => undef),
                Employee->new(id => 22, name => 'emp22', job => 'manager')
            ]
        );
        $entity_manager->insert($dept);
    }
    
    expected_xml_dataset_ok('insert');
    

    xml_dataset_ok('init');

    #cascade on update 
    {
        my ($dept) = $entity_manager->find(dept => 'Department', name => 'dept3');
        $dept->set_location('loc33');
        my @employees = $dept->employees;
        $employees[0]->set_job('sales assistant');
        $dept->add_employees(Employee->new(id => 22, name => 'emp22', job => 'manager'));
        $entity_manager->update($dept);
    }
    expected_xml_dataset_ok('update');
    
    
    
    xml_dataset_ok('init');
    
    #cascade on delete
    {
        my ($dept) = $entity_manager->find(dept => 'Department', name => 'dept3');
        $entity_manager->delete($dept);
        
    }
    expected_xml_dataset_ok('delete');
}

t/relationship/to_one_relationship.t  view on Meta::CPAN

    
    use Abstract::Meta::Class ':all';
    use Persistence::ORM ':all';

    entity 'dept';
    column deptno   => has('$.id');
    column dname    => has('$.name');
    column loc      => has('$.location');   
    to_one 'address' => (
        attribute        =>  has ('$.address', associated_class => 'Address'),
        cascade          => ALL,
        fetch_method     => LAZY,
    );
}


{
    package Employee;
    
    use Abstract::Meta::Class ':all';
    use Persistence::Entity ':all';
    use Persistence::ORM ':all';
    
    entity 'emp';
    column empno=> has('$.id');
    column ename => has('$.name');
    column job => has '$.job';
    my $relation = to_one 'dept' => (
        attribute        =>  has ('$.dept', associated_class => 'Department'),
        cascade          => ALL,
        fetch_method     => EAGER,
    );

    ::is_deeply([$class->insertable_to_one_relations('Employee')], [$relation], 'should have insertable relations');
    ::is_deeply([$class->updatable_to_one_relations('Employee')],  [$relation],  'should have updatable relations');
    ::is_deeply([$class->deleteable_to_one_relations('Employee')], [$relation], 'should have deleteable relations');

}

SKIP: {

t/relationship/to_one_relationship.t  view on Meta::CPAN

    }
    
    xml_dataset_ok('init');

    {   #fetch
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        my $dept = Department->new(id => 5, name => 'dept5', location   => 'loc5');
        is_deeply($emp->{'$.dept'}, $dept, 'should fetch eagerly association data')
    }
    
    #cascade on insert
    {
        
        my $emp = Employee->new(id => 21, name => 'emp21', job => undef);
        my $dept = Department->new(id => '50', name => 'dept50', location => 'loc50');
        $emp->set_dept($dept);
        $entity_manager->insert($emp);
    }
    
    expected_xml_dataset_ok('insert');


    #cascade on update 
    {
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        $emp->dept->set_location('Warsaw');
        $emp->set_job('Manager');
        $entity_manager->update($emp);
    }
    expected_xml_dataset_ok('update');

    xml_dataset_ok('update');
    {

t/relationship/to_one_relationship.t  view on Meta::CPAN

    xml_dataset_ok('update');
    {
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        $emp->set_dept(undef);
        $entity_manager->update($emp);
    }
    expected_xml_dataset_ok('update2');
    
    xml_dataset_ok('init');
    
    #cascade on delete
    {
        my ($emp) = $entity_manager->find(emp => 'Employee', name => 'emp2');
        $entity_manager->delete($emp);
    }
    expected_xml_dataset_ok('delete');
    
}



( run in 0.614 second using v1.01-cache-2.11-cpan-49f99fa48dc )