1 package DBIx::Class::ResultSource::MultipleTableInheritance;
5 use parent qw(DBIx::Class::ResultSource::View);
6 use Method::Signatures::Simple;
7 use Carp::Clan qw/^DBIx::Class/;
8 use aliased 'DBIx::Class::ResultSource::Table';
9 use aliased 'DBIx::Class::ResultClass::HashRefInflator';
10 use namespace::autoclean;
14 # On construction, we hook $self->result_class->result_source_instance
15 # if present to get the superclass' source object
17 # When attached to a schema, we need to add sources to that schema with
18 # appropriate relationships for the foreign keys so the concrete tables
21 # We also generate our own view definition using this class' concrete table
22 # and the view for the superclass, and stored procedures for the insert,
23 # update and delete operations on this view.
25 # deploying the postgres rules through SQLT may be a pain though.
27 __PACKAGE__->mk_group_accessors(simple => qw(parent_source));
29 method new ($class: @args) {
30 my $new = $class->next::method(@args);
31 my $rc = $new->result_class;
32 if (my $meth = $rc->can('result_source_instance')) {
33 my $source = $rc->$meth;
34 if ($source->result_class ne $new->result_class
35 && $new->result_class->isa($source->result_class)) {
36 $new->parent_source($source);
42 method schema (@args) {
43 my $ret = $self->next::method(@args);
45 $self->_attach_additional_sources;
50 method _attach_additional_sources () {
51 my $raw_name = $self->raw_source_name;
52 my $schema = $self->schema;
54 # if the raw source is already present we can assume we're done
55 return if grep { $_ eq $raw_name } $schema->sources;
57 # our parent should've been registered already actually due to DBIC
58 # attaching subclass sources later in load_namespaces
61 if ($self->parent_source) {
62 my $parent_name = $self->parent_source->name;
64 grep { $_->name eq $parent_name }
65 map $schema->source($_), $schema->sources;
66 confess "Couldn't find attached source for parent $parent_name - did you use load_classes? This module is only compatible with load_namespaces"
70 # create the raw table source
72 my $table = Table->new({ name => $self->raw_table_name });
74 # we don't need to add the PK cols explicitly if we're the root table
75 # since they'll get added below
79 foreach my $pri ($self->primary_columns) {
80 my %info = %{$self->column_info($pri)};
81 delete @info{qw(is_auto_increment sequence auto_nextval)};
82 $table->add_column($pri => \%info);
83 $join{"foreign.${pri}"} = "self.${pri}";
85 # have to use source name lookups rather than result class here
86 # because we don't actually have a result class on the raw sources
87 $table->add_relationship('parent', $parent->raw_source_name, \%join);
90 # add every column that's actually a concrete part of us
93 map { ($_ => { %{$self->column_info($_)} }) }
94 grep { $self->column_info($_)->{originally_defined_in} eq $self->name }
97 $table->set_primary_key($self->primary_columns);
98 $schema->register_source($raw_name => $table);
101 method set_primary_key (@args) {
102 if ($self->parent_source) {
103 confess "Can't set primary key on a subclass";
105 return $self->next::method(@args);
108 method raw_source_name () {
109 my $base = $self->source_name;
110 confess "Can't generate raw source name when we don't have a source_name"
112 return 'Raw::'.$base;
115 method raw_table_name () {
116 return '_'.$self->name;
119 method add_columns (@args) {
120 my $ret = $self->next::method(@args);
121 $_->{originally_defined_in} ||= $self->name for values %{$self->_columns};