partitioned 1.0.1 → 1.1.0
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.
- data/examples/created_at_referencing_awards.rb +2 -2
- data/lib/monkey_patch_activerecord.rb +35 -1
- data/lib/monkey_patch_postgres.rb +19 -1
- data/lib/partitioned/active_record_overrides.rb +1 -1
- data/lib/partitioned/bulk_methods_mixin.rb +2 -2
- data/lib/partitioned/by_integer_field.rb +5 -0
- data/lib/partitioned/partitioned_base/configurator/data.rb +8 -2
- data/lib/partitioned/partitioned_base/configurator/dsl.rb +19 -0
- data/lib/partitioned/partitioned_base/configurator/reader.rb +31 -0
- data/lib/partitioned/partitioned_base/partition_manager.rb +49 -8
- data/lib/partitioned/partitioned_base/sql_adapter.rb +7 -0
- data/lib/partitioned/partitioned_base.rb +58 -34
- data/lib/partitioned/version.rb +1 -1
- data/partitioned.gemspec +1 -1
- data/spec/monkey_patch_posgres_spec.rb +4 -4
- metadata +2 -8
@@ -105,7 +105,7 @@
|
|
105
105
|
# partitioned do |partition|
|
106
106
|
# partition.foreign_key lambda {|model, *partition_key_values|
|
107
107
|
# return Configurator::Data::ForeignKey.
|
108
|
-
# new(:employee_id, Employee.
|
108
|
+
# new(:employee_id, Employee.partition_table_name(*partition_key_values), :id)
|
109
109
|
# }
|
110
110
|
# end
|
111
111
|
# end
|
@@ -702,7 +702,7 @@ class Award < ByEmployeeCreatedAt
|
|
702
702
|
|
703
703
|
partitioned do |partition|
|
704
704
|
partition.foreign_key lambda {|model, *partition_key_values|
|
705
|
-
return Configurator::Data::ForeignKey.new(:employee_id, Employee.
|
705
|
+
return Configurator::Data::ForeignKey.new(:employee_id, Employee.partition_table_name(*partition_key_values), :id)
|
706
706
|
}
|
707
707
|
end
|
708
708
|
|
@@ -13,6 +13,40 @@ module ActiveRecord
|
|
13
13
|
# Patches for Persistence to allow certain partitioning (that related to the primary key) to work.
|
14
14
|
#
|
15
15
|
module Persistence
|
16
|
+
# Deletes the record in the database and freezes this instance to reflect
|
17
|
+
# that no changes should be made (since they can't be persisted).
|
18
|
+
def destroy
|
19
|
+
destroy_associations
|
20
|
+
|
21
|
+
if persisted?
|
22
|
+
IdentityMap.remove(self) if IdentityMap.enabled?
|
23
|
+
pk = self.class.primary_key
|
24
|
+
column = self.class.columns_hash[pk]
|
25
|
+
substitute = connection.substitute_at(column, 0)
|
26
|
+
|
27
|
+
using_arel_table = self.respond_to?(:dynamic_arel_table) ? dynamic_arel_table() : self.class.arel_table
|
28
|
+
relation = self.class.unscoped.where(
|
29
|
+
using_arel_table[pk].eq(substitute))
|
30
|
+
|
31
|
+
relation.bind_values = [[column, id]]
|
32
|
+
relation.delete_all
|
33
|
+
end
|
34
|
+
|
35
|
+
@destroyed = true
|
36
|
+
freeze
|
37
|
+
end
|
38
|
+
|
39
|
+
# Updates the associated record with values matching those of the instance attributes.
|
40
|
+
# Returns the number of affected rows.
|
41
|
+
def update(attribute_names = @attributes.keys)
|
42
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
43
|
+
return 0 if attributes_with_values.empty?
|
44
|
+
klass = self.class
|
45
|
+
using_arel_table = self.respond_to?(:dynamic_arel_table) ? dynamic_arel_table() : klass.arel_table
|
46
|
+
stmt = klass.unscoped.where(using_arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
|
47
|
+
klass.connection.update stmt
|
48
|
+
end
|
49
|
+
|
16
50
|
#
|
17
51
|
# patch the create method to prefetch the primary key if needed
|
18
52
|
#
|
@@ -65,7 +99,7 @@ module ActiveRecord
|
|
65
99
|
# that are used to determine the child table this insert should be
|
66
100
|
# redirected to)
|
67
101
|
#
|
68
|
-
actual_arel_table = @klass.dynamic_arel_table(Hash[*values.map{|k,v| [k.name,v]}.flatten]) if @klass.respond_to?
|
102
|
+
actual_arel_table = @klass.dynamic_arel_table(Hash[*values.map{|k,v| [k.name,v]}.flatten]) if @klass.respond_to?(:dynamic_arel_table)
|
69
103
|
actual_arel_table = @table unless actual_arel_table
|
70
104
|
im.into actual_arel_table
|
71
105
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'active_record/base'
|
3
3
|
require 'active_record/connection_adapters/abstract_adapter'
|
4
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
4
5
|
|
5
6
|
#
|
6
7
|
# Patching {ActiveRecord::ConnectionAdapters::TableDefinition} and
|
@@ -28,6 +29,23 @@ module ActiveRecord::ConnectionAdapters
|
|
28
29
|
# to take advantage of these SQL builders.
|
29
30
|
#
|
30
31
|
class PostgreSQLAdapter < AbstractAdapter
|
32
|
+
|
33
|
+
#
|
34
|
+
# Returns the sequence name for a table's primary key or some other specified key.
|
35
|
+
#
|
36
|
+
# the default version strips off the schema name on the table (if it exists), as:
|
37
|
+
# serial_sequence(table_name, pk || 'id').split('.').last
|
38
|
+
# i can't see any good reason for that -- in fact, it seems completely
|
39
|
+
# broken -- if you have a table public.foos and other.foos, you'll fail to
|
40
|
+
# get the correct schema if you fetch the default schema name from model
|
41
|
+
# associated with other.foos
|
42
|
+
#
|
43
|
+
def default_sequence_name(table_name, pk = nil) #:nodoc:
|
44
|
+
serial_sequence(table_name, pk || 'id')
|
45
|
+
rescue ActiveRecord::StatementInvalid => e
|
46
|
+
"#{table_name}_#{pk || 'id'}_seq"
|
47
|
+
end
|
48
|
+
|
31
49
|
#
|
32
50
|
# Get the next value in a sequence. Used on INSERT operation for
|
33
51
|
# partitioning like by_id because the ID is required before the insert
|
@@ -36,7 +54,7 @@ module ActiveRecord::ConnectionAdapters
|
|
36
54
|
# @param [String] sequence_name the name of the sequence to fetch the next value from
|
37
55
|
# @return [Integer] the value from the sequence
|
38
56
|
def next_sequence_value(sequence_name)
|
39
|
-
return execute("select nextval('#{sequence_name}')").field_values("nextval").first
|
57
|
+
return execute("select nextval('#{sequence_name}')").field_values("nextval").first.to_i
|
40
58
|
end
|
41
59
|
|
42
60
|
#
|
@@ -23,7 +23,7 @@ module Partitioned
|
|
23
23
|
# @return [Hash] hash of key value pairs associated with persistent attributes
|
24
24
|
def arel_attributes_values(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys)
|
25
25
|
attrs = super
|
26
|
-
actual_arel_table = dynamic_arel_table(
|
26
|
+
actual_arel_table = dynamic_arel_table()
|
27
27
|
return Hash[*attrs.map{|k,v| [actual_arel_table[k.name], v]}.flatten]
|
28
28
|
end
|
29
29
|
|
@@ -81,7 +81,7 @@ module Partitioned
|
|
81
81
|
# set :created_at if need be
|
82
82
|
row[:created_at] ||= created_at_value
|
83
83
|
end.group_by do |row|
|
84
|
-
respond_to?(:
|
84
|
+
respond_to?(:partition_table_name) ? partition_table_name(*partition_key_values(row)) : table_name
|
85
85
|
end.each do |table_name, rows_for_table|
|
86
86
|
column_names = rows_for_table[0].keys.sort{|a,b| a.to_s <=> b.to_s}
|
87
87
|
sql_insert_string = "insert into #{table_name} (#{column_names.join(',')}) values "
|
@@ -189,7 +189,7 @@ module Partitioned
|
|
189
189
|
returning = []
|
190
190
|
|
191
191
|
rows.group_by do |row|
|
192
|
-
respond_to?(:
|
192
|
+
respond_to?(:partition_table_name) ? partition_table_name(*partition_key_values(row)) : table_name
|
193
193
|
end.each do |table_name, rows_for_table|
|
194
194
|
column_names = rows_for_table[0].keys.sort{|a,b| a.to_s <=> b.to_s}
|
195
195
|
rows_for_table.each_slice(options[:slice_size]) do |update_slice|
|
@@ -23,6 +23,11 @@ module Partitioned
|
|
23
23
|
return integer_field_value / partition_table_size * partition_table_size
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.partition_generate_range(start_value, end_value, step = :default)
|
27
|
+
step = partition_table_size if step == :default
|
28
|
+
return Range.new(start_value, end_value).step(step)
|
29
|
+
end
|
30
|
+
|
26
31
|
partitioned do |partition|
|
27
32
|
partition.on lambda {|model| return model.partition_integer_field }
|
28
33
|
|
@@ -40,8 +40,9 @@ module Partitioned
|
|
40
40
|
|
41
41
|
attr_accessor :on_field, :indexes, :foreign_keys, :last_partitions_order_by_clause,
|
42
42
|
:schema_name, :name_prefix, :base_name,
|
43
|
-
:part_name, :table_name, :parent_table_schema_name,
|
44
|
-
:parent_table_name, :check_constraint, :encoded_name
|
43
|
+
:part_name, :table_name, :table_alias_name, :parent_table_schema_name,
|
44
|
+
:parent_table_name, :check_constraint, :encoded_name,
|
45
|
+
:janitorial_creates_needed, :janitorial_archives_needed, :janitorial_drops_needed
|
45
46
|
|
46
47
|
def initialize
|
47
48
|
@on_field = nil
|
@@ -57,6 +58,7 @@ module Partitioned
|
|
57
58
|
@part_name = nil
|
58
59
|
|
59
60
|
@table_name = nil
|
61
|
+
@table_alias_name = nil
|
60
62
|
|
61
63
|
@parent_table_schema_name = nil
|
62
64
|
@parent_table_name = nil
|
@@ -64,6 +66,10 @@ module Partitioned
|
|
64
66
|
@check_constraint = nil
|
65
67
|
|
66
68
|
@encoded_name = nil
|
69
|
+
|
70
|
+
@janitorial_creates_needed = nil
|
71
|
+
@janitorial_archives_needed = nil
|
72
|
+
@janitorial_drops_needed = nil
|
67
73
|
end
|
68
74
|
end
|
69
75
|
end
|
@@ -550,6 +550,11 @@ module Partitioned
|
|
550
550
|
data.table_name = value
|
551
551
|
end
|
552
552
|
|
553
|
+
# a reasonable alias for this table
|
554
|
+
def table_alias_name(value)
|
555
|
+
data.table_alias_name = value
|
556
|
+
end
|
557
|
+
|
553
558
|
#
|
554
559
|
# The table name of the table who is the direct ancestor of a child table.
|
555
560
|
#
|
@@ -627,6 +632,20 @@ module Partitioned
|
|
627
632
|
def parent_table_schema_name(value)
|
628
633
|
data.parent_table_schema_name = value
|
629
634
|
end
|
635
|
+
|
636
|
+
#
|
637
|
+
|
638
|
+
def janitorial_creates_needed(value)
|
639
|
+
data.janitorial_creates_needed = value
|
640
|
+
end
|
641
|
+
|
642
|
+
def janitorial_archives_needed(value)
|
643
|
+
data.janitorial_archives_needed = value
|
644
|
+
end
|
645
|
+
|
646
|
+
def janitorial_drops_needed(value)
|
647
|
+
data.janitorial_drops_needed = value
|
648
|
+
end
|
630
649
|
end
|
631
650
|
end
|
632
651
|
end
|
@@ -26,6 +26,10 @@ module Partitioned
|
|
26
26
|
@parent_table_name = nil
|
27
27
|
|
28
28
|
@encoded_name = nil
|
29
|
+
|
30
|
+
@janitorial_creates_needed = nil
|
31
|
+
@janitorial_archives_needed = nil
|
32
|
+
@janitorial_drops_needed = nil
|
29
33
|
end
|
30
34
|
|
31
35
|
#
|
@@ -100,6 +104,13 @@ module Partitioned
|
|
100
104
|
return collect_first(*partition_key_values, &:table_name)
|
101
105
|
end
|
102
106
|
|
107
|
+
#
|
108
|
+
# A reasonable alias for this partition table
|
109
|
+
#
|
110
|
+
def table_alias_name(*partition_key_values)
|
111
|
+
return collect_first(*partition_key_values, &:table_alias_name)
|
112
|
+
end
|
113
|
+
|
103
114
|
#
|
104
115
|
# The name of the child table without the schema name or name prefix.
|
105
116
|
#
|
@@ -135,6 +146,26 @@ module Partitioned
|
|
135
146
|
return @last_partitions_order_by_clause
|
136
147
|
end
|
137
148
|
|
149
|
+
def janitorial_creates_needed
|
150
|
+
unless @janitorial_creates_needed
|
151
|
+
@janitorial_creates_needed = collect_first(&:janitorial_creates_needed)
|
152
|
+
end
|
153
|
+
return @janitorial_creates_needed
|
154
|
+
end
|
155
|
+
|
156
|
+
def janitorial_archives_needed
|
157
|
+
unless @janitorial_archives_needed
|
158
|
+
@janitorial_archives_needed = collect_first(&:janitorial_archives_needed)
|
159
|
+
end
|
160
|
+
return @janitorial_archives_needed
|
161
|
+
end
|
162
|
+
|
163
|
+
def janitorial_drops_needed
|
164
|
+
unless @janitorial_drops_needed
|
165
|
+
@janitorial_drops_needed = collect_first(&:janitorial_drops_needed)
|
166
|
+
end
|
167
|
+
return @janitorial_drops_needed
|
168
|
+
end
|
138
169
|
|
139
170
|
protected
|
140
171
|
|
@@ -14,6 +14,17 @@ module Partitioned
|
|
14
14
|
@parent_table_class = parent_table_class
|
15
15
|
end
|
16
16
|
|
17
|
+
#
|
18
|
+
# Archive partitions that need such.
|
19
|
+
# uses #archive_old_partition_key_values_set as the list of
|
20
|
+
# partitions to remove.
|
21
|
+
#
|
22
|
+
def archive_old_partitions
|
23
|
+
archive_old_partition_key_values_set.each do |*partition_key_values|
|
24
|
+
archive_old_partition(*partition_key_values)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
17
28
|
#
|
18
29
|
# Drop partitions that are no longer necessary.
|
19
30
|
# uses #old_partition_key_values_set as the list of
|
@@ -64,10 +75,20 @@ module Partitioned
|
|
64
75
|
# Used by #create_new_partitions and generally called once a day to update
|
65
76
|
# the database with new soon-to-be needed child tables.
|
66
77
|
#
|
67
|
-
# Typically overridden by the concrete class as this is pure business logic.
|
68
|
-
#
|
69
78
|
def new_partition_key_values_set
|
70
|
-
|
79
|
+
return configurator.janitorial_creates_needed
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# An array of key values (each key value is an array of keys) that represent
|
84
|
+
# the child partitions that should be archived probably because they are
|
85
|
+
# about to be dropped.
|
86
|
+
#
|
87
|
+
# Used by #archive_old_partitions and generally called once a day to clean up
|
88
|
+
# unneeded child tables.
|
89
|
+
#
|
90
|
+
def archive_old_partition_key_values_set
|
91
|
+
return configurator.janitorial_archives_needed
|
71
92
|
end
|
72
93
|
|
73
94
|
#
|
@@ -77,10 +98,16 @@ module Partitioned
|
|
77
98
|
# Used by #drop_old_partitions and generally called once a day to clean up
|
78
99
|
# unneeded child tables.
|
79
100
|
#
|
80
|
-
# Typically overridden by the concrete class as this is pure business logic.
|
81
|
-
#
|
82
101
|
def old_partition_key_values_set
|
83
|
-
|
102
|
+
return configurator.janitorial_drops_needed
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Archive a specific partition from the database given
|
107
|
+
# the key value(s) of its check constraint columns.
|
108
|
+
#
|
109
|
+
def archive_old_partition(*partition_key_values)
|
110
|
+
archive_partition_table(*partition_key_values)
|
84
111
|
end
|
85
112
|
|
86
113
|
#
|
@@ -131,10 +158,24 @@ module Partitioned
|
|
131
158
|
# :method: partition_table_name
|
132
159
|
# delegated to Partitioned::PartitionedBase::PartitionManager::SqlAdapter#partition_table_name
|
133
160
|
|
161
|
+
##
|
162
|
+
# :method: partition_table_alias_name
|
163
|
+
# delegated to Partitioned::PartitionedBase::PartitionManager::SqlAdapter#partition_table_alias_name
|
164
|
+
|
165
|
+
##
|
166
|
+
# :method: sql_adapter
|
167
|
+
# delegated to Partitioned::PartitionedBase#sql_adapter
|
168
|
+
|
169
|
+
##
|
170
|
+
# :method: configurator
|
171
|
+
# delegated to Partitioned::PartitionedBase#configurator
|
172
|
+
|
134
173
|
extend Forwardable
|
135
|
-
def_delegators :parent_table_class, :sql_adapter
|
174
|
+
def_delegators :parent_table_class, :sql_adapter, :configurator
|
136
175
|
def_delegators :sql_adapter, :drop_partition_table, :create_partition_table, :add_partition_table_index,
|
137
|
-
:add_references_to_partition_table, :create_partition_schema, :add_parent_table_rules,
|
176
|
+
:add_references_to_partition_table, :create_partition_schema, :add_parent_table_rules,
|
177
|
+
:partition_table_name, :partition_table_alias_name
|
178
|
+
|
138
179
|
end
|
139
180
|
end
|
140
181
|
end
|
@@ -126,6 +126,13 @@ module Partitioned
|
|
126
126
|
return configurator.table_name(*partition_key_values)
|
127
127
|
end
|
128
128
|
|
129
|
+
#
|
130
|
+
# A reasonable alias for the partition table
|
131
|
+
#
|
132
|
+
def partition_table_alias_name(*partition_key_values)
|
133
|
+
return configurator.table_alias_name(*partition_key_values)
|
134
|
+
end
|
135
|
+
|
129
136
|
#
|
130
137
|
# Create a single child table.
|
131
138
|
#
|
@@ -61,7 +61,7 @@ module Partitioned
|
|
61
61
|
# @return [String] the fully qualified name of the database table, ie: foos_partitions.p17
|
62
62
|
def partition_table_name
|
63
63
|
symbolized_attributes = attributes.symbolize_keys
|
64
|
-
return self.class.
|
64
|
+
return self.class.partition_table_name(*self.class.partition_keys.map{|attribute_name| symbolized_attributes[attribute_name]})
|
65
65
|
end
|
66
66
|
|
67
67
|
#
|
@@ -119,7 +119,7 @@ module Partitioned
|
|
119
119
|
new_arel_table = @arel_tables[key_values]
|
120
120
|
arel_engine_hash = {:engine => self.arel_engine}
|
121
121
|
arel_engine_hash[:as] = as unless as.blank?
|
122
|
-
new_arel_table = Arel::Table.new(self.
|
122
|
+
new_arel_table = Arel::Table.new(self.partition_table_name(*key_values), arel_engine_hash)
|
123
123
|
return new_arel_table
|
124
124
|
end
|
125
125
|
|
@@ -135,19 +135,8 @@ module Partitioned
|
|
135
135
|
return self.class.dynamic_arel_table(key_values, as)
|
136
136
|
end
|
137
137
|
|
138
|
-
# :from_partition_scope is generally not used directly,
|
139
|
-
# use helper self.from_partition so that the derived class
|
140
|
-
# can be passed into :from_partition_scope
|
141
138
|
#
|
142
|
-
#
|
143
|
-
scope :from_partition_scope, lambda { |target_class, *partition_field|
|
144
|
-
{
|
145
|
-
:from => "#{target_class.partition_name(*partition_field)} AS #{target_class.table_name}"
|
146
|
-
}
|
147
|
-
}
|
148
|
-
|
149
|
-
#
|
150
|
-
# Real scope (uses #from_partition_scope). This scope is used to target the
|
139
|
+
# This scoping is used to target the
|
151
140
|
# active record find() to a specific child table and alias it to the name of the
|
152
141
|
# parent table (so activerecord can generally work with it)
|
153
142
|
#
|
@@ -157,29 +146,16 @@ module Partitioned
|
|
157
146
|
#
|
158
147
|
# where KEY is the key value(s) used as the check constraint on Foo's table.
|
159
148
|
#
|
160
|
-
# Because the scope is specific to a class (a class method) but unlike
|
161
|
-
# class methods is not inherited, one must use this form (#from_partition) instead
|
162
|
-
# of #from_partition_scope to get the most derived classes specific active record scope.
|
163
|
-
#
|
164
149
|
# @param [*Array<Object>] partition_field the field values to partition on
|
165
150
|
# @return [Hash] the scoping
|
166
151
|
def self.from_partition(*partition_field)
|
167
|
-
|
152
|
+
table_alias_name = partition_table_alias_name(*partition_field)
|
153
|
+
from("#{partition_table_name(*partition_field)} AS #{table_alias_name}").
|
154
|
+
tap{|relation| relation.table.table_alias = table_alias_name}
|
168
155
|
end
|
169
156
|
|
170
|
-
# :from_partitioned_without_alias_scope is generally not used directly,
|
171
|
-
# use helper self.from_partitioned_without_alias so that the derived class
|
172
|
-
# can be passed into :from_partitioned_without_alias_scope
|
173
157
|
#
|
174
|
-
#
|
175
|
-
scope :from_partitioned_without_alias_scope, lambda { |target_class, *partition_field|
|
176
|
-
{
|
177
|
-
:from => target_class.partition_name(*partition_field)
|
178
|
-
}
|
179
|
-
}
|
180
|
-
|
181
|
-
#
|
182
|
-
# Real scope (uses #from_partitioned_without_alias_scope). This scope is used to target the
|
158
|
+
# This scope is used to target the
|
183
159
|
# active record find() to a specific child table. Is probably best used in advanced
|
184
160
|
# activerecord queries when a number of tables are involved in the query.
|
185
161
|
#
|
@@ -205,7 +181,9 @@ module Partitioned
|
|
205
181
|
# @param [*Array<Object>] partition_field the field values to partition on
|
206
182
|
# @return [Hash] the scoping
|
207
183
|
def self.from_partitioned_without_alias(*partition_field)
|
208
|
-
|
184
|
+
table_alias_name = partition_table_name(*partition_field)
|
185
|
+
from(table_alias_name).
|
186
|
+
tap{|relation| relation.table.table_alias = table_alias_name}
|
209
187
|
end
|
210
188
|
|
211
189
|
#
|
@@ -252,8 +230,24 @@ module Partitioned
|
|
252
230
|
#
|
253
231
|
# For a parent table name foos, that would be foos_partitions
|
254
232
|
#
|
233
|
+
# N.B.: if the parent table is not in the default schema ("public") the name of the
|
234
|
+
# partition schema is prefixed by the schema name of the parent table and an
|
235
|
+
# underscore. That is, if a parent table schema/table name is "other.foos"
|
236
|
+
# the schema for its partitions will be "other_foos_partitions"
|
237
|
+
#
|
255
238
|
partition.schema_name lambda {|model|
|
256
|
-
|
239
|
+
schema_parts = []
|
240
|
+
table_parts = model.table_name.split('.')
|
241
|
+
# table_parts should be either ["table_name"] or ["schema_name", "table_name"]
|
242
|
+
if table_parts.length == 2
|
243
|
+
# XXX should we find the schema_path here and accept anything in the path as "public"
|
244
|
+
unless table_parts.first == "public"
|
245
|
+
schema_parts << table_parts.first
|
246
|
+
end
|
247
|
+
end
|
248
|
+
schema_parts << table_parts.last
|
249
|
+
schema_parts << 'partitions'
|
250
|
+
return schema_parts.join('_')
|
257
251
|
}
|
258
252
|
|
259
253
|
#
|
@@ -272,7 +266,9 @@ module Partitioned
|
|
272
266
|
# The child table is defined by the partition key values passed in.
|
273
267
|
#
|
274
268
|
partition.parent_table_schema_name lambda {|model, *partition_key_values|
|
275
|
-
|
269
|
+
table_parts = model.table_name.split('.')
|
270
|
+
# table_parts should be either ["table_name"] or ["schema_name", "table_name"]
|
271
|
+
return table_parts.first if table_parts.length == 2
|
276
272
|
return "public"
|
277
273
|
}
|
278
274
|
|
@@ -308,6 +304,13 @@ module Partitioned
|
|
308
304
|
return "#{configurator.schema_name}.#{configurator.part_name(*partition_key_values)}"
|
309
305
|
}
|
310
306
|
|
307
|
+
#
|
308
|
+
# A reasonable alias for this table
|
309
|
+
#
|
310
|
+
partition.table_alias_name lambda {|model, *partition_key_values|
|
311
|
+
return model.configurator.parent_table_name(*partition_key_values).gsub('.', '_')
|
312
|
+
}
|
313
|
+
|
311
314
|
#
|
312
315
|
# The name of the child table without a schema name or prefix. this is used to
|
313
316
|
# build child table names for multi-level partitions.
|
@@ -366,6 +369,13 @@ module Partitioned
|
|
366
369
|
partition_manager.add_parent_table_rules(*partition_key_values)
|
367
370
|
end
|
368
371
|
|
372
|
+
##
|
373
|
+
# :method: archive_old_partitions
|
374
|
+
# delegated to Partitioned::PartitionedBase::PartitionManager#archive_old_partitions
|
375
|
+
def self.archive_old_partitions
|
376
|
+
partition_manager.archive_old_partitions
|
377
|
+
end
|
378
|
+
|
369
379
|
##
|
370
380
|
# :method: drop_old_partitions
|
371
381
|
# delegated to Partitioned::PartitionedBase::PartitionManager#drop_old_partitions
|
@@ -380,6 +390,13 @@ module Partitioned
|
|
380
390
|
partition_manager.create_new_partitions
|
381
391
|
end
|
382
392
|
|
393
|
+
##
|
394
|
+
# :method: archive_old_partition
|
395
|
+
# delegated to Partitioned::PartitionedBase::PartitionManager#archive_old_partition
|
396
|
+
def self.archive_old_partition(*partition_key_values)
|
397
|
+
partition_manager.archive_old_partition(*partition_key_values)
|
398
|
+
end
|
399
|
+
|
383
400
|
##
|
384
401
|
# :method: drop_old_partition
|
385
402
|
# delegated to Partitioned::PartitionedBase::PartitionManager#drop_old_partition
|
@@ -421,5 +438,12 @@ module Partitioned
|
|
421
438
|
def self.partition_name(*partition_key_values)
|
422
439
|
return partition_manager.partition_table_name(*partition_key_values)
|
423
440
|
end
|
441
|
+
|
442
|
+
##
|
443
|
+
# :method: partition_table_alias_name
|
444
|
+
# delegated to Partitioned::PartitionedBase::PartitionManager#partition_table_alias_name
|
445
|
+
def self.partition_table_alias_name(*partition_key_values)
|
446
|
+
return partition_manager.partition_table_alias_name(*partition_key_values)
|
447
|
+
end
|
424
448
|
end
|
425
449
|
end
|
data/lib/partitioned/version.rb
CHANGED
data/partitioned.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.name = 'partitioned'
|
8
8
|
s.version = Partitioned::VERSION
|
9
9
|
s.license = 'New BSD License'
|
10
|
-
s.date = '2012-
|
10
|
+
s.date = '2012-09-11'
|
11
11
|
s.summary = "Postgres table partitioning support for ActiveRecord."
|
12
12
|
s.description = "A gem providing support for table partitioning in ActiveRecord. Support is only available for postgres databases. Other features include child table management (creation and deletion) and bulk data creating and updating."
|
13
13
|
s.authors = ["Keith Gabryelski", "Aleksandr Dembskiy"]
|
@@ -45,12 +45,12 @@ module ActiveRecord::ConnectionAdapters
|
|
45
45
|
describe "next_sequence_value" do
|
46
46
|
|
47
47
|
it "returns next_sequence_value" do
|
48
|
-
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should ==
|
48
|
+
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should == 1
|
49
49
|
ActiveRecord::Base.connection.execute <<-SQL
|
50
50
|
insert into employees(name, company_id) values ('Nikita', 1);
|
51
51
|
SQL
|
52
|
-
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should ==
|
53
|
-
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should ==
|
52
|
+
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should == 3
|
53
|
+
ActiveRecord::Base.connection.next_sequence_value(Employee.sequence_name).should == 4
|
54
54
|
end
|
55
55
|
|
56
56
|
end # next_sequence_value
|
@@ -173,4 +173,4 @@ module ActiveRecord::ConnectionAdapters
|
|
173
173
|
|
174
174
|
end # PostgreSQLAdapter
|
175
175
|
|
176
|
-
end # ActiveRecord::ConnectionAdapters
|
176
|
+
end # ActiveRecord::ConnectionAdapters
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: partitioned
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-09-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: pg
|
@@ -175,18 +175,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
175
175
|
- - ! '>='
|
176
176
|
- !ruby/object:Gem::Version
|
177
177
|
version: '0'
|
178
|
-
segments:
|
179
|
-
- 0
|
180
|
-
hash: -2034428678854769428
|
181
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
179
|
none: false
|
183
180
|
requirements:
|
184
181
|
- - ! '>='
|
185
182
|
- !ruby/object:Gem::Version
|
186
183
|
version: '0'
|
187
|
-
segments:
|
188
|
-
- 0
|
189
|
-
hash: -2034428678854769428
|
190
184
|
requirements: []
|
191
185
|
rubyforge_project:
|
192
186
|
rubygems_version: 1.8.24
|