Added more then one and non integer primary key support people/rbo/Bug#83282
Robert Bohne [Thu, 12 Sep 2013 20:23:43 +0000 (22:23 +0200)]
lib/SQL/Translator/Generator/DDL/SQLite.pm
lib/SQL/Translator/Producer/SQLite.pm
t/56-sqlite-producer.t

index 5a60d51..7d20524 100644 (file)
@@ -10,6 +10,7 @@ engine.
 I<documentation volunteers needed>
 
 =cut
+use Carp;
 use Moo;
 
 has quote_chars => (is=>'ro', default=>sub { +[qw(" ")] } );
@@ -63,30 +64,62 @@ sub _build_unquoted_defaults {
 
 sub nullable { () }
 
-sub _ipk {
-   my ($self, $field) = @_;
+sub field_autoinc {
+  my ($self,$field) = @_;
+  my $pk = $field->table->primary_key;
+  my @pk_fields = $pk ? $pk->fields : ();
+  if ( $field->is_auto_increment && scalar @pk_fields > 1 ){
+    croak sprintf
+      "SQLite doen't support auto increment with more then one primary key. Problem has occurred by table '%s' and column '%s'",
+      $field->table->name,
+      $field->name
+      ;
+  }
+  ( $_[1]->is_auto_increment ? 'AUTOINCREMENT' : () ) 
+}
 
-   my $pk = $field->table->primary_key;
-   my @pk_fields = $pk ? $pk->fields : ();
+sub primary_key_constraint {
+  my ($self,$table) = @_;
+  my $pk = $table->primary_key;
+  my @pk_fields = $pk ? $pk->fields : ();
+  return () if (scalar @pk_fields < 2);
 
-   $field->is_primary_key && scalar @pk_fields == 1 &&
-   ( $field->data_type =~ /int(eger)?$/i
-    ||
-   ( $field->data_type =~ /^number?$/i && $field->size !~ /,/ ) )
+  return 'PRIMARY KEY ('
+    . join(', ', map $self->quote($_), @pk_fields)
+    . ')';
 }
 
+sub field_type_and_single_pk {
+  my ($self, $field) = @_;
+  my $pk = $field->table->primary_key;
+  my @pk_fields = $pk ? $pk->fields : ();
+  my $field_type = $self->field_type($field);
+
+  if ( $field->is_primary_key && scalar @pk_fields == 1){
+    # Convert int(xx), number, .. to INTEGER. This is important for backward 
+    # compatibility and conversion from database to database.
+    if (  $field->data_type =~ /int(eger)?$/i 
+       || ( $field->data_type =~ /^number?$/i && $field->size !~ /,/ )
+    ){
+      $field_type = 'INTEGER';
+    }
+    
+    return $field_type . ' PRIMARY KEY';
+  }
+  return $field_type;
+}
+
+
 sub field {
    my ($self, $field) = @_;
 
    return join ' ',
       $self->field_comments($field),
       $self->field_name($field),
-      ( $self->_ipk($field)
-         ? $field->is_auto_increment
-            ? ( 'INTEGER PRIMARY KEY AUTOINCREMENT' )
-            : ( 'INTEGER PRIMARY KEY' )
-         : ( $self->field_type($field) )
-      ),
+      $self->field_type_and_single_pk($field),
+      $self->field_autoinc($field),
       $self->field_nullable($field),
       $self->field_default($field, {
          NULL => 1,
index 103c2de..499f4c5 100644 (file)
@@ -201,27 +201,15 @@ sub create_table
     }
 
     #
-    # How many fields in PK?
-    #
-    my $pk        = $table->primary_key;
-    my @pk_fields = $pk ? $pk->fields : ();
-
-    #
     # Fields
     #
-    my ( @field_defs, $pk_set );
+    my ( @field_defs );
     for my $field ( @fields ) {
         push @field_defs, create_field($field);
     }
 
-    if (
-         scalar @pk_fields > 1
-         ||
-         ( @pk_fields && !grep /INTEGER PRIMARY KEY/, @field_defs )
-         ) {
-        push @field_defs, 'PRIMARY KEY (' . join(', ', map _generator()->quote($_), @pk_fields ) . ')';
-    }
-
+    push @field_defs, _generator()->primary_key_constraint($table);
+    
     #
     # Indices
     #
index 2129c29..8ba09b3 100644 (file)
@@ -3,6 +3,7 @@
 
 use strict;
 use Test::More;
+use Test::Exception;
 use Test::SQL::Translator qw(maybe_plan);
 
 use SQL::Translator::Schema::View;
@@ -200,4 +201,86 @@ $SQL::Translator::Producer::SQLite::NO_QUOTES = 0;
    is_deeply($result, $expected, 'correctly built table without autoincrement on primary key');
 }
 
+{
+   # Multi primary key test
+   my $table = SQL::Translator::Schema::Table->new(
+       name => 'multi_pk',
+   );
+   $table->add_field(
+       name => 'id',
+       data_type => 'integer',
+       is_nullable => 0,
+       is_auto_increment => 0,
+   );
+   $table->add_field(
+       name => 'id2',
+       data_type => 'integer',
+       is_nullable => 0,
+       is_auto_increment => 0,
+   );
+   $table->primary_key('id');
+   $table->primary_key('id2');
+   my $expected = [ qq<CREATE TABLE "multi_pk" (
+  "id" integer NOT NULL,
+  "id2" integer NOT NULL,
+  PRIMARY KEY ("id", "id2")
+)>];
+   my $result =  [SQL::Translator::Producer::SQLite::create_table($table, { no_comments => 1 })];
+   is_deeply($result, $expected, 'correctly built table with more then one primary key');
+}
+
+{
+   # Multi primary key test
+   my $table = SQL::Translator::Schema::Table->new(
+       name => 'text_pk',
+   );
+   $table->add_field(
+       name => 'id',
+       data_type => 'text',
+       is_nullable => 0,
+       is_auto_increment => 0,
+   );
+   $table->primary_key('id');
+   my $expected = [ qq<CREATE TABLE "text_pk" (
+  "id" text PRIMARY KEY NOT NULL
+)>];
+   my $result =  [SQL::Translator::Producer::SQLite::create_table($table, { no_comments => 1 })];
+   is_deeply($result, $expected, 'correctly built table with text primary key');
+}
+
+
+{
+   # Multi primary key test
+   my $table = SQL::Translator::Schema::Table->new(
+       name => 'multi_pk_with_autoinc',
+   );
+   $table->add_field(
+       name => 'id',
+       data_type => 'integer',
+       is_nullable => 0,
+       is_auto_increment => 1,
+   );
+   $table->add_field(
+       name => 'id2',
+       data_type => 'integer',
+       is_nullable => 0,
+       is_auto_increment => 0,
+   );
+   $table->primary_key('id');
+   $table->primary_key('id2');
+   my $expected = [ qq<CREATE TABLE "multi_pk" (
+  "id" integer NOT NULL,
+  "id2" integer NOT NULL,
+  PRIMARY KEY ("id", "id2")
+)>];
+   
+   throws_ok {
+     SQL::Translator::Producer::SQLite::create_table(
+        $table, { no_comments => 1 }
+     )
+   } qr/SQLite doen't support auto increment with more then one primary key. Problem has occurred by table 'multi_pk_with_autoinc' and column 'id'/;
+    
+}
+
+
 done_testing;