File Coverage

lib/REST/Neo4p/Schema.pm
Criterion Covered Total %
statement 15 107 14.0
branch 0 60 0.0
condition 0 42 0.0
subroutine 6 17 35.2
pod 6 9 66.6
total 27 235 11.4


line stmt bran cond sub pod time code
1             #$Id$
2 1     1   793 use v5.10;
  1         4  
3             package REST::Neo4p::Schema;
4 1     1   5 use REST::Neo4p::Exceptions;
  1         2  
  1         21  
5 1     1   4 use Carp qw/carp/;
  1         1  
  1         53  
6 1     1   15 use strict;
  1         2  
  1         23  
7 1     1   4 use warnings;
  1         2  
  1         58  
8              
9             BEGIN {
10 1     1   1358 $REST::Neo4p::Schema::VERSION = '0.4001';
11             }
12              
13             #require 'REST::Neo4p';
14              
15             sub new {
16 0 0   0 0   REST::Neo4p::CommException->throw("Not connected\n") unless
17             REST::Neo4p->connected;
18 0 0         unless (REST::Neo4p->_check_version(2,0,1)) {
19 0           REST::Neo4p::VersionMismatchException->throw("REST endpoint indexes and constraints are buggy in Neo4j server version < 2.0.1\n");
20             }
21 0           my $class = shift;
22 0           my $self = {
23             _handle => REST::Neo4p->handle,
24             _agent => REST::Neo4p->agent
25             };
26 0           bless $self, $class;
27             }
28              
29 0     0     sub _handle { shift->{_handle} }
30 0     0     sub _agent { shift->{_agent} }
31              
32             sub create_index {
33 0     0 1   my $self = shift;
34 0           my ($label, @props) = @_;
35 0 0 0       REST::Neo4p::LocalException->throw("Arg 1 must be a label and arg 2..n a property name\n") unless (defined $label && @props);
36 0           foreach (@props) {
37 0           my $content = { property_keys => [$_] };
38 0           eval {
39 0           $self->_agent->post_data([qw/schema index/,$label], $content);
40             };
41 0 0         if (my $e = REST::Neo4p::ConflictException->caught) {
    0          
    0          
42 0           1; # ignore, already present
43             }
44             elsif ( $e = REST::Neo4p::IndexExistsException->caught ) {
45 0           1;
46             }
47             elsif ($e = Exception::Class->caught()) {
48 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
49             }
50             }
51 0           return 1;
52             }
53              
54             # get_indexes returns false if label not found
55             sub get_indexes {
56 0     0 1   my $self = shift;
57 0           my ($label) = @_;
58 0 0         REST::Neo4p::LocalException->throw("Arg 1 must be a label\n") unless defined $label;
59 0           my $decoded_resp;
60 0           eval {
61 0           $decoded_resp = $self->_agent->get_data(qw/schema index/, $label);
62             };
63 0 0         if (my $e = REST::Neo4p::NotFoundException->caught) {
    0          
64 0           return;
65             }
66             elsif ($e = Exception::Class->caught()) {
67 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
68             }
69 0           my @ret;
70             # kludge for Neo4j::Driver
71 0   0       foreach (@{$self->_agent->decoded_content // $decoded_resp}) {
  0            
72 0           push @ret, $_->{property_keys}[0];
73             }
74 0           return @ret;
75             }
76              
77             sub drop_index {
78 0     0 1   my $self = shift;
79 0           my ($label,@names) = @_;
80 0 0 0       REST::Neo4p::LocalException->throw("Arg 1 must be a label and arg 2 a property name\n") unless (defined $label && @names);
81 0           foreach (@names) {
82 0           eval {
83 0           $self->_agent->delete_data(qw/schema index/, $label, $_);
84             };
85 0 0         if (my $e = REST::Neo4p::NotFoundException->caught) {
    0          
86 0           1; #ignore if not found
87             }
88             elsif ($e = Exception::Class->caught()) {
89 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
90             }
91             }
92 0           return 1;
93             }
94              
95             sub create_unique_constraint {
96 0     0 1   my $self = shift;
97 0           my ($label, @props) = @_;
98 0           return $self->create_constraint($label, \@props, 'uniqueness');
99             }
100              
101             sub create_constraint {
102 0     0 0   my $self = shift;
103 0           my ($label, $property, $c_type) = @_;
104 0   0       $c_type ||= 'uniqueness';
105 0 0 0       REST::Neo4p::LocalException->throw("Arg 1 must be a label and arg 2 a property name or arrayref\n") unless (defined $label && defined $property);
106 0 0         my @props = ref $property ? @$property : ($property);
107 0           foreach (@props) {
108 0           my $content = { property_keys => [$_] };
109 0           eval {
110 0           $self->_agent->post_data([qw/schema constraint/,$label,$c_type], $content);
111             };
112 0 0         if (my $e = REST::Neo4p::ConflictException->caught) {
    0          
113 0 0         if ($e->neo4j_message =~ qr/constraint cannot be created/) {
114 0           carp $e->neo4j_message;
115             }
116 0           1; # ignore, already present
117             }
118             elsif ($e = Exception::Class->caught()) {
119 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
120             }
121             }
122 0           return 1;
123             }
124              
125             sub get_constraints {
126 0     0 1   my $self = shift;
127 0           my ($label, $c_type) = @_;
128 0   0       $c_type ||= 'uniqueness';
129 0 0         REST::Neo4p::LocalException->throw("Arg 1 must be a label\n") unless defined $label;
130 0           my $decoded_resp;
131 0           eval {
132 0           $decoded_resp = $self->_agent->get_data(qw/schema constraint/, $label, $c_type);
133             };
134 0 0         if (my $e = REST::Neo4p::NotFoundException->caught) {
    0          
135 0           return;
136             }
137             elsif ($e = Exception::Class->caught()) {
138 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
139             }
140 0           my @ret;
141             # kludge for Neo4j::Driver
142 0   0       foreach (@{$self->_agent->decoded_content // $decoded_resp}) {
  0            
143 0           push @ret, $_->{property_keys}[0];
144             }
145 0           return @ret;
146             }
147              
148             sub drop_unique_constraint {
149 0     0 1   my $self = shift;
150 0           my ($label, @props) = @_;
151 0           return $self->drop_constraint($label, \@props, 'uniqueness');
152             }
153              
154             sub drop_constraint {
155 0     0 0   my $self = shift;
156 0           my ($label, $property, $c_type) = @_;
157 0   0       $c_type ||= 'uniqueness';
158 0 0 0       REST::Neo4p::LocalException->throw("Arg 1 must be a label and arg 2 a property name or arrayref\n") unless (defined $label && defined $property);
159 0 0         my @props = ref $property ? @$property : ($property);
160 0           foreach (@props) {
161 0           eval {
162 0           $self->_agent->delete_data(qw/schema constraint/,$label,$c_type,$_);
163             };
164 0 0         if (my $e = REST::Neo4p::NotFoundException->caught) {
    0          
165 0           1; # ignore, not initially present
166             }
167             elsif ($e = Exception::Class->caught()) {
168 0 0 0       (ref $e && $e->can("rethrow")) ? $e->rethrow : die $e;
169             }
170             }
171 0           return 1;
172             }
173              
174             =head1 NAME
175              
176             REST::Neo4p::Schema - Label-based indexes and constraints
177              
178             =head1 SYNOPSIS
179            
180             REST::Neo4p->connect($server);
181             $schema = REST::Neo4p::Schema->new;
182             $schema->create_index('Person','name');
183            
184              
185             =head1 DESCRIPTION
186              
187             L v2.0+ provides a way to schematize the graph
188             on the basis of node labels, associated indexes, and property
189             uniqueness constraints. C allows access to this
190             system via the Neo4j REST API. Use a C object to create, list,
191             and drop indexes and constraints.
192              
193             =head1 METHODS
194              
195             =over
196              
197             =item create_index()
198              
199             $schema->create_index('Label', 'property');
200             $schema->create_index('Label', @properties);
201              
202             The second example is convenience for creating multiple single indexes
203             on each of a list of properties. It does not create a compound index
204             on the set of properties. Returns TRUE.
205              
206             =item get_indexes()
207              
208             @properties = $schema->get_indexes('Label');
209              
210             Get a list properties on which an index exists for a given label.
211              
212             =item drop_index()
213              
214             $schema->drop_index('Label','property');
215             $schema->drop_index('Label', @properties);
216              
217             Remove indexes on given property or properties for a given label.
218              
219             =item create_unique_constraint()
220              
221             $schema->create_unique_constraint('Label', 'property');
222             $schema->create_unique_constraint('Label', @properties);
223              
224             Create uniqueness constraints on a given property or properties for a
225             given label.
226              
227             I: For some inexplicable reason, this one schema feature went behind
228             the paywall in Neo4j version 4.0. Unless you are using the Enterprise
229             Edition, this method will throw the dreaded
230             L.
231              
232             =item get_constraints()
233              
234             @properties = $schema->get_constraints('Label');
235              
236             Get a list of properties for which (uniqueness) constraints exist for
237             a given label.
238              
239             =item drop_unique_constraint()
240              
241             $schema->drop_unique_constraint('Label', 'property');
242             $schema->drop_unique_constraint('Label', @properties);
243              
244             Remove uniqueness constraints on given property or properties for a
245             given label.
246              
247             =back
248              
249             =head1 SEE ALSO
250              
251             L, L, L
252              
253             =head1 AUTHOR
254              
255             Mark A. Jensen
256             CPAN ID: MAJENSEN
257             majensen -at- cpan -dot- org
258              
259             =head1 LICENSE
260              
261             Copyright (c) 2012-2021 Mark A. Jensen. This program is free software; you
262             can redistribute it and/or modify it under the same terms as Perl
263             itself.
264              
265             =cut
266              
267             1;