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');
}