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   20 use strict;
  3         9  
  3         87  
4 3     3   15 use warnings;
  3         9  
  3         83  
5              
6 3     3   17 use base qw/DBIx::Class::Schema/;
  3         6  
  3         1948  
7 3     3   182395 use DBIx::Class::Schema::Loader::Dynamic;
  3         538257  
  3         3983  
8              
9             __PACKAGE__->mk_group_accessors(inherited => qw/log connect_info model/);
10              
11             sub setup {
12 3     3 0 13 my ($class, $conf) = @_;
13 3 50       15 if (my $connect_info = $conf->{connect_info}) {
14 3         64 $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         47 my $schema = $class->connection(@{$class->connect_info});
  3         57  
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   854483 custom_column_info => sub { $class->custom_column_info(@_) },
27             naming => 'v8',
28             use_namespaces => 0,
29             schema => $schema,
30 3 50       244405 %{$conf->{loader_opts}||{}},
  3         43  
31             )->load;
32              
33 3         129755 $schema->model($schema->_model);
34              
35 3         69 return $schema;
36             }
37              
38 3     3 0 33 sub row_base { 'Mojolicious::Plugin::Tables::Model::Row' }
39              
40 48     48 1 211 sub glossary { +{ id => 'Identifier' } }
41              
42 27     27 1 181 sub input_attrs { +{ name => { size=>80 } } }
43              
44             sub make_label {
45 48     48 0 101 my $self = shift;
46 48         93 my $name = shift;
47 48         194 my @label = split '_', $name;
48 48         121 for (@label) {
49 48 50       138 $_ = $self->glossary->{$_}, next if $self->glossary->{$_};
50 48         192 $_ = ucfirst
51             }
52 48         243 join(' ', @label)
53             }
54              
55             sub custom_column_info {
56 27     27 0 122 my ($class, $table, $column, $column_info) = @_;
57 27         91 my $info = { label => $class->make_label($column) };
58 27         57 my $attrs1;
59 27         72 for ($column_info->{data_type}) {
60 27 100       252 $attrs1 =
    50          
    100          
61             /numeric|integer/ ? {type=>'number'} :
62             /timestamp/ ? {type=>'datetime-local'} :
63             /date|time/ ? {type=>$_} :
64             {};
65             }
66 27   100     86 my $attrs2 = $class->input_attrs->{$column} || {};
67 27 100 100     209 $info->{input_attrs} = {%$attrs1, %$attrs2} if keys(%$attrs1) || keys(%$attrs2);
68 27         112 $info
69             };
70              
71 3     3 1 19 sub rel_name_map { +{} }
72              
73             sub _model {
74 3     3   608 my $schema = shift;
75              
76 3         13 my @tablist = ();
77 3         12 my %bytable = ();
78             #my $log = $schema->log;
79             #$log->debug("$schema is building its model");
80 3         30 for my $source (sort $schema->sources) {
81 9         184 my $s = $schema->source($source);
82 9         461 my @has_a;
83             my %has_many;
84 9         50 for my $rel ($s->relationships) {
85 12         102 my $info = $s->relationship_info($rel);
86 12         216 my $ftable = $info->{class}->table;
87 12         582 my $attrs = $info->{attrs};
88 12         37 my $card = $attrs->{accessor};
89 12 100       56 if ($card eq 'single') {
    50          
    50          
90 6         18 my $fks = $attrs->{fk_columns};
91 6         25 my @fks = keys %$fks;
92 6 50       36 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         502 my $fpkey = join(',', $fsource->primary_columns);
106 6         53 my @ffkeys = keys %{$info->{cond}};
  6         85  
107 6 50       32 if (@ffkeys == 1) {
108 6         36 (my $cfkey = $ffkeys[0]) =~ s/^foreign\.//;
109 6         94 $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         63 my %info = %{$s->column_info($_)};
  27         124  
  27         68  
119 27         411 delete $info{name};
120 27   100     188 /^_/ && delete $info{$_} for keys %info;
121 27         98 ( $_ => \%info )
122             } $s->columns;
123 9         32 for (@has_a) {
124 6         16 my $fkey = $_->{fkey};
125 6         13 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         33 my $pkeys = [$s->primary_columns];
130 9         100 my $pknum = 0;
131 9         22 for (@$pkeys) {
132 9         31 $bycolumn{$_}{is_primary_key} = ++$pknum
133             }
134 9 100       30 my @columns = map { $_, $bycolumn{$_}{parent}? ($bycolumn{$_}{parent}): () }
  27         148  
135             $s->columns;
136 9         44 my $label = $schema->make_label($s->name);
137 9         52 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         35 push @tablist, $s->name;
146 9         37 $bytable{$s->name} = $tabinfo;
147             }
148 3         100 return {schema=>$schema, tablist=>\@tablist, bytable=>\%bytable};
149             }
150              
151             1;
152             __END__