1package Alzabo::Runtime;
2
3use strict;
4
5use Alzabo;
6
7use Alzabo::Runtime::Column;
8use Alzabo::Runtime::ColumnDefinition;
9use Alzabo::Runtime::ForeignKey;
10use Alzabo::Runtime::Index;
11use Alzabo::Runtime::InsertHandle;
12use Alzabo::Runtime::JoinCursor;
13use Alzabo::Runtime::Row;
14use Alzabo::Runtime::RowCursor;
15use Alzabo::Runtime::Schema;
16use Alzabo::Runtime::Table;
17use Alzabo::Utils;
18
19use vars qw($VERSION);
20
21$VERSION = 2.0;
22
231;
24
25sub import
26{
27    shift;
28
29    # ignore errors and let them be handled later in the app when it
30    # tries to access the schema.
31    eval { Alzabo::Runtime::Schema->load_from_file( name => $_ ); } foreach @_;
32}
33
34sub sqlmaker
35{
36    my ($schema, $p) = @_;
37
38    my %sqlmaker_p = ( exists $p->{quote_identifiers} ?
39                       ( quote_identifiers => $p->{quote_identifiers} ) :
40                       ()
41                     );
42
43    return $schema->sqlmaker(%sqlmaker_p);
44}
45
46sub process_where_clause
47{
48    my ($sql, $where) = @_;
49
50    $where = [ $where ]
51        unless Alzabo::Utils::is_arrayref( $where->[0] ) || $where->[0] eq '(';
52
53    my $has_where =
54        ( $sql->last_op eq 'where' || $sql->last_op eq 'condition' ) ? 1 : 0;
55
56    _process_conditions( $sql, $has_where, $where, 'where' );
57}
58
59sub process_having_clause
60{
61    my ($sql, $having) = @_;
62
63    $having = [ $having ]
64        unless Alzabo::Utils::is_arrayref( $having->[0] ) || $having->[0] eq '(';
65
66    my $has_having =
67        ( $sql->last_op eq 'having' || $sql->last_op eq 'condition' ) ? 1 : 0;
68
69    _process_conditions( $sql, $has_having, $having, 'having' );
70}
71
72sub _process_conditions
73{
74    my ($sql, $has_start, $conditions, $needed_op) = @_;
75
76    my $needs_op = $sql->last_op eq 'where' || $sql->last_op eq 'having' ? 0 : 1;
77
78    if ($has_start)
79    {
80        # wrap this in parens in order to protect from interactions with
81        # join clauses
82        $sql->and if $needs_op;
83
84        $sql->subgroup_start;
85
86        $needs_op = 0;
87    }
88
89    my $x = 0;
90    foreach my $clause (@$conditions)
91    {
92        if (ref $clause)
93        {
94            Alzabo::Exception::Params->throw
95                ( error => "Individual where clause components must be array references" )
96                    unless Alzabo::Utils::is_arrayref($clause);
97
98            Alzabo::Exception::Params->throw
99                ( error => "Individual where clause components cannot be empty" )
100                    unless @$clause;
101
102            if ($needs_op)
103            {
104                my $op = $x || $has_start ? 'and' : $needed_op;
105                $sql->$op();
106            }
107
108            $sql->condition(@$clause);
109            $needs_op = 1;
110        }
111        elsif (lc $clause eq 'and' || lc $clause eq 'or')
112        {
113            $sql->$clause();
114            $needs_op = 0;
115            next;
116        }
117        elsif ($clause eq '(')
118        {
119            if ($needs_op)
120            {
121                my $op = $x || $has_start ? 'and' : $needed_op;
122                $sql->$op();
123            }
124            $sql->subgroup_start;
125            $needs_op = 0;
126        }
127        elsif ($clause eq ')')
128        {
129            $sql->subgroup_end;
130            $needs_op = 1;
131        }
132        else
133        {
134            Alzabo::Exception::Params->throw( error => "Invalid where clause specification: $clause" );
135        }
136        $x++;
137    }
138
139    $sql->subgroup_end if $has_start;
140}
141
142sub process_order_by_clause
143{
144    _process_by_clause(@_, 'order');
145}
146
147sub process_group_by_clause
148{
149    _process_by_clause(@_, 'group');
150}
151
152sub _process_by_clause
153{
154    my ($sql, $by, $type) = @_;
155
156    my @items;
157    if ( Alzabo::Utils::safe_isa( $by, 'Alzabo::Column' ) || Alzabo::Utils::safe_isa( $by, 'Alzabo::SQLMaker::Function' ) )
158    {
159        @items = $by;
160    }
161    elsif ( Alzabo::Utils::is_arrayref($by) )
162    {
163        @items = @$by;
164    }
165
166    my $method = "${type}_by";
167    $sql->$method(@items);
168}
169
170
171
172__END__
173
174=head1 NAME
175
176Alzabo::Runtime - Loads all Alzabo::Runtime::* classes
177
178=head1 SYNOPSIS
179
180  use Alzabo::Runtime qw( schema_name );
181
182=head1 DESCRIPTION
183
184Using this module loads Alzabo::Runtime::* modules.
185
186These modules are what an end user of Alzabo uses to instantiate
187objects representing data in a given schema.
188
189=head1 import METHOD
190
191This method is called when you C<use> this class.  You can pass an
192array of strings to the module via the C<use> function.  These strings
193are assumed to be the names of schema objects that you want to load.
194This can be useful if you are running under a mod_perl (or similar)
195environment and has the potential to save some memory by preloading
196the objects before a fork, hopefully increasing shared memory.
197
198This method explicitly ignores errors that may occur when trying to
199load a particular schema.  This means that later attempts to retrieve
200that schema will probably also fail.  This is done so that the
201application that wants a particular schema can explicitly handle the
202failure later on.
203
204=head1 AUTHOR
205
206Dave Rolsky, <autarch@urth.org>
207
208=cut
209