File Coverage

blib/lib/KiokuX/Model/Role/Annotations.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package KiokuX::Model::Role::Annotations;
2 1     1   38322 use MooseX::Role::Parameterized;
  0            
  0            
3              
4             use Carp;
5             use KiokuDB::Util qw(set);
6              
7             use namespace::clean;
8              
9             our $VERSION = "0.01";
10              
11             parameter namespace => (
12             isa => "Str",
13             is => "ro",
14             default => "annotations",
15             );
16              
17             parameter method_namespace => (
18             isa => "Str",
19             is => "ro",
20             lazy => 1,
21             default => sub { shift->namespace },
22             );
23              
24             parameter key_callback => (
25             isa => "Str|CodeRef",
26             is => "ro",
27             lazy => 1,
28             default => sub {
29             my $self = shift;
30              
31             my $name = $self->method_namespace;
32            
33             return sprintf "_${name}_set_id";
34             },
35             );
36              
37             parameter id_callback => (
38             isa => "Str|CodeRef",
39             is => "ro",
40             default => "object_to_id",
41             );
42              
43             role {
44             with qw(KiokuDB::Role::API);
45              
46             my $p = shift;
47              
48             my $name = $p->method_namespace;
49             my $ns = $p->namespace;
50             my $set_id = $p->key_callback;
51             my $object_to_id = $p->id_callback;
52              
53             requires $set_id unless ref $set_id or $set_id eq "_${name}_set_id";
54              
55             requires $object_to_id unless ref $object_to_id;
56              
57             my $annotation_set = sub {
58             my ( $self, $key ) = @_;
59              
60             $self->lookup( $self->$set_id($key) );
61             };
62              
63             method "has_${name}" => sub {
64             my ( $self, @args ) = @_;
65              
66             $self->exists( $self->$set_id(@args) );
67             };
68              
69             method "${name}_for" => sub {
70             my ( $self, $key ) = @_;
71              
72             if ( my $set = $self->$annotation_set($key) ) {
73             return $set->members;
74             } else {
75             return ();
76             }
77             };
78              
79             my $insert_into_set = sub {
80             my ( $self, $key, @annotations ) = @_;
81              
82             if ( my $set = $self->$annotation_set($key) ) {
83             $set->insert(@annotations);
84             $self->insert_nonroot(@annotations);
85             $self->update($set);
86             } else {
87             $self->insert( $self->$set_id($key) => set(@annotations) );
88             }
89             };
90              
91             method "add_${name}_for" => sub {
92             my ( $self, $key, @annotations ) = @_;
93              
94             $self->txn_do(sub {
95             $self->$insert_into_set( $key, @annotations );
96             });
97             };
98              
99             method "add_${name}" => sub {
100             my ( $self, @annotations ) = @_;
101              
102             $self->txn_do(sub {
103             foreach my $annotation ( @annotations ) {
104             $self->$insert_into_set( $annotation->subject, $annotation );
105             }
106             });
107             };
108              
109             my $remove_from_set = sub {
110             my ( $self, $key, @annotations ) = @_;
111              
112             if ( my $set = $self->$annotation_set($key) ) {
113             $set->remove(@annotations);
114              
115             if ( $set->size ) {
116             $self->update($set);
117             } else {
118             $self->delete($set);
119             }
120             }
121              
122             $self->delete(@annotations);
123             };
124              
125             method "remove_${name}_for" => sub {
126             my ( $self, $key, @annotations ) = @_;
127              
128             $self->txn_do(sub {
129             $self->$remove_from_set( $key, @annotations );
130             });
131             };
132              
133             method "remove_${name}" => sub {
134             my ( $self, @annotations ) = @_;
135              
136             $self->txn_do(sub {
137             foreach my $annotation ( @annotations ) {
138             $self->$remove_from_set( $annotation->subject, $annotation );
139             }
140             });
141             };
142              
143             method "_${name}_set_id" => sub {
144             my ( $self, $item ) = @_;
145              
146             my $id = ref($item) ? $self->$object_to_id($item) : $item;
147              
148             croak "Can't determine ID for $item" unless defined $id;
149              
150             return "${ns}:${id}";
151             };
152             };
153              
154             # ex: set sw=4 et:
155              
156             __PACKAGE__
157              
158             __END__
159              
160             =pod
161              
162             =head1 NAME
163              
164             KiokuX::Model::Role::Annotations - A role for adding annotations to objects in a KiokuDB database.
165              
166             =head1 SYNOPSIS
167              
168             package MyApp::Model;
169             use Moose;
170              
171             extends qw(KiokuX::Model);
172              
173             with qw(KiokuX::Model::Role::Annotations);
174              
175            
176              
177             # any object can be an annotation for another object
178             $model->add_annotations_for( $obj => $annotation );
179              
180             # no need to specify the annotated object if the annotation does
181             # KiokuX::Model::Role::Annotations::Annotation
182             $model->add_annotations($annotation_object);
183              
184              
185             # get annotations
186             my @annotations = $model->annoations_for($obj);
187              
188             =head1 DESCRIPTION
189              
190             This role provides a mechanism to annotate objects with other objects.
191              
192             =head1 METHODS
193              
194             =over 4
195              
196             =item add_annotations @annotations
197              
198             =item add_annotations_for $obj, @annotations
199              
200             Add annotations for an object.
201              
202             The first form requires the annotation objects to do the role
203             L<KiokuX::Model::Role::Annotations::Annotation>.
204              
205             The second form has no restrictions on the annotation objects, but requires the
206             key object to be specified explicitly.
207              
208             =item remove_annoations @annotations
209              
210             =item remove_annotations_for $obj, @annotations
211              
212             Remove the specified annotations.
213              
214             =item has_annotations $obj
215              
216             Returns true if the object has been annotated.
217              
218             =item annotations_for $obj
219              
220             Returns a list of all annotations for the object.
221              
222             =head1 PARAMETERIZED USAGE
223              
224             The role is actually parameterizable.
225              
226             =over 4
227              
228             =item namespace
229              
230             Defaults to C<annotations>. This string is prepended to the annotated object's
231             ID and used as the key for the annotation set for that object.
232              
233             =item method_namespace
234              
235             Dfeaults to the value of C<namespace>.
236              
237             Used to provide the names of all the methods (the string C<annotations> in the
238             above methods would be replaced by the value of this).
239              
240             =item id_callback
241              
242             Defaults to C<object_to_id> (see L<KiokuDB>).
243              
244             The function to map from an object to an ID string, can be a code reference or
245             a string for a method name to be invoked on the model object.
246              
247             =item key_callback
248              
249             The default implementation concatenates C<namespace>, a colon and
250             C<id_callback> to provide the key of the set.
251              
252             If the key object is actually a string, the string is used as is.
253              
254             Can be overridden with a method name to be invoked on the model, or a code
255             reference.
256              
257             =back