partitioned 0.8.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.
Files changed (95) hide show
  1. data/Gemfile +17 -0
  2. data/LICENSE +30 -0
  3. data/PARTITIONING_EXPLAINED.txt +351 -0
  4. data/README +111 -0
  5. data/Rakefile +27 -0
  6. data/examples/README +23 -0
  7. data/examples/company_id.rb +417 -0
  8. data/examples/company_id_and_created_at.rb +689 -0
  9. data/examples/created_at.rb +590 -0
  10. data/examples/created_at_referencing_awards.rb +1000 -0
  11. data/examples/id.rb +475 -0
  12. data/examples/lib/by_company_id.rb +11 -0
  13. data/examples/lib/command_line_tool_mixin.rb +71 -0
  14. data/examples/lib/company.rb +29 -0
  15. data/examples/lib/get_options.rb +44 -0
  16. data/examples/lib/roman.rb +41 -0
  17. data/examples/start_date.rb +621 -0
  18. data/init.rb +1 -0
  19. data/lib/monkey_patch_activerecord.rb +92 -0
  20. data/lib/monkey_patch_postgres.rb +73 -0
  21. data/lib/partitioned.rb +26 -0
  22. data/lib/partitioned/active_record_overrides.rb +34 -0
  23. data/lib/partitioned/bulk_methods_mixin.rb +288 -0
  24. data/lib/partitioned/by_created_at.rb +13 -0
  25. data/lib/partitioned/by_foreign_key.rb +21 -0
  26. data/lib/partitioned/by_id.rb +35 -0
  27. data/lib/partitioned/by_integer_field.rb +32 -0
  28. data/lib/partitioned/by_monthly_time_field.rb +23 -0
  29. data/lib/partitioned/by_time_field.rb +65 -0
  30. data/lib/partitioned/by_weekly_time_field.rb +30 -0
  31. data/lib/partitioned/multi_level.rb +20 -0
  32. data/lib/partitioned/multi_level/configurator/data.rb +14 -0
  33. data/lib/partitioned/multi_level/configurator/dsl.rb +32 -0
  34. data/lib/partitioned/multi_level/configurator/reader.rb +162 -0
  35. data/lib/partitioned/multi_level/partition_manager.rb +47 -0
  36. data/lib/partitioned/partitioned_base.rb +354 -0
  37. data/lib/partitioned/partitioned_base/configurator.rb +6 -0
  38. data/lib/partitioned/partitioned_base/configurator/data.rb +62 -0
  39. data/lib/partitioned/partitioned_base/configurator/dsl.rb +628 -0
  40. data/lib/partitioned/partitioned_base/configurator/reader.rb +209 -0
  41. data/lib/partitioned/partitioned_base/partition_manager.rb +138 -0
  42. data/lib/partitioned/partitioned_base/sql_adapter.rb +286 -0
  43. data/lib/partitioned/version.rb +3 -0
  44. data/lib/tasks/desirable_tasks.rake +4 -0
  45. data/partitioned.gemspec +21 -0
  46. data/spec/dummy/.rspec +1 -0
  47. data/spec/dummy/README.rdoc +261 -0
  48. data/spec/dummy/Rakefile +7 -0
  49. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  50. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  51. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  52. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  53. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  54. data/spec/dummy/config.ru +4 -0
  55. data/spec/dummy/config/application.rb +51 -0
  56. data/spec/dummy/config/boot.rb +10 -0
  57. data/spec/dummy/config/database.yml +32 -0
  58. data/spec/dummy/config/environment.rb +5 -0
  59. data/spec/dummy/config/environments/development.rb +30 -0
  60. data/spec/dummy/config/environments/production.rb +60 -0
  61. data/spec/dummy/config/environments/test.rb +39 -0
  62. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  63. data/spec/dummy/config/initializers/inflections.rb +10 -0
  64. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  65. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  66. data/spec/dummy/config/initializers/session_store.rb +8 -0
  67. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  68. data/spec/dummy/config/locales/en.yml +5 -0
  69. data/spec/dummy/config/routes.rb +58 -0
  70. data/spec/dummy/public/404.html +26 -0
  71. data/spec/dummy/public/422.html +26 -0
  72. data/spec/dummy/public/500.html +26 -0
  73. data/spec/dummy/public/favicon.ico +0 -0
  74. data/spec/dummy/script/rails +6 -0
  75. data/spec/dummy/spec/spec_helper.rb +27 -0
  76. data/spec/monkey_patch_posgres_spec.rb +176 -0
  77. data/spec/partitioned/bulk_methods_mixin_spec.rb +512 -0
  78. data/spec/partitioned/by_created_at_spec.rb +62 -0
  79. data/spec/partitioned/by_foreign_key_spec.rb +95 -0
  80. data/spec/partitioned/by_id_spec.rb +97 -0
  81. data/spec/partitioned/by_integer_field_spec.rb +143 -0
  82. data/spec/partitioned/by_monthly_time_field_spec.rb +100 -0
  83. data/spec/partitioned/by_time_field_spec.rb +182 -0
  84. data/spec/partitioned/by_weekly_time_field_spec.rb +100 -0
  85. data/spec/partitioned/multi_level/configurator/dsl_spec.rb +88 -0
  86. data/spec/partitioned/multi_level/configurator/reader_spec.rb +147 -0
  87. data/spec/partitioned/partitioned_base/configurator/dsl_spec.rb +459 -0
  88. data/spec/partitioned/partitioned_base/configurator/reader_spec.rb +513 -0
  89. data/spec/partitioned/partitioned_base/sql_adapter_spec.rb +204 -0
  90. data/spec/partitioned/partitioned_base_spec.rb +173 -0
  91. data/spec/spec_helper.rb +32 -0
  92. data/spec/support/shared_example_spec_helper_for_integer_key.rb +137 -0
  93. data/spec/support/shared_example_spec_helper_for_time_key.rb +147 -0
  94. data/spec/support/tables_spec_helper.rb +47 -0
  95. metadata +250 -0
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Partitioned'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
data/examples/README ADDED
@@ -0,0 +1,23 @@
1
+ The directory holds examples of how to use the partitioned gem.
2
+
3
+ The lib directory contains:
4
+ by_company_id.rb - a partitioned model where the partition's key is the column company_id that references companies.
5
+ company.rb - an ActiveRecord model for the table companies.
6
+ roman.rb - some helper routines for generating roman numerals.
7
+
8
+ This directory holds executable rails scripts that create and populate partitioned tables. The scripts accept the following
9
+ parameters:
10
+ --force delete used tables before starting
11
+ --cleanup delete used tables and exit
12
+
13
+ The scripts are:
14
+ company_id.rb - table 'employees' partitioned by company_id
15
+ company_id_and_created_at.rb - table 'employees' has multi-level partitioning by company_id then created_at
16
+ created_at is grouped by week where weeks start on Monday.
17
+ created_at.rb - table 'employees' partitioned by created_at
18
+ created_at is grouped by week where weeks start on Monday.
19
+ created_at_referencing_awards.rb - table 'employees' partitioned by created_at and table 'awards' is partitioned
20
+ by created_at which a reference to specific child table of employees with the
21
+ created_at range.
22
+ id.rb - partitioned on 'id' grouping each 10 records into separate child tables.
23
+ start_date.rb - grouped by column start_date which is a date grouped by month.
@@ -0,0 +1,417 @@
1
+ #!/usr/bin/env ../spec/dummy/script/rails runner
2
+ # if you use linux, please change previous line to the
3
+ # "#! ../spec/dummy/script/rails runner"
4
+
5
+ # Before running this example you should execute "bundle install" and "rake db:create".
6
+ # To run this example you should open 'example' directory and execute example with one of the following flags:
7
+ # -C cleanup data in database and exit;
8
+ # -F cleanup data in database before creating new data;
9
+ #
10
+ # For example:
11
+ # ./company_id.rb - F
12
+
13
+ # Initial data:
14
+ #
15
+ # Companies table is completed by four companies:
16
+ #
17
+ # create table companies (
18
+ # id serial not null primary key,
19
+ # created_at timestamp not null default now(),
20
+ # updated_at timestamp,
21
+ # name text null
22
+ # );
23
+ #
24
+ # insert into companies (created_at,id,name) values
25
+ # ('2012-03-13 13:26:52.184347',1,'Fluent Mobile, inc.'),
26
+ # ('2012-03-13 13:26:52.184347',2,'Fiksu, inc.'),
27
+ # ('2012-03-13 13:26:52.184347',3,'AppExchanger, inc.'),
28
+ # ('2012-03-13 13:26:52.184347',4,'FreeMyApps, inc.');
29
+ #
30
+ # id | created_at | updated_at | name
31
+ # ---+----------------------------+------------+---------------------
32
+ # 1 | 2012-03-11 13:26:52.184347 | | Fluent Mobile, inc.
33
+ # 2 | 2012-03-11 13:26:52.184347 | | Fiksu, inc.
34
+ # 3 | 2012-03-11 13:26:52.184347 | | AppExchanger, inc.
35
+ # 4 | 2012-03-11 13:26:52.184347 | | FreeMyApps, inc.
36
+ #
37
+ # Employees table is associated with companies table via key - id:
38
+ #
39
+ # create table employees (
40
+ # id serial not null primary key,
41
+ # created_at timestamp not null default now(),
42
+ # updated_at timestamp,
43
+ # name text not null,
44
+ # salary money not null,
45
+ # company_id integer not null
46
+ # );
47
+ #
48
+ # id | created_at | updated_at | name | salary | company_id
49
+ # ----+------------+------------+------+--------+------------
50
+ #
51
+ # Task:
52
+ #
53
+ # To increase the speed of requests to the database and to reduce the time
54
+ # of the request, need to split the Employees table to the partition tables.
55
+ # Break criterion is a company (company_id).
56
+ #
57
+ # Implementation:
58
+ #
59
+ # Class Employee inherits from the abstract class ByCompanyId,
60
+ # which supports partitioning.
61
+ #
62
+ # class Employee < ByCompanyId
63
+ #
64
+ # Indicates a relationship to the companies table.
65
+ # belongs_to :company, :class_name => 'Company'
66
+ #
67
+ # Create a rules for each partition.
68
+ # Id is a unique index. Foreign key is company_id.
69
+ # This imposes a restriction on each of partition, that
70
+ # the column company_id associated with the table of companies
71
+ # and can not have values ​​that are not in the table companies.
72
+ # In this example, set up only 4 records in the table companies,
73
+ # so company_id can not be equal to 5 in any partition
74
+ # until it is an established company with id = 5.
75
+ # end
76
+ #
77
+ # Create a schema employees_partitions, within which to store all of our partitions:
78
+ #
79
+ # Employee.create_infrastructure
80
+ #
81
+ # Create a partitions for each company:
82
+ #
83
+ # company_ids = Company.all.map(&:id)
84
+ # Employee.create_new_partition_tables(company_ids)
85
+ #
86
+ # Each of partition has the same structure as that of the employees table:
87
+ #
88
+ # id | created_at | updated_at | name | salary | company_id
89
+ # ----+------------+------------+------+--------+------------
90
+ #
91
+ # CREATE TABLE "employees_partitions"."p1" (CHECK (( company_id = 1 ))) INHERITS (employees);
92
+ # CREATE UNIQUE INDEX "index_employees_partitions.p1_on_id" ON "employees_partitions"."p1" ("id");
93
+ # ALTER TABLE employees_partitions.p1 add foreign key (company_id) references companies(id);
94
+ #
95
+ # CREATE TABLE "employees_partitions"."p2" (CHECK (( company_id = 2 ))) INHERITS (employees);
96
+ # CREATE UNIQUE INDEX "index_employees_partitions.p2_on_id" ON "employees_partitions"."p2" ("id");
97
+ # ALTER TABLE employees_partitions.p2 add foreign key (company_id) references companies(id);
98
+ #
99
+ # CREATE TABLE "employees_partitions"."p3" (CHECK (( company_id = 3 ))) INHERITS (employees);
100
+ # CREATE UNIQUE INDEX "index_employees_partitions.p3_on_id" ON "employees_partitions"."p3" ("id");
101
+ # ALTER TABLE employees_partitions.p3 add foreign key (company_id) references companies(id);
102
+ #
103
+ # CREATE TABLE "employees_partitions"."p4" (CHECK (( company_id = 4 ))) INHERITS (employees);
104
+ # CREATE UNIQUE INDEX "index_employees_partitions.p4_on_id" ON "employees_partitions"."p4" ("id");
105
+ # ALTER TABLE employees_partitions.p4 add foreign key (company_id) references companies(id);
106
+ #
107
+ # Since we have done four records of companies in the table,
108
+ # we have four partitions:
109
+ #
110
+ # employees_partitions.p1
111
+ # employees_partitions.p2
112
+ # employees_partitions.p3
113
+ # employees_partitions.p4
114
+ #
115
+ # Each of partitions inherits from employees table,
116
+ # thus a new row will automatically be added to the employees table .
117
+ #
118
+ # To add data, we use the following constructions,
119
+ # in which employees and employee_data - a random data:
120
+ #
121
+ # create_many - allows you to add multiple records
122
+ # Employee.create_many(employees)
123
+ # create - allows you to add one record
124
+ # Employee.create(employee_data)
125
+ # new/save! - allows you to add one record without using "create" method
126
+ # employee = Employee.new(employee_data)
127
+ # employee.save!
128
+ #
129
+ # For update data, we use the following constructions,
130
+ # in which updates - a random data:
131
+ #
132
+ # update_many - allows you to update multiple records.
133
+ # :set_array - additional option, you may read the description
134
+ # of the method in the file update_many bulk_methods_mixin.rb about this option.
135
+ # Employee.update_many(updates, { :set_array => '"salary = #{table_name}.salary +
136
+ # datatable.salary, updated_at = now()"' })
137
+ #
138
+ # This construction using for update one record. You also may use update method.
139
+ # employee = Employee.from_partition(employee_record[:company_id]).find(employee_record[:id])
140
+ # employee.save
141
+ #
142
+ # The data get into the employees table ONLY through partition tables.
143
+ # You can not do an insert row into a table employees directly.
144
+ # For this purpose special restrictions are imposed on the table employees.
145
+ #
146
+ # Result:
147
+ #
148
+ # We have table companies:
149
+ #
150
+ # id | created_at | updated_at | name
151
+ # ---+----------------------------+------------+---------------------
152
+ # 1 | 2012-03-11 13:26:52.184347 | | Fluent Mobile, inc.
153
+ # 2 | 2012-03-11 13:26:52.184347 | | Fiksu, inc.
154
+ # 3 | 2012-03-11 13:26:52.184347 | | AppExchanger, inc.
155
+ # 4 | 2012-03-11 13:26:52.184347 | | FreeMyApps, inc.
156
+ #
157
+ # Table employees with random data from 1 to 5000:
158
+ #
159
+ # id | created_at | updated_at | name | salary | company_id
160
+ #------+----------------------------+----------------------------+-------------------------------------+-------------+------------
161
+ # 1 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:45.519874 | Winston J. Sillypants, I | $106,363.00 | 4
162
+ # 2 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, II | $103,767.00 | 3
163
+ # 3 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:43.250032 | Winston J. Sillypants, III | $128,998.00 | 1
164
+ # ...
165
+ # 4998 | 2012-03-26 11:26:40.43347 | 2012-03-26 11:26:44.570338 | Picholine Pimplenad, MMMMCMXCVIII | $93,628.00 | 3
166
+ # 4999 | 2012-03-26 11:26:40.437824 | 2012-03-26 11:26:40.437824 | Picholine Pimplenad, MMMMCMXCIX | $133,964.00 | 3
167
+ # 5000 | 2012-03-26 11:26:40.441958 | 2012-03-26 11:26:40.441958 | Picholine Pimplenad, _V | $76,519.00 | 4
168
+ #
169
+ # Partition employees_partitions.p1 - partition where company_id = 1:
170
+ #
171
+ # id | created_at | updated_at | name | salary | company_id
172
+ #------+----------------------------+----------------------------+-------------------------------------+-------------+------------
173
+ # 3 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:43.250032 | Winston J. Sillypants, III | $128,998.00 | 1
174
+ # 5 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, V | $134,319.00 | 1
175
+ # 8 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VIII | $82,995.00 | 1
176
+ # ...
177
+ # 4988 | 2012-03-26 11:26:40.392319 | 2012-03-26 11:26:44.077802 | Picholine Pimplenad, MMMMCMLXXXVIII | $132,535.00 | 1
178
+ # 4994 | 2012-03-26 11:26:40.416951 | 2012-03-26 11:26:40.416951 | Picholine Pimplenad, MMMMCMXCIV | $105,119.00 | 1
179
+ # 4996 | 2012-03-26 11:26:40.425268 | 2012-03-26 11:26:40.425268 | Picholine Pimplenad, MMMMCMXCVI | $81,403.00 | 1
180
+ #
181
+ # Partition employees_partitions.p2 - partition where company_id = 2:
182
+ #
183
+ # id | created_at | updated_at | name | salary | company_id
184
+ #------+----------------------------+----------------------------+-------------------------------------+-------------+------------
185
+ # 4 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, IV | $136,540.00 | 2
186
+ # 12 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XII | $103,200.00 | 2
187
+ # 13 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XIII | $139,077.00 | 2
188
+ # ...
189
+ # 4991 | 2012-03-26 11:26:40.40451 | 2012-03-26 11:26:42.057637 | Picholine Pimplenad, MMMMCMXCI | $122,115.00 | 2
190
+ # 4992 | 2012-03-26 11:26:40.408519 | 2012-03-26 11:26:40.408519 | Picholine Pimplenad, MMMMCMXCII | $90,176.00 | 2
191
+ # 4995 | 2012-03-26 11:26:40.421126 | 2012-03-26 12:26:49.969993 | Picholine Pimplenad, MMMMCMXCV | $86,410.00 | 2
192
+ #
193
+ #
194
+ # Partition employees_partitions.p3 - partition where company_id = 3:
195
+ #
196
+ # id | created_at | updated_at | name | salary | company_id
197
+ #------+----------------------------+----------------------------+-------------------------------------+-------------+------------
198
+ # 2 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, II | $103,767.00 | 3
199
+ # 6 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VI | $67,280.00 | 3
200
+ # 9 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, IX | $75,396.00 | 3
201
+ # ...
202
+ # 4990 | 2012-03-26 11:26:40.400746 | 2012-03-26 11:26:43.604349 | Picholine Pimplenad, MMMMCMXC | $95,882.00 | 3
203
+ # 4998 | 2012-03-26 11:26:40.43347 | 2012-03-26 11:26:44.570338 | Picholine Pimplenad, MMMMCMXCVIII | $93,628.00 | 3
204
+ # 4999 | 2012-03-26 11:26:40.437824 | 2012-03-26 11:26:40.437824 | Picholine Pimplenad, MMMMCMXCIX | $133,964.00 | 3
205
+ #
206
+ #
207
+ # Partition employees_partitions.p4 - partition where company_id = 4:
208
+ #
209
+ # id | created_at | updated_at | name | salary | company_id
210
+ #------+----------------------------+----------------------------+-------------------------------------+-------------+------------
211
+ # 1 | 2012-03-26 11:26:30.704959 | 2012-03-26 11:26:45.519874 | Winston J. Sillypants, I | $106,363.00 | 4
212
+ # 7 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, VII | $111,585.00 | 4
213
+ # 17 | 2012-03-26 11:26:30.704959 | | Winston J. Sillypants, XVII | $135,812.00 | 4
214
+ # ...
215
+ # 4993 | 2012-03-26 11:26:40.412815 | 2012-03-26 11:26:40.412815 | Picholine Pimplenad, MMMMCMXCIII | $95,851.00 | 4
216
+ # 4997 | 2012-03-26 11:26:40.429356 | 2012-03-26 11:26:40.429356 | Picholine Pimplenad, MMMMCMXCVII | $84,564.00 | 4
217
+ # 5000 | 2012-03-26 11:26:40.441958 | 2012-03-26 11:26:40.441958 | Picholine Pimplenad, _V | $76,519.00 | 4
218
+ #
219
+
220
+ require File.expand_path(File.dirname(__FILE__) + "/lib/command_line_tool_mixin")
221
+ require File.expand_path(File.dirname(__FILE__) + "/lib/get_options")
222
+
223
+ include CommandLineToolMixin
224
+
225
+ $cleanup = false
226
+ $force = false
227
+ $create_many = 3000
228
+ $create_individual = 1000
229
+ $new_individual = 1000
230
+ $update_many = 1000
231
+ $update_individual = 1000
232
+
233
+ @options = {
234
+ "--cleanup" => {
235
+ :short => "-C",
236
+ :argument => GetoptLong::NO_ARGUMENT,
237
+ :note => "cleanup data in database and exit"
238
+ },
239
+ "--force" => {
240
+ :short => "-F",
241
+ :argument => GetoptLong::NO_ARGUMENT,
242
+ :note => "cleanup data in database before creating new data"
243
+ },
244
+ "--create-many" => {
245
+ :short => "-m",
246
+ :argument => GetoptLong::REQUIRED_ARGUMENT,
247
+ :note => "how many objects to create via create_many",
248
+ :argument_note => "NUMBER"
249
+ },
250
+ "--create-individual" => {
251
+ :short => "-i",
252
+ :argument => GetoptLong::REQUIRED_ARGUMENT,
253
+ :note => "how many objects to create via create",
254
+ :argument_note => "NUMBER"
255
+ },
256
+ "--new-individual" => {
257
+ :short => "-I",
258
+ :argument => GetoptLong::REQUIRED_ARGUMENT,
259
+ :note => "how many objects to create via new/save",
260
+ :argument_note => "NUMBER"
261
+ },
262
+ "--update-individual" => {
263
+ :short => "-u",
264
+ :argument => GetoptLong::REQUIRED_ARGUMENT,
265
+ :note => "how many objects to update individually",
266
+ :argument_note => "NUMBER"
267
+ },
268
+ "--update-many" => {
269
+ :short => "-U",
270
+ :argument => GetoptLong::REQUIRED_ARGUMENT,
271
+ :note => "how many objects to update via update_many",
272
+ :argument_note => "NUMBER"
273
+ },
274
+ }
275
+
276
+ command_line_options(@options) do |option,argument|
277
+ if option == '--cleanup'
278
+ $cleanup = true
279
+ elsif option == '--force'
280
+ $force = true
281
+ elsif option == '--create-many'
282
+ $create_many = argument.to_i
283
+ elsif option == '--create-individual'
284
+ $create_individual = argument.to_i
285
+ elsif option == '--new-individual'
286
+ $new_individual = argument.to_i
287
+ elsif option == '--update-individual'
288
+ $update_individual = argument.to_i
289
+ elsif option == '--update-many'
290
+ $update_many = argument.to_i
291
+ end
292
+ end
293
+
294
+ if $cleanup || $force
295
+ ActiveRecord::Base.connection.drop_schema("employees_partitions", :cascade => true) rescue nil
296
+ ActiveRecord::Base.connection.drop_table("employees") rescue nil
297
+ ActiveRecord::Base.connection.drop_table("companies") rescue nil
298
+ exit(0) if $cleanup
299
+ end
300
+
301
+ $total_records = $create_many + $create_individual + $new_individual
302
+
303
+ puts "total records: #{$total_records}"
304
+
305
+ # the ActiveRecord classes
306
+
307
+ require File.expand_path(File.dirname(__FILE__) + "/lib/company")
308
+ require File.expand_path(File.dirname(__FILE__) + "/lib/by_company_id")
309
+
310
+ class Employee < ByCompanyId
311
+ belongs_to :company, :class_name => 'Company'
312
+ attr_accessible :salary, :company_id, :name
313
+
314
+ connection.execute <<-SQL
315
+ create table employees
316
+ (
317
+ id serial not null primary key,
318
+ created_at timestamp not null default now(),
319
+ updated_at timestamp,
320
+ name text not null,
321
+ salary money not null,
322
+ company_id integer not null
323
+ );
324
+ SQL
325
+ end
326
+
327
+ # You should have the following tables:
328
+ # public.companies
329
+ # public.employees
330
+
331
+ # create the infrastructure for EMPLOYEES table which includes the schema and partition tables
332
+
333
+ Employee.create_infrastructure
334
+
335
+ # You should have the following schema:
336
+ # employees_partitions
337
+
338
+ # add some companies
339
+
340
+ Company.create_many(COMPANIES)
341
+ company_ids = Company.all.map(&:id)
342
+
343
+ # create the employees partitions dependant on the all companies
344
+
345
+ Employee.create_new_partition_tables(company_ids)
346
+
347
+ # You should have the following tables:
348
+ # employees_partitions.p1
349
+ # employees_partitions.p2
350
+ # employees_partitions.p3
351
+ # employees_partitions.p4
352
+
353
+ employees = []
354
+
355
+ require File.expand_path(File.dirname(__FILE__) + "/lib/roman")
356
+
357
+ # generates data for employees_partitions and employees tables
358
+
359
+ base = 0
360
+ (1..$create_many).each do |i|
361
+ employees << {
362
+ :name => "Winston J. Sillypants, #{to_roman(base+i)}",
363
+ :salary => rand(80000) + 60000,
364
+ :company_id => company_ids[rand company_ids.length]
365
+ }
366
+ end
367
+
368
+ puts "creating many #{$create_many}"
369
+ Employee.create_many(employees)
370
+ base += $create_many
371
+
372
+ puts "creating individual #{$create_individual}"
373
+ (1..$create_individual).each do |i|
374
+ employee_data = {
375
+ :name => "Jonathan Crabapple, #{to_roman(base+i)}",
376
+ :salary => rand(80000) + 60000,
377
+ :company_id => company_ids[rand company_ids.length]
378
+ }
379
+ employees << Employee.create(employee_data)
380
+ end
381
+ base += $create_individual
382
+
383
+ puts "new individual #{$new_individual}"
384
+ (1..$new_individual).each do |i|
385
+ employee_data = {
386
+ :name => "Picholine Pimplenad, #{to_roman(base+i)}",
387
+ :salary => rand(80000) + 60000,
388
+ :company_id => company_ids[rand company_ids.length]
389
+ }
390
+ employee = Employee.new(employee_data)
391
+ employee.save!
392
+ employees << employee
393
+ end
394
+ base += $new_individual
395
+
396
+ updates = {}
397
+ puts "update many #{$update_many}"
398
+ (1..$update_many).each do |i|
399
+ employee_record = employees[rand(employees.length)]
400
+ updates[{
401
+ :id => employee_record[:id],
402
+ :company_id => employee_record[:company_id]
403
+ }] = {
404
+ :salary => 100
405
+ }
406
+ end
407
+
408
+ Employee.update_many(updates, {:set_array => '"salary = #{table_name}.salary + datatable.salary, updated_at = now()"'})
409
+
410
+ puts "update individual #{$update_individual}"
411
+ (1..$update_individual).each do |i|
412
+ employee_record = employees[rand(employees.length)]
413
+ employee = Employee.from_partition(employee_record[:company_id]).find(employee_record[:id])
414
+ employee.salary += 1000
415
+ employee.save
416
+ end
417
+