File Coverage

blib/lib/Prophet/Record.pm
Criterion Covered Total %
statement 21 244 8.6
branch 0 72 0.0
condition 0 25 0.0
subroutine 7 54 12.9
pod 30 34 88.2
total 58 429 13.5


line stmt bran cond sub pod time code
1             package Prophet::Record;
2 3     3   3485 use Any::Moose;
  3         6  
  3         21  
3 3     3   1592 use Params::Validate;
  3         5  
  3         204  
4 3     3   434 use Prophet::App; # for require_module. Kinda hacky
  3         6  
  3         140  
5 3     3   17 use constant collection_class => 'Prophet::Collection';
  3         5  
  3         1526  
6              
7             =head1 NAME
8              
9             Prophet::Record
10              
11             =head1 DESCRIPTION
12              
13             This class represents a base class for any record in a Prophet database.
14              
15             =cut
16              
17             has app_handle => (
18             isa => 'Prophet::App|Undef',
19             is => 'rw',
20             required => 0,
21             );
22              
23             has handle => (
24             is => 'rw',
25             required => 1,
26             default => sub { shift->app_handle->handle }
27             );
28              
29             has type => (
30             is => 'rw',
31             isa => 'Str',
32             predicate => 'has_type',
33             required => 1,
34             default => sub { undef}
35             );
36              
37             has uuid => (
38             is => 'rw',
39             isa => 'Str',
40             );
41              
42             has luid => (
43             is => 'rw',
44             isa => 'Str|Undef',
45             lazy => 1,
46             default => sub { my $self = shift; $self->find_or_create_luid; },
47             );
48              
49             our $REFERENCES = {};
50 0     0 0   sub REFERENCES { $REFERENCES }
51              
52             our $PROPERTIES = {};
53 0     0 0   sub PROPERTIES { $PROPERTIES }
54              
55             =head1 METHODS
56              
57             =head2 new { handle => Prophet::Replica, type => $type }
58              
59             Instantiates a new, empty L of type $type.
60              
61             =head2 declared_props
62              
63             Returns a sorted list of the names of the record's declared properties.
64             Declared properties are always validated even if the user provides no value
65             for that prop. This can be used for such things as requiring records to
66             have certain props in order to be created, for example.
67              
68             =cut
69              
70             sub declared_props {
71 0     0 1   return sort keys %{ $_[0]->PROPERTIES };
  0            
72             }
73              
74             =head2 record_type
75              
76             Returns the record's type.
77              
78             =cut
79              
80 0     0 1   sub record_type { $_[0]->type }
81              
82             =head2 register_reference $class, $accessor, $foreign_class, @args
83              
84             Registers a reference to a foreign class to this record. The
85             foreign class must be of type L or
86             L, or else a fatal error is triggered.
87              
88             =cut
89              
90             sub register_reference {
91 0     0 1   my ( $class, $accessor, $foreign_class, @args ) = @_;
92 0           Prophet::App->require($foreign_class);
93 0 0         if ( $foreign_class->isa('Prophet::Collection') ) {
    0          
94 0           return $class->register_collection_reference(
95             $accessor => $foreign_class,
96             @args
97             );
98             } elsif ( $foreign_class->isa('Prophet::Record') ) {
99 0           return $class->register_record_reference(
100             $accessor => $foreign_class,
101              
102             # default the lookup property to be the name of the accessor
103             by => $accessor,
104              
105             @args
106             );
107             } else {
108 0           die "Your foreign class ($foreign_class) must be a subclass of Prophet::Record or Prophet::Collection";
109             }
110              
111             }
112              
113             =head2 register_collection_reference $accessor, $collection_class, by => $key_in_model
114              
115             Registers and creates an accessor in the current class to the associated
116             collection C<$collection_class>, which refers to the current class by
117             C<$key_in_model> in the model class of C<$collection_class>.
118              
119             =cut
120              
121             sub register_collection_reference {
122 0     0 1   my ( $class, $accessor, $collection_class, @args ) = @_;
123 0           my %args = validate( @args, { by => 1 } );
124 3     3   19 no strict 'refs';
  3         4  
  3         751  
125              
126 0           Prophet::App->require( $collection_class->record_class );
127              
128 0           *{ $class . "::$accessor" } = sub {
129 0     0     my $self = shift;
130 0           my $collection = $collection_class->new(
131             app_handle => $self->app_handle,
132             );
133 0   0       $collection->matching( sub { ($_[0]->prop( $args{by} )||'') eq $self->uuid }
134 0           );
135 0           return $collection;
136 0           };
137              
138             # XXX: add validater for $args{by} in $model->record_class
139              
140 0           $class->REFERENCES->{$class}{$accessor} = {
141             %args,
142             arity => 'collection',
143             type => $collection_class->record_class,
144             };
145             }
146              
147             =head2 register_record_reference $accessor, $record_class, by => $key_in_model
148              
149             Registers and creates an accessor in the current class to the associated
150             record C<$record_class>, which refers to the current class by
151             C<$key_in_model> in the model class of C<$collection_class>.
152              
153             =cut
154              
155             sub register_record_reference {
156 0     0 1   my ( $class, $accessor, $record_class, @args ) = @_;
157 0           my %args = validate( @args, { by => 1 } );
158 3     3   19 no strict 'refs';
  3         4  
  3         10097  
159              
160 0           Prophet::App->require( $record_class );
161              
162 0           *{ $class . "::$accessor" } = sub {
163 0     0     my $self = shift;
164 0           my $record = $record_class->new(
165             app_handle => $self->app_handle,
166             handle => $self->handle,
167             );
168 0           $record->load(uuid => $self->prop($args{by}));
169 0           return $record;
170 0           };
171              
172             # XXX: add validater for $args{by} in $model->record_class
173              
174 0           $class->REFERENCES->{$class}{$accessor} = {
175             %args,
176             arity => 'scalar',
177             type => $record_class,
178             };
179             }
180              
181             =head2 create { props => { %hash_of_kv_pairs } }
182              
183             Creates a new Prophet database record in your database. Sets the record's properties to the keys and values passed in.
184              
185             Automatically canonicalizes and then validates the props.
186              
187             Upon successful creation, returns the new record's C.
188             In case of failure, returns undef.
189              
190             =cut
191              
192             sub create {
193 0     0 1   my $self = shift;
194 0           my %args = validate( @_, { props => 1 } );
195 0           my $uuid = $self->handle->uuid_generator->create_str;
196              
197 0           my $props = $args{props};
198              
199 0           $self->default_props($props);
200 0           $self->canonicalize_props($props);
201              
202             # XXX TODO - this should be a real exception
203 0 0         return undef unless (keys %$props);
204              
205 0 0         $self->validate_props($props) or return undef;
206 0           $self->_create_record(props => $props, uuid => $uuid);
207             }
208              
209              
210              
211              
212             # _create_record is a helper routine, used both by create and by databasesetting::create
213             sub _create_record {
214 0     0     my $self = shift;
215 0           my %args = validate( @_, { props => 1, uuid => 1 } );
216              
217 0           $self->uuid($args{uuid});
218              
219             $self->handle->create_record(
220 0           props => $args{'props'},
221             uuid => $self->uuid,
222             type => $self->type
223             );
224              
225 0           return $self->uuid;
226              
227             }
228              
229             =head2 load { uuid => $UUID } or { luid => $UUID }
230              
231             Given a UUID or LUID, look up the LUID or UUID (the opposite of what was
232             given) in the database. Set this record's LUID and UUID attributes, and return
233             the LUID or UUID (whichever wasn't given in the method call).
234              
235             Returns undef if the record doesn't exist in the database.
236              
237             =cut
238              
239             sub load {
240 0     0 1   my $self = shift;
241              
242             my %args = validate(
243             @_,
244             { uuid => {
245             optional => 1,
246             callbacks => {
247 0 0   0     'uuid or luid present' => sub { $_[0] || $_[1]->{luid} },
248             },
249             },
250             luid => {
251             optional => 1,
252             callbacks => {
253 0 0   0     'luid or uuid present' => sub { $_[0] || $_[1]->{uuid} },
254             },
255             },
256             }
257 0           );
258              
259 0 0         if ( $args{luid} ) {
260 0           $self->luid( $args{luid} );
261 0           $self->uuid( $self->handle->find_uuid_by_luid( luid => $args{luid} ) );
262 0 0         return($self->uuid) if ($self->uuid);
263             } else {
264 0           $self->uuid( $args{uuid} );
265 0           $self->luid( $self->handle->find_or_create_luid( uuid => $args{uuid}));
266 0 0         return($self->luid) if ($self->luid);
267             }
268              
269 0           return undef;
270             }
271              
272             # a private method to let collection search results instantiate records more quickly
273             # (See Prophet::Replica::sqlite)
274             sub _instantiate_from_hash {
275 0     0     my $self = shift;
276 0           my %args = ( uuid => undef, luid => undef, @_);
277             # we might not have a luid cheaply (see the prophet filesys backend)
278 0 0         $self->luid($args{'luid'}) if (defined $args{'luid'});
279             # We _Always_ have a luid
280 0           $self->uuid($args{'uuid'});
281             # XXX TODO - expect props as well
282             }
283              
284             sub loaded {
285 0     0 0   my $self = shift;
286 0 0         return $self->uuid ? 1 : 0;
287             }
288              
289             =head2 set_prop { name => $name, value => $value }
290              
291             Updates the current record to set an individual property called C<$name> to C<$value>
292              
293             This is a convenience method around L.
294              
295             =cut
296              
297             sub set_prop {
298 0     0 1   my $self = shift;
299              
300 0           my %args = validate( @_, { name => 1, value => 1 } );
301 0           my $props = { $args{'name'} => $args{'value'} };
302 0           $self->set_props( props => $props );
303             }
304              
305             =head2 set_props { props => { key1 => val1, key2 => val2} }
306              
307             Updates the current record to set all the keys contained in the C parameter to their associated values.
308             Automatically canonicalizes and validates the props in question.
309              
310             In case of failure, returns false.
311              
312             On success, returns true.
313              
314             =cut
315              
316             sub set_props {
317 0     0 1   my $self = shift;
318 0           my %args = validate( @_, { props => 1 } );
319              
320 0 0         confess "set_props called on a record that hasn't been loaded or created yet." if !$self->uuid;
321              
322 0           $self->canonicalize_props( $args{'props'} );
323 0 0         $self->validate_props( $args{'props'} ) || return undef;
324              
325 0 0         return 0 unless grep { defined } values %{$args{props}};
  0            
  0            
326              
327             $self->handle->set_record_props(
328             type => $self->type,
329             uuid => $self->uuid,
330 0           props => $args{'props'}
331             );
332 0           return 1;
333             }
334              
335             =head2 get_props
336              
337             Returns a hash of this record's properties as currently set in the database.
338              
339             =cut
340              
341             sub get_props {
342 0     0 1   my $self = shift;
343              
344 0 0         confess "get_props called on a record that hasn't been loaded or created yet." if !$self->uuid;
345              
346 0   0       return $self->handle->get_record_props(
347             uuid => $self->uuid,
348             type => $self->type) || {};
349              
350             }
351              
352             =head2 prop $name
353              
354             Returns the current value of the property C<$name> for this record.
355             (This is a convenience method wrapped around L).
356              
357             =cut
358              
359             sub prop {
360 0     0 1   my $self = shift;
361 0           my $prop = shift;
362 0           return $self->get_props->{$prop};
363             }
364              
365             =head2 delete_prop { name => $name }
366              
367             Deletes the current value for the property $name.
368             (This is currently equivalent to setting the prop to ''.)
369              
370             =cut
371              
372             sub delete_prop {
373 0     0 1   my $self = shift;
374 0           my %args = validate( @_, { name => 1 } );
375              
376 0 0         confess "delete_prop called on a record that hasn't been loaded or created yet." if !$self->uuid;
377              
378 0           $self->set_prop(name => $args{'name'}, value => '');
379              
380             # $self->handle->delete_record_prop(
381             # uuid => $self->uuid,
382             # name => $args{'name'}
383             # );
384             }
385              
386             =head2 delete
387              
388             Deletes this record from the database. (Note that it does _not_ purge historical versions of the record)
389              
390             =cut
391              
392             sub delete {
393 0     0 1   my $self = shift;
394 0           delete $self->{props};
395 0           $self->handle->delete_record( type => $self->type, uuid => $self->uuid );
396              
397             }
398              
399             =head2 changesets { limit => $int }
400              
401             Returns an ordered list of changeset objects for all changesets containing
402             changes to the record specified by this record object.
403              
404             Note that changesets may include changes to other records.
405              
406             If a limit is specified, this routine will only return that many
407             changesets, starting from the changeset containing the record's
408             creation.
409              
410             =cut
411              
412             sub changesets {
413 0     0 1   my $self = shift;
414 0           my %args = validate(@_, { limit => 0});
415             return $self->handle->changesets_for_record(
416             uuid => $self->uuid,
417             type => $self->type,
418 0 0         $args{limit} ? (limit => $args{limit}) : ()
419             );
420             }
421              
422             =head2 changes
423              
424             Returns an ordered list of all the change objects that represent changes
425             to the record specified by this record object.
426              
427             =cut
428              
429             sub changes {
430 0     0 1   my $self = shift;
431 0           my $uuid = $self->uuid;
432 0           my @changesets = $self->changesets;
433              
434 0           return grep { $_->record_uuid eq $uuid }
435 0           map { $_->changes }
  0            
436             @changesets;
437             }
438              
439             =head2 uniq @list
440              
441             The C function (taken from version 0.21).
442              
443             Returns a new list by stripping duplicate values in @list. The order of
444             elements in the returned list is the same as in @list. In scalar
445             context, returns the number of unique elements in @list.
446              
447             my @x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 1 2 3 5 4
448             my $x = uniq 1, 1, 2, 2, 3, 5, 3, 4; # returns 5
449              
450             =cut
451              
452 0 0   0 1   sub uniq (@) { my %h; map { $h{$_}++ == 0 ? $_ : () } @_; }
  0            
  0            
453              
454             =head2 validate_props $propsref
455              
456             Takes a reference to a props hash and validates each prop in the
457             hash or in the C attribute that has a validation routine
458             (C).
459              
460             Dies if any prop fails validation. Returns true on success. Returns
461             false if any prop is not allowable (prop name fails validation).
462              
463             =cut
464              
465             sub validate_props {
466 0     0 1   my $self = shift;
467 0           my $props = shift;
468 0           my $errors = {};
469 0           my @errors;
470 0           for my $key ( uniq( keys %$props, $self->declared_props ) ) {
471 0 0         return undef unless ( $self->_validate_prop_name($key) );
472 0 0         if ( my $sub = $self->can( 'validate_prop_' . $key ) ) {
473             $sub->( $self, props => $props, errors => $errors ) ||
474             push @errors,"Validation error for '$key': " .
475 0 0 0       ( $errors->{$key} || '' ) . '.';
476             }
477             }
478 0 0         if (@errors) {
479 0           die join( "\n", @errors )."\n";
480             }
481 0           return 1;
482             }
483              
484             =head2 _validate_prop_name
485              
486             A hook to allow forcing users to only use certain prop names.
487              
488             Currently just returns true for all inputs.
489              
490             =cut
491              
492 0     0     sub _validate_prop_name {1}
493              
494             =head2 canonicalize_props $propsref
495              
496             Takes a hashref to a props hash and canonicalizes each one if a
497             C routine is available.
498              
499             Returns true on completion.
500              
501             =cut
502              
503             sub canonicalize_props {
504 0     0 1   my $self = shift;
505 0           my $props = shift;
506 0           my $errors = {};
507 0           for my $key ( uniq( keys %$props, $self->declared_props ) ) {
508 0           $self->canonicalize_prop($key, $props, $errors);
509             }
510 0           return 1;
511             }
512              
513             sub canonicalize_prop {
514 0     0 0   my $self = shift;
515 0           my $prop = shift;
516 0           my $props = shift;
517 0           my $errors = shift;
518 0 0         if ( my $sub = $self->can( 'canonicalize_prop_' . $prop ) ) {
519 0           $sub->( $self, props => $props, errors => $errors );
520 0           return 1;
521             }
522              
523              
524 0           return 0;
525             }
526              
527              
528             =head2 default_props $props_ref
529              
530             Takes a reference to a hash of props and looks up the defaults for those
531             props, if they exist (by way of C routines). Sets the
532             values of the props in the hash to the defaults.
533              
534             =cut
535              
536             sub default_props {
537 0     0 1   my $self = shift;
538 0           my $props = shift;
539              
540 0           my @methods = grep { /^default_prop_/ } $self->meta->get_all_method_names;
  0            
541              
542 0           for my $method (@methods) {
543 0           my ($key) = $method =~ /^default_prop_(.+)$/;
544              
545             $props->{$key} = $self->$method(props => $props)
546 0 0         if !defined($props->{$key});
547             }
548              
549 0           return 1;
550             }
551              
552             =head2 default_prop_creator
553              
554             Default the creator of every record to the changeset_creator (usually the current user's email address.)
555              
556             =cut
557              
558             sub default_prop_creator {
559 0     0 1   my $self = shift;
560 0           return $self->handle->changeset_creator;
561             }
562              
563             =head2 default_prop_original_replica
564              
565             Default the original_replica of every record to the replica's uuid.
566              
567             =cut
568              
569             sub default_prop_original_replica {
570 0     0 1   my $self = shift;
571 0           return $self->handle->uuid;
572             }
573              
574             =head2 validate_prop_from_recommended_values 'prop', $argsref
575              
576             Checks to see if the given property has a valid value and returns true if so.
577             If not, adds an error message to $argsref->{errors}{prop} and returns false.
578              
579             =cut
580              
581             sub validate_prop_from_recommended_values {
582 0     0 1   my $self = shift;
583 0           my $prop = shift;
584 0           my $args = shift;
585              
586 0 0         if ( my @options = $self->recommended_values_for_prop($prop) ) {
587 0           return 1 if ((scalar grep { $args->{props}{$prop} eq $_ } @options)
588             # force-set props with ! to bypass validation
589 0 0 0       || $args->{props}{$prop} =~ s/!$//);
590              
591             $args->{errors}{$prop}
592 0           = "'" . $args->{props}->{$prop} . "' is not a valid $prop";
593 0           return 0;
594             }
595 0           return 1;
596              
597             }
598              
599             =head2 recommended_values_for_prop 'prop'
600              
601             Given a record property, return an array of the values that should usually be
602             associated with this property.
603              
604             If a property doesn't have a specific range of values, undef is
605             returned.
606              
607             This is mainly intended for use in prop validation (see
608             L). Recommended values for a
609             prop are set by defining methods called C<_recommended_values_for_prop_$prop>
610             in application modules that inherit from L.
611              
612             =cut
613              
614             sub recommended_values_for_prop {
615 0     0 1   my $self = shift;
616 0           my $prop = shift;
617              
618 0 0         if (my $code = $self->can("_recommended_values_for_prop_".$prop)) {
619 0           $code->($self, @_);
620             } else {
621 0           return undef;
622             }
623            
624             }
625              
626             =head2 _default_summary_format
627              
628             A string of the default summary format for record types that do not
629             define their own summary format.
630              
631             A summary format should consist of format_string,field pairs, separated
632             by | characters.
633              
634             Fields that are not property names must start with the C<$> character and be
635             handled in the C routine.
636              
637             Example:
638              
639             C<'%s,$luid | %s,summary | %s,status'>
640              
641             =cut
642              
643 0     0     sub _default_summary_format { undef }
644              
645             =head2 _summary_format
646              
647             Tries to find the summary format for the record type. Returns
648             L<_default_summary_format> if nothing better can be found.
649              
650             =cut
651              
652             sub _summary_format {
653 0     0     my $self = shift;
654             return
655 0   0       $self->app_handle->config->get( key => $self->type.'.summary-format' )
656             || $self->app_handle->config->get( key => 'record.summary-format' )
657             || $self->_default_summary_format;
658             }
659              
660             =head2 _atomize_summary_format [$format]
661              
662             Splits a summary format into pieces (separated by arbitrary whitespace and
663             the | character). Returns the split list.
664              
665             If no summary format is supplied, this routine attempts to find one by
666             calling L<_summary_format>.
667              
668             =cut
669              
670             sub _atomize_summary_format {
671 0     0     my $self = shift;
672 0   0       my $format = shift || $self->_summary_format;
673              
674 0 0         return undef unless $format;
675 0           return split /\s*\|\s*/, $format;
676             }
677              
678             =head2 _parse_format_summary
679              
680             Parses the summary format for this record's type (or the default summary
681             format if no type-specific format exists).
682              
683             Returns a list of hashrefs to hashes which contain the following keys:
684             C, C, C, and C
685              
686             (These are the format string, the property to be formatted, the value
687             of that property, and the atom formatted according to C,
688             respectively.)
689              
690             If no format string is supplied in a given format atom, C<%s> is used.
691              
692             If a format atom C<$value>'s value does not start with a C<$> character, it is
693             swapped with the value of the prop C<$value> (or the string "(no value)".
694              
695             All values are filtered through the function C.
696              
697             =cut
698              
699             sub _parse_format_summary {
700 0     0     my $self = shift;
701              
702 0           my $props = $self->get_props;
703              
704 0           my @out;
705 0           for my $atom ($self->_atomize_summary_format) {
706 0           my %atom_data;
707 0           my ($format, $prop, $value);
708              
709 0 0         if ($atom =~ /,/) {
710 0           ($format, $prop) = split /,/, $atom;
711              
712 0           $value = $prop;
713              
714 0 0         unless ($value =~ /^\$/) {
715 0   0       $value = $props->{$value}
716             || "-"
717             }
718              
719             } else {
720 0           $format = '%s';
721 0           $prop = $value = $atom;
722             }
723              
724 0           my $atom_value = $self->atom_value($value);
725 0           push @out, {
726             format => $format,
727             prop => $prop,
728             value => $atom_value,
729             formatted => $self->format_atom( $format => $atom_value )
730              
731             };
732             }
733 0           return @out;
734             }
735              
736             =head2 format_summary
737              
738             Returns a formatted string that is the summary for the record. In an
739             array context, returns a list of
740              
741             =cut
742              
743             sub format_summary {
744 0     0 1   my $self = shift;
745              
746 0 0         my @out = $self->_summary_format ?
747             $self->_parse_format_summary
748             :
749             $self->_format_all_props_raw
750             ;
751 0 0         return @out if wantarray;
752 0           return join ' ', map { $_->{formatted} } @out;
  0            
753             }
754              
755             sub _format_all_props_raw {
756 0     0     my $self = shift;
757 0           my $props = $self->get_props;
758              
759 0           my @out;
760              
761 0           push @out,
762             {
763             prop => 'uuid',
764             value => $self->uuid,
765             format => '%s',
766             formatted => "'uuid': '" . $self->uuid . "'"
767             };
768 0           push @out, {
769             prop => 'luid',
770             value => $self->luid,
771             format => '%s',
772             formatted => "'luid': '"
773             . $self->luid . "'"
774              
775             };
776              
777 0           for my $prop ( keys %$props ) {
778             push @out,
779             {
780             prop => $prop,
781             value => $props->{$prop},
782             format => '%s',
783 0           formatted => "'$prop': '" . $props->{$prop} . "'"
784             };
785             }
786 0           return @out;
787             }
788              
789              
790             =head2 atom_value $value_in
791              
792             Takes an input value from a summary format atom and returns either its
793             output value or itself (because it is a property and its value should be
794             retrieved from the props attribute instead).
795              
796             For example, an input value of "$uuid" would return the record object's
797             C field.
798              
799             =cut
800              
801             sub atom_value {
802 0     0 1   my $self = shift;
803 0   0       my $value_in = shift || '';
804              
805 0 0         if ($value_in =~ /^\$[gu]uid/) {
    0          
806 0           return $self->uuid;
807             } elsif ($value_in eq '$luid') {
808 0           return $self->luid;
809             }
810              
811 0           return $value_in;
812             }
813              
814             =head2 format_atom $string => $value
815              
816             Takes a format string / value pair and returns a formatted string for printing.
817              
818             =cut
819              
820             sub format_atom {
821 0     0 1   my $self = shift;
822 0           my $string = shift;
823 0           my $value = shift;
824 0           return sprintf($string, $self->atom_value($value));
825             }
826              
827             =head2 find_or_create_luid
828              
829             Finds the luid for the records uuid, or creates a new one. Returns the luid.
830              
831             =cut
832              
833             sub find_or_create_luid {
834 0     0 1   my $self = shift;
835 0           my $luid = $self->handle->find_or_create_luid( uuid => $self->uuid );
836 0           $self->luid($luid);
837 0           return $luid;
838             }
839              
840             =head2 history_as_string
841              
842             Returns this record's changesets as a single string.
843              
844             =cut
845              
846             sub history_as_string {
847 0     0 1   my $self = shift;
848 0           my $out ='';
849 0           for my $changeset ($self->changesets) {
850             $out .= $changeset->as_string(change_filter => sub {
851 0     0     shift->record_uuid eq $self->uuid
852 0           });
853             }
854              
855 0           return $out;
856             }
857              
858             =head2 record_reference_methods
859              
860             Returns a list of method names that refer to other individual records
861              
862             =cut
863              
864             sub record_reference_methods {
865 0     0 1   my $self = shift;
866 0   0       my $class = blessed($self) || $self;
867 0 0         my %accessors = %{ $self->REFERENCES->{$class} || {} };
  0            
868              
869 0           return grep { $accessors{$_}{arity} eq 'record' }
  0            
870             keys %accessors;
871             }
872              
873             =head2 collection_reference_methods
874              
875             Returns a list of method names that refer to collections
876              
877             =cut
878              
879             sub collection_reference_methods {
880 0     0 1   my $self = shift;
881 0   0       my $class = blessed($self) || $self;
882 0 0         my %accessors = %{ $self->REFERENCES->{$class} || {} };
  0            
883              
884 0           return grep { $accessors{$_}{arity} eq 'collection' }
  0            
885             keys %accessors;
886             }
887              
888             __PACKAGE__->meta->make_immutable;
889 3     3   25 no Any::Moose;
  3         4  
  3         17  
890             1;