NAME
DBIx::Class::Schema::SanityChecker - Extensible "critic" for your Schema class hierarchy
SYNOPSIS
package MyApp::Schema;
use base 'DBIx::Class::Schema';
# this is the default setting
__PACKAGE__->schema_sanity_checker('DBIx::Class::Schema::SanityChecker');
...
DESCRIPTION
This is the default implementation of the Schema and related classes validation framework.
The validator is enabled by default. See "Performance considerations" for discussion of the runtime effects.
Use of this class begins by invoking "perform_schema_sanity_checks" (usually via "connection" in DBIx::Class::Schema), which in turn starts invoking validators check_$checkname()
in the order listed in "available_checks". For each set of returned errors (if any) format_$checkname_errors()
is called and the resulting strings are passed to "emit_errors", where final headers are prepended and the entire thing is printed on STDERR
.
The class does not provide a constructor, due to the lack of state to be passed around: object orientation was chosen purely for the ease of overriding parts of the chain of events as described above. The general pattern of communicating errors between the individual methods (both before and after formatting) is an arrayref of hash references.
WHY
DBIC existed for more than a decade without any such setup validation fanciness, let alone something that is enabled by default (which in turn isn't free). The reason for this relatively drastic change is a set of revamps within the metadata handling framework, in order to resolve once and for all problems like RT#107462, RT#114440, etc. While DBIC internals are now way more robust than they were before, this comes at a price: some non-issues in code that has been working for a while, will now become hard to explain, or if you are unlucky: silent breakages.
Thus, in order to protect existing codebases to the fullest extent possible, the executive decision (and substantial effort) was made to introduce this on-by-default setup validation framework. A massive amount of work has been invested ensuring that none of the builtin checks emit a false-positive: each and every complaint made by these checks should be investigated.
Performance considerations
First of all - after your connection has been established - there is no runtime penalty whenever the checks are enabled.
By default the checks are triggered every time "connection" in DBIx::Class::Schema is called. Thus there is a noticeable startup slowdown, most notably during testing (each test is effectively a standalone program connecting anew). As an example the test execution phase of the DBIx::Class::Helpers v2.032002
distribution suffers a consistent slowdown of about 16%
. This is considered a relatively small price to pay for the benefits provided.
Nevertheless, there are valid cases for disabling the checks during day-to-day development, and having them run only during CI builds. In fact the test suite of DBIC does exactly this as can be seen in t/lib/DBICTest/BaseSchema.pm:
~/dbic_repo$ git show 39636786 | perl -ne "print if 16..61"
Whatever you do, please do not disable the checks entirely: it is not worth the risk.
Perl5.8
The situation with perl interpreters before v5.10.0
is sadly more complicated: due to lack of built-in pluggable mro support, the mechanism used to interrogate various classes is much slower. As a result the very same version of DBIx::Class::Helpers mentioned above takes a 220%
hit on its test execution time (these numbers are observed with the speedups of Class::C3::XS available, without them the slowdown reaches the whopping 350%
).
It is the author's strongest recommendation to find a way to run the checks on your codebase continuously, even if it takes much longer. Refer to the last paragraph of "Performance considerations" above for an example how to do this during CI builds only.
Validations provided by this module
no_indirect_method_overrides
There are many methods within DBIC which are "strictly sugar" and should never be overridden by your application (e.g. see warnings at the end of "create" in DBIx::Class::ResultSet and "connect" in DBIx::Class::Schema). Starting with v0.082900
DBIC is much more aggressive in calling the underlying non-sugar methods directly, which in turn means that almost all user-side overrides of sugar methods are never going to be invoked. These situations are now reliably detected and reported individually (you may end up with a lot of output on STDERR
due to this).
Note: ANY AND ALL ISSUES reported by this check *MUST* be resolved before upgrading DBIC in production. Malfunctioning business logic and/or SEVERE DATA LOSS may result otherwise.
valid_c3_composition
Looks through everything returned by "all_schema_related_classes", and for any class that does not already utilize c3 MRO a method shadowing map is calculated and then compared to the shadowing map as if c3 MRO
was requested in the first place. Any discrepancies are reported in order to clearly identify hard to explain bugs especially when encountered within complex inheritance hierarchies.
no_inheritance_crosscontamination
Checks that every individual Schema, Storage, ResultSource, ResultSet and Result class does not inherit from an unexpected DBIC base class: e.g. an error will be raised if your MyApp::Schema
inherits from both DBIx::Class::Schema
and DBIx::Class::ResultSet
.
METHODS
perform_schema_sanity_checks
- Arguments: $schema
- Return Value: unspecified (ignored by caller)
The entry point expected by the validation framework. See "DESCRIPTION" for details.
available_checks
The list of checks "perform_schema_sanity_checks" will perform on the provided $schema object. For every entry returned by this method, there must be a pair of check_$checkname()
and format_$checkname_errors()
methods available.
Override this method to add checks to the currently available set.
emit_errors
Takes an array reference of individual errors returned by various format_$checkname_errors()
formatters, and outputs them on STDERR
.
This method is the most convenient integration point for a 3rd party logging framework.
Each individual error is expected to be a hash reference with all values being plain strings as follows:
{
schema_desc => $human_readable_description_of_the_passed_in_schema
check_name => $name_of_the_check_as_listed_in_available_checks()
formatted_error => $error_text_as_returned_by_format_$checkname_errors()
}
If the environment variable DBIC_ASSERT_NO_FAILING_SANITY_CHECKS
is set to a true value this method will throw an exception with the same text. Those who prefer to take no chances could set this variable permanently as part of their deployment scripts.
all_schema_related_classes
- Arguments: $schema
- Return Value: @sorted_list_of_unique_class_names
This is a convenience method providing a list (not an arrayref) of "interesting classes" related to the supplied schema. The returned list currently contains the following class names:
The Schema class itself
The associated Storage class if any
The classes of all registered ResultSource instances if any
All Result classes for all registered ResultSource instances
All ResultSet classes for all registered ResultSource instances
FURTHER QUESTIONS?
Check the list of additional DBIC resources.
COPYRIGHT AND LICENSE
This module is free software copyright by the DBIx::Class (DBIC) authors. You can redistribute it and/or modify it under the same terms as the DBIx::Class library.