diff options
Diffstat (limited to 'lib/arel')
-rw-r--r-- | lib/arel/algebra.rb | 2 | ||||
-rw-r--r-- | lib/arel/algebra/attributes.rb | 7 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/attribute.rb (renamed from lib/arel/algebra/attribute.rb) | 31 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/boolean.rb | 20 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/decimal.rb | 9 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/float.rb | 9 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/integer.rb | 10 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/string.rb | 10 | ||||
-rw-r--r-- | lib/arel/algebra/attributes/time.rb | 6 | ||||
-rw-r--r-- | lib/arel/engines/memory/relations/array.rb | 11 | ||||
-rw-r--r-- | lib/arel/engines/sql.rb | 1 | ||||
-rw-r--r-- | lib/arel/engines/sql/attributes.rb | 40 | ||||
-rw-r--r-- | lib/arel/engines/sql/primitives.rb | 4 | ||||
-rw-r--r-- | lib/arel/engines/sql/relations/table.rb | 8 |
14 files changed, 155 insertions, 13 deletions
diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index 980c558918..83f6a54326 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,6 +1,6 @@ require 'arel/algebra/core_extensions' -require 'arel/algebra/attribute' +require 'arel/algebra/attributes' require 'arel/algebra/expression' require 'arel/algebra/ordering' require 'arel/algebra/predicates' diff --git a/lib/arel/algebra/attributes.rb b/lib/arel/algebra/attributes.rb new file mode 100644 index 0000000000..98302b6b18 --- /dev/null +++ b/lib/arel/algebra/attributes.rb @@ -0,0 +1,7 @@ +require "arel/algebra/attributes/attribute" +require "arel/algebra/attributes/boolean" +require "arel/algebra/attributes/decimal" +require "arel/algebra/attributes/float" +require "arel/algebra/attributes/integer" +require "arel/algebra/attributes/string" +require "arel/algebra/attributes/time"
\ No newline at end of file diff --git a/lib/arel/algebra/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 40a7d61a53..f4cec828e3 100644 --- a/lib/arel/algebra/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -1,6 +1,7 @@ require 'set' module Arel + class TypecastError < StandardError ; end class Attribute attributes :relation, :name, :alias, :ancestor deriving :== @@ -146,5 +147,35 @@ module Arel alias_method :to_ordering, :asc end include Orderings + + module Types + def type_cast(value) + if root == self + raise NotImplementedError, "#type_cast should be implemented in a subclass." + else + root.type_cast(value) + end + end + + def type_cast_to_numeric(value, method) + return unless value + if value.respond_to?(:to_str) + if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/ + $1.send(method) + else + value + end + elsif value.respond_to?(method) + value.send(method) + else + raise typecast_error(value) + end + end + + def typecast_error(value) + raise TypecastError, "could not typecast #{value.inspect} to #{self.class.name.split('::').last}" + end + end + include Types end end diff --git a/lib/arel/algebra/attributes/boolean.rb b/lib/arel/algebra/attributes/boolean.rb new file mode 100644 index 0000000000..0ca7cd6d24 --- /dev/null +++ b/lib/arel/algebra/attributes/boolean.rb @@ -0,0 +1,20 @@ +module Arel + module Attributes + class Boolean < Attribute + def type_cast(value) + case value + when true, false then value + when nil then options[:allow_nil] ? nil : false + when 1 then true + when 0 then false + else + case value.to_s.downcase.strip + when 'true' then true + when 'false' then false + else raise typecast_error(value) + end + end + end + end + end +end diff --git a/lib/arel/algebra/attributes/decimal.rb b/lib/arel/algebra/attributes/decimal.rb new file mode 100644 index 0000000000..bf6587fa34 --- /dev/null +++ b/lib/arel/algebra/attributes/decimal.rb @@ -0,0 +1,9 @@ +module Arel + module Attributes + class Decimal < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_d) + end + end + end +end diff --git a/lib/arel/algebra/attributes/float.rb b/lib/arel/algebra/attributes/float.rb new file mode 100644 index 0000000000..01c95e69f9 --- /dev/null +++ b/lib/arel/algebra/attributes/float.rb @@ -0,0 +1,9 @@ +module Arel + module Attributes + class Float < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_f) + end + end + end +end diff --git a/lib/arel/algebra/attributes/integer.rb b/lib/arel/algebra/attributes/integer.rb new file mode 100644 index 0000000000..9a564565ff --- /dev/null +++ b/lib/arel/algebra/attributes/integer.rb @@ -0,0 +1,10 @@ +module Arel + module Attributes + class Integer < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_i) + end + end + end +end +
\ No newline at end of file diff --git a/lib/arel/algebra/attributes/string.rb b/lib/arel/algebra/attributes/string.rb new file mode 100644 index 0000000000..5ea91a59d8 --- /dev/null +++ b/lib/arel/algebra/attributes/string.rb @@ -0,0 +1,10 @@ +module Arel + module Attributes + class String < Attribute + def type_cast(value) + return unless value + value.to_s + end + end + end +end diff --git a/lib/arel/algebra/attributes/time.rb b/lib/arel/algebra/attributes/time.rb new file mode 100644 index 0000000000..7a2de726c8 --- /dev/null +++ b/lib/arel/algebra/attributes/time.rb @@ -0,0 +1,6 @@ +module Arel + module Attributes + class Time < Attribute + end + end +end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 5e7c0a4ab1..577e327b19 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,16 +1,21 @@ module Arel class Array < Relation - attributes :array, :attribute_names + attributes :array, :attribute_names_and_types include Recursion::BaseCase deriving :==, :initialize + def initialize(array, attribute_names_and_types) + @array, @attribute_names_and_types = array, attribute_names_and_types + end + def engine @engine ||= Memory::Engine.new end def attributes - @attributes ||= @attribute_names.collect do |name| - name.to_attribute(self) + @attributes ||= @attribute_names_and_types.collect do |attribute, type| + attribute = type.new(self, attribute) if Symbol === attribute + attribute end end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index dc40428b77..a7721eb909 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -1,3 +1,4 @@ +require 'arel/engines/sql/attributes' require 'arel/engines/sql/engine' require 'arel/engines/sql/relations' require 'arel/engines/sql/primitives' diff --git a/lib/arel/engines/sql/attributes.rb b/lib/arel/engines/sql/attributes.rb new file mode 100644 index 0000000000..2d315d53fc --- /dev/null +++ b/lib/arel/engines/sql/attributes.rb @@ -0,0 +1,40 @@ +module Arel + module Sql + module Attributes + def self.for(column) + case column.type + when :string then String + when :text then String + when :integer then Integer + when :float then Float + when :decimal then Decimal + when :date then Time + when :datetime then Time + when :timestamp then Time + when :time then Time + when :binary then String + when :boolean then Boolean + else + raise NotImplementedError, "Column type `#{column.type}` is not currently handled" + end + end + + def initialize(column, *args) + @column = column + super(*args) + end + + def type_cast(value) + @column.type_cast(value) + end + + %w(Boolean Decimal Float Integer String Time).each do |klass| + class_eval <<-R + class #{klass} < Arel::Attributes::#{klass} + include Attributes + end + R + end + end + end +end
\ No newline at end of file diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 6cce46a441..666579331a 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -16,10 +16,6 @@ module Arel original_relation.column_for(self) end - def type_cast(value) - root.relation.format(self, value) - end - def format(object) object.to_sql(Sql::Attribute.new(self)) end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index d10b761ea3..c0d3386463 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -41,7 +41,9 @@ module Arel def attributes return @attributes if defined?(@attributes) if table_exists? - @attributes = columns.collect { |column| Attribute.new(self, column.name.to_sym) } + @attributes = columns.collect do |column| + Sql::Attributes.for(column).new(column, self, column.name.to_sym) + end else [] end @@ -55,10 +57,6 @@ module Arel @hash ||= :name.hash end - def format(attribute, value) - attribute.column.type_cast(value) - end - def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end |