better option validation for result_component_map, result_role_map and rel_collision_map
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / 10_03pg_common.t
1 use strict;
2 use lib qw(t/lib);
3 use DBIx::Class::Schema::Loader 'make_schema_at';
4 use DBIx::Class::Schema::Loader::Utils 'no_warnings';
5 use dbixcsl_common_tests;
6 use Test::More;
7 use Test::Exception;
8 use File::Slurp 'slurp';
9 use utf8;
10 use Encode 'decode';
11 use Try::Tiny;
12
13 my $dsn      = $ENV{DBICTEST_PG_DSN} || '';
14 my $user     = $ENV{DBICTEST_PG_USER} || '';
15 my $password = $ENV{DBICTEST_PG_PASS} || '';
16
17 my $tester = dbixcsl_common_tests->new(
18     vendor      => 'Pg',
19     auto_inc_pk => 'SERIAL NOT NULL PRIMARY KEY',
20     dsn         => $dsn,
21     user        => $user,
22     password    => $password,
23     loader_options  => { preserve_case => 1 },
24     connect_info_opts => {
25         pg_enable_utf8 => 1,
26         on_connect_do  => [ 'SET client_min_messages=WARNING' ],
27     },
28     quote_char  => '"',
29     data_types  => {
30         # http://www.postgresql.org/docs/7.4/interactive/datatype.html
31         #
32         # Numeric Types
33         boolean     => { data_type => 'boolean' },
34         bool        => { data_type => 'boolean' },
35         'bool default false'
36                     => { data_type => 'boolean', default_value => \'false' },
37
38         bigint      => { data_type => 'bigint' },
39         int8        => { data_type => 'bigint' },
40         bigserial   => { data_type => 'bigint', is_auto_increment => 1 },
41         serial8     => { data_type => 'bigint', is_auto_increment => 1 },
42         integer     => { data_type => 'integer' },
43         int         => { data_type => 'integer' },
44         int4        => { data_type => 'integer' },
45         serial      => { data_type => 'integer', is_auto_increment => 1 },
46         serial4     => { data_type => 'integer', is_auto_increment => 1 },
47         smallint    => { data_type => 'smallint' },
48         int2        => { data_type => 'smallint' },
49
50         money       => { data_type => 'money' },
51
52         'double precision' => { data_type => 'double precision' },
53         float8             => { data_type => 'double precision' },
54         real               => { data_type => 'real' },
55         float4             => { data_type => 'real' },
56         'float(24)'        => { data_type => 'real' },
57         'float(25)'        => { data_type => 'double precision' },
58         'float(53)'        => { data_type => 'double precision' },
59         float              => { data_type => 'double precision' },
60
61         numeric        => { data_type => 'numeric' },
62         decimal        => { data_type => 'numeric' },
63         'numeric(6,3)' => { data_type => 'numeric', size => [6,3] },
64         'decimal(6,3)' => { data_type => 'numeric', size => [6,3] },
65
66         # Bit String Types
67         'bit varying(2)' => { data_type => 'varbit', size => 2 },
68         'varbit(2)'      => { data_type => 'varbit', size => 2 },
69         'varbit'         => { data_type => 'varbit' },
70         bit              => { data_type => 'bit', size => 1 },
71         'bit(3)'         => { data_type => 'bit', size => 3 },
72
73         # Network Types
74         inet    => { data_type => 'inet' },
75         cidr    => { data_type => 'cidr' },
76         macaddr => { data_type => 'macaddr' },
77
78         # Geometric Types
79         point   => { data_type => 'point' },
80         line    => { data_type => 'line' },
81         lseg    => { data_type => 'lseg' },
82         box     => { data_type => 'box' },
83         path    => { data_type => 'path' },
84         polygon => { data_type => 'polygon' },
85         circle  => { data_type => 'circle' },
86
87         # Character Types
88         'character varying(2)'           => { data_type => 'varchar', size => 2 },
89         'varchar(2)'                     => { data_type => 'varchar', size => 2 },
90         'character(2)'                   => { data_type => 'char', size => 2 },
91         'char(2)'                        => { data_type => 'char', size => 2 },
92         'character'                      => { data_type => 'char', size => 1 },
93         'char'                           => { data_type => 'char', size => 1 },
94         text                             => { data_type => 'text' },
95         # varchar with no size has unlimited size, we rewrite to 'text'
96         varchar                          => { data_type => 'text',
97                                               original => { data_type => 'varchar' } },
98
99         # Datetime Types
100         date                             => { data_type => 'date' },
101         interval                         => { data_type => 'interval' },
102         'interval(2)'                    => { data_type => 'interval', size => 2 },
103         time                             => { data_type => 'time' },
104         'time(2)'                        => { data_type => 'time', size => 2 },
105         'time without time zone'         => { data_type => 'time' },
106         'time(2) without time zone'      => { data_type => 'time', size => 2 },
107         'time with time zone'            => { data_type => 'time with time zone' },
108         'time(2) with time zone'         => { data_type => 'time with time zone', size => 2 },
109         timestamp                        => { data_type => 'timestamp' },
110         'timestamp default now()'
111                                          => { data_type => 'timestamp', default_value => \'current_timestamp',
112                                               original => { default_value => \'now()' } },
113         'timestamp(2)'                   => { data_type => 'timestamp', size => 2 },
114         'timestamp without time zone'    => { data_type => 'timestamp' },
115         'timestamp(2) without time zone' => { data_type => 'timestamp', size => 2 },
116
117         'timestamp with time zone'       => { data_type => 'timestamp with time zone' },
118         'timestamp(2) with time zone'    => { data_type => 'timestamp with time zone', size => 2 },
119
120         # Blob Types
121         bytea => { data_type => 'bytea' },
122
123         # Enum Types
124         pg_loader_test_enum => { data_type => 'enum', extra => { custom_type_name => 'pg_loader_test_enum',
125                                                                  list => [ qw/foo bar baz/] } },
126     },
127     pre_create => [
128         q{
129             CREATE TYPE pg_loader_test_enum AS ENUM (
130                 'foo', 'bar', 'baz'
131             )
132         },
133     ],
134     extra       => {
135         create => [
136             q{
137                 CREATE SCHEMA dbicsl_test
138             },
139             q{
140                 CREATE SEQUENCE dbicsl_test.myseq
141             },
142             q{
143                 CREATE TABLE pg_loader_test1 (
144                     id INTEGER NOT NULL DEFAULT nextval('dbicsl_test.myseq') PRIMARY KEY,
145                     value VARCHAR(100)
146                 )
147             },
148             qq{
149                 COMMENT ON TABLE pg_loader_test1 IS 'The\15\12Table ∑'
150             },
151             qq{
152                 COMMENT ON COLUMN pg_loader_test1.value IS 'The\15\12Column'
153             },
154             q{
155                 CREATE TABLE pg_loader_test2 (
156                     id SERIAL PRIMARY KEY,
157                     value VARCHAR(100)
158                 )
159             },
160             q{
161                 COMMENT ON TABLE pg_loader_test2 IS 'very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long comment'
162             },
163             q{
164                 CREATE SCHEMA "dbicsl-test"
165             },
166             q{
167                 CREATE TABLE "dbicsl-test".pg_loader_test3 (
168                     id SERIAL PRIMARY KEY,
169                     value VARCHAR(100)
170                 )
171             },
172             q{
173                 CREATE TABLE "dbicsl-test".pg_loader_test4 (
174                     id SERIAL PRIMARY KEY,
175                     value VARCHAR(100),
176                     three_id INTEGER UNIQUE REFERENCES "dbicsl-test".pg_loader_test3 (id)
177                 )
178             },
179             q{
180                 CREATE SCHEMA "dbicsl.test"
181             },
182             q{
183                 CREATE TABLE "dbicsl.test".pg_loader_test5 (
184                     id SERIAL PRIMARY KEY,
185                     value VARCHAR(100)
186                 )
187             },
188             q{
189                 CREATE TABLE "dbicsl.test".pg_loader_test6 (
190                     id SERIAL PRIMARY KEY,
191                     value VARCHAR(100),
192                     five_id INTEGER UNIQUE REFERENCES "dbicsl.test".pg_loader_test5 (id)
193                 )
194             },
195         ],
196         pre_drop_ddl => [
197             'DROP SCHEMA dbicsl_test CASCADE',
198             'DROP SCHEMA "dbicsl-test" CASCADE',
199             'DROP SCHEMA "dbicsl.test" CASCADE',
200             'DROP TYPE pg_loader_test_enum',
201         ],
202         drop  => [ qw/ pg_loader_test1 pg_loader_test2 / ],
203         count => 24,
204         run   => sub {
205             my ($schema, $monikers, $classes) = @_;
206
207             is $schema->source($monikers->{pg_loader_test1})->column_info('id')->{sequence},
208                 'dbicsl_test.myseq',
209                 'qualified sequence detected';
210
211             my $class    = $classes->{pg_loader_test1};
212             my $filename = $schema->_loader->get_dump_filename($class);
213
214             my $code = decode('UTF-8', scalar slurp $filename);
215
216             like $code, qr/^=head1 NAME\n\n^$class - The\nTable ∑\n\n^=cut\n/m,
217                 'table comment';
218
219             like $code, qr/^=head2 value\n\n(.+:.+\n)+\nThe\nColumn\n\n/m,
220                 'column comment and attrs';
221
222             $class    = $classes->{pg_loader_test2};
223             $filename = $schema->_loader->get_dump_filename($class);
224
225             $code = decode('UTF-8', scalar slurp $filename);
226
227             like $code, qr/^=head1 NAME\n\n^$class\n\n=head1 DESCRIPTION\n\n^very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long comment\n\n^=cut\n/m,
228                 'long table comment is in DESCRIPTION';
229
230             lives_and {
231                 no_warnings {
232                     make_schema_at(
233                         'PGSchemaWithDash',
234                         {
235                             naming => 'current',
236                             preserve_case => 1,
237                             db_schema => 'dbicsl-test'
238                         },
239                         [ $dsn, $user, $password, {
240                             on_connect_do  => [ 'SET client_min_messages=WARNING' ],
241                         } ],
242                     );
243                 };
244             } 'created dynamic schema for "dbicsl-test" with no warnings';
245
246             my ($rsrc, %uniqs, $rel_info);
247
248             lives_and {
249                 ok $rsrc = PGSchemaWithDash->source('PgLoaderTest3');
250             } 'got source for table in schema name with dash';
251
252             is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
253                 'column in schema name with dash';
254
255             is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
256                 'column in schema name with dash';
257
258             is try { $rsrc->column_info('value')->{size} }, 100,
259                 'column in schema name with dash';
260
261             $rel_info = try { $rsrc->relationship_info('pg_loader_test4') };
262
263             is_deeply $rel_info->{cond}, {
264                 'foreign.three_id' => 'self.id'
265             }, 'relationship in schema name with dash';
266
267             is $rel_info->{attrs}{accessor}, 'single',
268                 'relationship in schema name with dash';
269
270             is $rel_info->{attrs}{join_type}, 'LEFT',
271                 'relationship in schema name with dash';
272
273             lives_and {
274                 ok $rsrc = PGSchemaWithDash->source('PgLoaderTest4');
275             } 'got source for table in schema name with dash';
276
277             %uniqs = try { $rsrc->unique_constraints };
278
279             is keys %uniqs, 2,
280                 'got unique and primary constraint in schema name with dash';
281
282             lives_and {
283                 no_warnings {
284                     make_schema_at(
285                         'PGSchemaWithDot',
286                         {
287                             naming => 'current',
288                             preserve_case => 1,
289                             db_schema => 'dbicsl.test'
290                         },
291                         [ $dsn, $user, $password, {
292                             on_connect_do  => [ 'SET client_min_messages=WARNING' ],
293                         } ],
294                     );
295                 };
296             } 'created dynamic schema for "dbicsl.test" with no warnings';
297
298             lives_and {
299                 ok $rsrc = PGSchemaWithDot->source('PgLoaderTest5');
300             } 'got source for table in schema name with dot';
301
302             is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
303                 'column in schema name with dot introspected correctly';
304
305             is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
306                 'column in schema name with dash introspected correctly';
307
308             is try { $rsrc->column_info('value')->{size} }, 100,
309                 'column in schema name with dash introspected correctly';
310
311             $rel_info = try { $rsrc->relationship_info('pg_loader_test6') };
312
313             is_deeply $rel_info->{cond}, {
314                 'foreign.five_id' => 'self.id'
315             }, 'relationship in schema name with dot';
316
317             is $rel_info->{attrs}{accessor}, 'single',
318                 'relationship in schema name with dot';
319
320             is $rel_info->{attrs}{join_type}, 'LEFT',
321                 'relationship in schema name with dot';
322
323             lives_and {
324                 ok $rsrc = PGSchemaWithDot->source('PgLoaderTest6');
325             } 'got source for table in schema name with dot';
326
327             %uniqs = try { $rsrc->unique_constraints };
328
329             is keys %uniqs, 2,
330                 'got unique and primary constraint in schema name with dot';
331
332         },
333     },
334 );
335
336 if( !$dsn || !$user ) {
337     $tester->skip_tests('You need to set the DBICTEST_PG_DSN, _USER, and _PASS environment variables');
338 }
339 else {
340     $tester->run_tests();
341 }
342 # vim:et sw=4 sts=4 tw=0: