pg_party 1.0.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +297 -9
- data/lib/pg_party.rb +24 -3
- data/lib/pg_party/adapter/abstract_methods.rb +36 -0
- data/lib/pg_party/adapter/postgresql_methods.rb +45 -8
- data/lib/pg_party/adapter_decorator.rb +281 -27
- data/lib/pg_party/cache.rb +51 -16
- data/lib/pg_party/config.rb +22 -0
- data/lib/pg_party/hacks/postgresql_database_tasks.rb +25 -0
- data/lib/pg_party/model/hash_methods.rb +18 -0
- data/lib/pg_party/model/list_methods.rb +7 -2
- data/lib/pg_party/model/methods.rb +8 -4
- data/lib/pg_party/model/range_methods.rb +7 -2
- data/lib/pg_party/model/shared_methods.rb +14 -4
- data/lib/pg_party/model_decorator.rb +54 -42
- data/lib/pg_party/model_injector.rb +17 -5
- data/lib/pg_party/version.rb +1 -1
- metadata +57 -35
- data/lib/pg_party/hacks/schema_cache.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0edf666f9d4e7d3a7af82990be55d58b970949c5a549c1d8f1e1aeb2c066b09
|
4
|
+
data.tar.gz: 8c1164c72ffec0f00a892f9f4cf7028969a7aa39d056f4aae5e05674651a6142
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60baccd0471cd1628714d9d10e918d5b3be2708d07850bedf8751323cd91737321f93441fec5a576346de409580c3a7f2bb99a384c7edb0b1c70b0e96a2be84b
|
7
|
+
data.tar.gz: 12126fee3f2eae1b3a70771c79a07cab254b061c3b11ed20fbc8095f7521db05672219e93437f7a3cbb062b4ed95dd56aa2f09ae8e032b7a26cfaab7f6878def
|
data/README.md
CHANGED
@@ -48,6 +48,50 @@ $ gem install pg_party
|
|
48
48
|
Note that the gemspec does not require `pg`, as some model methods _may_ work for other databases.
|
49
49
|
Migration methods will be unavailable unless `pg` is installed.
|
50
50
|
|
51
|
+
## Configuration
|
52
|
+
|
53
|
+
These values can be accessed and set via `PgParty.config` and `PgParty.configure`.
|
54
|
+
|
55
|
+
- `caching`
|
56
|
+
- Whether to cache currently attached partitions and anonymous model classes
|
57
|
+
- Default: `true`
|
58
|
+
- `caching_ttl`
|
59
|
+
- Length of time (in seconds) that cache entries are considered valid
|
60
|
+
- Default: `-1` (never expire cache entries)
|
61
|
+
- `schema_exclude_partitions`
|
62
|
+
- Whether to exclude child partitions in `rake db:structure:dump`
|
63
|
+
- Default: `true`
|
64
|
+
- `create_template_tables`
|
65
|
+
- Whether to create template tables by default. Use the `template:` option when creating partitioned tables to override this default.
|
66
|
+
- Default: `true`
|
67
|
+
- `create_with_primary_key`
|
68
|
+
- Whether to add primary key constraints to partitioned (parent) tables by default.
|
69
|
+
* This is not supported for Postgres 10 but is recommended for Postgres 11
|
70
|
+
* Primary key constraints must include all partition keys, for example: `primary_key: [:id, :created_at], partition_key: :created_at`
|
71
|
+
* Partition keys cannot use expressions
|
72
|
+
* Can be overridden via the `create_with_primary_key:` option when creating partitioned tables
|
73
|
+
- Default: `false`
|
74
|
+
- `include_subpartitions_in_partition_list`
|
75
|
+
- Whether to include nested subpartitions in the result of `YourModelClass.partiton_list` mby default.
|
76
|
+
You can always pass the `include_subpartitions:` option to override this.
|
77
|
+
- Default: `false` (for backward compatibility)
|
78
|
+
|
79
|
+
Note that caching is done in-memory for each process of an application. Attaching / detaching partitions _will_ clear the cache, but only for the process that initiated the request. For multi-process web servers, it is recommended to use a TTL or disable caching entirely.
|
80
|
+
|
81
|
+
### Example
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# in a Rails initializer
|
85
|
+
PgParty.configure do |c|
|
86
|
+
c.caching_ttl = 60
|
87
|
+
c.schema_exclude_partitions = false
|
88
|
+
c.include_subpartitions_in_partition_list = true
|
89
|
+
# Postgres 11+ users starting fresh may want to use below options
|
90
|
+
c.create_template_tables = false
|
91
|
+
c.create_with_primary_key = true
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
51
95
|
## Usage
|
52
96
|
|
53
97
|
### Migrations
|
@@ -62,25 +106,63 @@ These methods are available in migrations as well as `ActiveRecord::Base#connect
|
|
62
106
|
- `create_list_partition`
|
63
107
|
- Create partitioned table using the _list_ partitioning method
|
64
108
|
- Required args: `table_name`, `partition_key:`
|
109
|
+
- `create_hash_partition` (Postgres 11+)
|
110
|
+
- Create partitioned table using the _hash_ partitioning method
|
111
|
+
- Required args: `table_name`, `partition_key:`
|
65
112
|
- `create_range_partition_of`
|
66
113
|
- Create partition in _range_ partitioned table with partition key between _range_ of values
|
67
114
|
- Required args: `table_name`, `start_range:`, `end_range:`
|
115
|
+
- Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`
|
68
116
|
- `create_list_partition_of`
|
69
117
|
- Create partition in _list_ partitioned table with partition key in _list_ of values
|
70
118
|
- Required args: `table_name`, `values:`
|
119
|
+
- Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`
|
120
|
+
- `create_hash_partition_of` (Postgres 11+)
|
121
|
+
- Create partition in _hash_ partitioned table for partition keys with hashed values having a specific remainder
|
122
|
+
- Required args: `table_name`, `modulus:`, `remainder`
|
123
|
+
- Create a subpartition by specifying a `partition_type:` of `:range`, `:list`, or `:hash` and a `partition_key:`
|
124
|
+
- Note that all partitions in a _hash_ partitioned table should have the same modulus. See [Examples](#examples) for more info.
|
125
|
+
- `create_default_partition_of` (Postgres 11+)
|
126
|
+
- Create a default partition for values not falling in the range or list constraints of any other partitions
|
127
|
+
- Required args: `table_name`
|
71
128
|
- `attach_range_partition`
|
72
129
|
- Attach existing table to _range_ partitioned table with partition key between _range_ of values
|
73
130
|
- Required args: `parent_table_name`, `child_table_name`, `start_range:`, `end_range:`
|
74
131
|
- `attach_list_partition`
|
75
132
|
- Attach existing table to _list_ partitioned table with partition key in _list_ of values
|
76
133
|
- Required args: `parent_table_name`, `child_table_name`, `values:`
|
134
|
+
- `attach_hash_partition` (Postgres 11+)
|
135
|
+
- Attach existing table to _hash_ partitioned table with partition key hashed values having a specific remainder
|
136
|
+
- Required args: `parent_table_name`, `child_table_name`, `modulus:`, `remainder`
|
137
|
+
- `attach_default_partition` (Postgres 11+)
|
138
|
+
- Attach existing table as the _default_ partition
|
139
|
+
- Required args: `parent_table_name`, `child_table_name`
|
77
140
|
- `detach_partition`
|
78
141
|
- Detach partition from both _range and list_ partitioned tables
|
79
142
|
- Required args: `parent_table_name`, `child_table_name`
|
80
143
|
- `create_table_like`
|
81
144
|
- Clone _any_ existing table
|
82
145
|
- Required args: `table_name`, `new_table_name`
|
83
|
-
|
146
|
+
- `partitions_for_table_name`
|
147
|
+
- List all attached partitions for a given table
|
148
|
+
- Required args: `table_name`, `include_subpartitions:` (true or false)
|
149
|
+
- `parent_for_table_name`
|
150
|
+
- Fetch the parent table for a partition
|
151
|
+
- Required args: `table_name`
|
152
|
+
- Pass optional `traverse: true` to return the top-level table in the hierarchy (for subpartitions)
|
153
|
+
- Returns `nil` if the table is not a partition / has no parent
|
154
|
+
- `table_partitioned?`
|
155
|
+
- Returns true if the table is partitioned (false for non-partitioned tables and partitions themselves)
|
156
|
+
- Required args: `table_name`
|
157
|
+
- `add_index_on_all_partitions`
|
158
|
+
- Recursively add an index to all partitions and subpartitions of `table_name` using Postgres's ADD INDEX CONCURRENTLY
|
159
|
+
algorithm which adds the index in a non-blocking manner.
|
160
|
+
- Required args: `table_name`, `column_name` (all `add_index` arguments are supported)
|
161
|
+
- Use the `in_threads:` option to add indexes in parallel threads when there are many partitions. A value of 2 to 4
|
162
|
+
may be reasonable for tables with many large partitions and hosts with 4+ CPUs/cores.
|
163
|
+
- Use `disable_ddl_transaction!` in your migration to disable transactions when using this command with `in_threads:`
|
164
|
+
or `algorithm: :concurrently`.
|
165
|
+
|
84
166
|
#### Examples
|
85
167
|
|
86
168
|
Create _range_ partitioned table on `created_at::date` with two partitions:
|
@@ -131,20 +213,130 @@ class CreateSomeListRecord < ActiveRecord::Migration[5.1]
|
|
131
213
|
create_list_partition_of \
|
132
214
|
:some_list_records,
|
133
215
|
values: 101..200
|
216
|
+
|
217
|
+
# default partition support is available in Postgres 11 or higher
|
218
|
+
create_default_partition_of \
|
219
|
+
:some_list_records
|
220
|
+
end
|
221
|
+
end
|
222
|
+
```
|
223
|
+
|
224
|
+
Create _hash_ partitioned table on `id` with two partitions (Postgres 11+ required):
|
225
|
+
* A hash partition can be used to spread keys evenly(ish) across partitions
|
226
|
+
* `modulus:` should always equal the total number of partitions planned for the table
|
227
|
+
* `remainder:` is an integer which should be in the range of 0 to modulus-1
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
class CreateSomeHashRecord < ActiveRecord::Migration[5.1]
|
231
|
+
def up
|
232
|
+
# symbol is used for partition keys referring to individual columns
|
233
|
+
# create_with_primary_key: true, template: false on Postgres 11 will rely on PostgreSQL's native partition schema
|
234
|
+
# management vs this gem's template tables
|
235
|
+
create_hash_partition :some_hash_records, partition_key: :id, create_with_primary_key: true, template: false do |t|
|
236
|
+
t.text :some_value
|
237
|
+
t.timestamps
|
238
|
+
end
|
239
|
+
|
240
|
+
# without name argument, child partition created as "some_list_records_<hash>"
|
241
|
+
create_hash_partition_of \
|
242
|
+
:some_hash_records,
|
243
|
+
modulus: 2,
|
244
|
+
remainder: 0
|
245
|
+
|
246
|
+
# without name argument, child partition created as "some_list_records_<hash>"
|
247
|
+
create_hash_partition_of \
|
248
|
+
:some_hash_records,
|
249
|
+
modulus: 2,
|
250
|
+
remainder: 1
|
251
|
+
end
|
252
|
+
end
|
253
|
+
```
|
254
|
+
|
255
|
+
Advanced example with subpartitioning: Create _list_ partitioned table on `id` subpartitioned by _range_ on `created_at`
|
256
|
+
with default partitions
|
257
|
+
* We can use Postgres 11's support for primary keys vs template tables, using the composite primary key `[:id, :created_at]`
|
258
|
+
to ensure all partition keys are present in the primary key
|
259
|
+
* Default partitions are only supported in Postgres 11+
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
class CreateSomeListSubpartitionedRecord < ActiveRecord::Migration[5.1]
|
263
|
+
def up
|
264
|
+
# when specifying a composite primary key, the primary keys must be specified as columns
|
265
|
+
create_list_partition \
|
266
|
+
:some_list_subpartitioned_records,
|
267
|
+
partition_key: [:id],
|
268
|
+
primary_key: [:id, :created_at],
|
269
|
+
template: false,
|
270
|
+
create_with_primary_key: true do |t|
|
271
|
+
|
272
|
+
t.integer :id
|
273
|
+
t.text :some_value
|
274
|
+
t.timestamps
|
275
|
+
end
|
276
|
+
|
277
|
+
create_default_partition_of \
|
278
|
+
:some_list_subpartitioned_records,
|
279
|
+
name: :some_list_subpartitioned_records_default,
|
280
|
+
partition_type: :range,
|
281
|
+
partition_key: :created_at
|
282
|
+
|
283
|
+
create_range_partition_of \
|
284
|
+
:some_list_subpartitioned_records_default,
|
285
|
+
name: :some_list_subpartitioned_records_default_2019,
|
286
|
+
start_range: '2019-01-01',
|
287
|
+
end_range: '2019-12-31T23:59:59'
|
288
|
+
|
289
|
+
create_default_partition_of \
|
290
|
+
:some_list_subpartitioned_records_default
|
291
|
+
|
292
|
+
create_list_partition_of \
|
293
|
+
:some_list_subpartitioned_records,
|
294
|
+
name: :some_list_subpartitioned_records_1,
|
295
|
+
values: 1..100,
|
296
|
+
partition_type: :range,
|
297
|
+
partition_key: :created_at
|
298
|
+
|
299
|
+
create_range_partition_of \
|
300
|
+
:some_list_subpartitioned_records_1,
|
301
|
+
name: :some_list_subpartitioned_records_1_2019,
|
302
|
+
start_range: '2019-01-01',
|
303
|
+
end_range: '2019-12-31T23:59:59'
|
304
|
+
|
305
|
+
create_default_partition_of
|
306
|
+
:some_list_subpartitioned_records_1
|
307
|
+
|
308
|
+
create_list_partition_of \
|
309
|
+
:some_list_subpartitioned_records,
|
310
|
+
name: :some_list_subpartitioned_records_2,
|
311
|
+
values: 101..200,
|
312
|
+
partition_type: :range,
|
313
|
+
partition_key: :created_at
|
314
|
+
|
315
|
+
create_range_partition_of \
|
316
|
+
:some_list_subpartitioned_records_2,
|
317
|
+
name: :some_list_subpartitioned_records_2_2019,
|
318
|
+
start_range: '2019-01-01',
|
319
|
+
end_range: '2019-12-31T23:59:59'
|
320
|
+
|
321
|
+
create_default_partition_of \
|
322
|
+
:some_list_subpartitioned_records_2
|
134
323
|
end
|
135
324
|
end
|
136
325
|
```
|
137
326
|
|
327
|
+
#### Template Tables
|
138
328
|
Unfortunately, PostgreSQL 10 doesn't support indexes on partitioned tables.
|
139
329
|
However, individual _partitions_ can have indexes.
|
140
330
|
To avoid explicit index creation for _every_ new partition, we've introduced the idea of template tables.
|
141
331
|
For every call to `create_list_partition` and `create_range_partition`, a clone `<table_name>_template` is created.
|
142
332
|
Indexes, constraints, etc. created on the template table will propagate to new partitions in calls to `create_list_partition_of` and `create_range_partition_of`:
|
333
|
+
* Subpartitions will correctly clone from template tables if a template table exists for the top-level ancestor
|
334
|
+
* When using Postgres 11 or higher, you may wish to disable template tables and use the native features instead, see [Configuration](#configuration)
|
143
335
|
|
144
336
|
```ruby
|
145
337
|
class CreateSomeListRecord < ActiveRecord::Migration[5.1]
|
146
338
|
def up
|
147
|
-
# template table creation is enabled by default - use "template: false" to opt-out
|
339
|
+
# template table creation is enabled by default - use "template: false" or the config option to opt-out
|
148
340
|
create_list_partition :some_list_records, partition_key: :id do |t|
|
149
341
|
t.integer :some_foreign_id
|
150
342
|
t.text :some_value
|
@@ -167,6 +359,8 @@ class CreateSomeListRecord < ActiveRecord::Migration[5.1]
|
|
167
359
|
end
|
168
360
|
```
|
169
361
|
|
362
|
+
#### Attaching Existing Tables as Partitions
|
363
|
+
|
170
364
|
Attach an existing table to a _range_ partitioned table:
|
171
365
|
|
172
366
|
```ruby
|
@@ -194,6 +388,20 @@ class AttachListPartition < ActiveRecord::Migration[5.1]
|
|
194
388
|
end
|
195
389
|
```
|
196
390
|
|
391
|
+
Attach an existing table to a _hash_ partitioned table:
|
392
|
+
|
393
|
+
```ruby
|
394
|
+
class AttachHashPartition < ActiveRecord::Migration[5.1]
|
395
|
+
def up
|
396
|
+
attach_hash_partition \
|
397
|
+
:some_hash_records,
|
398
|
+
:some_existing_table,
|
399
|
+
modulus: 2,
|
400
|
+
remainder: 1
|
401
|
+
end
|
402
|
+
end
|
403
|
+
```
|
404
|
+
|
197
405
|
Detach a partition from any partitioned table:
|
198
406
|
|
199
407
|
```ruby
|
@@ -204,6 +412,31 @@ class DetachPartition < ActiveRecord::Migration[5.1]
|
|
204
412
|
end
|
205
413
|
```
|
206
414
|
|
415
|
+
#### Safely cascading `add_index` commands
|
416
|
+
Postgres 11+ will automatically cascade CREATE INDEX operations to partitions and subpartitions, however
|
417
|
+
CREATE INDEX CONCURRENTLY is not supported, meaning table locks will be taken on each table while the new index is built.
|
418
|
+
Postgres 10 provides no way to cascade index creation natively.
|
419
|
+
* The `add_index_on_all_partitions` method solves for these limitations by recursively creating the specified
|
420
|
+
index on all partitions and subpartitions. Index names on individual partitions will include a hash suffix to avoid conflicts.
|
421
|
+
* On Postgres 11+, the created indices are correctly attached to an index on the parent table
|
422
|
+
* On Postgres 10, if you are using [Template Tables](#template-tables-for-postgres-10), you will want to add the index to the template table separately.
|
423
|
+
* This command can also be used on subpartitions to cascade targeted indices starting at one level of the table hierarchy
|
424
|
+
|
425
|
+
```ruby
|
426
|
+
class AddSomeValueIndexToSomeListRecord < ActiveRecord::Migration[5.1]
|
427
|
+
# add_index_on_all_partitions with in_threads option may not be used within a transaction
|
428
|
+
# (also, algorithm: :concurrently cannot be used within a transaction)
|
429
|
+
disable_ddl_transaction!
|
430
|
+
|
431
|
+
def up
|
432
|
+
add_index :some_records_template, :some_value # Only if using Postgres 10 with template tables
|
433
|
+
|
434
|
+
# Pass the `in_threads:` option to create indices in parallel across multiple Postgres connections
|
435
|
+
add_index_on_all_partitions :some_records, :some_value, algorithm: :concurrently, in_threads: 4
|
436
|
+
end
|
437
|
+
end
|
438
|
+
```
|
439
|
+
|
207
440
|
For more examples, take a look at the Combustion schema definition and integration specs:
|
208
441
|
|
209
442
|
- https://github.com/rkrage/pg_party/blob/master/spec/dummy/db/schema.rb
|
@@ -224,12 +457,15 @@ Class methods available to _all_ ActiveRecord models:
|
|
224
457
|
- `list_partition_by`
|
225
458
|
- Configure a model backed by a _list_ partitioned table
|
226
459
|
- Required arg: `key` (partition key column) or block returning partition key expression
|
460
|
+
- `hash_partition_by`
|
461
|
+
- Configure a model backed by a _hash_ partitioned table
|
462
|
+
- Required arg: `key` (partition key column) or block returning partition key expression
|
227
463
|
|
228
464
|
Class methods available to both _range and list_ partitioned models:
|
229
465
|
|
230
466
|
- `partitions`
|
231
467
|
- Retrieve a list of currently attached partitions
|
232
|
-
-
|
468
|
+
- Optional `include_subpartitions:` argument to include all subpartitions in the returned list
|
233
469
|
- `in_partition`
|
234
470
|
- Retrieve an ActiveRecord model scoped to an individual partition
|
235
471
|
- Required arg: `child_table_name`
|
@@ -254,6 +490,16 @@ Class methods available to _list_ partitioned models:
|
|
254
490
|
- `partition_key_in`
|
255
491
|
- Query for records where partition key in _list_ of values
|
256
492
|
- Required arg: list of `values`
|
493
|
+
|
494
|
+
|
495
|
+
Class methods available to _hash_ partitioned models:
|
496
|
+
|
497
|
+
- `create_partition`
|
498
|
+
- Dynamically create new partition with hashed partition key divided by _modulus_ equals _remainder_
|
499
|
+
- Required arg: `modulus:`, `remainder:`
|
500
|
+
- `partition_key_in`
|
501
|
+
- Query for records where partition key in _list_ of values (method operates the same as for _list_ partitions above)
|
502
|
+
- Required arg: list of `values`
|
257
503
|
|
258
504
|
#### Examples
|
259
505
|
|
@@ -275,6 +521,15 @@ class SomeListRecord < ApplicationRecord
|
|
275
521
|
end
|
276
522
|
```
|
277
523
|
|
524
|
+
Configure model backed by a _hash_ partitioned table to get access to the methods described above:
|
525
|
+
|
526
|
+
```ruby
|
527
|
+
class SomeHashRecord < ApplicationRecord
|
528
|
+
# symbol is used for partition keys referring to individual columns
|
529
|
+
hash_partition_by :id
|
530
|
+
end
|
531
|
+
```
|
532
|
+
|
278
533
|
Dynamically create new partition from _range_ partitioned model:
|
279
534
|
|
280
535
|
```ruby
|
@@ -289,19 +544,26 @@ Dynamically create new partition from _list_ partitioned model:
|
|
289
544
|
SomeListRecord.create_partition(values: 200..300)
|
290
545
|
```
|
291
546
|
|
547
|
+
Dynamically create new partition from _hash_ partitioned model:
|
548
|
+
|
549
|
+
```ruby
|
550
|
+
# additional options include: "name:" and "primary_key:"
|
551
|
+
SomeHashRecord.create_partition(modulus: 2, remainder: 1)
|
552
|
+
```
|
553
|
+
|
292
554
|
For _range_ partitioned model, query for records where partition key in _range_ of values:
|
293
555
|
|
294
556
|
```ruby
|
295
557
|
SomeRangeRecord.partition_key_in("2019-06-08", "2019-06-10")
|
296
558
|
```
|
297
559
|
|
298
|
-
For _list_ partitioned
|
560
|
+
For _list_ and _hash_ partitioned models, query for records where partition key in _list_ of values:
|
299
561
|
|
300
562
|
```ruby
|
301
563
|
SomeListRecord.partition_key_in(1, 2, 3, 4)
|
302
564
|
```
|
303
565
|
|
304
|
-
For
|
566
|
+
For all partitioned models, query for records matching partition key:
|
305
567
|
|
306
568
|
```ruby
|
307
569
|
SomeRangeRecord.partition_key_eq(Date.current)
|
@@ -309,15 +571,15 @@ SomeRangeRecord.partition_key_eq(Date.current)
|
|
309
571
|
SomeListRecord.partition_key_eq(100)
|
310
572
|
```
|
311
573
|
|
312
|
-
For
|
574
|
+
For all partitioned models, retrieve currently attached partitions:
|
313
575
|
|
314
576
|
```ruby
|
315
577
|
SomeRangeRecord.partitions
|
316
578
|
|
317
|
-
SomeListRecord.partitions
|
579
|
+
SomeListRecord.partitions(include_subpartitions: true) # Include nested subpartitions
|
318
580
|
```
|
319
581
|
|
320
|
-
For both
|
582
|
+
For both all partitioned models, retrieve ActiveRecord model scoped to individual partition:
|
321
583
|
|
322
584
|
```ruby
|
323
585
|
SomeRangeRecord.in_partition(:some_range_records_partition_name)
|
@@ -325,9 +587,35 @@ SomeRangeRecord.in_partition(:some_range_records_partition_name)
|
|
325
587
|
SomeListRecord.in_partition(:some_list_records_partition_name)
|
326
588
|
```
|
327
589
|
|
590
|
+
To create _range_ partitions by month for previous, current and next months it's possible to use this example. To automate creation of partitions, run `Log.maintenance` every day with cron:
|
591
|
+
|
592
|
+
```ruby
|
593
|
+
class Log < ApplicationRecord
|
594
|
+
range_partition_by { '(created_at::date)' }
|
595
|
+
|
596
|
+
def self.maintenance
|
597
|
+
partitions = [Date.today.prev_month, Date.today, Date.today.next_month]
|
598
|
+
|
599
|
+
partitions.each do |day|
|
600
|
+
name = Log.partition_name_for(day)
|
601
|
+
next if ActiveRecord::Base.connection.table_exists?(name)
|
602
|
+
Log.create_partition(
|
603
|
+
name: name,
|
604
|
+
start_range: day.beginning_of_month,
|
605
|
+
end_range: day.next_month.beginning_of_month
|
606
|
+
)
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
def self.partition_name_for(day)
|
611
|
+
"logs_y#{day.year}_m#{day.month}"
|
612
|
+
end
|
613
|
+
end
|
614
|
+
```
|
615
|
+
|
328
616
|
For more examples, take a look at the model integration specs:
|
329
617
|
|
330
|
-
- https://github.com/rkrage/pg_party/tree/
|
618
|
+
- https://github.com/rkrage/pg_party/tree/master/spec/integration/model
|
331
619
|
|
332
620
|
## Development
|
333
621
|
|
data/lib/pg_party.rb
CHANGED
@@ -1,8 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "pg_party/version"
|
4
|
+
require "pg_party/config"
|
5
|
+
require "pg_party/cache"
|
4
6
|
require "active_support"
|
5
7
|
|
8
|
+
module PgParty
|
9
|
+
@config = Config.new
|
10
|
+
@cache = Cache.new
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_reader :config, :cache
|
14
|
+
|
15
|
+
def configure(&blk)
|
16
|
+
blk.call(config)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reset
|
20
|
+
@config = Config.new
|
21
|
+
@cache = Cache.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
6
26
|
ActiveSupport.on_load(:active_record) do
|
7
27
|
require "pg_party/model/methods"
|
8
28
|
|
@@ -14,10 +34,11 @@ ActiveSupport.on_load(:active_record) do
|
|
14
34
|
PgParty::Adapter::AbstractMethods
|
15
35
|
)
|
16
36
|
|
17
|
-
require "
|
37
|
+
require "active_record/tasks/postgresql_database_tasks"
|
38
|
+
require "pg_party/hacks/postgresql_database_tasks"
|
18
39
|
|
19
|
-
ActiveRecord::
|
20
|
-
PgParty::Hacks::
|
40
|
+
ActiveRecord::Tasks::PostgreSQLDatabaseTasks.prepend(
|
41
|
+
PgParty::Hacks::PostgreSQLDatabaseTasks
|
21
42
|
)
|
22
43
|
|
23
44
|
begin
|