Fixed some typos, added some basic re-logicing (is that even a word?)
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Validator.pm
CommitLineData
e2158c40 1package SQL::Translator::Validator;
2
3# ----------------------------------------------------------------------
38254289 4# $Id: Validator.pm,v 1.3 2002-06-11 12:09:13 dlc Exp $
e2158c40 5# ----------------------------------------------------------------------
6# Copyright (C) 2002 Ken Y. Clark <kycl4rk@users.sourceforge.net>,
7# darren chamberlain <darren@cpan.org>
8#
9# This program is free software; you can redistribute it and/or
10# modify it under the terms of the GNU General Public License as
11# published by the Free Software Foundation; version 2.
12#
13# This program is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16# General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21# 02111-1307 USA
22# ----------------------------------------------------------------------
23
24use strict;
25use vars qw($VERSION @EXPORT);
38254289 26$VERSION = sprintf "%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
e2158c40 27
28use Exporter;
29use base qw(Exporter);
30@EXPORT = qw(validate);
31
32use Data::Dumper;
33
34sub by_context($$$) { ($_[0]) ? ($_[1], $_[2]) : $_[1]; }
35
9398955f 36# XXX If called in scalar context, then validate should *not*
37# genertate or return $log. It's a lot of extra work if we know we
38# are not going to use it.
e2158c40 39sub validate {
40 my $data = shift;
41 my $wa = wantarray;
42 my ($ok, $log);
43
44 unless (ref $data) {
45 return by_context $wa, 0, "Not a reference";
46 }
47
48 unless (UNIVERSAL::isa($data, "HASH")) {
49 return by_context $wa, 0, "Not a HASH reference";
50 } else {
51 my $num = scalar keys %{$data};
52 $log = sprintf "Contains %d table%s.", $num, ($num == 1 ? "" : "s");
53 }
54
55 my @tables = sort keys %{$data};
56 for (my $i = 0; $i < @tables; $i++) {
57 my $table = $tables[$i];
58 my $table_num = $i + 1;
59
60 $log .= "\nTable $table_num: $table";
61 my $table_data = $data->{$table};
62
63 # Table must be a hashref
64 unless (UNIVERSAL::isa($table_data, "HASH")) {
65 return by_context $wa, 0,
66 "Table `$table' is not a HASH reference";
67 }
68
69 # Table must contain three elements: type, indeces, and fields
70 # XXX If there are other keys, is this an error?
71 unless (exists $table_data->{"type"}) {
72 return by_context $wa, 0, "Missing type for table `$table'";
73 } else {
74 $log .= sprintf "\n\tType: %s", $table_data->{"type"} ||
75 "not defined";
76 }
77
38254289 78 # Indices: array of hashes
e2158c40 79 unless (defined $table_data->{"indeces"} &&
80 UNIVERSAL::isa($table_data->{"indeces"}, "ARRAY")) {
38254289 81 return by_context $wa, 0, "Indices is missing or is not an ARRAY";
e2158c40 82 } else {
83 my @indeces = @{$table_data->{"indeces"}};
38254289 84 $log .= "\n\tIndices:";
e2158c40 85 if (@indeces) {
86 for my $index (@indeces) {
87 $log .= "\n\t\t" . ($index->{"name"} || "(unnamed)")
88 . " on "
89 . join ", ", @{$index->{"fields"}};
90 }
91 } else {
92 $log .= " none defined";
93 }
94 }
95
96 # Fields
97 unless (defined $table_data->{"fields"} &&
98 UNIVERSAL::isa($table_data->{"fields"}, "HASH")) {
99 return by_context $wa, 0, "Fields is missing or is not a HASH";
100 } else {
101 $log .= "\n\tFields:";
102 my @fields = sort { $table_data->{$a}->{"order"} <=>
103 $table_data->{$b}->{"order"}
104 } keys %{$table_data->{"fields"}};
105 for my $field (@fields) {
106 my $field_data = $table_data->{"fields"}->{$field};
107 $log .= qq|\n\t\t$field_data->{"name"}|
108 . qq| $field_data->{"data_type"} ($field_data->{"size"})|;
109 $log .= qq|\n\t\t\tDefault: $field_data->{"default"}|
110 if length $field_data->{"default"};
111 $log .= sprintf qq|\n\t\t\tNull: %s|,
112 $field_data->{"null"} ? "yes" : "no";
113 }
114 }
115 }
116
117 $log .= "\n";
118
119 return by_context $wa, 1, $log;
120}
121
122
1231;
124__END__
125
126=head1 NAME
127
128SQL::Translator::Validate - Validate that a data structure is correct
129
130=head1 SYNOPSIS
131
132 print "1..1\n";
133
134 use SQL::Translator;
135 use SQL::Translator::Validator;
136
137 my $tr = SQL::Translator->new(parser => "My::Swell::Parser");
138
139 # Default producer passes the data structure through unchanged
140 my $parsed = $tr->translate($datafile);
141
142 print "not " unless validate($parsed);
143 print "ok 1 # data structure looks OK\n";
144
145=head1 DESCRIPTION
146
147When writing a parser module for SQL::Translator, it is helpful to
148have a tool to automatically check the return of your module, to make
149sure that it is returning the Right Thing. While only a full Producer
38254289 150and the associated database can determine if you are producing valid
e2158c40 151output, SQL::Translator::Validator can tell you if the basic format of
152the data structure is correct. While this will not catch many errors,
153it will catch the basic ones.
154
155SQL::Translator::Validator can be used as a development tool, a
156testing tool (every SQL::Translator install will have this module),
157or, potentially, even as a runtime assertion for producers you don't
158trust:
159
160 $tr->producer(\&paranoid_producer);
161 sub paranoid_producer {
162 my ($tr, $data) = @_;
163 return unless validate($data);
164
165 # continue...
166
9398955f 167SQL::Translator::Validator can also be used as a reporting tool. When
168B<validate> is called in a list context, the second value returned
169(assuming the data structure is well-formed) is a summary of the
170table's information. For example, the following table definition
171(MySQL format):
172
173 CREATE TABLE random (
174 id int(11) not null default 1,
175 seed char(32) not null default 1
176 );
177
178 CREATE TABLE session (
179 foo char(255),
180 id int(11) not null default 1 primary key
181 ) TYPE=HEAP;
182
183Produces the following summary:
184
185 Contains 2 tables.
186 Table 1: random
187 Type: not defined
38254289 188 Indices: none defined
9398955f 189 Fields:
190 id int (11)
191 Default: 1
192 Null: no
193 seed char (32)
194 Default: 1
195 Null: no
196 Table 2: session
197 Type: HEAP
38254289 198 Indices:
9398955f 199 (unnamed) on id
200 Fields:
201 foo char (255)
202 Null: yes
203 id int (11)
204 Default: 1
205 Null: no
206
207
e2158c40 208=head1 EXPORTED FUNCTIONS
209
210SQL::Translator::Validator exports a single function, called
211B<validate>, which expects a data structure as its only argument.
212When called in scalar context, it returns a 1 (valid data structure)
213or 0 (not a valid data structure). In list context, B<validate>
214returns a 2 element list: the first element is a 1 or 0, as in scalar
215context, and the second value is a reason (for a malformed data
216structure) or a summary of the data (for a well-formed data
217structure).
218
219=head1 TODO
220
221=over 4
222
223=item *
224
225color, either via Term::ANSI, or something along those lines, or just
226plain $RED = "\033[31m" type stuff.
227
228=back
229
230=head1 AUTHOR
231
232darren chamberlain E<lt>darren@cpan.orgE<gt>