Class: Mongify::Database::Column

Inherits:
Object
  • Object
show all
Defined in:
lib/mongify/database/column.rb

Overview

A column that is used to access sql data and transform it into the no sql database

Structure

Structure for defining a column is as follows:

column "name", :type, {options}

Columns with no type given will be set to :string

Notes

Leaving a column out when defining a table will result in a copy of the information (as a string).

Types

Types of columns are supported:

:key                  # Columns that are primary keys need to be marked as :key type. You can provide an :as if your :key is not an integer column
:integer              # Will be converted to a integer
:float                # Will be converted to a float
:decimal              # Will be converted to a string *(you can change default behaviour read below)
:string               # Will be converted to a string
:text                 # Will be converted to a string
:datetime             # Will be converted to a Time format (DateTime is not currently supported in the Mongo ruby driver)
:date                 # Will be converted to a Time format (Date is not currently supported in the Mongo ruby driver)
:timestamps           # Will be converted to a Time format
:time                 # Will be converted to a Time format (the date portion of the Time object will be 2000-01-01)
:binary               # Will be converted to a string
:boolean              # Will be converted to a true or false values

Options

column "post_id", :integer, :references => :posts   # Referenced columns need to be marked as such, this will mean that they will be updated
                                                    # with the new BSON::ObjectID.

NOTE: if you rename the table 'posts', you should set the :references to the new name

column "name", :string, :ignore => true             # Ignoring a column will make the column NOT copy over to the new database

column "surname", :string, :rename_to => 'last_name'# Rename_to allows you to rename the column

column "post_id", :integer, :auto_detect => true    # Will run auto detect and make this column a :references => 'posts', :on => 'post_id' for you
                                                    # More used when reading a sql database, NOT recommended for use during processing of translation

For decimal columns you can specify a few options:

column "total",                                     # This is a default conversion setting.
       :decimal,
       :as => 'string'

column "total",                                     # You can specify to convert your decimal to integer
        :decimal,                                   # specifying scale will define how many decimal places to keep
        :as => 'integer',                           # Example: :scale => 2 will convert 123.4567 to 12346 in to mongodb
        :scale => 2

Decimal Storage

Unfortunately MongoDB Ruby Drivers doesn't support BigDecimal, so to ensure all data is stored correctly (without losing information) I've chosen to store as String, however you can overwrite this functionality in one of two ways: The reason you would want to do this, is to make this searchable via a query.

1) You can specify :as => 'integer', :scale => 2

column "total", :decimal, :as => 'integer', :scale => 2

#It would take a value of 123.456 and store it as an integer of value 12346

<b>2) You can specify your own custom conversion by doing a Table#before_save

Example:

table "invoice" do
  column "name", :string
  column "total", :decimal
  before_save do |row|
    row.total = (BigDecimal.new(row.total) * 1000).round
  end
end

This would take 123.456789 in the total column and convert it to an interger of value 123457 (and in your app you can convert it back to a decimal)

REMEMBER there is a limit on how big of an integer you can store in BSON/MongoDB (bsonspec.org/#/specification)

Constant Summary

AVAILABLE_OPTIONS =

List of available options for a column

['references', 'ignore', 'rename_to', 'as', 'scale']

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sql_name, type = :string, options = {}) ⇒ Column

Returns a new instance of Column



96
97
98
99
100
101
102
103
104
105
# File 'lib/mongify/database/column.rb', line 96

def initialize(sql_name, type=:string, options={})
  @sql_name = sql_name
  options, type = type, nil if type.is_a?(Hash)
  self.type = type
  @options = options.stringify_keys
  @auto_detect = @options.delete('auto_detect')
  run_auto_detect!

  self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &blk) ⇒ Object

Sets up a accessor method for an option

def rename_to=(value)
  options['rename_to'] = value
end
def rename_to
  options['rename_to']
end


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/mongify/database/column.rb', line 153

def method_missing(meth, *args, &blk)
  method_name = meth.to_s.gsub("=", '')
  if AVAILABLE_OPTIONS.include?(method_name)
    unless self.class.method_defined?(method_name.to_sym)
      class_eval <<-EOF
                      def #{method_name}=(value)
                        options['#{method_name}'] = value
                      end
                    EOF
    end
    unless self.class.method_defined?("#{method_name}=".to_sym)
      class_eval <<-EOF
                      def #{method_name}
                        options['#{method_name}']
                      end
                    EOF
    end
    send(meth, *args, &blk)
  else
    super(meth, *args, &blk)
  end
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options



80
81
82
# File 'lib/mongify/database/column.rb', line 80

def options
  @options
end

#sql_nameObject (readonly)

Returns the value of attribute sql_name



80
81
82
# File 'lib/mongify/database/column.rb', line 80

def sql_name
  @sql_name
end

#typeObject

Returns the value of attribute type



80
81
82
# File 'lib/mongify/database/column.rb', line 80

def type
  @type
end

Class Method Details

.auto_detect(column) ⇒ Object

Auto detects if a column is an :key column or is a reference column



86
87
88
89
90
91
92
93
94
# File 'lib/mongify/database/column.rb', line 86

def self.auto_detect(column)
  case column.sql_name.downcase
  when 'id'
    column.as = column.type
    column.type = :key
  when /(.*)_id/
    column.references = $1.to_s.pluralize unless column.referenced?
  end
end

Instance Method Details

#asString

Used when trying to figure out how to convert a decimal value

Returns:

  • (String)

    passed option or defaults to 'string'



203
204
205
# File 'lib/mongify/database/column.rb', line 203

def as
  options['as'] ||= :string
end

#as=(value) ⇒ Object

Sets option to either 'string' or 'integer', defults to 'string' for unknown values

Parameters:

  • value, (String|Symbol)

    can be either 'string' or 'integer



208
209
210
211
# File 'lib/mongify/database/column.rb', line 208

def as=(value)
  value = value.to_s.downcase.to_sym
  options['as'] = [:string, :integer].include?(value) ? value : :string
end

#as_integer?Boolean

Returns true if :as was passed as integer

Returns:

  • (Boolean)


213
214
215
# File 'lib/mongify/database/column.rb', line 213

def as_integer?
  self.as == :integer
end

#auto_detect?Boolean

Returns true if column should be auto_detected (passed via options)

Returns:

  • (Boolean)


192
193
194
# File 'lib/mongify/database/column.rb', line 192

def auto_detect?
  !!@auto_detect
end

#ignored?Boolean

Returns true if column is ignored

Returns:

  • (Boolean)


197
198
199
# File 'lib/mongify/database/column.rb', line 197

def ignored?
  !!self.ignore
end

#key?Boolean

Returns true if column is a :key type column

Returns:

  • (Boolean)


187
188
189
# File 'lib/mongify/database/column.rb', line 187

def key?
  self.type == :key
end

#nameObject

Returns the no_sql record name



114
115
116
# File 'lib/mongify/database/column.rb', line 114

def name
  @name ||= rename_to || sql_name
end

#referenced?Boolean

Returns true if the column is a reference column

Returns:

  • (Boolean)


177
178
179
# File 'lib/mongify/database/column.rb', line 177

def referenced?
  !self.options['references'].nil?
end

#renamed?Boolean

Returns true if column is being renamed

Returns:

  • (Boolean)


182
183
184
# File 'lib/mongify/database/column.rb', line 182

def renamed?
  self.name != self.sql_name
end

#scaleinteger

Get the scale option for decimal to integer conversion

column 'total', :decimal, :as => 'integer', :scale => 3

Returns:

  • (integer)

    passed option or 0



220
221
222
# File 'lib/mongify/database/column.rb', line 220

def scale
  options['scale'] ||= 0
end

#scale=(value) ⇒ Object

Set the scale option for decimal to integer conversion

column 'total', :decimal, :as => 'integer', :scale => 3

Parameters:

  • number (Integer)

    of decimal places to round off to



226
227
228
# File 'lib/mongify/database/column.rb', line 226

def scale=(value)
  options['scale'] = value.to_i
end

#to_printObject Also known as: to_s

Returns a string representation of the column as it would show in a translation file. Mainly used during print out of translation file



134
135
136
137
138
139
140
141
142
# File 'lib/mongify/database/column.rb', line 134

def to_print
  "column \"#{sql_name}\", :#{type}".tap do |output|
    output_options = options.map do |k, v|
      next if v.nil?
      ":#{k} => #{v.is_a?(Symbol) ? ":#{v}" : %Q["#{v}"] }"
    end.compact
    output << ", #{output_options.join(', ')}" unless output_options.blank?
  end
end

#translate(value) ⇒ Object

Returns a translated hash from a given value Example:

@column = Column.new("surname", :string, :rename_to => 'last_name')
@column.translate("Smith") # => {"last_name" => "Smith"}


122
123
124
125
126
127
128
129
130
# File 'lib/mongify/database/column.rb', line 122

def translate(value)
  return {} if ignored?
  case type
    when :key
      {"pre_mongified_id" => type_cast(value)}
    else
      {"#{self.name}" => type_cast(value)}
  end
end

#type_cast(value) ⇒ Object

Casts the value to a given type



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/mongify/database/column.rb', line 231

def type_cast(value)
  return nil if value.nil?
  case type
    when :key       then options['as'] == :string ? value.to_s : value.to_i #If :as is provided, check if it's string, otherwise integer
    when :string    then value.to_s
    when :text      then value.to_s
    when :integer   then value.to_i
    when :float     then value.to_f
    when :decimal
      value = ActiveRecord::Type::Decimal.new.type_cast_from_database(value)
      if as_integer?
        (value * (10 ** self.scale)).round.to_i
      else
        value.to_s
      end
    when :datetime  then ActiveRecord::Type::DateTime.new.type_cast_from_database(value)
    when :timestamp then ActiveRecord::Type::DateTime.new.type_cast_from_database(value)
    when :time      then ActiveRecord::Type::Time.new.type_cast_from_database(value)
    when :date      then ActiveRecord::Type::DateTime.new.type_cast_from_database(value)
    when :binary    then ActiveRecord::Type::Binary.new.type_cast_from_database(value)
    when :boolean   then ActiveRecord::Type::Boolean.new.type_cast_from_database(value)
    else value.to_s
  end
end