partitioned 0.8.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,77 +1,56 @@
1
1
  module Partitioned
2
+ #
3
+ # MixIn used to extend ActiveRecord::Base classes implementing bulk insert and update operations
4
+ # through {#create_many} and {#update_many}. {Partitioned::PartitionedBase} classes are extended
5
+ # with these methods by default.
6
+ #
7
+ # @example to use in non-{Partitioned::PartitionedBase} class:
8
+ # class Company < ActiveRecord::Base
9
+ # extend Partitioned::BulkMethodsMixin
10
+ # end
11
+ #
2
12
  module BulkMethodsMixin
13
+ # exception thrown when row data structures are inconsistent between rows in single call to {#create_many} or {#update_many}
3
14
  class BulkUploadDataInconsistent < StandardError
4
15
  def initialize(model, table_name, expected_columns, found_columns, while_doing)
5
16
  super("#{model.name}: for table: #{table_name}; #{expected_columns} != #{found_columns}; #{while_doing}")
6
17
  end
7
18
  end
8
- #
19
+
9
20
  # BULK creation of many rows
10
21
  #
11
- # rows: an array of hashtables of data to insert into the database
12
- # each hashtable must have the same number of keys (and same
13
- # names for each key).
14
- #
15
- # options:
16
- # :slice_size = 1000
17
- # :returning = nil
18
- # :check_consistency = true
19
- #
20
- # examples:
21
- # first example didn't uses more options.
22
- #
23
- # rows = [{
24
- # :name => 'Keith',
25
- # :salary => 1000,
26
- # },
27
- # {
28
- # :name => 'Alex',
29
- # :salary => 2000,
30
- # }]
31
- #
32
- # Employee.create_many(rows)
33
- #
34
- # this second example uses :returning option
35
- # to returns key values
36
- #
37
- # rows = [{
38
- # :name => 'Keith',
39
- # :salary => 1000,
40
- # },
41
- # {
42
- # :name => 'Alex',
43
- # :salary => 2000,
44
- # }]
45
- #
46
- # options = {
47
- # :returning => [:id]
48
- # }
49
- #
50
- # Employee.create_many(rows, options) returns [#<Employee id: 1>, #<Employee id: 2>]
51
- #
52
- # third example uses :slice_size option.
53
- # Slice_size - is an integer that specifies how many
54
- # records will be created in a single SQL query.
55
- #
56
- # rows = [{
57
- # :name => 'Keith',
58
- # :salary => 1000,
59
- # },
60
- # {
61
- # :name => 'Alex',
62
- # :salary => 2000,
63
- # },
64
- # {
65
- # :name => 'Mark',
66
- # :salary => 3000,
67
- # }]
68
- #
69
- # options = {
70
- # :slice_size => 2
71
- # }
72
- #
73
- # Employee.create_many(rows, options) will generate two insert queries
74
- #
22
+ # @example no options used
23
+ # rows = [
24
+ # { :name => 'Keith', :salary => 1000 },
25
+ # { :name => 'Alex', :salary => 2000 }
26
+ # ]
27
+ # Employee.create_many(rows)
28
+ #
29
+ # @example with :returning option to returns key value
30
+ # rows = [
31
+ # { :name => 'Keith', :salary => 1000 },
32
+ # { :name => 'Alex', :salary => 2000 }
33
+ # ]
34
+ # options = { :returning => [:id] }
35
+ # Employee.create_many(rows, options)
36
+ # [#<Employee id: 1>, #<Employee id: 2>]
37
+ #
38
+ # @example with :slice_size option (will generate two insert queries)
39
+ # rows = [
40
+ # { :name => 'Keith', :salary => 1000 },
41
+ # { :name => 'Alex', :salary => 2000 },
42
+ # { :name => 'Mark', :salary => 3000 }
43
+ # ]
44
+ # options = { :slice_size => 2 }
45
+ # Employee.create_many(rows, options)
46
+ #
47
+ # @param [Array<Hash>] rows ([]) data to be inserted into database
48
+ # @param [Hash] options ({}) options for bulk inserts
49
+ # @option options [Integer] :slice_size (1000) how many records will be created in a single SQL query
50
+ # @option options [Boolean] :check_consitency (true) ensure some modicum of sanity on the incoming dataset, specifically: does each row define the same set of key/value pairs
51
+ # @option options [Array or String] :returning (nil) list of fields to return.
52
+ # @return [Array<Hash>] rows returned from DB as option[:returning] requests
53
+ # @raise [BulkUploadDataInconsistent] raised when key/value pairs between rows are inconsistent (check disabled with option :check_consistency)
75
54
  def create_many(rows, options = {})
76
55
  return [] if rows.blank?
77
56
  options[:slice_size] = 1000 unless options.has_key?(:slice_size)
@@ -127,90 +106,56 @@ module Partitioned
127
106
  #
128
107
  # BULK updates of many rows
129
108
  #
130
- # rows: an array of hashtables of data to insert into the database
131
- # each hashtable must have the same number of keys (and same
132
- # names for each key).
133
- #
134
- # options:
135
- # :slice_size = 1000
136
- # :returning = nil
137
- # :set_array = from first row passed in
138
- # :check_consistency = true
139
- # :where = '"#{table_name}.id = datatable.id"'
140
- #
141
- # examples:
142
- # this first example uses "set_array" to add the value of "salary"
143
- # to the specific employee's salary
144
- # the default where clause is to match IDs so, it works here.
145
- # rows = [{
146
- # :id => 1,
147
- # :salary => 1000,
148
- # },
149
- # {
150
- # :id => 10,
151
- # :salary => 2000,
152
- # },
153
- # {
154
- # :id => 23,
155
- # :salary => 2500,
156
- # }]
157
- #
158
- # options = {
159
- # :set_array => '"salary = datatable.salary"'
160
- # }
161
- #
162
- # Employee.update_many(rows, options)
163
- #
164
- #
165
- # this versions sets the where clause to match Salaries.
166
- # rows = [{
167
- # :id => 1,
168
- # :salary => 1000,
169
- # :company_id => 10
170
- # },
171
- # {
172
- # :id => 10,
173
- # :salary => 2000,
174
- # :company_id => 12
175
- # },
176
- # {
177
- # :id => 23,
178
- # :salary => 2500,
179
- # :company_id => 5
180
- # }]
181
- #
182
- # options = {
183
- # :set_array => '"company_id = datatable.company_id"',
184
- # :where => '"#{table_name}.salary = datatable.salary"'
185
- # }
186
- #
187
- # Employee.update_many(rows, options)
188
- #
189
- #
190
- # this version sets the where clause to the KEY of the hash passed in
191
- # and the set_array is generated from the VALUES
192
- #
193
- # rows = {
194
- # { :id => 1 } => {
195
- # :salary => 100000,
196
- # :company_id => 10
197
- # },
198
- # { :id => 10 } => {
199
- # :salary => 110000,
200
- # :company_id => 12
201
- # },
202
- # { :id => 23 } => {
203
- # :salary => 90000,
204
- # :company_id => 5
109
+ # @return [Array<Hash>] rows returned from DB as option[:returning] requests
110
+ # @raise [BulkUploadDataInconsistent] raised when key/value pairs between rows are inconsistent (check disabled with option :check_consistency)
111
+ # @param [Hash] options ({}) options for bulk inserts
112
+ # @option options [Integer] :slice_size (1000) how many records will be created in a single SQL query
113
+ # @option options [Boolean] :check_consitency (true) ensure some modicum of sanity on the incoming dataset, specifically: does each row define the same set of key/value pairs
114
+ # @option options [Array] :returning (nil) list of fields to return.
115
+ # @option options [String] :returning (nil) single field to return.
116
+ #
117
+ # @overload update_many(rows = [], options = {})
118
+ # @param [Array<Hash>] rows ([]) data to be updated
119
+ # @option options [String] :set_array (built from first row passed in) the set clause
120
+ # @option options [String] :where ('"#{table_name}.id = datatable.id"') the where clause
121
+ #
122
+ # @overload update_many(rows = {}, options = {})
123
+ # @param [Hash<Hash, Hash>] rows ({}) data to be updated
124
+ # @option options [String] :set_array (built from the values in the first key/value pair of `rows`) the set clause
125
+ # @option options [String] :where (built from the keys in the first key/value pair of `rows`) the where clause
126
+ #
127
+ # @example using "set_array" to add the value of "salary" to the specific employee's salary the default where clause matches IDs so, it works here.
128
+ # rows = [
129
+ # { :id => 1, :salary => 1000 },
130
+ # { :id => 10, :salary => 2000 },
131
+ # { :id => 23, :salary => 2500 }
132
+ # ]
133
+ # options = { :set_array => '"salary = datatable.salary"' }
134
+ # Employee.update_many(rows, options)
135
+ #
136
+ # @example using where clause to match salary.
137
+ # rows = [
138
+ # { :id => 1, :salary => 1000, :company_id => 10 },
139
+ # { :id => 10, :salary => 2000, :company_id => 12 },
140
+ # { :id => 23, :salary => 2500, :company_id => 5 }
141
+ # ]
142
+ # options = {
143
+ # :set_array => '"company_id = datatable.company_id"',
144
+ # :where => '"#{table_name}.salary = datatable.salary"'
205
145
  # }
206
- # }
146
+ # Employee.update_many(rows, options)
207
147
  #
208
- # Employee.update_many(rows)
148
+ # @example setting where clause to the KEY of the hash passed in and the set_array is generated from the VALUES
149
+ # rows = {
150
+ # { :id => 1 } => { :salary => 100000, :company_id => 10 },
151
+ # { :id => 10 } => { :salary => 110000, :company_id => 12 },
152
+ # { :id => 23 } => { :salary => 90000, :company_id => 5 }
153
+ # }
154
+ # Employee.update_many(rows)
209
155
  #
210
- # Remember that you should probably set updated_at using "updated = datatable.updated_at"
211
- # or "updated_at = now()" in the set_array if you want to follow
212
- # the standard active record model for time columns (and you have an updated_at column)
213
-
156
+ # @note Remember that you should probably set updated_at using "updated = datatable.updated_at"
157
+ # or "updated_at = now()" in the set_array if you want to follow
158
+ # the standard active record model for time columns (and you have an updated_at column)
214
159
  def update_many(rows, options = {})
215
160
  return [] if rows.blank?
216
161
  if rows.is_a?(Hash)
@@ -1,11 +1,13 @@
1
1
  module Partitioned
2
2
  #
3
- # partition tables by created_at grouping them by week, with
3
+ # Partition tables by created_at grouping them by week, with
4
4
  # a week defined as seven days starting on Monday.
5
5
  #
6
6
  class ByCreatedAt < ByWeeklyTimeField
7
7
  self.abstract_class = true
8
8
 
9
+ # the field to partition on, `created_at`
10
+ # @return [Symbol] the partition field: `created_at`
9
11
  def self.partition_time_field
10
12
  return :created_at
11
13
  end
@@ -1,11 +1,16 @@
1
1
  module Partitioned
2
+ # Partitioned abstract class for all partitioned models based as a single integer field value that is used as a foreign key
2
3
  class ByForeignKey < ByIntegerField
3
4
  self.abstract_class = true
4
5
 
6
+ # the field to partition on
7
+ # @return [Integer] re-routed to {#self.partition_foreign_key}
5
8
  def self.partition_integer_field
6
9
  return partition_foreign_key
7
10
  end
8
11
 
12
+ # the field to partition on
13
+ # @return [String] the name of the foreign key field
9
14
  def self.partition_foreign_key
10
15
  raise MethodNotImplemented.new(self, :partition_foreign_key)
11
16
  end
@@ -1,7 +1,7 @@
1
1
  module Partitioned
2
2
  #
3
- # table partitioning by id. this partitioning breaks up data by
4
- # the value of its primary key. a specific record's child table
3
+ # Table partitioning by id. this partitioning breaks up data by
4
+ # the value of its primary key. A specific record's child table
5
5
  # is determined by the number resulting from the integer math:
6
6
  # ID / ById::partition_table_size * ById::partition_table_size
7
7
  #
@@ -9,21 +9,27 @@ module Partitioned
9
9
  self.abstract_class = true
10
10
 
11
11
  #
12
- # specific to this partitioning, we need to prefetch the primary key (id)
12
+ # Specific to this partitioning, we need to prefetch the primary key (id)
13
13
  # before we attempt to do the insert because the insert wants to know the
14
14
  # name of the specific child table to access.
15
15
  #
16
+ # @return [Boolean] true
16
17
  def self.prefetch_primary_key?
17
18
  return true
18
19
  end
19
20
 
20
21
  #
21
- # the number of records in each child table.
22
+ # The number of records in each child table.
22
23
  #
24
+ # @return [Integer] the number of rows in a partition
23
25
  def self.partition_table_size
24
26
  return 10000000
25
27
  end
26
28
 
29
+ #
30
+ # The name of the field to partition on
31
+ #
32
+ # @return [String] the name of the field to partition on
27
33
  def self.partition_integer_field
28
34
  return :id
29
35
  end
@@ -1,15 +1,24 @@
1
1
  module Partitioned
2
+ #
3
+ # Partitioned abstract class for all partitioned models based as a single integer field value.
4
+ #
2
5
  class ByIntegerField < PartitionedBase
3
6
  self.abstract_class = true
4
7
 
8
+ # the size of each table
9
+ # @return [Integer] how many different values are in each partition
5
10
  def self.partition_table_size
6
11
  return 1
7
12
  end
8
13
 
14
+ # the name of the partition key field
15
+ # @return [String] the name of the field
9
16
  def self.partition_integer_field
10
17
  raise MethodNotImplemented.new(self, :partition_integer_field)
11
18
  end
12
19
 
20
+ # the normalized key value for a given key value
21
+ # @return [Integer] the normalized value
13
22
  def self.partition_normalize_key_value(integer_field_value)
14
23
  return integer_field_value / partition_table_size * partition_table_size
15
24
  end
@@ -1,15 +1,22 @@
1
1
  module Partitioned
2
2
  #
3
- # partition tables by a time field grouping them by week, with
3
+ # Partition tables by a time field grouping them by week, with
4
4
  # a week defined as seven days starting on Monday.
5
5
  #
6
6
  class ByMonthlyTimeField < ByTimeField
7
7
  self.abstract_class = true
8
8
 
9
+ # Normalize a partition key value by month.
10
+ #
11
+ # @param [Time] time_value the time value to normalize
12
+ # @return [Time] the value normalized
9
13
  def self.partition_normalize_key_value(time_value)
10
14
  return time_value.at_beginning_of_month
11
15
  end
12
16
 
17
+ # The size of the partition table, a month
18
+ #
19
+ # @return [Integer] the size of this partition
13
20
  def self.partition_table_size
14
21
  return 1.month
15
22
  end
@@ -1,16 +1,20 @@
1
1
  module Partitioned
2
2
  #
3
- # partition tables by a time field grouping them by day
3
+ # Partition tables by a time field grouping them by day.
4
4
  #
5
5
  class ByTimeField < PartitionedBase
6
6
  self.abstract_class = true
7
7
 
8
8
  #
9
- # generate an enumerable that represents all the dates between
10
- # start_date and end_date skipping step
9
+ # Generate an enumerable that represents all the dates between
10
+ # start_date and end_date skipping step.
11
11
  #
12
- # this can be used to calls that take an enumerable like create_infrastructure
12
+ # This can be used to calls that take an enumerable like create_infrastructure.
13
13
  #
14
+ # @param [Date] start_date the first date to generate the range from
15
+ # @param [Date] end_date the last date to generate the range from
16
+ # @param [Object] step (:default) number of values to advance (:default means use {#self.partition_table_size}).
17
+ # @return [Enumerable] the range generated
14
18
  def self.partition_generate_range(start_date, end_date, step = :default)
15
19
  step = partition_table_size if step == :default
16
20
  current_date = partition_normalize_key_value(start_date)
@@ -23,23 +27,27 @@ module Partitioned
23
27
  end
24
28
 
25
29
  #
26
- # normalize the value to the current day
30
+ # Normalize the value to the current day.
27
31
  #
32
+ # @param [Time] time_value the partitioned key value
33
+ # @return [Time] time_value normalized
28
34
  def self.partition_normalize_key_value(time_value)
29
35
  return time_value.to_date
30
36
  end
31
37
 
32
38
  #
33
- # the size of the partition, 1.day
39
+ # The size of the partition, 1.day
34
40
  #
41
+ # @return [Integer] the size of the partition
35
42
  def self.partition_table_size
36
43
  return 1.day
37
44
  end
38
45
 
39
46
  #
40
- # abstract -- implement in a derived clas.
41
- # the name of the time-related field we will use to partition child tables
47
+ # Abstract -- implement in a derived class.
48
+ # The name of the time-related field we will use to partition child tables.
42
49
  #
50
+ # @raise MethodNotImplemented
43
51
  def self.partition_time_field
44
52
  raise MethodNotImplemented.new(self, :partition_time_field)
45
53
  end
@@ -1,15 +1,17 @@
1
1
  module Partitioned
2
2
  #
3
- # partition tables by a time field grouping them by week, with
3
+ # Partition tables by a time field grouping them by week, with
4
4
  # a week defined as seven days starting on Monday.
5
5
  #
6
6
  class ByWeeklyTimeField < ByTimeField
7
7
  self.abstract_class = true
8
8
 
9
9
  #
10
- # normalize a partition key value by week. We've picked
11
- # the begining of the week to key on, which is Monday.
10
+ # Normalize a partition key value by week. We've picked
11
+ # the beginning of the week to key on, which is Monday.
12
12
  #
13
+ # @param [Time] time_value the time value to normalize
14
+ # @return [Time] the value normalized
13
15
  def self.partition_normalize_key_value(time_value)
14
16
  return time_value.at_beginning_of_week
15
17
  end
@@ -17,6 +19,7 @@ module Partitioned
17
19
  #
18
20
  # The size of the partition table, 7 days (1.week)
19
21
  #
22
+ # @return [Integer] the size of this partition
20
23
  def self.partition_table_size
21
24
  return 1.week
22
25
  end
@@ -1,6 +1,7 @@
1
1
  module Partitioned
2
2
  class MultiLevel
3
3
  module Configurator
4
+ # partitioning configuration information
4
5
  class Data < Partitioned::PartitionedBase::Configurator::Data
5
6
  attr_accessor :using_classes
6
7
 
@@ -1,7 +1,15 @@
1
1
  module Partitioned
2
2
  class MultiLevel
3
+ #
4
+ # Configuration manager for multi-level partitioning
5
+ # it supports, the front-end UI (a Domain Specific Language) using {Dsl}
6
+ # state using {Data}
7
+ # and a parser using {Reader}
8
+ #
3
9
  module Configurator
10
+ # The Domain Specific Language UI manager for multi level partitioning classes
4
11
  class Dsl < Partitioned::PartitionedBase::Configurator::Dsl
12
+ # used to prevent use of invalid directives
5
13
  class InvalidForMultiLevelPartitioning < StandardError
6
14
  def initialize(model, dsl_key, remedy)
7
15
  super("#{model.name}: '#{dsl_key}' is not valid for multi-level partitioning. #{remedy}")
@@ -18,10 +26,13 @@ module Partitioned
18
26
  #
19
27
  # Definition of classes which will be used at multi level partitioning.
20
28
  #
29
+ # @param [*Array<Class>] classes the classes, in order, used to partition this model
30
+ # @return [optional]
21
31
  def using_classes(*classes)
22
32
  data.using_classes += [*classes]
23
33
  end
24
34
 
35
+ # @raise [InvalidForMultiLevelPartitioning] always raised. `on` is not a valid DSL directive for multi-level partitioning
25
36
  def on(*ignored)
26
37
  raise InvalidForMultiLevelPartitioning.new(model, :on, "the partitioned keyword 'using' is used to define multi-level partitioned tables.")
27
38
  end
@@ -1,8 +1,13 @@
1
1
  module Partitioned
2
2
  class MultiLevel
3
3
  module Configurator
4
+ # coalesces and parses all {Data} objects allowing the
5
+ # {PartitionManager} to request partitioning information froma
6
+ # centralized source from multi level partitioned models
4
7
  class Reader < Partitioned::PartitionedBase::Configurator::Reader
8
+ # configurator for a specific class level
5
9
  UsingConfigurator = Struct.new(:model, :sliced_class, :dsl)
10
+
6
11
  def initialize(most_derived_activerecord_class)
7
12
  super
8
13
  @using_classes = nil
@@ -12,6 +17,7 @@ module Partitioned
12
17
  #
13
18
  # The field used to partition child tables.
14
19
  #
20
+ # @return [Array<Symbol>] fields used to partition this model
15
21
  def on_fields
16
22
  unless @on_fields
17
23
  @on_fields = using_collect(&:on_field).map(&:to_sym)
@@ -72,10 +78,22 @@ module Partitioned
72
78
  return parts.join('_')
73
79
  end
74
80
 
81
+ # retrieve a specific configurator from an ordered list. for multi-level partitioning
82
+ # we need to find the specific configurator for the partitioning level we are interested
83
+ # in managing.
84
+ #
85
+ # @param [Integer] index the partitioning level to query
86
+ # @return [Configurator] the configurator for the specific level queried
75
87
  def using_configurator(index)
76
88
  return using_class(index).configurator
77
89
  end
78
90
 
91
+ # retrieve a specific partitioning class from an ordered list. for multi-level partitioning
92
+ # we need to find the specific {Partitioned::PartitionedBase} class for the partitioning level we are interested
93
+ # in managing.
94
+ #
95
+ # @param [Integer] index the partitioning level to query
96
+ # @return [{Partitioned::PartitionedBase}] the class for the specific level queried
79
97
  def using_class(index)
80
98
  return using_classes[index]
81
99
  end
@@ -1,10 +1,15 @@
1
1
  module Partitioned
2
2
  class MultiLevel
3
+ #
4
+ # the manger of partitioned requests for models partitioned multiple times
5
+ #
3
6
  class PartitionManager < Partitioned::PartitionedBase::PartitionManager
4
7
  #
5
- # the once called function to prepare a parent table for partitioning as well
8
+ # The once called function to prepare a parent table for partitioning as well
6
9
  # as create the schema that the child tables will be placed in.
7
10
  #
11
+ # @param [Enumerable] enumerable (Array<Array>) the key values that should be used to create the parent partition tables.
12
+ # @return [optional]
8
13
  def create_infrastructure(enumerable = [[]])
9
14
  super()
10
15
  enumerable.each do |*partition_key_values|
@@ -15,11 +20,13 @@ module Partitioned
15
20
  protected
16
21
 
17
22
  #
18
- # create a specific child table that does not currently
23
+ # Create a specific child table that does not currently
19
24
  # exist and whose schema (the schema that the table exists in)
20
25
  # also already exists (#create_infrastructure is designed to
21
26
  # create this).
22
27
  #
28
+ # @param [*Array<Object>] partition_key_values all key values needed to create a partition
29
+ # @return [optional]
23
30
  def create_new_partition(*partition_key_values)
24
31
  create_partition_table(*partition_key_values)
25
32
  if is_leaf_partition?(*partition_key_values)
@@ -31,14 +38,16 @@ module Partitioned
31
38
  end
32
39
 
33
40
  #
34
- # is the table a child table without itself having any children.
41
+ # Is the table a child table without itself having any children.
35
42
  # generally leaf tables are where all indexes and foreign key
36
43
  # constraints will be placed because that is where the data will be.
37
44
  #
38
45
  # Non leaf tables will typically have a rule placed on them
39
- # (via add_parent_table_rules) that prevents any inserts from occuring
46
+ # (via add_parent_table_rules) that prevents any inserts from occurring
40
47
  # on them.
41
48
  #
49
+ # @param [*Array<Object>] partition_key_values all key values specifying a given child table
50
+ # @return [Boolean] true if this partition should contain records
42
51
  def is_leaf_partition?(*partition_key_values)
43
52
  return partition_key_values.length == parent_table_class.configurator.on_fields.length
44
53
  end
@@ -1,6 +1,6 @@
1
1
  module Partitioned
2
2
  #
3
- # table partitioning by a referenced id column which itself is partitioned
3
+ # Table partitioning by a referenced id column which itself is partitioned
4
4
  # further weekly by a date column.
5
5
  #
6
6
  class MultiLevel < PartitionedBase
@@ -9,6 +9,8 @@ module Partitioned
9
9
  #
10
10
  # Normalize the values for the each of using class.
11
11
  #
12
+ # @param [Array<Object>] value the partition key values
13
+ # @return [Array<Object>] the normalized values for the key values passed in
12
14
  def self.partition_normalize_key_value(values)
13
15
  normalized_values = []
14
16
  [*values].each_with_index do |value,index|
@@ -2,9 +2,10 @@ module Partitioned
2
2
  class PartitionedBase
3
3
  module Configurator
4
4
  #
5
- # the state configured by the Dsl and read by Reader
5
+ # The state configured by the Dsl and read by Reader.
6
6
  #
7
7
  class Data
8
+ # represents a SQL index
8
9
  class Index
9
10
  attr_accessor :field, :options
10
11
  def initialize(field, options = {})
@@ -12,6 +13,7 @@ module Partitioned
12
13
  @options = options
13
14
  end
14
15
  end
16
+ # represents a SQL foreign key reference
15
17
  class ForeignKey
16
18
  attr_accessor :referencing_field, :referenced_table, :referenced_field
17
19
  def initialize(referencing_field, referenced_table = nil, referenced_field = :id)
@@ -24,6 +26,13 @@ module Partitioned
24
26
  @referenced_field = referenced_field
25
27
  end
26
28
 
29
+ #
30
+ # Produce a table name from the name of the foreign key. in rails, this really
31
+ # means "foo_id" should be mapped to "foos", and "company_id" should be mapped to
32
+ # "companies"
33
+ #
34
+ # @param [String] foreign_key_field the name of the foreign key field
35
+ # @return [String] the name of the table associated with the foreign key
27
36
  def self.foreign_key_to_foreign_table_name(foreign_key_field)
28
37
  return ActiveSupport::Inflector::pluralize(foreign_key_field.to_s.sub(/_id$/,''))
29
38
  end