File Coverage

blib/lib/Mojolicious/Plugin/ORM/DBIx.pm
Criterion Covered Total %
statement 67 85 78.8
branch 5 14 35.7
condition 11 28 39.2
subroutine 13 14 92.8
pod 1 1 100.0
total 97 142 68.3


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::ORM::DBIx 0.02;
2 2     2   1333576 use v5.26;
  2         12  
3 2     2   12 use warnings;
  2         4  
  2         181  
4              
5             # ABSTRACT: Easily load and access DBIx::Class functionality in Mojolicious apps
6              
7             =encoding UTF-8
8            
9             =head1 NAME
10            
11             Mojolicious::Plugin::ORM::DBix - Easily load and access DBIx::Class functionality in Mojolicious apps
12            
13             =head1 SYNOPSIS
14              
15             # Register plugin
16             $self->plugin('ORM::DBIx' => {
17             dsn => $conf->{dsn},
18             username => $conf->{user},
19             password => $conf->{pass},
20             });
21              
22             ...
23              
24             # access in controller
25             sub get_user($self) {
26             my $user = $self->model("User")->find($self->req->param('id'));
27             $self->render(json => {user => $user->username});
28             }
29              
30             ..
31              
32             # use from command-line during development, following schema migration
33            
34             tyrrminal@devserver:/app$ script/myapp schema-load --noquiet
35             Dumping manual schema for Myapp::Model to directory /app/lib ...
36             Schema dump completed.
37              
38             =head1 DESCRIPTION
39              
40             Mojolicious::Plugin::ORM::DBIx streamlines the process of getting DBIC classes
41             generated and accessible from within a Mojolicious application.
42              
43             =head1 METHODS
44              
45             L inherits all methods from L
46             and implements the following new ones
47              
48             =cut
49              
50 2     2   1931 use Mojo::Base 'Mojolicious::Plugin';
  2         15237  
  2         13  
51              
52 2     2   3426 use DBIx::Class::Schema::Loader qw(make_schema_at);
  2         195452  
  2         14  
53 2     2   2651 use Mojo::Util qw(class_to_path);
  2         241082  
  2         279  
54 2     2   1359 use Module::Load::Conditional qw(check_install);
  2         44219  
  2         170  
55 2     2   1425 use Readonly;
  2         9148  
  2         145  
56 2     2   1176 use Syntax::Keyword::Try;
  2         13323  
  2         14  
57 2     2   226 use version;
  2         4  
  2         16  
58              
59 2     2   1415 use experimental qw(signatures);
  2         4573  
  2         13  
60              
61             Readonly::Scalar my $DEFAULT_DSN => 'dbi:SQLite:dbname=:memory:';
62             Readonly::Array my @DEFAULT_DBIX_COMPONENTS => qw(Relationship::Predicate InflateColumn::DateTime);
63              
64             =pod
65              
66             =head2 register( $args )
67              
68             Register plugin in L application. The following keys are supported
69             in C<$args>
70              
71             =head4 dsn
72              
73             The L for connecting
74             to the database. Defaults to C if omitted.
75              
76             =head4 namespace
77              
78             The perl class name of the root schema object for the application. Defaults to
79             C<$Moniker::Model> if omitted, where C<$Moniker> is the mojolicious moniker with the
80             first letter capitalized. This class does not need to be manually created, as
81             L can create it along with the rest of the schema.
82              
83             =head4 username
84              
85             The database connection username
86              
87             =head4 password
88              
89             The database connection password
90              
91             =head4 connect_params
92              
93             An optional HashRef of additional connection parameters to be passed to DBI at
94             connection time.
95              
96             I
97              
98             =head4 lib
99              
100             The directory where the schema loader files will be written to.
101             Default C<$MOJO_HOME/lib>
102              
103             =head4 codegen_filters
104              
105             An optional ordered ArrayRef of functions for filtering/modifying the code
106             generated by the schema loader. See
107             L for details.
108              
109             =head4 overwrite
110              
111             A proxy value for L.
112             B defaults to true
113              
114             =head4 feature_bundle
115              
116             When generating code, add a C line near the end of the file, such
117             that it applies to manual additions to the Result class files (but not to the
118             generated code itself). Defaults to the perl version being used to generate the
119             code. Any value that is not a valid perl
120             L will cause this option to be disabled
121             with a warning written to the mojolicious log. Pass undef to disable this option
122             without a warning.
123              
124             See L for
125             more information on valid values.
126              
127             If enabled, this line is added to the code before running any custom
128             L
129              
130             =head4 tidy_format_skipping
131              
132             When using L you may wind up with formatting disagreements between
133             the generated code and perltidy's ruleset. This option allows you to add lines
134             around the generated code to disable perltidy formatting, while leaving it
135             enabled for any custom code added to the end of the Result class files.
136              
137             Takes an ArrayRef containing two strings: C<[$disable_formatting, $enable_formatting]>.
138             Default is C<['#EEE','#EEE']>
139              
140             See L.
141              
142             Pass undef to disable this behavior.
143              
144             If enabled, these lines are added after running any custom L
145              
146             =head4 dbix_components
147              
148             An optional ArrayRef of DBIx components to load into generated classes. Defaults
149             to C<[>LC<,>LC<]>
150              
151             The defaults will be prepended to the contents of the passed ArrayRef; to
152             circumvent this behavior, pass C as the first element of the array.
153              
154             =head4 loader_options
155              
156             An optional HashRef of additional parameters to pass to
157             L. See
158             L for possible values and their meanings.
159              
160             =cut
161              
162 1     1 1 78 sub register($self, $app, $conf) {
  1         1  
  1         2  
  1         3  
  1         2  
163 1         13 push($app->commands->namespaces->@*, 'Mojolicious::Plugin::ORM::DBIx::Command');
164 1   50     103 my $conf_dbix_components = $conf->{dbix_components} // [];
165              
166 1         3 my @credentials = grep {defined} ($conf->{username}, $conf->{password});
  2         4  
167 1   33     30 my $model_directory = $conf->{lib} // $app->home->child('lib')->to_string;
168 1   33     96 my $dsn = $conf->{dsn} // $DEFAULT_DSN;
169 1   33     7 my $namespace = $conf->{namespace} // join(q{::}, ucfirst($app->moniker), 'Model');
170 1   50     10 my $connect_params = $conf->{connect_params} // {};
171 1   50     3 my $codegen_filters = $conf->{codegen_filters} // [];
172 1   50     3 my $overwrite = $conf->{overwrite} // 1;
173 1   50     4 my $loader_options = $conf->{loader_options} // {};
174 1 50 33     32 my $feature_bundle = $conf->{feature_bundle} // (exists($conf->{feature_bundle}) ? undef : "$^V");
175 1 50 33     5 my $tidy_fs = $conf->{tidy_format_skipping} // (exists($conf->{tidy_format_skipping}) ? undef : ['#<<<', '#>>>']);
176 1         30 my $dbix_components = [@DEFAULT_DBIX_COMPONENTS, $conf_dbix_components->@*];
177 1 50 33     20 splice($dbix_components->@*, 0, scalar(@DEFAULT_DBIX_COMPONENTS))
178             if (scalar($conf_dbix_components->@*) && !defined($conf_dbix_components->[0]));
179              
180             try {
181             version->declare($feature_bundle); #ensure feature_bundle is a properly-formed version number/string
182 1         3 } catch ($e) {
183             $app->log->warn("ORM::DBIx ignoring feature_bundle due to invalid version format: $feature_bundle");
184             $feature_bundle = undef;
185             }
186              
187 1         3 my $schema;
188 1 50       4 if (check_install(module => $namespace)) {
189 1         1044 require(class_to_path($namespace));
190 1         196037 $schema = $namespace->connect($dsn, @credentials, $connect_params);
191             } else {
192 0         0 $app->log->fatal(
193             "ORM::DBIx error: '$namespace' could not be loaded. ORM functions unavailable; do you need to run schema-load?");
194             }
195              
196             =pod
197              
198             =head2 db
199              
200             Returns the root schema object for the application, a subclass of L
201              
202             =cut
203              
204 1         4 $app->helper(
205 1     1   12875 db => sub($c) {
  1         2  
206 1         10 return $schema;
207             }
208 1         163895 );
209              
210             =pod
211              
212             =head2 model( $model_name )
213              
214             Returns the resultset object for the specified model name. Identical to Cdb-Eresultset($model_name)>
215              
216             =cut
217              
218 1         4 $app->helper(
219 1     1   121 model => sub($c, $model) {
  1         3  
  1         2  
220 1 50       6 return undef unless (defined($schema));
221 1         16 return $schema->resultset($model);
222             }
223 1         230 );
224              
225             =pod
226              
227             =head2 run_schema_load( $debug, $quiet )
228              
229             Generate (or regenerate) model classes from database schema. More or less, this
230             just runs L with options set at the
231             time of plugin registration.
232              
233             Parameters:
234              
235             =head4 $debug
236              
237             Write generated classes to C. Default: false
238              
239             See L
240              
241             =head4 $quiet
242              
243             Don't print the C, C messages.
244             Default: true
245              
246             See L
247              
248             =cut
249              
250 0           $app->helper(
251 0     0     run_schema_load => sub($c, $debug = 0, $quiet = 1) {
  0            
  0            
  0            
252 0         0 $c->log->debug("Creating model from database schema");
253 0         0 my @filters = $codegen_filters->@*;
254 0 0       0 if (defined($feature_bundle)) {
255 0         0 unshift(@filters, sub($type, $class, $text) {$text .= sprintf("\nuse %s;", $feature_bundle)});
  0         0  
256             }
257 0 0       0 if (defined($tidy_fs)) {
258 0         0 my ($end, $start) = (reverse($tidy_fs->@*))[0, 1];
259 0         0 push(@filters, sub($type, $class, $text) {join("\n", $start, $text, $end)});
  0         0  
260             }
261             make_schema_at(
262             $namespace, {
263             $loader_options->%*,
264             debug => $debug,
265             quiet => $quiet,
266             overwrite_modifications => $overwrite,
267             dump_directory => $model_directory,
268             components => $dbix_components,
269             filter_generated_code => sub ($type, $class, $text) {
270 0         0 $text = $_->($type, $class, $text) foreach (@filters);
271 0         0 return $text;
272             },
273             },
274 0         0 [$dsn, @credentials]
275             );
276             }
277 1         124 );
278              
279             }
280              
281             =pod
282              
283             =head1 COMMANDS
284              
285             =head2 schema-load [--debug] [--[no]quiet]
286              
287             Mojolicious command to execute L
288              
289             =head1 AUTHOR
290              
291             Mark Tyrrell C<< >>
292              
293             =head1 LICENSE
294              
295             Copyright (c) 2024 Mark Tyrrell
296              
297             Permission is hereby granted, free of charge, to any person obtaining a copy
298             of this software and associated documentation files (the "Software"), to deal
299             in the Software without restriction, including without limitation the rights
300             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
301             copies of the Software, and to permit persons to whom the Software is
302             furnished to do so, subject to the following conditions:
303              
304             The above copyright notice and this permission notice shall be included in all
305             copies or substantial portions of the Software.
306              
307             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
308             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
309             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
310             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
311             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
312             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
313             SOFTWARE.
314              
315             =cut
316              
317             1;
318              
319             __END__