New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor ColumnDefinition
to contain options
hash
#27890
Conversation
Column options are passed as an hash args then used as `options` hash in `add_column_options!`. Converting args to attributes is inconvinient for using options as an hash.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the improvement to creating column definitions. Much simpler.
But the tradeoff is that code is accessing column.options[…]
directly and breaking compat with other adapters.
Perhaps there's a path to using options hash and keyword args to construct column definitions, but expose an opaque attr-style API for the option values.
primary_key || type.to_sym == :primary_key | ||
ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc: | ||
def [](key) | ||
options[key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This poses a compatibility challenge for third party database adapters. Could we offer an gentler upgrade path? Possibly by deprecating the old methods:
class ColumnDefinition
attr_reader :name, :type, :sql_type, :options
def initialize(*args, options: nil)
if options
initialize_with_options(*args, options)
else
initialize_with_struct_args(*args)
end
end
def initialize_with_options(name, type, sql_type, options)
@name, @type, @options, @sql_type = name, type, options, sql_type
end
def initialize_with_struct_args(name, type, limit, etc…)
ActiveSupport::Deprecation.warn …
@name, @type, @sql_type = name, type, sql_type
@options = { limit: limit, precision: precision, … }
end
%i[ limit precision … ].each do |option_name|
define_method(option_name) do
ActiveSupport::Deprecation.warn …
options[option_name]
end
define_method("#{option_name}=") do |value|
ActiveSupport::Deprecation.warn …
options[option_name] = value
end
end
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading the rest of the PR, perhaps we could provide these reader/writer methods without deprecation.
@@ -305,7 +305,7 @@ def column(name, type, options = {}) | |||
type = type.to_sym if type | |||
options = options.dup | |||
|
|||
if @columns_hash[name] && @columns_hash[name].primary_key? | |||
if @columns_hash[name] && @columns_hash[name][:primary_key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This usage feels like a regression. It's nice to call a clear predicate method to ask about the column's attributes rather than digging in to the column options to fetch the data.
@@ -360,28 +360,16 @@ def references(*args, **options) | |||
end | |||
alias :belongs_to :references | |||
|
|||
def new_column_definition(name, type, options) # :nodoc: | |||
def new_column_definition(name, type, **options) # :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+keyword args for options.
|
||
def create_column_definition(name, type) | ||
PostgreSQL::ColumnDefinition.new name, type | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice simplification. Pays off.
class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc: | ||
private | ||
def visit_ColumnDefinition(o) | ||
o.sql_type = type_to_sql(o.type, o[:limit], o[:precision], o[:scale], o[:array]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing this repeated. Good candidate to switch to keyword args also.
options[:null] = false if o.primary_key | ||
options | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
self.precision = options[:precision] if options.include?(:precision) | ||
self.scale = options[:scale] if options.include?(:scale) | ||
self.collation = options[:collation] if options.include?(:collation) | ||
self.options = options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to overwrite all the existing column options instead of just the ones provided by change_column
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah... good catch. I'll fix it.
@@ -418,21 +418,15 @@ def change_column_null(table_name, column_name, null, default = nil) #:nodoc: | |||
exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") | |||
end | |||
alter_table(table_name) do |definition| | |||
definition[column_name].null = null | |||
definition[column_name].options[:null] = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These cases of modifying a data collection directly feel like a step back from calling specific writer methods.
It's nice to call a clear predicate method to ask about the column's attributes rather than digging in to the column options to fetch the data.
I addressed to switch to keyword args for Originally So it is enough to address only the changes of I created a patch for oracle-enhanced and sqlserver-adapter. oracle-enhanced: sqlserver-adapter: How about it? |
Merged @ ae39b1a |
@kamipo Thanks for making a patch for Oracle enhanced adapter. Would you mind pushing the branch to github. of course pull request is welcomed. |
Yeah, I'll create the branch and pull request. |
column.as = options[:as] | ||
column | ||
options[:primary_key] ||= type == :primary_key | ||
options[:null] = false if options[:primary_key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Column options are passed as an hash args then used as
options
hash inadd_column_options!
. Converting args to attributes is inconvinient forusing options as an hash.