DBIx-Class-Schema-Loader

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

        - do not try to detect driver and rebless when used with a custom
          'loader_class'
        - suppress 'bad table or view' warnings for filtered tables/views
        - croak if several tables reduce to an identical moniker (ribasushi)
        - better type info for Sybase ASE
        - better type info for Pg: sets sequence for serials, handles numerics
          without precision
        - better _tables_list for MSSQL
        - pick up views in SQLite too
        - better rel inflection using Lingua::EN::Inflect::Phrase
        - cascade_delete and cascade_copy are turned off for has_many/might_have
          by default, and belongs_to has on_delete => 'CASCADE', on_update =>
          'CASCADE' and is_deferrable => 1 by default, overridable via
          relationship_attrs
        - added config_file option for loading loader options from a file
        - set inflate_datetime => 1 for 'AS getdate()' computed columns in
          Sybase
        - Firebird support
        - use introspection pragmas instead of regexes to introspect SQLite
          (hobbs)
        - generate POD for refs correctly from column_info

lib/DBIx/Class/Schema/Loader/Base.pm  view on Meta::CPAN


Hashref of attributes to pass to each generated relationship, listed by type.
Also supports relationship type 'all', containing options to pass to all
generated relationships.  Attributes set for more specific relationship types
override those set in 'all', and any attributes specified by this option
override the introspected attributes of the foreign key if any.

For example:

    relationship_attrs => {
        has_many   => { cascade_delete => 1, cascade_copy => 1 },
        might_have => { cascade_delete => 1, cascade_copy => 1 },
    },

use this to turn L<DBIx::Class> cascades to on on your
L<has_many|DBIx::Class::Relationship/has_many> and
L<might_have|DBIx::Class::Relationship/might_have> relationships, they default
to off.

Can also be a coderef, for more precise control, in which case the coderef gets
this hash of parameters (as a list):

    rel_name        # the name of the relationship
    rel_type        # the type of the relationship: 'belongs_to', 'has_many' or 'might_have'
    local_source    # the DBIx::Class::ResultSource object for the source the rel is *from*

lib/DBIx/Class/Schema/Loader/Base.pm  view on Meta::CPAN

        if ($p{local_table} eq 'dogs' && @{$p{local_cols}} == 1 && $p{local_cols}[0] eq 'name') {
            $p{attrs}{could_be_snoopy} = 1;

            return $p{attrs};
        }
    },

These are the default attributes:

    has_many => {
        cascade_delete => 0,
        cascade_copy   => 0,
    },
    might_have => {
        cascade_delete => 0,
        cascade_copy   => 0,
    },
    belongs_to => {
        on_delete => 'CASCADE',
        on_update => 'CASCADE',
        is_deferrable => 1,
    },

For L<belongs_to|DBIx::Class::Relationship/belongs_to> relationships, these
defaults are overridden by the attributes introspected from the foreign key in
the database, if this information is available (and the driver is capable of

lib/DBIx/Class/Schema/Loader/DBI/SQLite.pm  view on Meta::CPAN

where name = ? and tbl_name = ?
EOF

    foreach my $fk (@rels) {
        my $local_cols  = '"?' . (join '"? \s* , \s* "?', map quotemeta, @{ $fk->{local_columns} })        . '"?';
        my $remote_cols = '"?' . (join '"? \s* , \s* "?', map quotemeta, @{ $fk->{remote_columns} || [] }) . '"?';
        my ($deferrable_clause) = $ddl =~ /
                foreign \s+ key \s* \( \s* $local_cols \s* \) \s* references \s* (?:\S+|".+?(?<!")") \s*
                (?:\( \s* $remote_cols \s* \) \s*)?
                (?:(?:
                    on \s+ (?:delete|update) \s+ (?:set \s+ null|set \s+ default|cascade|restrict|no \s+ action)
                |
                    match \s* (?:\S+|".+?(?<!")")
                ) \s*)*
                ((?:not)? \s* deferrable)?
        /sxi;

        if ($deferrable_clause) {
            $fk->{attrs}{is_deferrable} = $deferrable_clause =~ /not/i ? 0 : 1;
        }
        else {
            # check for inline constraint if 1 local column
            if (@{ $fk->{local_columns} } == 1) {
                my ($local_col)  = @{ $fk->{local_columns} };
                my ($remote_col) = @{ $fk->{remote_columns} || [] };
                $remote_col ||= '';

                my ($deferrable_clause) = $ddl =~ /
                    "?\Q$local_col\E"? \s* (?:\w+\s*)* (?: \( \s* \d\+ (?:\s*,\s*\d+)* \s* \) )? \s*
                    references \s+ (?:\S+|".+?(?<!")") (?:\s* \( \s* "?\Q$remote_col\E"? \s* \))? \s*
                    (?:(?:
                      on \s+ (?:delete|update) \s+ (?:set \s+ null|set \s+ default|cascade|restrict|no \s+ action)
                    |
                      match \s* (?:\S+|".+?(?<!")")
                    ) \s*)*
                    ((?:not)? \s* deferrable)?
                /sxi;

                if ($deferrable_clause) {
                    $fk->{attrs}{is_deferrable} = $deferrable_clause =~ /not/i ? 0 : 1;
                }
                else {

lib/DBIx/Class/Schema/Loader/Manual/UpgradingFromV4.pod  view on Meta::CPAN

RelBuilder

The new RelBuilder will give you nicer accessor names for relationships, so you
will no longer have conflicts between a foreign key column and the relationship
accessor itself (if the FK is named C<_id>.)

It will also more correctly infer the relationship type, e.g. some relationships
that were previously detected as a C<has_many> will now be a C<might_have>
(when it detects a unique constraint on the foreign key column.)

Also C<cascade_delete> and C<cascade_copy> are turned off for by default for
C<has_many> and C<might_have> relationships, while C<belongs_to> relationships
are created with C<< on_delete => 'CASCADE' >> and C<< on_update => 'CASCADE' >>
by default. This is overridable via
L<relationship_attrs|DBIx::Class::Schema::Loader::Base/relationship_attrs>.

=item *

moniker_map

Table names are now singularized when determining the C<Result> class names. So

lib/DBIx/Class/Schema/Loader/RelBuilder.pm  view on Meta::CPAN


    $name =~ s/_/ /g;
    my $singular = Lingua::EN::Inflect::Phrase::to_S($name);
    $singular =~ s/ /_/g;

    return $singular;
}

sub _default_relationship_attrs { +{
    has_many => {
        cascade_delete => 0,
        cascade_copy   => 0,
    },
    might_have => {
        cascade_delete => 0,
        cascade_copy   => 0,
    },
    belongs_to => {
        on_delete => 'CASCADE',
        on_update => 'CASCADE',
        is_deferrable => 1,
    },
} }

# Accessor for options to be passed to each generated relationship type. takes
# the relationship type name and optionally any attributes from the database

t/10_08sqlanywhere_common.t  view on Meta::CPAN

            q{
                create table sqlanywhere_loader_test9 (
                    id int identity not null primary key
                )
            },
            q{
                create table sqlanywhere_loader_test10 (
                    id int identity not null primary key,
                    nine_id int,
                    foreign key (nine_id) references sqlanywhere_loader_test9(id)
                        on delete cascade on update set null
                )
            },
        ],
        drop  => [ qw/sqlanywhere_loader_test9 sqlanywhere_loader_test10/ ],
        count => 4 + 30 * 2,
        run => sub {
            SKIP: {
                $schema  = $_[0];
                my $self = $_[3];

t/45relationships.t  view on Meta::CPAN

throws_ok {
    schema_with( relationship_attrs => 'laughably invalid!!!' );
} qr/relationship_attrs/, 'throws error for invalid (scalar) relationship_attrs';

throws_ok {
    schema_with( relationship_attrs => [qw/laughably invalid/] );
} qr/relationship_attrs/, 'throws error for invalid (arrayref) relationship_attrs';

{
    my $nodelete = schema_with( relationship_attrs => {
        all        => { cascade_delete => 0 },
        belongs_to => { cascade_delete => 1 },
    });

    my $bars_info   = $nodelete->source('Foo')->relationship_info('bars');
    #use Data::Dumper;
    #die Dumper([ $nodelete->source('Foo')->relationships() ]);
    my $fooref_info = $nodelete->source('Bar')->relationship_info('fooref');
    is( ref($fooref_info), 'HASH',
        'fooref rel is present',
    );
    is( $bars_info->{attrs}->{cascade_delete}, 0,
        'relationship_attrs settings seem to be getting through to the generated rels',
    );
    is( $fooref_info->{attrs}->{cascade_delete}, 1,
        'belongs_to in relationship_attrs overrides all def',
    );
}

# test relationship_attrs coderef
{
    my $relationship_attrs_coderef_invoked = 0;
    my $schema;

    lives_ok {

t/45relationships.t  view on Meta::CPAN


            $relationship_attrs_coderef_invoked++;

            if ($p{rel_name} eq 'bars') {
                is $p{rel_type}, 'has_many', 'correct rel_type';
                is $p{local_table},  'foo', 'correct local_table';
                is_deeply $p{local_cols}, [ 'fooid' ], 'correct local_cols';
                is $p{remote_table}, 'bar', 'correct remote_table';
                is_deeply $p{remote_cols}, [ 'fooref' ], 'correct remote_cols';
                is_deeply $p{attrs}, {
                    cascade_delete => 0,
                    cascade_copy   => 0,
                }, "got default rel attrs for $p{rel_name} in $p{local_table}";

                like $p{local_source}->result_class,
                    qr/^DBICTest::Schema::\d+::Result::Foo\z/,
                    'correct local source';

                like $p{remote_source}->result_class,
                    qr/^DBICTest::Schema::\d+::Result::Bar\z/,
                    'correct remote source';

t/backcompat/0.04006/lib/dbixcsl_common_tests.pm  view on Meta::CPAN


        # test that _id is not stripped and prepositions in rel names are
        # ignored
        ok ($rsobj4->result_source->has_relationship('loader_test5_to_ids'),
            "rel with preposition 'to' and _id pluralized backward-compatibly");

        ok ($rsobj4->result_source->has_relationship('loader_test5_from_ids'),
            "rel with preposition 'from' and _id pluralized backward-compatibly");

        # check that default relationship attributes are not applied in 0.04006 mode
        is $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{cascade_delete}, 1,
            'cascade_delete => 1 on has_many by default';

        is $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{cascade_copy}, 1,
            'cascade_copy => 1 on has_many by default';

        ok ((not exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{on_delete}),
            'has_many does not have on_delete');

        ok ((not exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{on_update}),
            'has_many does not have on_update');

        ok ((not exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{is_deferrable}),
            'has_many does not have is_deferrable');

        isnt $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_delete}, 'CASCADE',
            "on_delete => 'CASCADE' not on belongs_to by default";

        isnt $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{on_update}, 'CASCADE',
            "on_update => 'CASCADE' not on belongs_to by default";

        isnt $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{is_deferrable}, 1,
            "is_deferrable => 1 not on belongs_to by default";

        ok ((not exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{cascade_delete}),
            'belongs_to does not have cascade_delete');

        ok ((not exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{cascade_copy}),
            'belongs_to does not have cascade_copy');

        # find on multi-col pk
        my $obj5 = $rsobj5->find({id1 => 1, id2 => 1});
        is( $obj5->id2, 1 );

        # mulit-col fk def
        my $obj6 = $rsobj6->find(1);
        isa_ok( $obj6->loader_test2, $class2);
        isa_ok( $obj6->loader_test5, $class5);

t/lib/dbixcsl_common_tests.pm  view on Meta::CPAN

        isa_ok( try { $rs_rel4->single }, $class4);

        # check rel naming with prepositions
        ok ($rsobj4->result_source->has_relationship('loader_test5s_to'),
            "rel with preposition 'to' pluralized correctly");

        ok ($rsobj4->result_source->has_relationship('loader_test5s_from'),
            "rel with preposition 'from' pluralized correctly");

        # check default relationship attributes
        is try { $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{cascade_delete} }, 0,
            'cascade_delete => 0 on has_many by default';

        is try { $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{cascade_copy} }, 0,
            'cascade_copy => 0 on has_many by default';

        ok ((not try { exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{on_delete} }),
            'has_many does not have on_delete');

        ok ((not try { exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{on_update} }),
            'has_many does not have on_update');

        ok ((not try { exists $rsobj3->result_source->relationship_info('loader_test4zes')->{attrs}{is_deferrable} }),
            'has_many does not have is_deferrable');

t/lib/dbixcsl_common_tests.pm  view on Meta::CPAN


        my $default_is_deferrable = $self->{default_is_deferrable};

        $default_is_deferrable = 1
            if not defined $default_is_deferrable;

        is try { $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{is_deferrable} },
            $default_is_deferrable,
            "is_deferrable => $default_is_deferrable on belongs_to by default";

        ok ((not try { exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{cascade_delete} }),
            'belongs_to does not have cascade_delete');

        ok ((not try { exists $rsobj4->result_source->relationship_info('fkid_singular')->{attrs}{cascade_copy} }),
            'belongs_to does not have cascade_copy');

        is try { $rsobj27->result_source->relationship_info('loader_test28')->{attrs}{cascade_delete} }, 0,
            'cascade_delete => 0 on might_have by default';

        is try { $rsobj27->result_source->relationship_info('loader_test28')->{attrs}{cascade_copy} }, 0,
            'cascade_copy => 0 on might_have by default';

        ok ((not try { exists $rsobj27->result_source->relationship_info('loader_test28')->{attrs}{on_delete} }),
            'might_have does not have on_delete');

        ok ((not try { exists $rsobj27->result_source->relationship_info('loader_test28')->{attrs}{on_update} }),
            'might_have does not have on_update');

        ok ((not try { exists $rsobj27->result_source->relationship_info('loader_test28')->{attrs}{is_deferrable} }),
            'might_have does not have is_deferrable');



( run in 0.484 second using v1.01-cache-2.11-cpan-49f99fa48dc )