File: SchemaGenerator.pm

package info (click to toggle)
libdbix-searchbuilder-perl 1.82-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 776 kB
  • sloc: perl: 10,608; makefile: 2
file content (178 lines) | stat: -rw-r--r-- 4,495 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
use strict;
use warnings;

package DBIx::SearchBuilder::SchemaGenerator;

use base qw(Class::Accessor);
use DBIx::DBSchema;
use Class::ReturnValue;

# Public accessors
__PACKAGE__->mk_accessors(qw(handle));
# Internal accessors: do not use from outside class
__PACKAGE__->mk_accessors(qw(_db_schema));

=head2 new HANDLE

Creates a new C<DBIx::SearchBuilder::SchemaGenerator> object.  The single
required argument is a C<DBIx::SearchBuilder::Handle>.

=cut

sub new {
    my $class = shift;
    my $handle = shift;
    my $self = $class->SUPER::new();

    $self->handle($handle);

    my $schema = DBIx::DBSchema->new;
    $self->_db_schema($schema);

    return $self;
}

=for public_doc AddModel MODEL

Adds a new model class to the SchemaGenerator.  Model should either be an object
of a subclass of C<DBIx::SearchBuilder::Record>, or the name of such a subclass; in the
latter case, C<AddModel> will instantiate an object of the subclass.

The model must define the instance methods C<Schema> and C<Table>.

Returns true if the model was added successfully; returns a false C<Class::ReturnValue> error
otherwise.

=cut

sub AddModel {
    my $self = shift;
    my $model = shift;

    # $model could either be a (presumably unfilled) object of a subclass of
    # DBIx::SearchBuilder::Record, or it could be the name of such a subclass.

    unless (ref $model and UNIVERSAL::isa($model, 'DBIx::SearchBuilder::Record')) {
        my $new_model;
        eval { $new_model = $model->new; };

        if ($@) {
            return $self->_error("Error making new object from $model: $@");
        }

        return $self->_error("Didn't get a DBIx::SearchBuilder::Record from $model, got $new_model")
            unless UNIVERSAL::isa($new_model, 'DBIx::SearchBuilder::Record');

        $model = $new_model;
    }

    my $table_obj = $self->_DBSchemaTableFromModel($model);

    $self->_db_schema->addtable($table_obj);

    1;
}

=for public_doc CreateTableSQLStatements

Returns a list of SQL statements (as strings) to create tables for all of
the models added to the SchemaGenerator.

=cut

sub CreateTableSQLStatements {
    my $self = shift;
    # The sort here is to make it predictable, so that we can write tests.
    return sort $self->_db_schema->sql($self->handle->dbh);
}

=for public_doc CreateTableSQLText

Returns a string containing a sequence of SQL statements to create tables for
all of the models added to the SchemaGenerator.

=cut

sub CreateTableSQLText {
    my $self = shift;

    return join "\n", map { "$_ ;\n" } $self->CreateTableSQLStatements;
}

=for private_doc _DBSchemaTableFromModel MODEL

Takes an object of a subclass of DBIx::SearchBuilder::Record; returns a new
C<DBIx::DBSchema::Table> object corresponding to the model.

=cut

sub _DBSchemaTableFromModel {
    my $self = shift;
    my $model = shift;

    my $table_name = $model->Table;
    my $schema     = $model->Schema;

    my $primary = "id"; # TODO allow override
    my $primary_col = DBIx::DBSchema::Column->new({
        name => $primary,
        type => 'serial',
        null => 'NOT NULL',
    });

    my @cols = ($primary_col);

    # The sort here is to make it predictable, so that we can write tests.
    for my $field (sort keys %$schema) {
        # Skip foreign keys

        next if defined $schema->{$field}->{'REFERENCES'} and defined $schema->{$field}->{'KEY'};

        # TODO XXX FIXME
        # In lieu of real reference support, make references just integers
        $schema->{$field}{'TYPE'} = 'integer' if $schema->{$field}{'REFERENCES'};

        push @cols, DBIx::DBSchema::Column->new({
            name    => $field,
            type    => $schema->{$field}{'TYPE'},
            null    => 'NULL',
            default => $schema->{$field}{'DEFAULT'},
        });
    }

    my $table = DBIx::DBSchema::Table->new({
        name => $table_name,
        primary_key => $primary,
        columns => \@cols,
    });

    return $table;
}

=for private_doc _error STRING

Takes in a string and returns it as a Class::ReturnValue error object.

=cut

sub _error {
    my $self = shift;
    my $message = shift;

    my $ret = Class::ReturnValue->new;
    $ret->as_error(errno => 1, message => $message);
    return $ret->return_value;
}


1; # Magic true value required at end of module

__END__

=head1 NAME

DBIx::SearchBuilder::SchemaGenerator - Generate table schemas from DBIx::SearchBuilder records

=head1 SYNOPSIS

    use DBIx::SearchBuilder::SchemaGenerator;