4 use DBIx::Class::Schema::Loader 'make_schema_at';
5 use DBIx::Class::Schema::Loader::Utils qw/no_warnings slurp_file/;
9 use File::Path 'rmtree';
13 use dbixcsl_common_tests ();
14 use dbixcsl_test_dir '$tdir';
16 use constant EXTRA_DUMP_DIR => "$tdir/pg_extra_dump";
18 my $dsn = $ENV{DBICTEST_PG_DSN} || '';
19 my $user = $ENV{DBICTEST_PG_USER} || '';
20 my $password = $ENV{DBICTEST_PG_PASS} || '';
22 my $tester = dbixcsl_common_tests->new(
24 auto_inc_pk => 'SERIAL NOT NULL PRIMARY KEY',
27 password => $password,
28 loader_options => { preserve_case => 1 },
29 connect_info_opts => {
31 on_connect_do => [ 'SET client_min_messages=WARNING' ],
35 # http://www.postgresql.org/docs/7.4/interactive/datatype.html
38 boolean => { data_type => 'boolean' },
39 bool => { data_type => 'boolean' },
41 => { data_type => 'boolean', default_value => \'false' },
43 => { data_type => 'boolean', default_value => \'true' },
44 'bool default 0::bool'
45 => { data_type => 'boolean', default_value => \'false' },
46 'bool default 1::bool'
47 => { data_type => 'boolean', default_value => \'true' },
49 bigint => { data_type => 'bigint' },
50 int8 => { data_type => 'bigint' },
51 bigserial => { data_type => 'bigint', is_auto_increment => 1 },
52 serial8 => { data_type => 'bigint', is_auto_increment => 1 },
53 integer => { data_type => 'integer' },
54 int => { data_type => 'integer' },
55 int4 => { data_type => 'integer' },
56 serial => { data_type => 'integer', is_auto_increment => 1 },
57 serial4 => { data_type => 'integer', is_auto_increment => 1 },
58 smallint => { data_type => 'smallint' },
59 int2 => { data_type => 'smallint' },
61 money => { data_type => 'money' },
63 'double precision' => { data_type => 'double precision' },
64 float8 => { data_type => 'double precision' },
65 real => { data_type => 'real' },
66 float4 => { data_type => 'real' },
67 'float(24)' => { data_type => 'real' },
68 'float(25)' => { data_type => 'double precision' },
69 'float(53)' => { data_type => 'double precision' },
70 float => { data_type => 'double precision' },
72 numeric => { data_type => 'numeric' },
73 decimal => { data_type => 'numeric' },
74 'numeric(6,3)' => { data_type => 'numeric', size => [6,3] },
75 'decimal(6,3)' => { data_type => 'numeric', size => [6,3] },
78 'bit varying(2)' => { data_type => 'varbit', size => 2 },
79 'varbit(2)' => { data_type => 'varbit', size => 2 },
80 'varbit' => { data_type => 'varbit' },
81 bit => { data_type => 'bit', size => 1 },
82 'bit(3)' => { data_type => 'bit', size => 3 },
85 inet => { data_type => 'inet' },
86 cidr => { data_type => 'cidr' },
87 macaddr => { data_type => 'macaddr' },
90 point => { data_type => 'point' },
91 line => { data_type => 'line' },
92 lseg => { data_type => 'lseg' },
93 box => { data_type => 'box' },
94 path => { data_type => 'path' },
95 polygon => { data_type => 'polygon' },
96 circle => { data_type => 'circle' },
99 'character varying(2)' => { data_type => 'varchar', size => 2 },
100 'varchar(2)' => { data_type => 'varchar', size => 2 },
101 'character(2)' => { data_type => 'char', size => 2 },
102 'char(2)' => { data_type => 'char', size => 2 },
103 # check that default null is correctly rewritten
104 'char(3) default null' => { data_type => 'char', size => 3,
105 default_value => \'null' },
106 'character' => { data_type => 'char', size => 1 },
107 'char' => { data_type => 'char', size => 1 },
108 text => { data_type => 'text' },
109 # varchar with no size has unlimited size, we rewrite to 'text'
110 varchar => { data_type => 'text',
111 original => { data_type => 'varchar' } },
112 # check default null again (to make sure ref is safe)
113 'varchar(3) default null' => { data_type => 'varchar', size => 3,
114 default_value => \'null' },
117 date => { data_type => 'date' },
118 interval => { data_type => 'interval' },
119 'interval(2)' => { data_type => 'interval', size => 2 },
120 time => { data_type => 'time' },
121 'time(2)' => { data_type => 'time', size => 2 },
122 'time without time zone' => { data_type => 'time' },
123 'time(2) without time zone' => { data_type => 'time', size => 2 },
124 'time with time zone' => { data_type => 'time with time zone' },
125 'time(2) with time zone' => { data_type => 'time with time zone', size => 2 },
126 timestamp => { data_type => 'timestamp' },
127 'timestamp default now()'
128 => { data_type => 'timestamp', default_value => \'current_timestamp',
129 original => { default_value => \'now()' } },
130 'timestamp(2)' => { data_type => 'timestamp', size => 2 },
131 'timestamp without time zone' => { data_type => 'timestamp' },
132 'timestamp(2) without time zone' => { data_type => 'timestamp', size => 2 },
134 'timestamp with time zone' => { data_type => 'timestamp with time zone' },
135 'timestamp(2) with time zone' => { data_type => 'timestamp with time zone', size => 2 },
138 bytea => { data_type => 'bytea' },
141 pg_loader_test_enum => { data_type => 'enum', extra => { custom_type_name => 'pg_loader_test_enum',
142 list => [ qw/foo bar baz/] } },
146 CREATE TYPE pg_loader_test_enum AS ENUM (
154 CREATE SCHEMA dbicsl_test
157 CREATE SEQUENCE dbicsl_test.myseq
160 CREATE TABLE pg_loader_test1 (
161 id INTEGER NOT NULL DEFAULT nextval('dbicsl_test.myseq') PRIMARY KEY,
166 COMMENT ON TABLE pg_loader_test1 IS 'The\15\12Table ∑'
169 COMMENT ON COLUMN pg_loader_test1.value IS 'The\15\12Column'
172 CREATE TABLE pg_loader_test2 (
173 id SERIAL PRIMARY KEY,
178 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'
181 CREATE SCHEMA "dbicsl-test"
184 CREATE TABLE "dbicsl-test".pg_loader_test4 (
185 id SERIAL PRIMARY KEY,
190 CREATE TABLE "dbicsl-test".pg_loader_test5 (
191 id SERIAL PRIMARY KEY,
193 four_id INTEGER REFERENCES "dbicsl-test".pg_loader_test4 (id),
194 CONSTRAINT loader_test5_uniq UNIQUE (four_id)
198 CREATE SCHEMA "dbicsl.test"
201 CREATE TABLE "dbicsl.test".pg_loader_test5 (
202 pk SERIAL PRIMARY KEY,
204 four_id INTEGER REFERENCES "dbicsl-test".pg_loader_test4 (id),
205 CONSTRAINT loader_test5_uniq UNIQUE (four_id)
209 CREATE TABLE "dbicsl.test".pg_loader_test6 (
210 id SERIAL PRIMARY KEY,
212 pg_loader_test4_id INTEGER REFERENCES "dbicsl-test".pg_loader_test4 (id)
216 CREATE TABLE "dbicsl.test".pg_loader_test7 (
217 id SERIAL PRIMARY KEY,
219 six_id INTEGER UNIQUE REFERENCES "dbicsl.test".pg_loader_test6 (id)
223 CREATE TABLE "dbicsl-test".pg_loader_test8 (
224 id SERIAL PRIMARY KEY,
226 pg_loader_test7_id INTEGER REFERENCES "dbicsl.test".pg_loader_test7 (id)
231 'DROP SCHEMA dbicsl_test CASCADE',
232 'DROP SCHEMA "dbicsl-test" CASCADE',
233 'DROP SCHEMA "dbicsl.test" CASCADE',
234 'DROP TYPE pg_loader_test_enum',
236 drop => [ qw/ pg_loader_test1 pg_loader_test2 / ],
239 my ($schema, $monikers, $classes) = @_;
241 is $schema->source($monikers->{pg_loader_test1})->column_info('id')->{sequence},
243 'qualified sequence detected';
245 my $class = $classes->{pg_loader_test1};
246 my $filename = $schema->loader->get_dump_filename($class);
248 my $code = slurp_file $filename;
250 like $code, qr/^=head1 NAME\n\n^$class - The\nTable ∑\n\n^=cut\n/m,
253 like $code, qr/^=head2 value\n\n(.+:.+\n)+\nThe\nColumn\n\n/m,
254 'column comment and attrs';
256 $class = $classes->{pg_loader_test2};
257 $filename = $schema->loader->get_dump_filename($class);
259 $code = slurp_file $filename;
261 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,
262 'long table comment is in DESCRIPTION';
264 foreach my $db_schema (['dbicsl-test', 'dbicsl.test'], '%') {
266 rmtree EXTRA_DUMP_DIR;
269 local $SIG{__WARN__} = sub {
270 push @warns, $_[0] unless $_[0] =~ /\bcollides\b/;
277 db_schema => $db_schema,
278 moniker_parts => [qw/schema name/],
280 dump_directory => EXTRA_DUMP_DIR,
283 [ $dsn, $user, $password, {
284 on_connect_do => [ 'SET client_min_messages=WARNING' ],
288 diag join "\n", @warns if @warns;
291 } 'dumped schema for "dbicsl-test" and "dbicsl.test" schemas with no warnings';
293 my ($test_schema, $rsrc, $rs, $row, %uniqs, $rel_info);
296 ok $test_schema = PGMultiSchema->connect($dsn, $user, $password, {
297 on_connect_do => [ 'SET client_min_messages=WARNING' ],
299 } 'connected test schema';
302 ok $rsrc = $test_schema->source('DbicslDashTestPgLoaderTest4');
303 } 'got source for table in schema name with dash';
305 is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
306 'column in schema name with dash';
308 is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
309 'column in schema name with dash';
311 is try { $rsrc->column_info('value')->{size} }, 100,
312 'column in schema name with dash';
315 ok $rs = $test_schema->resultset('DbicslDashTestPgLoaderTest4');
316 } 'got resultset for table in schema name with dash';
319 ok $row = $rs->create({ value => 'foo' });
320 } 'executed SQL on table in schema name with dash';
322 $rel_info = try { $rsrc->relationship_info('dbicsl_dash_test_pg_loader_test5') };
324 is_deeply $rel_info->{cond}, {
325 'foreign.four_id' => 'self.id'
326 }, 'relationship in schema name with dash';
328 is $rel_info->{attrs}{accessor}, 'single',
329 'relationship in schema name with dash';
331 is $rel_info->{attrs}{join_type}, 'LEFT',
332 'relationship in schema name with dash';
335 ok $rsrc = $test_schema->source('DbicslDashTestPgLoaderTest5');
336 } 'got source for table in schema name with dash';
338 %uniqs = try { $rsrc->unique_constraints };
341 'got unique and primary constraint in schema name with dash';
343 delete $uniqs{primary};
345 is_deeply ((values %uniqs)[0], ['four_id'],
346 'unique constraint is correct in schema name with dash');
349 ok $rsrc = $test_schema->source('DbicslDotTestPgLoaderTest6');
350 } 'got source for table in schema name with dot';
352 is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
353 'column in schema name with dot introspected correctly';
355 is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
356 'column in schema name with dot introspected correctly';
358 is try { $rsrc->column_info('value')->{size} }, 100,
359 'column in schema name with dot introspected correctly';
362 ok $rs = $test_schema->resultset('DbicslDotTestPgLoaderTest6');
363 } 'got resultset for table in schema name with dot';
366 ok $row = $rs->create({ value => 'foo' });
367 } 'executed SQL on table in schema name with dot';
369 $rel_info = try { $rsrc->relationship_info('pg_loader_test7') };
371 is_deeply $rel_info->{cond}, {
372 'foreign.six_id' => 'self.id'
373 }, 'relationship in schema name with dot';
375 is $rel_info->{attrs}{accessor}, 'single',
376 'relationship in schema name with dot';
378 is $rel_info->{attrs}{join_type}, 'LEFT',
379 'relationship in schema name with dot';
382 ok $rsrc = $test_schema->source('DbicslDotTestPgLoaderTest7');
383 } 'got source for table in schema name with dot';
385 %uniqs = try { $rsrc->unique_constraints };
388 'got unique and primary constraint in schema name with dot';
390 delete $uniqs{primary};
392 is_deeply ((values %uniqs)[0], ['six_id'],
393 'unique constraint is correct in schema name with dot');
396 ok $test_schema->source('DbicslDotTestPgLoaderTest6')
397 ->has_relationship('pg_loader_test4');
398 } 'cross-schema relationship in multi-db_schema';
401 ok $test_schema->source('DbicslDashTestPgLoaderTest4')
402 ->has_relationship('pg_loader_test6s');
403 } 'cross-schema relationship in multi-db_schema';
406 ok $test_schema->source('DbicslDashTestPgLoaderTest8')
407 ->has_relationship('pg_loader_test7');
408 } 'cross-schema relationship in multi-db_schema';
411 ok $test_schema->source('DbicslDotTestPgLoaderTest7')
412 ->has_relationship('pg_loader_test8s');
413 } 'cross-schema relationship in multi-db_schema';
419 if( !$dsn || !$user ) {
420 $tester->skip_tests('You need to set the DBICTEST_PG_DSN, _USER, and _PASS environment variables');
423 $tester->run_tests();
427 rmtree EXTRA_DUMP_DIR unless $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP};
429 # vim:et sw=4 sts=4 tw=0: