File Coverage

blib/lib/Cosmic/DB/Schema.pm
Criterion Covered Total %
statement 14 36 38.8
branch 1 14 7.1
condition 0 3 0.0
subroutine 4 6 66.6
pod 3 3 100.0
total 22 62 35.4


line stmt bran cond sub pod time code
1             package Cosmic::DB::Schema;
2 4     4   268116 use strict;
  4         12  
  4         211  
3 4     4   33 use warnings;
  4         8  
  4         130  
4 4     4   25 use Carp;
  4         8  
  4         3167  
5              
6             =pod
7              
8             =head1 Schema
9              
10             Methods for defining, loading and creating DB schemas
11              
12             =head1 Methodology
13              
14             1) Create tables with primary keys
15             2) Create indexes
16             3) Create foreign key constraints
17              
18             my $schema = {
19             table => {
20             columns => [
21             {
22             name => 'COLUMN',
23             type => 'ALLOWED TYPE',
24             unique => 0|1,
25             null => 0|1,
26             size => [0-9]*,
27             default => '',
28             }
29             ],
30             primary_key => [
31             'COLUMN',
32             ],
33             indexes => [
34             {
35             name => 'INDEX NAME',
36             unique => 0|1,
37             columns => [
38             'COLUMN',
39             ],
40             },
41             ],
42             constraints => {
43             foreign => [
44             {
45             name => 'CONSTRAINT NAME',
46             columns => [
47             'COLUMN',
48             ],
49             references => {
50             table => 'TABLE',
51             columns => [
52             'COLUMN',
53             ],
54             },
55             cascade => 0|1,
56             },
57             ],
58             },
59             },
60             };
61              
62             =head1 Allowed types
63              
64             =head2 Numeric
65              
66             All numbers are signed (apart from some serials). Numbers are of fixed size,
67             i.e int(10) is invalid.
68              
69             =item int
70              
71             Safe range -2147483648 to 2147483647
72              
73             =item smallint
74              
75             Safe range -32768 to 32767
76              
77             =item bigint
78              
79             Safe range -9223372036854775808 to 9223372036854775807
80              
81             =item real
82              
83             Safe range - 3.40E + 38 to -1.18E - 38, 0 and 1.18E - 38 to 3.40E + 38
84              
85             =item double
86              
87             Safe range - 1.79E+308 to -2.23E-308, 0 and 2.23E-308 to 1.79E+308
88              
89             =head2 Dates and times
90              
91             Always store dates in the database as GMT (UTC), you shouldn't be storing
92             timezones in the DB (and we don't plan to support it).
93             Date implementations vary a lot, you might be better off just using integers,
94             such as 20100101 for 1st of January 2010.
95              
96             =item date
97              
98             Safe range '1000-01-01' to '9999-12-31'
99              
100             =item time
101              
102             Safe range 00:00:00 to 23:59:59
103              
104             =item timezone
105              
106             Safe range '1000-01-01 00:00:00' to '9999-12-31 23:59:59'
107             Format YYYY-MM-DD HH:MM:SS
108              
109             =head2 Strings
110              
111             By default all strings are created unicode compatible. You should be planning
112             for wide characters in the first place, it'll save you much pain later.
113             It is possible to use the standard ASCII string types by TODO
114              
115             =item char
116              
117             Safe range 1 to 255
118             Default 1
119              
120             =item varchar
121              
122             Safe range 1 to 2000
123              
124             =item text
125              
126             Safe storage up to 2GB
127              
128             =head2 Special
129              
130             =item serial
131              
132             Safe range 1 to 2147483647 (int based)
133              
134             Beware oracle warning below
135              
136             =item bigserial
137              
138             Safe range 1 to 9223372036854775807 (bigint based)
139              
140             =head1 FAQ
141              
142             =item Why no ON UPDATE CASCADE?
143              
144             Oracle doesn't support it, and for good reason.
145             http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:5773459616034
146              
147             =head1 Known issues
148              
149             =item MySQL floats
150              
151             MySQL uses doubles for internal calculations, so floats may not calculate the
152             same as the other dbs
153              
154             =item Oracle unicode
155              
156             SELECT translated_description FROM product_descriptions
157             WHERE translated_name = N'LCD Monitor 11/PM';
158              
159             =item Oracle auto increment
160              
161             Much more complicated. We automatically create a sequence and trigger
162              
163             # additional code is needed:-
164             #create sequence test_seq
165             #start with 1
166             #increment by 1
167             #nomaxvalue;
168             #
169             #create trigger test_trigger
170             #before insert on my_test
171             #for each row
172             #begin
173             #select test_seq.nextval into :new.id from dual;
174             #end;
175              
176             =item Postgres index names must be unique across tables
177              
178             It appears so. Should we automatically append table name to postgres indexes???
179              
180             =item Oracle dates and times
181              
182             Oracle date fields are different, they include a time and must be formatted.
183             The helper method TODO is provided to eleviate this problem. Oracle also has no
184             native time, we use a timestamp field with date 1000-01-01 to simulate.
185              
186             =item SQL Server serials
187              
188             To explicitly insert a serial, you must first run
189              
190             SET IDENTITY_INSERT "I" ON
191              
192             The helper method TODO is provided to eliviate this problem.
193              
194             =head1 methods
195              
196             =cut
197              
198             =item new
199              
200             $db_schema = new Cosmic::DB::Schema( $dbh );
201              
202             =cut
203              
204             sub new {
205 1     1 1 529 my $class = shift;
206 1         4 my ( $dbh ) = @_;
207 1 50       5 croak( 'No database handle passed' ) unless ref( $dbh ) eq 'DBI::db';
208 1         4 my $self = bless { dbh => $dbh }, $class;
209 1         3 return $self;
210             }#sub
211              
212              
213             =item load
214              
215             $db_schema->load( $schema );
216              
217             =cut
218              
219             sub load {
220 0     0 1   my $self = shift;
221 0           $self->{schema} = $_[0];
222             # TODO load from JSON, YAML, XML
223             # TODO validation
224 0           return $self;
225             }#sub
226              
227              
228             =item create
229              
230             my $ddl = $db_schema->create;
231              
232             =cut
233              
234             sub create {
235 0     0 1   my $self = shift;
236 0           my %options = @_;
237 0           my $schema;
238 0 0 0       if ( $self->{dbh}->{Driver}->{Name} eq 'mysql' || $self->{dbh}->{Driver}->{Name} eq 'mysqlPP' ) {
239 0           require Cosmic::DB::Schema::MySQL;
240 0           $schema = new Cosmic::DB::Schema::MySQL( $self->{dbh} );
241             }#if
242 0 0         if ( $self->{dbh}->{Driver}->{Name} eq 'Pg' ) {
243 0           require Cosmic::DB::Schema::Postgres;
244 0           $schema = new Cosmic::DB::Schema::Postgres( $self->{dbh} );
245             }#if
246 0 0         if ( $self->{dbh}->{Driver}->{Name} eq 'Oracle' ) {
247 0           require Cosmic::DB::Schema::Oracle;
248 0           $schema = new Cosmic::DB::Schema::Oracle( $self->{dbh} );
249             }#if
250 0 0         if ( $self->{dbh}->{Driver}->{Name} eq 'ODBC' ) {
251             # TODO extra ODBC check for SQL Server
252 0           require Cosmic::DB::Schema::SQLServer;
253 0           $schema = new Cosmic::DB::Schema::SQLServer( $self->{dbh} );
254             }#if
255 0 0         if ( $schema ) {
256 0           $options{schema} = $self->{schema};
257 0 0         return wantarray ? ( $schema->producer( %options ) ) : $schema->producer( %options );
258             }#if
259             else {
260 0           croak( "DB $self->{dbh}->{Driver}->{Name} not supported" );
261             }#else
262             }#sub
263              
264              
265             1;