1  package Address;
2  use Moose;
3  use Moose::Util::TypeConstraints;
4  with 'Mongoose::EmbeddedDocument';
5
6  use Locale::US;
7  use Regexp::Common 'zip';
8
9  my $STATES = Locale::US->new;
10  subtype 'USState'
11      => as Str
12      => where {
13             (    exists $STATES->{code2state}{ uc($_) }
14               || exists $STATES->{state2code}{ uc($_) } );
15         };
16
17  subtype 'USZipCode'
18      => as Value
19      => where {
20             /^$RE{zip}{US}{-extended => 'allow'}$/;
21         };
22
23  has 'street'   => ( is => 'rw', isa => 'Str' );
24  has 'city'     => ( is => 'rw', isa => 'Str' );
25  has 'state'    => ( is => 'rw', isa => 'USState' );
26  has 'zip_code' => ( is => 'rw', isa => 'USZipCode' );
27
28  package Company;
29  use Moose;
30  use Moose::Util::TypeConstraints;
31  with 'Mongoose::Document';
32
33  has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
34  has 'address'   => ( is => 'rw', isa => 'Address' );
35  has 'employees' => ( is => 'rw', isa => 'ArrayRef[Employee]' );
36
37  sub BUILD {
38      my ( $self, $params ) = @_;
39      foreach my $employee ( @{ $self->employees || [] } ) {
40          $employee->employer($self);
41      }
42  }
43
44  after 'employees' => sub {
45      my ( $self, $employees ) = @_;
46      foreach my $employee ( @{ $employees || [] } ) {
47          $employee->employer($self);
48      }
49  };
50
51  package Person;
52  use Moose;
53  with 'Mongoose::Document';
54
55  has 'first_name' => ( is => 'rw', isa => 'Str', required => 1 );
56  has 'last_name'  => ( is => 'rw', isa => 'Str', required => 1 );
57  has 'middle_initial' => (
58      is        => 'rw', isa => 'Str',
59      predicate => 'has_middle_initial'
60  );
61  has 'address' => ( is => 'rw', isa => 'Address' );
62
63  sub full_name {
64      my $self = shift;
65      return $self->first_name
66          . (
67          $self->has_middle_initial
68          ? ' ' . $self->middle_initial . '. '
69          : ' '
70          ) . $self->last_name;
71  }
72
73  package Employee;
74  use Moose;
75  with 'Mongoose::Document';
76
77  extends 'Person';
78
79  has 'title'    => ( is => 'rw', isa => 'Str',     required => 1 );
80  has 'employer' => ( is => 'rw', isa => 'Company', weak_ref => 1 );
81
82  override 'full_name' => sub {
83      my $self = shift;
84      super() . ', ' . $self->title;
85  };
86
87
88package main;
89use v5.10;
90use Mongoose;
91use Benchmark;
92my $db = Mongoose->db( 'mediadb' );
93sub cleanup {
94	$db->run_command({ drop => 'address' });
95	$db->run_command({ drop => 'company' });
96	$db->run_command({ drop => 'person' });
97	$db->run_command({ drop => 'employee' });
98}
99cleanup();
100{
101	my $address = new Address( street=>'1st st. 212', city=>'Gotham', zip_code=>'12345', state=>'NY'  );
102	my $company = new Company( name=> 'Acme', address=>$address );
103	my $employee = new Employee( first_name=>'John', last_name=>'Doe', title=>'CEO');
104	$company->employees([ $employee ]);
105	timethis( 1000, sub { $company->save; });
106	say $company->dump
107}
108{
109	my $rs = Company->find;
110	while ( my $c = $rs->next ) {
111		say $c->dump;
112		#say $c->address->dump;
113		#$c->address->save;
114		#$c->save;
115	}
116
117
118}
119