From 69ef76a6f8b1fbfdee81e753d6e50c3c0396d47c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 19:22:07 -0700 Subject: remove knowledge of SQL from the column definition object --- .../abstract/schema_definitions.rb | 23 ++---------- .../connection_adapters/abstract_adapter.rb | 41 ++++++++++++++++++++++ activerecord/test/cases/column_definition_test.rb | 7 ++-- 3 files changed, 47 insertions(+), 24 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 902dbd148e..4642d6a0c7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -20,29 +20,9 @@ module ActiveRecord value end - def sql_type - base.type_to_sql(type.to_sym, limit, precision, scale) - end - def primary_key? type.to_sym == :primary_key end - - def to_sql - column_sql = "#{base.quote_column_name(name)} #{sql_type}" - column_options = {} - column_options[:null] = null unless null.nil? - column_options[:default] = default unless default.nil? - column_options[:column] = self - add_column_options!(column_sql, column_options) unless primary_key? - column_sql - end - - private - - def add_column_options!(sql, options) - base.add_column_options!(sql, options) - end end # Represents the schema of an SQL table in an abstract way. This class @@ -287,7 +267,8 @@ module ActiveRecord # concatenated together. This string can then be prepended and appended to # to generate the final SQL to create the table. def to_sql - columns.map { |c| c.to_sql } * ', ' + viz = @base.schema_creation + columns.map { |c| viz.accept c }.join ', ' end private diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 7949bcb5ce..41ccaf8e58 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -100,6 +100,47 @@ module ActiveRecord @visitor = nil end + class SchemaCreation + def initialize(conn) + @conn = conn + @cache = {} + end + + def accept(o) + m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}" + send m, o + end + + private + + def visit_ColumnDefinition(o) + sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + column_sql = "#{quote_column_name(o.name)} #{sql_type}" + column_options = {} + column_options[:null] = o.null unless o.null.nil? + column_options[:default] = o.default unless o.default.nil? + column_options[:column] = o + add_column_options!(column_sql, column_options) unless o.primary_key? + column_sql + end + + def quote_column_name(name) + @conn.quote_column_name name + end + + def type_to_sql(type, limit, precision, scale) + @conn.type_to_sql type.to_sym, limit, precision, scale + end + + def add_column_options!(column_sql, column_options) + @conn.add_column_options! column_sql, column_options + end + end + + def schema_creation + SchemaCreation.new self + end + def lease synchronize do unless in_use diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index bd2fbaa7db..000096c4b9 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -8,6 +8,7 @@ module ActiveRecord def @adapter.native_database_types {:string => "varchar"} end + @viz = @adapter.schema_creation end def test_can_set_coder @@ -37,7 +38,7 @@ module ActiveRecord column_def = ColumnDefinition.new( @adapter, column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal "title varchar(20)", column_def.to_sql + assert_equal "title varchar(20)", @viz.accept(column_def) end def test_should_include_default_clause_when_default_is_present @@ -45,7 +46,7 @@ module ActiveRecord column_def = ColumnDefinition.new( @adapter, column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal %Q{title varchar(20) DEFAULT 'Hello'}, column_def.to_sql + assert_equal %Q{title varchar(20) DEFAULT 'Hello'}, @viz.accept(column_def) end def test_should_specify_not_null_if_null_option_is_false @@ -53,7 +54,7 @@ module ActiveRecord column_def = ColumnDefinition.new( @adapter, column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) - assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, column_def.to_sql + assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, @viz.accept(column_def) end if current_adapter?(:MysqlAdapter) -- cgit v1.2.3 From 4b4c8bdc776e2d42cd070d9cb1b3cc22f82469b1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 19:29:23 -0700 Subject: stop depending on sql_type in pg --- .../connection_adapters/postgresql/quoting.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index 43f991b362..49b93e5626 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -18,10 +18,12 @@ module ActiveRecord def quote(value, column = nil) #:nodoc: return super unless column + sql_type = type_to_sql(column.type, column.limit, column.precision, column.scale) + case value when Range - if /range$/ =~ column.sql_type - "'#{PostgreSQLColumn.range_to_string(value)}'::#{column.sql_type}" + if /range$/ =~ sql_type + "'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}" else super end @@ -32,13 +34,13 @@ module ActiveRecord super end when Hash - case column.sql_type + case sql_type when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column) when 'json' then super(PostgreSQLColumn.json_to_string(value), column) else super end when IPAddr - case column.sql_type + case sql_type when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column) else super end @@ -51,14 +53,14 @@ module ActiveRecord super end when Numeric - if column.sql_type == 'money' || [:string, :text].include?(column.type) + if sql_type == 'money' || [:string, :text].include?(column.type) # Not truly string input, so doesn't require (or allow) escape string syntax. "'#{value}'" else super end when String - case column.sql_type + case sql_type when 'bytea' then "'#{escape_bytea(value)}'" when 'xml' then "xml '#{quote_string(value)}'" when /^bit/ -- cgit v1.2.3 From cd07f194dc2d8e4278ea9a7d4ccebfe74513b0ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 19:34:20 -0700 Subject: decouple column definition from the database connection --- .../connection_adapters/abstract/schema_definitions.rb | 12 ++++++------ .../active_record/connection_adapters/postgresql_adapter.rb | 4 ++-- activerecord/test/cases/column_definition_test.rb | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 4642d6a0c7..952b872f7a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -15,7 +15,7 @@ module ActiveRecord # are typically created by methods in TableDefinition, and added to the # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. - class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: + class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: def string_to_binary(value) value end @@ -213,7 +213,7 @@ module ActiveRecord raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." end - column = self[name] || new_column_definition(@base, name, type) + column = self[name] || new_column_definition(name, type) limit = options.fetch(:limit) do native[type][:limit] if native[type].is_a?(Hash) @@ -272,12 +272,12 @@ module ActiveRecord end private - def create_column_definition(base, name, type) - ColumnDefinition.new base, name, type + def create_column_definition(name, type) + ColumnDefinition.new name, type end - def new_column_definition(base, name, type) - definition = create_column_definition base, name, type + def new_column_definition(name, type) + definition = create_column_definition name, type @columns << definition @columns_hash[name] = definition definition diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 940de7e4f6..48a3d5439f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -344,8 +344,8 @@ module ActiveRecord private - def create_column_definition(base, name, type) - ColumnDefinition.new base, name, type + def create_column_definition(name, type) + ColumnDefinition.new name, type end end diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index 000096c4b9..dbb2f223cd 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -36,7 +36,7 @@ module ActiveRecord def test_should_not_include_default_clause_when_default_is_null column = Column.new("title", nil, "varchar(20)") column_def = ColumnDefinition.new( - @adapter, column.name, "string", + column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) assert_equal "title varchar(20)", @viz.accept(column_def) end @@ -44,7 +44,7 @@ module ActiveRecord def test_should_include_default_clause_when_default_is_present column = Column.new("title", "Hello", "varchar(20)") column_def = ColumnDefinition.new( - @adapter, column.name, "string", + column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) assert_equal %Q{title varchar(20) DEFAULT 'Hello'}, @viz.accept(column_def) end @@ -52,7 +52,7 @@ module ActiveRecord def test_should_specify_not_null_if_null_option_is_false column = Column.new("title", "Hello", "varchar(20)", false) column_def = ColumnDefinition.new( - @adapter, column.name, "string", + column.name, "string", column.limit, column.precision, column.scale, column.default, column.null) assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, @viz.accept(column_def) end -- cgit v1.2.3 From 1c9f7fa6e17d3b026ad6e0bc1f07a9dd47d8a360 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 19:37:44 -0700 Subject: remove to_sql from TableDefinition --- .../connection_adapters/abstract/schema_definitions.rb | 8 -------- .../connection_adapters/abstract/schema_statements.rb | 2 +- .../lib/active_record/connection_adapters/abstract_adapter.rb | 4 ++++ 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 952b872f7a..dd1be694e4 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -263,14 +263,6 @@ module ActiveRecord end alias :belongs_to :references - # Returns a String whose contents are the column definitions - # concatenated together. This string can then be prepended and appended to - # to generate the final SQL to create the table. - def to_sql - viz = @base.schema_creation - columns.map { |c| viz.accept c }.join ', ' - end - private def create_column_definition(name, type) ColumnDefinition.new name, type diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index cd4409295f..4b5adb1d59 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -189,7 +189,7 @@ module ActiveRecord create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE " create_sql << "#{quote_table_name(table_name)} (" - create_sql << td.to_sql + create_sql << schema_creation.accept(td) create_sql << ") #{options[:options]}" execute create_sql td.indexes.each_pair { |c,o| add_index table_name, c, o } diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 41ccaf8e58..781ba6a733 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -124,6 +124,10 @@ module ActiveRecord column_sql end + def visit_TableDefinition(o) + o.columns.map { |c| accept c }.join ', ' + end + def quote_column_name(name) @conn.quote_column_name name end -- cgit v1.2.3 From a80bcc395cd691f5a1ad11af8ad9cff1ab79163f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 19:49:13 -0700 Subject: mostly decouple TableDefinition from the database connection --- .../connection_adapters/abstract/schema_definitions.rb | 6 +++--- .../active_record/connection_adapters/abstract/schema_statements.rb | 2 +- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index dd1be694e4..d6d33e9d17 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -50,11 +50,11 @@ module ActiveRecord # that have been defined. attr_accessor :columns, :indexes - def initialize(base) + def initialize(types) @columns = [] @columns_hash = {} @indexes = {} - @base = base + @native = types end # Appends a primary key definition to the table definition. @@ -281,7 +281,7 @@ module ActiveRecord end def native - @base.native_database_types + @native end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 4b5adb1d59..b291c47742 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -830,7 +830,7 @@ module ActiveRecord private def create_table_definition - TableDefinition.new(self) + TableDefinition.new native_database_types end def update_table_definition(table_name, base) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 48a3d5439f..ef1bbed04b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -901,7 +901,7 @@ module ActiveRecord end def create_table_definition - TableDefinition.new(self) + TableDefinition.new native_database_types end def update_table_definition(table_name, base) -- cgit v1.2.3 From 14d7dc0811fc946ffb63ceed7e0389ed14b50800 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Mar 2013 20:20:35 -0700 Subject: push SQL generation inside the schema creation object --- .../connection_adapters/abstract/schema_definitions.rb | 6 +++++- .../connection_adapters/abstract/schema_statements.rb | 12 ++++-------- .../active_record/connection_adapters/abstract_adapter.rb | 10 +++++++++- .../active_record/connection_adapters/postgresql_adapter.rb | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d6d33e9d17..8f79cc17fe 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -49,12 +49,16 @@ module ActiveRecord # An array of ColumnDefinition objects, representing the column changes # that have been defined. attr_accessor :columns, :indexes + attr_reader :name, :temporary, :options - def initialize(types) + def initialize(types, name, temporary, options) @columns = [] @columns_hash = {} @indexes = {} @native = types + @temporary = temporary + @options = options + @name = name end # Appends a primary key definition to the table definition. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index b291c47742..08e8d3ca20 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -171,7 +171,7 @@ module ActiveRecord # # See also TableDefinition#column for details on how to create columns. def create_table(table_name, options = {}) - td = create_table_definition + td = create_table_definition table_name, options[:temporary], options[:options] unless options[:id] == false pk = options.fetch(:primary_key) { @@ -187,11 +187,7 @@ module ActiveRecord drop_table(table_name, options) end - create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE " - create_sql << "#{quote_table_name(table_name)} (" - create_sql << schema_creation.accept(td) - create_sql << ") #{options[:options]}" - execute create_sql + execute schema_creation.accept td td.indexes.each_pair { |c,o| add_index table_name, c, o } end @@ -829,8 +825,8 @@ module ActiveRecord end private - def create_table_definition - TableDefinition.new native_database_types + def create_table_definition(name, temporary, options) + TableDefinition.new native_database_types, name, temporary, options end def update_table_definition(table_name, base) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 781ba6a733..b3c55dfbbb 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -125,13 +125,21 @@ module ActiveRecord end def visit_TableDefinition(o) - o.columns.map { |c| accept c }.join ', ' + create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE " + create_sql << "#{quote_table_name(o.name)} (" + create_sql << o.columns.map { |c| accept c }.join(', ') + create_sql << ") #{o.options}" + create_sql end def quote_column_name(name) @conn.quote_column_name name end + def quote_table_name(name) + @conn.quote_table_name name + end + def type_to_sql(type, limit, precision, scale) @conn.type_to_sql type.to_sym, limit, precision, scale end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ef1bbed04b..2a19f4ab0b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -900,8 +900,8 @@ module ActiveRecord $1.strip if $1 end - def create_table_definition - TableDefinition.new native_database_types + def create_table_definition(name, temporary, options) + TableDefinition.new native_database_types, name, temporary, options end def update_table_definition(table_name, base) -- cgit v1.2.3 From a724096ca5f0d40914fe2310da898477f5835e75 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 14:51:52 -0700 Subject: factory methods should not alter object state --- .../connection_adapters/abstract/schema_definitions.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 8f79cc17fe..ebf9a662c3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -217,7 +217,12 @@ module ActiveRecord raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." end - column = self[name] || new_column_definition(name, type) + column = @columns_hash.fetch(name) { + col = new_column_definition(name, type) + @columns << col + @columns_hash[name] = col + col + } limit = options.fetch(:limit) do native[type][:limit] if native[type].is_a?(Hash) @@ -273,10 +278,7 @@ module ActiveRecord end def new_column_definition(name, type) - definition = create_column_definition name, type - @columns << definition - @columns_hash[name] = definition - definition + create_column_definition name, type end def primary_key_column_name -- cgit v1.2.3 From c5e03e87eeb100900ce6c87bc5a1977d36f74522 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 15:08:41 -0700 Subject: keep ivars private, do not manipulate them outside their owner object --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 4 ++++ activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index ebf9a662c3..57bc4da5cc 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -236,6 +236,10 @@ module ActiveRecord self end + def remove_column(name) + @columns_hash.delete name.to_s + end + [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type| define_method column_type do |*args| options = args.extract_options! diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index d3ffee3a8b..50d189d27a 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -458,7 +458,7 @@ module ActiveRecord def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc: alter_table(table_name) do |definition| - definition.columns.delete(definition[column_name]) + definition.remove_column column_name end end -- cgit v1.2.3 From b8a533d5f16de5c9df59a9275a1f15d49f1b0256 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 15:08:49 -0700 Subject: @columns list is no longer necessary --- .../connection_adapters/abstract/schema_definitions.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 57bc4da5cc..53589ab958 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -48,11 +48,10 @@ module ActiveRecord class TableDefinition # An array of ColumnDefinition objects, representing the column changes # that have been defined. - attr_accessor :columns, :indexes + attr_accessor :indexes attr_reader :name, :temporary, :options def initialize(types, name, temporary, options) - @columns = [] @columns_hash = {} @indexes = {} @native = types @@ -61,6 +60,8 @@ module ActiveRecord @name = name end + def columns; @columns_hash.values; end + # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. def primary_key(name) @@ -217,12 +218,7 @@ module ActiveRecord raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." end - column = @columns_hash.fetch(name) { - col = new_column_definition(name, type) - @columns << col - @columns_hash[name] = col - col - } + column = @columns_hash[name] ||= new_column_definition(name, type) limit = options.fetch(:limit) do native[type][:limit] if native[type].is_a?(Hash) -- cgit v1.2.3 From d43edf6718e4b0fe2eb144adc6c2c39f15fcd92f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 15:17:05 -0700 Subject: push column initialization down to the factory method --- .../abstract/schema_definitions.rb | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 53589ab958..fe381bcf01 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -218,17 +218,7 @@ module ActiveRecord raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." end - column = @columns_hash[name] ||= new_column_definition(name, type) - - limit = options.fetch(:limit) do - native[type][:limit] if native[type].is_a?(Hash) - end - - column.limit = limit - column.precision = options[:precision] - column.scale = options[:scale] - column.default = options[:default] - column.null = options[:null] + @columns_hash[name] ||= new_column_definition(name, type, options) self end @@ -277,8 +267,18 @@ module ActiveRecord ColumnDefinition.new name, type end - def new_column_definition(name, type) - create_column_definition name, type + def new_column_definition(name, type, options) + column = create_column_definition name, type + limit = options.fetch(:limit) do + native[type][:limit] if native[type].is_a?(Hash) + end + + column.limit = limit + column.precision = options[:precision] + column.scale = options[:scale] + column.default = options[:default] + column.null = options[:null] + column end def primary_key_column_name -- cgit v1.2.3 From f84cf418f607c69d3e71fc6e7a161d224fc7fb86 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 15:17:32 -0700 Subject: there is no reason to check for an already defined column --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index fe381bcf01..922a544e81 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -218,7 +218,7 @@ module ActiveRecord raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table." end - @columns_hash[name] ||= new_column_definition(name, type, options) + @columns_hash[name] = new_column_definition(name, type, options) self end -- cgit v1.2.3 From f20b2f4e54d27f7f98ca537ac69b1be8f88fc2a5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 16:01:03 -0700 Subject: push alter table add column sql in to the schema modification visitor --- .../abstract/schema_definitions.rb | 29 +++++++++++++++++----- .../abstract/schema_statements.rb | 10 +++++--- .../connection_adapters/abstract_adapter.rb | 26 +++++++++++++++---- 3 files changed, 51 insertions(+), 14 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 922a544e81..7f0be28080 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -262,12 +262,7 @@ module ActiveRecord end alias :belongs_to :references - private - def create_column_definition(name, type) - ColumnDefinition.new name, type - end - - def new_column_definition(name, type, options) + def new_column_definition(name, type, options) # :nodoc: column = create_column_definition name, type limit = options.fetch(:limit) do native[type][:limit] if native[type].is_a?(Hash) @@ -281,6 +276,11 @@ module ActiveRecord column end + private + def create_column_definition(name, type) + ColumnDefinition.new name, type + end + def primary_key_column_name primary_key_column = columns.detect { |c| c.primary_key? } primary_key_column && primary_key_column.name @@ -291,6 +291,23 @@ module ActiveRecord end end + class AlterTable # :nodoc: + attr_reader :add + + def initialize(td) + @td = td + @add = nil + end + + def name; @td.name; end + + def add_column(name, type, options) + name = name.to_s + type = type.to_sym + @add = @td.new_column_definition(name, type, options) + end + end + # Represents an SQL table in an abstract way for updating a table. # Also see TableDefinition and SchemaStatements#create_table # diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 08e8d3ca20..6631a278ab 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -355,9 +355,9 @@ module ActiveRecord # Adds a new column to the named table. # See TableDefinition#column for details of the options you can use. def add_column(table_name, column_name, type, options = {}) - add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - execute(add_column_sql) + at = create_alter_table table_name + at.add_column(column_name, type, options) + execute schema_creation.accept at end # Removes the given columns from the table definition. @@ -829,6 +829,10 @@ module ActiveRecord TableDefinition.new native_database_types, name, temporary, options end + def create_alter_table(name) + AlterTable.new create_table_definition(name, false, {}) + end + def update_table_definition(table_name, base) Table.new(table_name, base) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index b3c55dfbbb..5d38b45a5b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -113,14 +113,22 @@ module ActiveRecord private + def visit_AlterTable(o) + sql = "ALTER TABLE #{quote_table_name(o.name)} " + + if col = o.add + sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) + sql << "ADD #{quote_column_name(col.name)} #{sql_type}" + add_column_options!(sql, column_options(col)) + end + + sql + end + def visit_ColumnDefinition(o) sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) column_sql = "#{quote_column_name(o.name)} #{sql_type}" - column_options = {} - column_options[:null] = o.null unless o.null.nil? - column_options[:default] = o.default unless o.default.nil? - column_options[:column] = o - add_column_options!(column_sql, column_options) unless o.primary_key? + add_column_options!(column_sql, column_options(o)) unless o.primary_key? column_sql end @@ -132,6 +140,14 @@ module ActiveRecord create_sql end + def column_options(o) + column_options = {} + column_options[:null] = o.null unless o.null.nil? + column_options[:default] = o.default unless o.default.nil? + column_options[:column] = o + column_options + end + def quote_column_name(name) @conn.quote_column_name name end -- cgit v1.2.3 From 6b7fdf3bf3675a14eae74acc5241089308153a34 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 16:17:12 -0700 Subject: add a pg visitor for dealing with schema modification --- .../postgresql/schema_statements.rb | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 3bc61c5e0c..766b5f07b1 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -1,6 +1,26 @@ module ActiveRecord module ConnectionAdapters class PostgreSQLAdapter < AbstractAdapter + class SchemaCreation < AbstractAdapter::SchemaCreation + private + + def visit_AlterTable(o) + sql = "ALTER TABLE #{quote_table_name(o.name)} " + + if col = o.add + sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) + sql << "ADD COLUMN #{quote_column_name(col.name)} #{sql_type}" + add_column_options!(sql, column_options(col)) + end + + sql + end + end + + def schema_creation + SchemaCreation.new self + end + module SchemaStatements # Drops the database specified on the +name+ attribute # and creates it again using the provided +options+. @@ -337,10 +357,7 @@ module ActiveRecord # See TableDefinition#column for details of the options you can use. def add_column(table_name, column_name, type, options = {}) clear_cache! - add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - - execute add_column_sql + super end # Changes the column of a table. -- cgit v1.2.3 From 072dbbf2aeb2be4f074ba8e404ee157f281bedf9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 16:19:48 -0700 Subject: pull add_column_options! off the pg connection class --- .../connection_adapters/postgresql/schema_statements.rb | 13 +++++++++++++ .../active_record/connection_adapters/postgresql_adapter.rb | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 766b5f07b1..28c5209ad4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -15,6 +15,19 @@ module ActiveRecord sql end + + def add_column_options!(sql, options) + if options[:array] || options[:column].try(:array) + sql << '[]' + end + + column = options.fetch(:column) { return super } + if column.type == :uuid && options[:default] =~ /\(\)/ + sql << " DEFAULT #{options[:default]}" + else + super + end + end end def schema_creation diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2a19f4ab0b..0a903d8aad 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -627,19 +627,6 @@ module ActiveRecord @table_alias_length ||= query('SHOW max_identifier_length', 'SCHEMA')[0][0].to_i end - def add_column_options!(sql, options) - if options[:array] || options[:column].try(:array) - sql << '[]' - end - - column = options.fetch(:column) { return super } - if column.type == :uuid && options[:default] =~ /\(\)/ - sql << " DEFAULT #{options[:default]}" - else - super - end - end - # Set the authorized user for this session def session_auth=(user) clear_cache! -- cgit v1.2.3 From 739a72036162b4057ceb4de6950624c0c0ed93b4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 16:41:14 -0700 Subject: allow multiple add columns --- .../connection_adapters/abstract/schema_definitions.rb | 8 ++++---- .../lib/active_record/connection_adapters/abstract_adapter.rb | 2 +- .../connection_adapters/postgresql/schema_statements.rb | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 7f0be28080..962c63effd 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -292,11 +292,11 @@ module ActiveRecord end class AlterTable # :nodoc: - attr_reader :add + attr_reader :adds def initialize(td) - @td = td - @add = nil + @td = td + @adds = [] end def name; @td.name; end @@ -304,7 +304,7 @@ module ActiveRecord def add_column(name, type, options) name = name.to_s type = type.to_sym - @add = @td.new_column_definition(name, type, options) + @adds << @td.new_column_definition(name, type, options) end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 5d38b45a5b..3dc284b4ce 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -116,7 +116,7 @@ module ActiveRecord def visit_AlterTable(o) sql = "ALTER TABLE #{quote_table_name(o.name)} " - if col = o.add + o.adds.each do |col| sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) sql << "ADD #{quote_column_name(col.name)} #{sql_type}" add_column_options!(sql, column_options(col)) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 28c5209ad4..df2315d0ff 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -7,7 +7,7 @@ module ActiveRecord def visit_AlterTable(o) sql = "ALTER TABLE #{quote_table_name(o.name)} " - if col = o.add + o.adds.each do |col| sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) sql << "ADD COLUMN #{quote_column_name(col.name)} #{sql_type}" add_column_options!(sql, column_options(col)) -- cgit v1.2.3 From 2ac300ba7cd867c6606b7d7fb458b4a0412c766d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Mar 2013 17:04:04 -0700 Subject: push the mysql add_column up to the abstract adapter --- .../abstract/schema_definitions.rb | 4 +++- .../connection_adapters/abstract_adapter.rb | 14 ++++++------ .../connection_adapters/abstract_mysql_adapter.rb | 25 ++++++++++++++++++---- .../postgresql/schema_statements.rb | 14 ++++-------- 4 files changed, 35 insertions(+), 22 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 962c63effd..bd7e5be567 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -15,7 +15,7 @@ module ActiveRecord # are typically created by methods in TableDefinition, and added to the # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. - class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null) #:nodoc: + class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after) #:nodoc: def string_to_binary(value) value end @@ -273,6 +273,8 @@ module ActiveRecord column.scale = options[:scale] column.default = options[:default] column.null = options[:null] + column.first = options[:first] + column.after = options[:after] column end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 3dc284b4ce..0ebe46be55 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -115,14 +115,13 @@ module ActiveRecord def visit_AlterTable(o) sql = "ALTER TABLE #{quote_table_name(o.name)} " + sql << o.adds.map { |col| visit_AddColumn col }.join(' ') + end - o.adds.each do |col| - sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) - sql << "ADD #{quote_column_name(col.name)} #{sql_type}" - add_column_options!(sql, column_options(col)) - end - - sql + def visit_AddColumn(o) + sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + sql = "ADD #{quote_column_name(o.name)} #{sql_type}" + add_column_options!(sql, column_options(o)) end def visit_ColumnDefinition(o) @@ -162,6 +161,7 @@ module ActiveRecord def add_column_options!(column_sql, column_options) @conn.add_column_options! column_sql, column_options + column_sql end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index f88f5742a8..b1baf24cb6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -3,6 +3,27 @@ require 'arel/visitors/bind_visitor' module ActiveRecord module ConnectionAdapters class AbstractMysqlAdapter < AbstractAdapter + class SchemaCreation < AbstractAdapter::SchemaCreation + private + + def visit_AddColumn(o) + add_column_position!(super, o) + end + + def add_column_position!(sql, column) + if column.first + sql << " FIRST" + elsif column.after + sql << " AFTER #{quote_column_name(column.after)}" + end + sql + end + end + + def schema_creation + SchemaCreation.new self + end + class Column < ConnectionAdapters::Column # :nodoc: attr_reader :collation, :strict @@ -459,10 +480,6 @@ module ActiveRecord rename_table_indexes(table_name, new_name) end - def add_column(table_name, column_name, type, options = {}) - execute("ALTER TABLE #{quote_table_name(table_name)} #{add_column_sql(table_name, column_name, type, options)}") - end - def change_column_default(table_name, column_name, default) column = column_for(table_name, column_name) change_column table_name, column_name, column.sql_type, :default => default diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index df2315d0ff..923241b89f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -4,16 +4,10 @@ module ActiveRecord class SchemaCreation < AbstractAdapter::SchemaCreation private - def visit_AlterTable(o) - sql = "ALTER TABLE #{quote_table_name(o.name)} " - - o.adds.each do |col| - sql_type = type_to_sql(col.type.to_sym, col.limit, col.precision, col.scale) - sql << "ADD COLUMN #{quote_column_name(col.name)} #{sql_type}" - add_column_options!(sql, column_options(col)) - end - - sql + def visit_AddColumn(o) + sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale) + sql = "ADD COLUMN #{quote_column_name(o.name)} #{sql_type}" + add_column_options!(sql, column_options(o)) end def add_column_options!(sql, options) -- cgit v1.2.3 From d25e4076ba2061baf7b96784c9b4df4256ce736e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 22 Mar 2013 19:24:30 -0700 Subject: separate primary key from column type --- .../abstract/schema_definitions.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index bd7e5be567..3d0ddd3f5d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -15,13 +15,13 @@ module ActiveRecord # are typically created by methods in TableDefinition, and added to the # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. - class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after) #:nodoc: + class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc: def string_to_binary(value) value end def primary_key? - type.to_sym == :primary_key + primary_key || type.to_sym == :primary_key end end @@ -65,7 +65,7 @@ module ActiveRecord # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. def primary_key(name) - column(name, :primary_key) + column(name, :primary_key, primary_key: true) end # Returns a ColumnDefinition for the column with name +name+. @@ -268,13 +268,14 @@ module ActiveRecord native[type][:limit] if native[type].is_a?(Hash) end - column.limit = limit - column.precision = options[:precision] - column.scale = options[:scale] - column.default = options[:default] - column.null = options[:null] - column.first = options[:first] - column.after = options[:after] + column.limit = limit + column.precision = options[:precision] + column.scale = options[:scale] + column.default = options[:default] + column.null = options[:null] + column.first = options[:first] + column.after = options[:after] + column.primary_key = type == :primary_key || options[:primary_key] column end -- cgit v1.2.3 From bc8ebefe9825dbff2cffa29ff015a1e7a31f9812 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 22 Mar 2013 19:30:24 -0700 Subject: add uuid primary key support --- .../connection_adapters/abstract/schema_definitions.rb | 5 +++-- .../connection_adapters/abstract/schema_statements.rb | 2 +- .../connection_adapters/postgresql/schema_statements.rb | 9 +++++++++ .../active_record/connection_adapters/postgresql_adapter.rb | 7 +++++++ activerecord/test/cases/adapters/postgresql/uuid_test.rb | 10 ++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 3d0ddd3f5d..b358d84365 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -64,8 +64,9 @@ module ActiveRecord # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. - def primary_key(name) - column(name, :primary_key, primary_key: true) + def primary_key(name, type = :primary_key, options = {}) + options[:primary_key] = true + column(name, type, options) end # Returns a ColumnDefinition for the column with name +name+. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 6631a278ab..a26a0b54ea 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -178,7 +178,7 @@ module ActiveRecord Base.get_primary_key table_name.to_s.singularize } - td.primary_key pk + td.primary_key pk, options.fetch(:id, :primary_key), options end yield td if block_given? diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 923241b89f..0622d0a909 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -10,6 +10,15 @@ module ActiveRecord add_column_options!(sql, column_options(o)) end + def visit_ColumnDefinition(o) + sql = super + if o.primary_key? && o.type == :uuid + sql << " PRIMARY KEY " + add_column_options!(sql, column_options(o)) + end + sql + end + def add_column_options!(sql, options) if options[:array] || options[:column].try(:array) sql << '[]' diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 0a903d8aad..6f1eb25990 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -330,6 +330,13 @@ module ActiveRecord class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition include ColumnMethods + def primary_key(name, type = :primary_key, options = {}) + return super unless type == :uuid + options[:default] ||= 'uuid_generate_v4()' + options[:primary_key] = true + column name, type, options + end + def column(name, type = nil, options = {}) super column = self[name] diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb index 53002c5265..c0c0e8898c 100644 --- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb +++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb @@ -35,6 +35,16 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase @connection.execute 'drop table if exists pg_uuids' end + def test_id_is_uuid + assert_equal :uuid, UUID.columns_hash['id'].type + assert UUID.primary_key + end + + def test_id_has_a_default + u = UUID.create + assert_not_nil u.id + end + def test_auto_create_uuid u = UUID.create u.reload -- cgit v1.2.3