File Coverage

blib/lib/Math/DifferenceSet/Planar/Data.pm
Criterion Covered Total %
statement 130 130 100.0
branch 43 50 86.0
condition 12 15 80.0
subroutine 41 41 100.0
pod 20 20 100.0
total 246 256 96.0


line stmt bran cond sub pod time code
1             package Math::DifferenceSet::Planar::Data;
2              
3 7     7   71404 use strict;
  7         28  
  7         199  
4 7     7   36 use warnings;
  7         14  
  7         195  
5 7     7   84 use Carp qw(croak);
  7         29  
  7         346  
6 7     7   58 use File::Spec;
  7         15  
  7         211  
7 7     7   2891 use File::Share qw(dist_dir);
  7         226945  
  7         459  
8 7     7   4037 use DBD::SQLite::Constants qw(SQLITE_OPEN_READONLY);
  7         229183  
  7         1018  
9 7     7   3334 use Math::DifferenceSet::Planar::Schema;
  7         36  
  7         340  
10              
11             # Math::DifferenceSet::Planar::Data=ARRAY(...)
12              
13             # .......... index .......... # .......... value ..........
14 7     7   53 use constant _F_DATA => 0; # difference set result set object
  7         19  
  7         490  
15 7     7   47 use constant _F_SPACES => 1; # PDS space result set object or undef
  7         48  
  7         395  
16 7     7   64 use constant _F_VERSION => 2; # PDS space result set object or undef
  7         16  
  7         424  
17 7     7   90 use constant _F_PATH => 3; # database path name
  7         24  
  7         430  
18 7     7   50 use constant _NFIELDS => 4;
  7         15  
  7         805  
19              
20             our $VERSION = '1.000';
21             our @CARP_NOT = qw(Math::DifferenceSet::Planar);
22              
23             our $DATABASE_DIR = dist_dir('Math-DifferenceSet-Planar');
24              
25 7     7   84 use constant _KNOWN => { '<>' => 0 };
  7         39  
  7         12874  
26              
27             # ----- private subroutines -----
28              
29             sub _iterate {
30 24     24   68 my ($domain, $query, $min, $max, @columns) = @_;
31 24 100       79 my @sel = $query? @{$query}: ();
  6         15  
32 24         76 my @osel = ();
33 24         43 my $dir = 'ASC';
34 24 100 100     143 if (defined($min) && defined($max) && $min > $max) {
      100        
35 4         22 ($min, $max, $dir) = ($max, $min, 'DESC');
36             }
37 24 100       69 push @osel, '>=' => $min if defined $min;
38 24 100       66 push @osel, '<=' => $max if defined $max;
39 24 100       91 push @sel, order_ => { @osel } if @osel;
40 24 100       173 my $results = $domain->search(
    100          
41             @sel? { @sel }: undef,
42             {
43             @columns? ( columns => \@columns ): (),
44             order_by => "order_ $dir",
45             }
46             );
47 24     104   7569 return sub { $results->next };
  104         29132  
48             }
49              
50             # ----- private accessor methods -----
51              
52 143     143   794 sub _data { $_[0]->[_F_DATA] }
53 32     32   82 sub _spaces { $_[0]->[_F_SPACES] }
54 2     2   5 sub _version { $_[0]->[_F_VERSION] }
55 1     1   6 sub _path { $_[0]->[_F_PATH] }
56              
57             sub _get_version_of {
58 2     2   8 my ($this, $table_name) = @_;
59 2         7 my $version = $this->_version;
60 2 50       12 return (0, 0) if !defined $version;
61 2         11 my $rec = $version->search({ table_name => $table_name })->single;
62 2 50       4254 return (0, 0) if !defined $rec;
63 2         100 return ($rec->major, $rec->minor);
64             }
65              
66             # ----- class methods -----
67              
68             sub list_databases {
69 8 50   8 1 430 opendir my $dh, $DATABASE_DIR or return ();
70             my @files =
71             map {
72 12 100       67 my $is_standard = /^pds[_\W]/i? 1: 0;
73 12         347 my $path = File::Spec->rel2abs($_, $DATABASE_DIR);
74 12 50       269 (-f $path)? [$_, $is_standard, -s _]: ()
75             }
76 8         308 grep { /\.db\z/i } readdir $dh;
  40         173  
77 8         151 closedir $dh;
78             return
79 12         92 map { $_->[0] }
80             sort {
81 8 50 66     57 $b->[1] <=> $a->[1] || $b->[2] <=> $a->[2] ||
  6         35  
82             $a->[0] cmp $b->[0]
83             }
84             @files;
85             }
86              
87             sub new {
88 14     14 1 714 my $class = shift;
89 14 100       83 my ($filename) = @_? @_: $class->list_databases
    50          
90             or croak "bad database: empty share directory: $DATABASE_DIR";
91 14         313 my $path = File::Spec->rel2abs($filename, $DATABASE_DIR);
92 14 100       825 -e $path or croak "bad database: file does not exist: $path";
93 12         297 my $schema =
94             Math::DifferenceSet::Planar::Schema->connect(
95             "dbi:SQLite:$path", q[], q[],
96             { sqlite_open_flags => SQLITE_OPEN_READONLY },
97             );
98 12         498790 my $data = $schema->resultset('DifferenceSet');
99 12         7081 my $count = eval { $data->search->count };
  12         60  
100 12 100       323530 croak "bad database: query failed: $@" if !defined $count;
101 11         303 my $spaces = $schema->resultset('DifferenceSetSpace');
102 11 100       4136 undef $spaces if !eval { $spaces->search->count };
  11         55  
103 11         44632 my $version = $schema->resultset('DatabaseVersion');
104 11 50       3931 undef $version if !eval { $version->search->count };
  11         56  
105 11         36780 return bless [$data, $spaces, $version, $path], $class;
106             }
107              
108             # ----- object methods -----
109              
110             sub get {
111 73     73 1 5081 my ($this, $order, @columns) = @_;
112 73 100       187 return $this->_data->search(
113             { order_ => $order },
114             @columns ? { columns => \@columns } : ()
115             )->single;
116             }
117              
118             sub get_space {
119 11     11 1 933 my ($this, $order) = @_;
120 11         38 my $spaces = $this->_spaces;
121 11 100       43 return undef if !defined $spaces;
122 10         49 return $spaces->search({ order_ => $order })->single;
123             }
124              
125 1     1 1 3133 sub get_version { $_[0]->_get_version_of('difference_set') }
126 1     1 1 776 sub get_space_version { $_[0]->_get_version_of('difference_set_space') }
127              
128             sub iterate {
129 6     6 1 38 my ($this, $min, $max) = @_;
130 6         18 return _iterate($this->_data, undef, $min, $max);
131             }
132              
133             sub iterate_properties {
134 7     7 1 6771 my ($this, $min, $max, @columns) = @_;
135 7         19 foreach my $col (@columns) {
136 3 100       12 $col = 'order_' if $col eq 'order';
137             }
138             @columns =
139 7 100       137 grep {!/delta/}
  30         792  
140             Math::DifferenceSet::Planar::Schema::Result::DifferenceSet->columns
141             if !@columns;
142 7         24 return _iterate($this->_data, undef, $min, $max, @columns);
143             }
144              
145             sub iterate_refs {
146 6     6 1 18 my ($this, $type, $min, $max) = @_;
147 6         20 return _iterate($this->_data, [$type => { '<>' => 0 }], $min, $max);
148             }
149              
150             sub iterate_spaces {
151 6     6 1 2119 my ($this, $min, $max) = @_;
152 6         18 my $spaces = $this->_spaces;
153 6 100   1   24 return sub {} if !defined $spaces;
154 5         17 return _iterate($spaces, undef, $min, $max);
155             }
156              
157 4     4 1 2942 sub min_order { $_[0]->_data->get_column('order_')->min }
158 22     22 1 10238 sub max_order { $_[0]->_data->get_column('order_')->max }
159 7     7 1 9468 sub count { $_[0]->_data->search->count }
160 1     1 1 3845 sub path { $_[0]->_path }
161              
162             sub sp_min_order {
163 3     3 1 3996 my ($this) = @_;
164 3         12 my $spaces = $this->_spaces;
165 3   66     33 return $spaces && $spaces->get_column('order_')->min;
166             }
167              
168             sub sp_max_order {
169 9     9 1 3373 my ($this) = @_;
170 9         24 my $spaces = $this->_spaces;
171 9   66     69 return $spaces && $spaces->get_column('order_')->max;
172             }
173              
174             sub sp_count {
175 3     3 1 4519 my ($this) = @_;
176 3         12 my $spaces = $this->_spaces;
177 3 100       17 return 0 if !defined $spaces;
178 2         9 return $spaces->search->count;
179             }
180              
181             sub ref_min_order {
182 6     6 1 16 my ($this, $type) = @_;
183 6         17 return $this->_data->search({$type => _KNOWN})->get_column('order_')->min;
184             }
185              
186             sub ref_max_order {
187 6     6 1 15 my ($this, $type) = @_;
188 6         18 return $this->_data->search({$type => _KNOWN})->get_column('order_')->max;
189             }
190              
191             sub ref_count {
192 6     6 1 17 my ($this, $type) = @_;
193 6         18 return $this->_data->search({$type => _KNOWN})->count;
194             }
195              
196             1;
197              
198             __END__