Class: Partitioned::PartitionedBase

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
BulkMethodsMixin, SingleForwardable
Includes:
ActiveRecordOverrides
Defined in:
lib/partitioned/partitioned_base.rb,
lib/partitioned/partitioned_base/sql_adapter.rb,
lib/partitioned/partitioned_base/configurator.rb,
lib/partitioned/partitioned_base/configurator/dsl.rb,
lib/partitioned/partitioned_base/configurator/data.rb,
lib/partitioned/partitioned_base/partition_manager.rb,
lib/partitioned/partitioned_base/configurator/reader.rb

Overview

PartitionedBase an ActiveRecord::Base class that can be partitioned.

Uses a domain specific language to configure, see Partitioned::PartitionedBase::Configurator for more information.

Extends Partitioned::BulkMethodsMixin to provide create_many and update_many.

Uses PartitionManager to manage creation of child tables.

Monkey patches some ActiveRecord routines to call back to this class when INSERT and UPDATE statements are built (to determine the table_name with respect to values being inserted or updated)

Direct Known Subclasses

ByIntegerField, ByTimeField, MultiLevel

Defined Under Namespace

Modules: Configurator Classes: PartitionManager, SqlAdapter

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BulkMethodsMixin

create_many, update_many

Methods included from ActiveRecordOverrides

#arel_attributes_values, #delete

Class Method Details

.configurator{Configurator::Reader}

Return a object used to read configurator information.

Returns:



214
215
216
217
218
219
# File 'lib/partitioned/partitioned_base.rb', line 214

def self.configurator
  unless @configurator
    @configurator = self::Configurator::Reader.new(self)
  end
  return @configurator
end

.configurator_dsl{Configurator::Dsl}

Returns the configurator DSL object.

Returns:



242
243
244
# File 'lib/partitioned/partitioned_base.rb', line 242

def self.configurator_dsl
  return @configurator_dsl
end

.dynamic_arel_table(values, as = nil) ⇒ Arel::Table

In activerecord 3.0 we need to supply an Arel::Table for the key value(s) used to determine the specific child table to access.

Parameters:

  • values (Hash)

    key/value pairs for all attributes

  • as (String) (defaults to: nil)

    (nil) the name of the table associated with this Arel::Table

Returns:

  • (Arel::Table)

    the generated Arel::Table



115
116
117
118
119
120
121
122
123
# File 'lib/partitioned/partitioned_base.rb', line 115

def self.dynamic_arel_table(values, as = nil)
  @arel_tables ||= {}
  key_values = self.partition_key_values(values)
  new_arel_table = @arel_tables[key_values]
  arel_engine_hash = {:engine => self.arel_engine}
  arel_engine_hash[:as] = as unless as.blank?
  new_arel_table = Arel::Table.new(self.partition_name(*key_values), arel_engine_hash)
  return new_arel_table
end

.from_partition(*partition_field) ⇒ Hash

Real scope (uses #from_partition_scope). This scope is used to target the active record find() to a specific child table and alias it to the name of the parent table (so activerecord can generally work with it)

Use as:

Foo.from_partition(KEY).find(:first)

where KEY is the key value(s) used as the check constraint on Foo's table.

Because the scope is specific to a class (a class method) but unlike class methods is not inherited, one must use this form (#from_partition) instead of #from_partition_scope to get the most derived classes specific active record scope.

Parameters:

  • partition_field (*Array<Object>)

    the field values to partition on

Returns:

  • (Hash)

    the scoping



165
166
167
# File 'lib/partitioned/partitioned_base.rb', line 165

def self.from_partition(*partition_field)
  from_partition_scope(self, *partition_field)
end

.from_partitioned_without_alias(*partition_field) ⇒ Hash

Real scope (uses #from_partitioned_without_alias_scope). This scope is used to target the active record find() to a specific child table. Is probably best used in advanced activerecord queries when a number of tables are involved in the query.

Use as:

Foo.from_partitioned_without_alias(KEY).find(:all, :select => "*")

where KEY is the key value(s) used as the check constraint on Foo's table.

it's not obvious why :select => "*" is supplied. note activerecord wants to use the name of parent table for access to any attributes, so without the :select argument the sql result would be something like:

SELECT foos.* FROM foos_partitions.pXXX

which fails because table foos is not referenced. using the form #from_partition is almost always the correct thing when using activerecord.

Because the scope is specific to a class (a class method) but unlike class methods is not inherited, one must use this form (#from_partitioned_without_alias) instead of #from_partitioned_without_alias_scope to get the most derived classes specific active record scope.

Parameters:

  • partition_field (*Array<Object>)

    the field values to partition on

Returns:

  • (Hash)

    the scoping



206
207
208
# File 'lib/partitioned/partitioned_base.rb', line 206

def self.from_partitioned_without_alias(*partition_field)
  from_partitioned_without_alias_scope(self, *partition_field)
end

.partition_generate_range(start_value, end_value, step = 1) ⇒ Enumerable

Range generation provided for methods like created_infrastructure that need a set of partition key values to operate on.

Parameters:

  • start_value (Object)

    the first value to generate the range from

  • end_value (Object)

    the last value to generate the range from

  • step (Object) (defaults to: 1)

    (1) number of values to advance.

Returns:

  • (Enumerable)

    the range generated



85
86
87
# File 'lib/partitioned/partitioned_base.rb', line 85

def self.partition_generate_range(start_value, end_value, step = 1)
  return Range.new(start_value, end_value).step(step)
end

.partition_key_values(values) ⇒ Object+

The specific values for a partition of this active record's type which are defined by Partitioned::PartitionedBase#self#self.partition_keys

Parameters:

  • values (Hash)

    key/value pairs to extract values from

Returns:

  • (Object)

    value of partition key

  • (Array<Object>)

    values of partition keys



51
52
53
54
# File 'lib/partitioned/partitioned_base.rb', line 51

def self.partition_key_values(values)
  symbolized_values = values.symbolize_keys
  return self.partition_keys.map{|key| symbolized_values[key.to_sym]}
end

.partition_keysString+

Returns an array of attribute names (strings) used to fetch the key value(s) the determine this specific partition table.

Returns:

  • (String)

    the column name used to partition this table

  • (Array<String>)

    the column names used to partition this table



40
41
42
# File 'lib/partitioned/partitioned_base.rb', line 40

def self.partition_keys
  return configurator.on_fields
end

.partition_manager{PartitionManager}

Return an instance of this partition table's table manager.

Returns:



93
94
95
96
# File 'lib/partitioned/partitioned_base.rb', line 93

def self.partition_manager
  @partition_manager = self::PartitionManager.new(self) unless @partition_manager.present?
  return @partition_manager
end

.partition_normalize_key_value(value) ⇒ Object

Normalize the value to be used for partitioning. This allows, for instance, a class that partitions on a time field to group the times by month. An integer field might be grouped by every 10mil values, A string field might be grouped by its first character.

Parameters:

  • value (Object)

    the partition key value

Returns:

  • (Object)

    the normalized value for the key value passed in



73
74
75
# File 'lib/partitioned/partitioned_base.rb', line 73

def self.partition_normalize_key_value(value)
  return value
end

.partitioned {|@configurator_dsl| ... } ⇒ {Configurator::Dsl}

Yields an object used to configure the ActiveRecord class for partitioning using the Configurator Domain Specific Language.

usage:

partitioned do |partition|
  partition.on    :company_id
  partition.index :id, :unique => true
  partition.foreign_key :company_id
end

Yields:

Returns:



233
234
235
236
# File 'lib/partitioned/partitioned_base.rb', line 233

def self.partitioned
  @configurator_dsl ||= self::Configurator::Dsl.new(self)
  yield @configurator_dsl
end

.sql_adapter{SqlAdapter}

Return an instance of this partition table's sql_adapter (used by the partition manage to create SQL statements)

Returns:

  • ({SqlAdapter})

    the object used to create sql statements for this partitioned model



103
104
105
106
# File 'lib/partitioned/partitioned_base.rb', line 103

def self.sql_adapter
  @sql_adapter = self::SqlAdapter.new(self) unless @sql_adapter.present?
  return @sql_adapter
end

Instance Method Details

#dynamic_arel_table(as = nil) ⇒ Arel::Table

Used by our active record hacks to supply an Arel::Table given this active record's current attributes.

Parameters:

  • as (String) (defaults to: nil)

    (nil) the name of the table associated with the Arel::Table

Returns:

  • (Arel::Table)

    the generated Arel::Table



131
132
133
134
135
# File 'lib/partitioned/partitioned_base.rb', line 131

def dynamic_arel_table(as = nil)
  symbolized_attributes = attributes.symbolize_keys
  key_values = Hash[*self.class.partition_keys.map{|name| [name,symbolized_attributes[name]]}.flatten]
  return self.class.dynamic_arel_table(key_values, as)
end

#from_partition_scopeHash

:from_partition_scope is generally not used directly, use helper self.from_partition so that the derived class can be passed into :from_partition_scope

Returns:

  • (Hash)

    the from scoping



142
143
144
145
146
# File 'lib/partitioned/partitioned_base.rb', line 142

scope :from_partition_scope, lambda { |target_class, *partition_field|
  {
    :from => "#{target_class.partition_name(*partition_field)} AS #{target_class.table_name}"
  }
}

#from_partitioned_without_alias_scopeHash

:from_partitioned_without_alias_scope is generally not used directly, use helper self.from_partitioned_without_alias so that the derived class can be passed into :from_partitioned_without_alias_scope

Returns:

  • (Hash)

    the from scoping



174
175
176
177
178
# File 'lib/partitioned/partitioned_base.rb', line 174

scope :from_partitioned_without_alias_scope, lambda { |target_class, *partition_field|
  {
    :from => target_class.partition_name(*partition_field)
  }
}

#partition_table_nameString

The name of the current partition table determined by this active records attributes that define the key value(s) for the constraint check.

Returns:

  • (String)

    the fully qualified name of the database table, ie: foos_partitions.p17



61
62
63
64
# File 'lib/partitioned/partitioned_base.rb', line 61

def partition_table_name
  symbolized_attributes = attributes.symbolize_keys
  return self.class.partition_name(*self.class.partition_keys.map{|attribute_name| symbolized_attributes[attribute_name]})
end