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