/
Objects.pm
160 lines (121 loc) · 4.34 KB
/
Objects.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package Elastic::Model::TypeMap::Objects;
use Elastic::Model::TypeMap::Base qw(:all);
use Scalar::Util qw(reftype);
use Moose::Util qw(does_role);
use namespace::autoclean;
#===================================
has_type 'Moose::Meta::TypeConstraint::Class',
#===================================
deflate_via { _deflate_class(@_) },
inflate_via { _inflate_class(@_) },
map_via { _map_class(@_) };
#===================================
has_type 'Moose::Meta::TypeConstraint::Role',
#===================================
deflate_via {undef}, inflate_via {undef};
#===================================
has_type 'Object', ### TODO: Completely broken, needs rewriting
#===================================
deflate_via { ## TODO: Object deflator/inflator
sub { ## Moose class?
my $obj = shift;
my $ref = ref $obj;
die "$ref does not provide a deflate() method"
unless $obj->can('deflate');
my $deflated = $obj->deflate();
die "${ref}->deflate() should return a HASH ref"
unless reftype $deflated eq 'HASH';
$deflated->{__CLASS__} ||= ref $obj;
return $deflated;
}
},
inflate_via {
sub {
my $hash = shift;
my $class = delete $hash->{__CLASS__}
or die "Object missing __CLASS__ key";
$class->inflate($hash); ## TODO: bless?
}
},
map_via {
( type => 'object',
dynamic => 1,
properties => { __CLASS__ => { type => 'string', index => 'no' } }
);
};
#===================================
sub _deflate_class {
#===================================
my ( $tc, $attr, $map ) = @_;
my $class = $tc->name;
if ( my $handler = $map->deflators->{$class} ) {
return $handler->(@_);
}
die "Class $class is not a Moose class and no deflator is defined."
unless $class->isa('Moose::Object');
my $attrs = _class_attrs( $map, $class, $attr );
# TODO: make sure ESDocs have UID, and make them a reference
return $map->class_deflator( $class, $attrs );
}
#===================================
sub _inflate_class {
#===================================
my ( $tc, $attr, $map ) = @_;
my $class = $tc->name;
my $custom = $map->inflators->{$class};
die "Class $class is not a Moose class and no inflator is defined."
unless $custom || $class->isa('Moose::Object');
my $attr_inflator;
return sub {
my ( $hash, $model ) = @_;
if ( $hash->{uid} && $model->knows_class($class) ) {
my $uid = Elastic::Model::UID->new( %{ $hash->{uid} },
from_store => 1 );
return $model->get_doc($uid);
}
return $custom->(@_) if $custom;
$attr_inflator ||= $map->class_inflator($class);
my $obj = $class->meta->get_meta_instance->create_instance;
$attr_inflator->( $obj, $hash, $model );
};
# TODO: decide what to do with non-ES classes
# TODO: inflate objects as references
}
#===================================
sub _map_class {
#===================================
my ( $tc, $attr, $map ) = @_;
my $class = $tc->name;
if ( my $handler = $map->mappers->{$class} ) {
return $handler->(@_);
}
die "Class $class is not a Moose class and no mapper is defined."
unless $class->isa('Moose::Object');
return ( type => 'object', enabled => 0 )
if $attr->has_enabled && !$attr->enabled;
my $attrs = _class_attrs( $map, $class, $attr );
return $map->class_mapping( $class, $attrs );
}
#===================================
sub _class_attrs {
#===================================
my ( $map, $class, $attr ) = @_;
$class = $map->model->class_for($class) || $class;
my $meta = $class->meta;
return { map { $_->name => $_ } $meta->get_all_attributes }
unless does_role( $meta, 'Elastic::Model::Meta::Class::Doc' );
my %attrs;
my $inc = $attr->include_attrs;
my $exc = $attr->exclude_attrs;
my @inc_attr = $inc
? map {
$meta->find_attribute_by_name($_)
or die "Unknown attribute ($_) in class $class"
} @$inc
: $meta->get_all_attributes;
%attrs = map { $_->name => $_ } grep { !$_->exclude } @inc_attr;
delete @attrs{@$exc} if $exc;
$attrs{uid} = $meta->find_attribute_by_name('uid');
return \%attrs;
}
1;