File Coverage

blib/lib/Mojolicious/Plugin/Tables/Model.pm
Criterion Covered Total %
statement 86 95 90.5
branch 19 32 59.3
condition 7 7 100.0
subroutine 13 13 100.0
pod 3 7 42.8
total 128 154 83.1


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Tables::Model;
2              
3 3     3   24 use strict;
  3         8  
  3         92  
4 3     3   15 use warnings;
  3         7  
  3         103  
5              
6 3     3   17 use base qw/DBIx::Class::Schema/;
  3         9  
  3         2064  
7 3     3   178280 use DBIx::Class::Schema::Loader::Dynamic;
  3         536708  
  3         3920  
8              
9             __PACKAGE__->mk_group_accessors(inherited => qw/log connect_info model/);
10              
11             sub setup {
12 3     3 0 9 my ($class, $conf) = @_;
13 3 50       16 if (my $connect_info = $conf->{connect_info}) {
14 3         65 $class->connect_info($connect_info)
15             } else {
16 0 0       0 die "Provide connect_info either as a config value or an override"
17             unless $class->connect_info
18             }
19              
20             # to return a schema object-ref here say 'connect' instead of 'connection'.
21 3         85 my $schema = $class->connection(@{$class->connect_info});
  3         63  
22              
23             DBIx::Class::Schema::Loader::Dynamic->new(
24             left_base_classes => $class->row_base,
25             rel_name_map => $class->rel_name_map,
26 27     27   777040 custom_column_info => sub { $class->custom_column_info(@_) },
27             naming => 'v8',
28             use_namespaces => 0,
29             schema => $schema,
30 3 50       269910 %{$conf->{loader_opts}||{}},
  3         48  
31             )->load;
32              
33 3         119510 $schema->model($schema->_model);
34              
35 3         68 return $schema;
36             }
37              
38 3     3 0 40 sub row_base { 'Mojolicious::Plugin::Tables::Model::Row' }
39              
40 48     48 1 219 sub glossary { +{ id => 'Identifier' } }
41              
42 27     27 1 177 sub input_attrs { +{ name => { size=>80 } } }
43              
44             sub make_label {
45 48     48 0 101 my $self = shift;
46 48         95 my $name = shift;
47 48         136 my @label = split '_', $name;
48 48         118 for (@label) {
49 48 50       115 $_ = $self->glossary->{$_}, next if $self->glossary->{$_};
50 48         160 $_ = ucfirst
51             }
52 48         229 join(' ', @label)
53             }
54              
55             sub custom_column_info {
56 27     27 0 72 my ($class, $table, $column, $column_info) = @_;
57 27         73 my $info = { label => $class->make_label($column) };
58 27         53 my $attrs1;
59 27         63 for ($column_info->{data_type}) {
60 27 100       216 $attrs1 =
    50          
    100          
61             /numeric|integer/ ? {type=>'number'} :
62             /timestamp/ ? {type=>'datetime-local'} :
63             /date|time/ ? {type=>$_} :
64             {};
65             }
66 27   100     74 my $attrs2 = $class->input_attrs->{$column} || {};
67 27 100 100     189 $info->{input_attrs} = {%$attrs1, %$attrs2} if keys(%$attrs1) || keys(%$attrs2);
68 27         102 $info
69             };
70              
71 3     3 1 23 sub rel_name_map { +{} }
72              
73             sub _model {
74 3     3   444 my $schema = shift;
75              
76 3         12 my @tablist = ();
77 3         10 my %bytable = ();
78             #my $log = $schema->log;
79             #$log->debug("$schema is building its model");
80 3         28 for my $source (sort $schema->sources) {
81 9         191 my $s = $schema->source($source);
82 9         432 my @has_a;
83             my %has_many;
84 9         49 for my $rel ($s->relationships) {
85 12         93 my $info = $s->relationship_info($rel);
86 12         175 my $ftable = $info->{class}->table;
87 12         524 my $attrs = $info->{attrs};
88 12         32 my $card = $attrs->{accessor};
89 12 100       53 if ($card eq 'single') {
    50          
    50          
90 6         15 my $fks = $attrs->{fk_columns};
91 6         27 my @fks = keys %$fks;
92 6 50       39 push @has_a, { fkey=>$fks[0], parent=>$rel, label=>$schema->make_label($rel), ptable=>$ftable }
93             if @fks == 1
94             } elsif ($card eq 'filter') {
95 0         0 my @ffkeys = keys %{$info->{cond}};
  0         0  
96 0 0       0 if (@ffkeys == 1) {
97 0         0 (my $cfkey = $ffkeys[0]) =~ s/^foreign\.//;
98 0         0 push @has_a, { fkey=>$cfkey, parent=>$rel, label=>$schema->make_label($rel), ptable=>$ftable }
99             } else {
100 0         0 warn __PACKAGE__." model: $source: $rel: multi-barrelled M-1 keys not supported\n"
101             }
102             } elsif ($card eq 'multi') {
103 6         17 my $fsource_name = $info->{source};
104 6         24 my $fsource = $schema->source($fsource_name);
105 6         462 my $fpkey = join(',', $fsource->primary_columns);
106 6         56 my @ffkeys = keys %{$info->{cond}};
  6         26  
107 6 50       29 if (@ffkeys == 1) {
108 6         31 (my $cfkey = $ffkeys[0]) =~ s/^foreign\.//;
109 6         96 $has_many{$rel} = {ctable=>$ftable, cpkey=>$fpkey, cfkey=>$cfkey, label=>$schema->make_label($rel)};
110             } else {
111 0         0 warn __PACKAGE__." model: $source: $rel: multi-barrelled 1-M keys not supported\n"
112             }
113             } else {
114 0         0 warn __PACKAGE__." model: $source: $rel: strange cardinality: $card\n";
115             }
116             }
117             my %bycolumn = map {
118 9         65 my %info = %{$s->column_info($_)};
  27         123  
  27         64  
119 27         366 delete $info{name};
120 27   100     177 /^_/ && delete $info{$_} for keys %info;
121 27         100 ( $_ => \%info )
122             } $s->columns;
123 9         38 for (@has_a) {
124 6         16 my $fkey = $_->{fkey};
125 6         15 my $parent = delete $_->{parent};
126 6 50       28 $bycolumn{$fkey}->{parent} = $parent if $bycolumn{$fkey};
127 6         17 $bycolumn{$parent} = $_; # gets {fkey=>, label=>, ptable=>,}
128             }
129 9         31 my $pkeys = [$s->primary_columns];
130 9         87 my $pknum = 0;
131 9         23 for (@$pkeys) {
132 9         27 $bycolumn{$_}{is_primary_key} = ++$pknum
133             }
134 9 100       31 my @columns = map { $_, $bycolumn{$_}{parent}? ($bycolumn{$_}{parent}): () }
  27         146  
135             $s->columns;
136 9         42 my $label = $schema->make_label($s->name);
137 9         55 my $tabinfo = {
138             source => $source,
139             columns => \@columns,
140             bycolumn => \%bycolumn,
141             has_many => \%has_many,
142             label => $label,
143             pkeys => $pkeys,
144             };
145 9         63 push @tablist, $s->name;
146 9         44 $bytable{$s->name} = $tabinfo;
147             }
148 3         115 return {schema=>$schema, tablist=>\@tablist, bytable=>\%bytable};
149             }
150              
151             1;
152             __END__