From 21ce117f514b12e816320fd9819109b501287e35 Mon Sep 17 00:00:00 2001 From: Aaron Crane Date: Fri, 23 Feb 2018 16:37:59 +0000 Subject: [PATCH] New exclude_columns option --- lib/DBIx/Class/Schema/Loader/Base.pm | 26 ++++++++++++++++++++- t/lib/dbixcsl_common_tests.pm | 34 ++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/DBIx/Class/Schema/Loader/Base.pm b/lib/DBIx/Class/Schema/Loader/Base.pm index 34817116b..44a421949 100644 --- a/lib/DBIx/Class/Schema/Loader/Base.pm +++ b/lib/DBIx/Class/Schema/Loader/Base.pm @@ -26,7 +26,7 @@ use DBIx::Class::Schema::Loader::Optional::Dependencies (); use Try::Tiny; use DBIx::Class (); use Encode qw/encode decode/; -use List::Util qw/all any none/; +use List::Util qw/all any none pairgrep/; use File::Temp 'tempfile'; use curry; use namespace::clean; @@ -49,6 +49,7 @@ __PACKAGE__->mk_group_ro_accessors('simple', qw/ moniker_map col_accessor_map custom_column_info + exclude_columns inflect_singular inflect_plural debug @@ -905,6 +906,22 @@ Omit the package version from the signature comment. Omit the creation timestamp from the signature comment. +=head2 exclude_columns + +Hook for excluding some columns from the generated schema. + +Receives the L object, column name and +column_info. This is called at the last possible moment before emitting an +C call; in particular, it happens after L. + +For example, to exclude columns of type "tsvector" (which might be useful in +a PostgreSQL database where those columns are maintained by triggers): + + exclude_columns => sub { + my ($table, $column_name, $column_info) = @_; + return $column_info->{data_type} eq 'tsvector'; + }, + =head2 custom_column_info Hook for adding extra attributes to the @@ -1254,6 +1271,10 @@ sub new { croak 'custom_column_info must be a CODE ref'; } + if ($self->exclude_columns && ref $self->exclude_columns ne 'CODE') { + croak 'exclude_columns must be a CODE ref'; + } + $self->_check_back_compat; $self->use_namespaces(1) unless defined $self->use_namespaces; @@ -2710,9 +2731,12 @@ sub _setup_src_meta { $col_info->{$pkcol}{is_nullable} = 0; } + my $exclude_columns = $self->exclude_columns; + $self->_dbic_stmt( $table_class, 'add_columns', + pairgrep { !$exclude_columns || !$exclude_columns->($table, $a, $b) } map { $_, ($col_info->{$_}||{}) } @$cols ); diff --git a/t/lib/dbixcsl_common_tests.pm b/t/lib/dbixcsl_common_tests.pm index 1d425bbe7..275c61009 100644 --- a/t/lib/dbixcsl_common_tests.pm +++ b/t/lib/dbixcsl_common_tests.pm @@ -120,7 +120,7 @@ sub run_tests { my $col_accessor_map_tests = 6; plan tests => @connect_info * - (233 + $col_accessor_map_tests + $extra_count + ($self->{data_type_tests}{test_count} || 0)); + (237 + $col_accessor_map_tests + $extra_count + ($self->{data_type_tests}{test_count} || 0)); foreach my $info_idx (0..$#connect_info) { my $info = $connect_info[$info_idx]; @@ -248,6 +248,7 @@ sub setup_schema { inflect_singular => { fkid => 'fkid_singular' }, moniker_map => \&_monikerize, custom_column_info => \&_custom_column_info, + exclude_columns => \&_exclude_columns, debug => $debug, dump_directory => DUMP_DIR, datetime_timezone => 'Europe/Berlin', @@ -289,7 +290,7 @@ sub setup_schema { my $standard_sources = not defined $expected_count; if ($standard_sources) { - $expected_count = 41; + $expected_count = 42; if (not ($self->{vendor} eq 'mssql' && $connect_info->[0] =~ /Sybase/)) { $expected_count++ for @{ $self->{data_type_tests}{table_names} || [] }; @@ -736,6 +737,10 @@ qr/\n__PACKAGE__->load_components\("TestSchemaComponent", "\+TestSchemaComponent my $class37 = $classes->{loader_test37}; my $rsobj37 = $conn->resultset($moniker37); + my $moniker38 = $monikers->{loader_test38}; + my $class38 = $classes->{loader_test38}; + my $rsobj38 = $conn->resultset($moniker38); + my $moniker42 = $monikers->{loader_test42}; my $class42 = $classes->{loader_test42}; my $rsobj42 = $conn->resultset($moniker42); @@ -773,6 +778,7 @@ qr/\n__PACKAGE__->load_components\("TestSchemaComponent", "\+TestSchemaComponent isa_ok( $rsobj34, "DBIx::Class::ResultSet" ); isa_ok( $rsobj36, "DBIx::Class::ResultSet" ); isa_ok( $rsobj37, "DBIx::Class::ResultSet" ); + isa_ok( $rsobj38, "DBIx::Class::ResultSet" ); isa_ok( $rsobj42, "DBIx::Class::ResultSet" ); isa_ok( $rsobj43, "DBIx::Class::ResultSet" ); isa_ok( $rsobj44, "DBIx::Class::ResultSet" ); @@ -1007,6 +1013,12 @@ qr/\n__PACKAGE__->load_components\("TestSchemaComponent", "\+TestSchemaComponent ok( $class37->relationship_info('parent'), 'parents rel created' ); ok( $class37->relationship_info('child'), 'child rel created' ); + ok (!$class38->has_column('b_char_as_data'), + 'column loader_test38.b_char_as_data correctly excluded' ); + ok( $class38->has_column($_), + "column loader_test38.$_ correctly included" ) + for qw/a_char_as_data b_int/; + is_deeply($class32->_m2m_metadata, {}, 'many_to_many not created for might_have'); is_deeply($class34->_m2m_metadata, {}, 'many_to_many not created for might_have'); @@ -1657,6 +1669,16 @@ sub create { c_char_as_data VARCHAR(100) ) $self->{innodb} }, + + qq{ + CREATE TABLE loader_test38 ( + id INTEGER NOT NULL PRIMARY KEY, + a_char_as_data VARCHAR(100), + b_char_as_data VARCHAR(100), + b_int INTEGER + ) $self->{innodb} + }, + # DB2 does not allow nullable uniq components, SQLAnywhere automatically # converts nullable uniq components to NOT NULL qq{ @@ -2173,6 +2195,7 @@ sub drop_tables { LoAdEr_test24 loader_test35 loader_test36 + loader_test38 loader_test50 /; @@ -2345,6 +2368,13 @@ sub _custom_column_info { return; } +sub _exclude_columns { + my ( $table, $column_name, $column_info ) = @_; + return lc $table eq 'loader_test38' + && $column_name =~ /^b_/i + && $column_info->{data_type} =~ /char/i; +} + my %DATA_TYPE_MULTI_TABLE_OVERRIDES = ( oracle => qr/\blong\b/i, mssql => qr/\b(?:timestamp|rowversion)\b/i,