Added collection tags for the Schemas objects (tables, views, etc)
Mark Addison [Thu, 19 Aug 2004 14:09:00 +0000 (14:09 +0000)]
lib/SQL/Translator/Parser/XML/SQLFairy.pm
lib/SQL/Translator/Producer/XML/SQLFairy.pm
t/17sqlfxml-producer.t
t/data/xml/schema.xml

index f8af966..d4a06ad 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Parser::XML::SQLFairy;
 
 # -------------------------------------------------------------------
-# $Id: SQLFairy.pm,v 1.8 2004-07-09 00:50:06 grommit Exp $
+# $Id: SQLFairy.pm,v 1.9 2004-08-19 14:08:59 grommit Exp $
 # -------------------------------------------------------------------
 # Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
 #
@@ -103,7 +103,7 @@ To convert your old format files simply pass them through the translator;
 use strict;
 
 use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.8 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.9 $ =~ /(\d+)\.(\d+)/;
 $DEBUG   = 0 unless defined $DEBUG;
 
 use Data::Dumper;
@@ -127,7 +127,9 @@ sub parse {
     #
     # Work our way through the tables
     #
-    my @nodes = $xp->findnodes('/sqlf:schema/sqlf:table');
+    my @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:table|/sqlf:schema/sqlf:tables/sqlf:table'
+    );
     for my $tblnode (
         sort {
             "".$xp->findvalue('sqlf:order|@order',$a)
@@ -207,7 +209,9 @@ sub parse {
     #
     # Views
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:view');
+    @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:view|/sqlf:schema/sqlf:views/sqlf:view'
+    );
     foreach (@nodes) {
         my %data = get_tagfields($xp, $_, "sqlf:",
             qw/name sql fields order/
@@ -218,7 +222,9 @@ sub parse {
     #
     # Triggers
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:trigger');
+    @nodes = $xp->findnodes(
+        '/sqlf:schema/sqlf:trigger|/sqlf:schema/sqlf:triggers/sqlf:trigger'
+    );
     foreach (@nodes) {
         my %data = get_tagfields($xp, $_, "sqlf:",
         qw/name perform_action_when database_event fields on_table action order/
@@ -229,7 +235,9 @@ sub parse {
     #
     # Procedures
     #
-    @nodes = $xp->findnodes('/sqlf:schema/sqlf:procedure');
+    @nodes = $xp->findnodes(
+       '/sqlf:schema/sqlf:procedure|/sqlf:schema/sqlf:procedures/sqlf:procedure'
+    );
     foreach (@nodes) {
         my %data = get_tagfields($xp, $_, "sqlf:",
         qw/name sql parameters owner comments order/
index c956383..73fa851 100644 (file)
@@ -1,7 +1,7 @@
 package SQL::Translator::Producer::XML::SQLFairy;
 
 # -------------------------------------------------------------------
-# $Id: SQLFairy.pm,v 1.16 2004-08-18 20:27:58 grommit Exp $
+# $Id: SQLFairy.pm,v 1.17 2004-08-19 14:09:00 grommit Exp $
 # -------------------------------------------------------------------
 # Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>,
 #                    darren chamberlain <darren@cpan.org>,
@@ -163,7 +163,7 @@ To convert your old format files simply pass them through the translator;
 
 use strict;
 use vars qw[ $VERSION @EXPORT_OK ];
-$VERSION = sprintf "%d.%02d", q$Revision: 1.16 $ =~ /(\d+)\.(\d+)/;
+$VERSION = sprintf "%d.%02d", q$Revision: 1.17 $ =~ /(\d+)\.(\d+)/;
 
 use Exporter;
 use base qw(Exporter);
@@ -217,85 +217,74 @@ sub produce {
     #
     # Table
     #
+    $xml->startTag( [ $Namespace => "tables" ] );
     for my $table ( $schema->get_tables ) {
         debug "Table:",$table->name;
         xml_obj($xml, $table,
-             tag => "table", methods => [qw/name order/], end_tag => 0 );
+             tag => "table",
+             methods => [qw/name order/],
+             end_tag => 0
+         );
 
         #
         # Fields
         #
-        $xml->startTag( [ $Namespace => 'fields' ] );
-        for my $field ( $table->get_fields ) {
-            debug "    Field:",$field->name;
-            xml_obj($xml, $field,
-                tag     =>"field",
-                end_tag => 1,
-                methods =>[qw/name data_type size is_nullable default_value
-                    is_auto_increment is_primary_key is_foreign_key extra comments order
-                /],
-            );
-        }
-        $xml->endTag( [ $Namespace => 'fields' ] );
+        xml_obj_children( $xml, $table,
+            tag   => 'field',
+            methods =>[qw/
+                name data_type size is_nullable default_value is_auto_increment
+                is_primary_key is_foreign_key extra comments order
+            /],
+        );
 
         #
         # Indices
         #
-        $xml->startTag( [ $Namespace => 'indices' ] );
-        for my $index ( $table->get_indices ) {
-            debug "Index:",$index->name;
-            xml_obj($xml, $index,
-                tag     => "index",
-                end_tag => 1,
-                methods =>[qw/ name type fields options/],
-            );
-        }
-        $xml->endTag( [ $Namespace => 'indices' ] );
+        xml_obj_children( $xml, $table,
+            tag   => 'index',
+            collection_tag => "indices",
+            methods => [qw/name type fields options/],
+        );
 
         #
         # Constraints
         #
-        $xml->startTag( [ $Namespace => 'constraints' ] );
-        for my $index ( $table->get_constraints ) {
-            debug "Constraint:",$index->name;
-            xml_obj($xml, $index,
-                tag     => "constraint",
-                end_tag => 1,
-                methods =>[qw/
-                    name type fields reference_table reference_fields
-                    on_delete on_update match_type expression options deferrable
-                    /],
-            );
-        }
-        $xml->endTag( [ $Namespace => 'constraints' ] );
+        xml_obj_children( $xml, $table,
+            tag   => 'constraint',
+            methods => [qw/
+                name type fields reference_table reference_fields
+                on_delete on_update match_type expression options deferrable
+            /],
+        );
 
         $xml->endTag( [ $Namespace => 'table' ] );
     }
+    $xml->endTag( [ $Namespace => 'tables' ] );
 
     #
     # Views
     #
-    for my $foo ( $schema->get_views ) {
-        xml_obj($xml, $foo, tag => "view",
-        methods => [qw/name sql fields order/], end_tag => 1 );
-    }
+    xml_obj_children( $xml, $schema,
+        tag   => 'view',
+        methods => [qw/name sql fields order/],
+    );
 
     #
     # Tiggers
     #
-    for my $foo ( $schema->get_triggers ) {
-        xml_obj($xml, $foo, tag => "trigger",
+    xml_obj_children( $xml, $schema,
+        tag    => 'trigger',
         methods => [qw/name database_event action on_table perform_action_when
-        fields order/], end_tag => 1 );
-    }
+            fields order/],
+    );
 
     #
     # Procedures
     #
-    for my $foo ( $schema->get_procedures ) {
-        xml_obj($xml, $foo, tag => "procedure",
-        methods => [qw/name sql parameters owner comments order/], end_tag=>1 );
-    }
+    xml_obj_children( $xml, $schema,
+        tag   => 'procedure',
+        methods => [qw/name sql parameters owner comments order/],
+    );
 
     $xml->endTag([ $Namespace => 'schema' ]);
     $xml->end;
@@ -303,11 +292,40 @@ sub produce {
     return $io;
 }
 
-# -------------------------------------------------------------------
+
+#
+# Takes and XML::Write object, Schema::* parent object, the tag name,
+# the collection name and a list of methods (of the children) to write as XML.
+# The collection name defaults to the name with an s on the end and is used to
+# work out the method to get the children with. eg a name of 'foo' gives a
+# collection of foos and gets the members using ->get_foos.
+#
+sub xml_obj_children {
+    my ($xml,$parent) = (shift,shift);
+    my %args = @_;
+    my ($name,$collection_name,$methods)
+        = @args{qw/tag collection_tag methods/};
+    $collection_name ||= "${name}s";
+    my $meth = "get_$collection_name";
+
+    my @kids = $parent->$meth;
+    #@kids || return;
+    $xml->startTag( [ $Namespace => $collection_name ] );
+    for my $obj ( @kids ) {
+        xml_obj($xml, $obj,
+            tag     => "$name",
+            end_tag => 1,
+            methods => $methods,
+        );
+    }
+    $xml->endTag( [ $Namespace => $collection_name ] );
+}
+
 #
 # Takes an XML::Writer, Schema::* object and list of method names
 # and writes the obect out as XML. All methods values are written as attributes
-# except for comments, sql and action which get written as child data elements.
+# except for the methods listed in @MAP_AS_ELEMENTS which get written as child
+# data elements.
 #
 # The attributes/tags are written in the same order as the method names are
 # passed.
index 3f39727..091bee1 100644 (file)
@@ -30,7 +30,7 @@ local $SIG{__WARN__} = sub {
 #=============================================================================
 
 BEGIN {
-    maybe_plan(15,
+    maybe_plan(14,
         'XML::Writer',
         'Test::Differences',
         'SQL::Translator::Producer::XML::SQLFairy');
@@ -48,33 +48,38 @@ my ($obj,$ans,$xml);
 
 $ans = <<EOXML;
 <schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
-  <table name="Basic" order="1">
-    <fields>
-      <field name="id" data_type="integer" size="10" is_nullable="0" is_auto_increment="1" is_primary_key="1" is_foreign_key="0" order="1">
-        <extra />
-        <comments>comment on id field</comments>
-      </field>
-      <field name="title" data_type="varchar" size="100" is_nullable="0" default_value="hello" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="2">
-        <extra />
-        <comments></comments>
-      </field>
-      <field name="description" data_type="text" size="65535" is_nullable="1" default_value="" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="3">
-        <extra />
-        <comments></comments>
-      </field>
-      <field name="email" data_type="varchar" size="255" is_nullable="1" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="4">
-        <extra />
-        <comments></comments>
-      </field>
-    </fields>
-    <indices>
-      <index name="titleindex" type="NORMAL" fields="title" options="" />
-    </indices>
-    <constraints>
-      <constraint name="" type="PRIMARY KEY" fields="id" reference_table="" reference_fields="" on_delete="" on_update="" match_type="" expression="" options="" deferrable="1" />
-      <constraint name="" type="UNIQUE" fields="email" reference_table="" reference_fields="" on_delete="" on_update="" match_type="" expression="" options="" deferrable="1" />
-    </constraints>
-  </table>
+  <tables>
+    <table name="Basic" order="1">
+      <fields>
+        <field name="id" data_type="integer" size="10" is_nullable="0" is_auto_increment="1" is_primary_key="1" is_foreign_key="0" order="1">
+          <extra />
+          <comments>comment on id field</comments>
+        </field>
+        <field name="title" data_type="varchar" size="100" is_nullable="0" default_value="hello" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="2">
+          <extra />
+          <comments></comments>
+        </field>
+        <field name="description" data_type="text" size="65535" is_nullable="1" default_value="" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="3">
+          <extra />
+          <comments></comments>
+        </field>
+        <field name="email" data_type="varchar" size="255" is_nullable="1" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="4">
+          <extra />
+          <comments></comments>
+        </field>
+      </fields>
+      <indices>
+        <index name="titleindex" type="NORMAL" fields="title" options="" />
+      </indices>
+      <constraints>
+        <constraint name="" type="PRIMARY KEY" fields="id" reference_table="" reference_fields="" on_delete="" on_update="" match_type="" expression="" options="" deferrable="1" />
+        <constraint name="" type="UNIQUE" fields="email" reference_table="" reference_fields="" on_delete="" on_update="" match_type="" expression="" options="" deferrable="1" />
+      </constraints>
+    </table>
+  </tables>
+  <views></views>
+  <triggers></triggers>
+  <procedures></procedures>
 </schema>
 EOXML
 
@@ -86,7 +91,7 @@ $obj = SQL::Translator->new(
     from           => "MySQL",
     to             => "XML-SQLFairy",
 );
-lives_ok {$xml = $obj->translate($file);} "Translate (attrib_values=>1) ran";
+$xml = $obj->translate($file) or die $obj->error;
 ok("$xml" ne ""                             ,"Produced something!");
 print "XML:\n$xml" if DEBUG;
 # Strip sqlf header with its variable date so we diff safely
@@ -104,9 +109,14 @@ my ($obj,$ans,$xml);
 
 $ans = <<EOXML;
 <schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
-  <view name="foo_view" fields="name,age" order="1">
-    <sql>select name, age from person</sql>
-  </view>
+  <tables></tables>
+  <views>
+    <view name="foo_view" fields="name,age" order="1">
+      <sql>select name, age from person</sql>
+    </view>
+  </views>
+  <triggers></triggers>
+  <procedures></procedures>
 </schema>
 EOXML
 
@@ -148,9 +158,14 @@ my ($obj,$ans,$xml);
 
 $ans = <<EOXML;
 <schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
-  <trigger name="foo_trigger" database_event="insert" on_table="foo" perform_action_when="after" order="1">
-    <action>update modified=timestamp();</action>
-  </trigger>
+  <tables></tables>
+  <views></views>
+  <triggers>
+    <trigger name="foo_trigger" database_event="insert" on_table="foo" perform_action_when="after" order="1">
+      <action>update modified=timestamp();</action>
+    </trigger>
+  </triggers>
+  <procedures></procedures>
 </schema>
 EOXML
 
@@ -195,10 +210,15 @@ my ($obj,$ans,$xml);
 
 $ans = <<EOXML;
 <schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
-  <procedure name="foo_proc" parameters="foo,bar" owner="Nomar" order="1">
-    <sql>select foo from bar</sql>
-    <comments>Go Sox!</comments>
-  </procedure>
+  <tables></tables>
+  <views></views>
+  <triggers></triggers>
+  <procedures>
+    <procedure name="foo_proc" parameters="foo,bar" owner="Nomar" order="1">
+      <sql>select foo from bar</sql>
+      <comments>Go Sox!</comments>
+    </procedure>
+  </procedures>
 </schema>
 EOXML
 
@@ -242,16 +262,21 @@ my ($obj,$ans,$xml);
 
 $ans = <<EOXML;
 <schema name="" database="" xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
-  <table name="Basic" order="2">
-    <fields>
-      <field name="foo" data_type="integer" size="10" is_nullable="1" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="5">
-        <extra ZEROFILL="1" />
-        <comments></comments>
-      </field>
-    </fields>
-    <indices></indices>
-    <constraints></constraints>
-  </table>
+  <tables>
+    <table name="Basic" order="2">
+      <fields>
+        <field name="foo" data_type="integer" size="10" is_nullable="1" is_auto_increment="0" is_primary_key="0" is_foreign_key="0" order="5">
+          <extra ZEROFILL="1" />
+          <comments></comments>
+        </field>
+      </fields>
+      <indices></indices>
+      <constraints></constraints>
+    </table>
+  </tables>
+  <views></views>
+  <triggers></triggers>
+  <procedures></procedures>
 </schema>
 EOXML
 
index aec20ff..3750076 100644 (file)
@@ -6,59 +6,67 @@ Created on Fri Aug 15 15:08:18 2003
  -->
 <schema xmlns="http://sqlfairy.sourceforge.net/sqlfairy.xml">
 
-  <table order="1" name="Basic">
-    <fields>
-      <field
-          name="id"
-          is_primary_key="1" is_foreign_key="0"
-          size="10" data_type="int" is_auto_increment="1" order="1"
-          is_nullable="0">
-          <extra ZEROFILL="1" />
-      </field>
-      <field
-          name="title"
-          is_primary_key="0" is_foreign_key="0"
-          size="100" is_auto_increment="0" data_type="varchar"
-          order="2" default_value="hello" is_nullable="0" />
-      <field
-          name="description"
-          size="0" data_type="text" order="3" default_value="" />
-      <field name="email" size="255" data_type="varchar" order="4">
-          <extra foo="bar" hello="world" bar="baz" />
-      </field>
-      <field name="explicitnulldef" size="0" data_type="varchar" order="5" />
-      <field name="explicitemptystring" size="0"
-          data_type="varchar" order="6" default_value="" />
-      <field name="emptytagdef" size="0"
-          data_type="varchar" order="7" default_value="" >
-          <comments>Hello emptytagdef</comments>
-      </field>
-    </fields>
+  <tables>
+      <table order="1" name="Basic">
+        <fields>
+          <field
+              name="id"
+              is_primary_key="1" is_foreign_key="0"
+              size="10" data_type="int" is_auto_increment="1" order="1"
+              is_nullable="0">
+              <extra ZEROFILL="1" />
+          </field>
+          <field
+              name="title"
+              is_primary_key="0" is_foreign_key="0"
+              size="100" is_auto_increment="0" data_type="varchar"
+              order="2" default_value="hello" is_nullable="0" />
+          <field
+              name="description"
+              size="0" data_type="text" order="3" default_value="" />
+          <field name="email" size="255" data_type="varchar" order="4">
+              <extra foo="bar" hello="world" bar="baz" />
+          </field>
+          <field name="explicitnulldef" size="0" data_type="varchar" order="5" />
+          <field name="explicitemptystring" size="0"
+              data_type="varchar" order="6" default_value="" />
+          <field name="emptytagdef" size="0"
+              data_type="varchar" order="7" default_value="" >
+              <comments>Hello emptytagdef</comments>
+          </field>
+        </fields>
 
-    <indices>
-      <index name="titleindex" fields="title" type="NORMAL" />
-    </indices>
+        <indices>
+          <index name="titleindex" fields="title" type="NORMAL" />
+        </indices>
 
-    <constraints>
-      <constraint name="" type="PRIMARY KEY" fields="id"
-          reference_table="" options="" deferrable="1" match_type=""
-          expression="" on_update="" on_delete="" />
-      <constraint name="emailuniqueindex" type="UNIQUE" fields="email" />
-    </constraints>
-  </table>
+        <constraints>
+          <constraint name="" type="PRIMARY KEY" fields="id"
+              reference_table="" options="" deferrable="1" match_type=""
+              expression="" on_update="" on_delete="" />
+          <constraint name="emailuniqueindex" type="UNIQUE" fields="email" />
+        </constraints>
+      </table>
+  </tables>
 
-  <view name="email_list" fields="email" order="1">
-      <sql>SELECT email FROM Basic WHERE email IS NOT NULL</sql>
-  </view>
+  <views>
+      <view name="email_list" fields="email" order="1">
+          <sql>SELECT email FROM Basic WHERE email IS NOT NULL</sql>
+      </view>
+  </views>
 
-  <trigger name="foo_trigger" database_event="insert" on_table="foo"
-      perform_action_when="after" order="1">
-      <action>update modified=timestamp();</action>
-  </trigger>
+  <triggers>
+      <trigger name="foo_trigger" database_event="insert" on_table="foo"
+          perform_action_when="after" order="1">
+          <action>update modified=timestamp();</action>
+      </trigger>
+  </triggers>
 
-  <procedure name="foo_proc" order="1" owner="Nomar" parameters="foo,bar">
-      <sql>select foo from bar</sql>
-      <comments>Go Sox!</comments>
-  </procedure>
+  <procedures>
+      <procedure name="foo_proc" order="1" owner="Nomar" parameters="foo,bar">
+          <sql>select foo from bar</sql>
+          <comments>Go Sox!</comments>
+      </procedure>
+  </procedures>
 
 </schema>