pg_partitioner 0.4.3 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +29 -1
- data/lib/pg_partitioner/separation_type/base.rb +64 -0
- data/lib/pg_partitioner/separation_type/month.rb +5 -55
- data/lib/pg_partitioner/separation_type/quater.rb +74 -0
- data/lib/pg_partitioner/separation_type/week.rb +80 -0
- data/lib/pg_partitioner/version.rb +1 -1
- data/lib/pg_partitioner.rb +9 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2fde7de994fd9c1895b12d6347fce42e8fa84a622ad917ac73ed90d249daa27
|
4
|
+
data.tar.gz: '08bf1490d4a4462890291353eaadeec9a88cf101e54ccb982af8633c3eeab868'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 726173d02f3c6f173e784667f0543cf51d95170b9eb1446db7138707ebefa45774f727b25be8a5eb5cb3e6d3efa87f279817acc4ddd7e40772f08e735c2b30db
|
7
|
+
data.tar.gz: 571636fac008a954653af4c54b34eb43d3e1080c8dbd55a7c5aa4fe3357620849372ade89b97646c2b75daab6b5771276e9280c7c1e55ff4ff1c6e4b0b0154de
|
data/README.md
CHANGED
@@ -61,6 +61,16 @@ rails g migration make_partitioning_of_you_table
|
|
61
61
|
|
62
62
|
add instructions to migration:
|
63
63
|
|
64
|
+
```ruby
|
65
|
+
class YouMigrationClassName
|
66
|
+
def change
|
67
|
+
YourModel.create_partitioning_by_week_trigger_sql
|
68
|
+
YourModel.create_current_week_table
|
69
|
+
YourModel.create_next_week_table
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
64
74
|
```ruby
|
65
75
|
class YouMigrationClassName
|
66
76
|
def change
|
@@ -71,9 +81,27 @@ class YouMigrationClassName
|
|
71
81
|
end
|
72
82
|
```
|
73
83
|
|
74
|
-
|
84
|
+
```ruby
|
85
|
+
class YouMigrationClassName
|
86
|
+
def change
|
87
|
+
YourModel.create_partitioning_by_quater_trigger_sql
|
88
|
+
YourModel.create_current_quater_table
|
89
|
+
YourModel.create_next_quater_table
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
3) For correct work you need to create next partition every month/quater.
|
75
95
|
We recommend you to create a rake task and run it once a month by crontab. Code for a rake task:
|
76
96
|
|
77
97
|
```ruby
|
98
|
+
YourModel.create_next_week_table
|
99
|
+
```
|
100
|
+
or
|
101
|
+
```ruby
|
78
102
|
YourModel.create_next_month_table
|
79
103
|
```
|
104
|
+
or
|
105
|
+
```ruby
|
106
|
+
YourModel.create_next_quater_table
|
107
|
+
```
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module PgPartitioner
|
2
|
+
module SeparationType
|
3
|
+
module Base
|
4
|
+
def drop_table(table_name)
|
5
|
+
sql = "DROP TABLE IF EXISTS #{table_name};"
|
6
|
+
execute_sql(sql)
|
7
|
+
end
|
8
|
+
|
9
|
+
def drop_partitioning_trigger_sql
|
10
|
+
sql = "DROP TRIGGER #{table_name}_insert ON #{table_name};
|
11
|
+
DROP FUNCTION #{table_name}_insert_trigger();
|
12
|
+
DROP TRIGGER #{table_name}_after_insert ON #{table_name};
|
13
|
+
DROP FUNCTION #{table_name}_delete_trigger();"
|
14
|
+
|
15
|
+
execute_sql(sql)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_partition_indexes(partition_table_name)
|
19
|
+
custom_indexes = partition_table_indexes.presence
|
20
|
+
return unless custom_indexes
|
21
|
+
|
22
|
+
custom_indexes.each { |custom_index| create_custom_index(partition_table_name, custom_index) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_partition_named_indexes(partition_table_name)
|
26
|
+
custom_indexes = partition_table_named_indexes.presence
|
27
|
+
return unless custom_indexes
|
28
|
+
|
29
|
+
custom_indexes.map do |name, custom_index|
|
30
|
+
index_name = "index_#{partition_table_name}_#{name}"
|
31
|
+
create_custom_named_index(partition_table_name, custom_index, index_name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_partition_unique_indexes(partition_table_name)
|
36
|
+
custom_unique_indexes = partition_table_unique_indexes.presence
|
37
|
+
return unless custom_unique_indexes
|
38
|
+
|
39
|
+
custom_unique_indexes.each { |custom_index| create_custom_index(partition_table_name, custom_index, true) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_partition_named_unique_indexes(partition_table_name)
|
43
|
+
custom_indexes = partition_table_named_unique_indexes.presence
|
44
|
+
return unless custom_indexes
|
45
|
+
|
46
|
+
custom_indexes.map do |name, custom_index|
|
47
|
+
index_name = "index_#{partition_table_name}_#{name}"
|
48
|
+
create_custom_named_index(partition_table_name, custom_index, index_name, true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def name_of_partition_table(date = Date.today, type:)
|
53
|
+
case type
|
54
|
+
when :month
|
55
|
+
date.strftime("#{table_name}_y%Ym%m")
|
56
|
+
when :quater
|
57
|
+
"#{table_name}_y#{date.year}q#{(((date.month - 1) / 3) + 1).to_i}"
|
58
|
+
when :week
|
59
|
+
"#{table_name}_y#{date.year}w#{date.cweek}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -10,13 +10,15 @@ module PgPartitioner
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def drop_old_month_table
|
13
|
-
|
13
|
+
table_name = name_of_partition_table(Date.today.prev_month.prev_month,
|
14
|
+
type: :quater)
|
15
|
+
drop_month_table(table_name)
|
14
16
|
end
|
15
17
|
|
16
18
|
def create_month_table(date = Date.today)
|
17
19
|
date_start = date.at_beginning_of_month
|
18
20
|
date_end = date.at_beginning_of_month.next_month
|
19
|
-
partition_table_name = name_of_partition_table(date)
|
21
|
+
partition_table_name = name_of_partition_table(date, type: :month)
|
20
22
|
return 'Already exists' if connection.table_exists? partition_table_name
|
21
23
|
|
22
24
|
sql = "CREATE TABLE IF NOT EXISTS #{partition_table_name} (
|
@@ -32,18 +34,13 @@ module PgPartitioner
|
|
32
34
|
create_partition_named_unique_indexes(partition_table_name)
|
33
35
|
end
|
34
36
|
|
35
|
-
def drop_month_table(date = Date.today)
|
36
|
-
sql = "DROP TABLE IF EXISTS #{name_of_partition_table(date)};"
|
37
|
-
execute_sql(sql)
|
38
|
-
end
|
39
|
-
|
40
37
|
def create_partitioning_by_month_triggers
|
41
38
|
sql = "CREATE OR REPLACE FUNCTION #{table_name}_insert_trigger() RETURNS trigger AS
|
42
39
|
$$
|
43
40
|
DECLARE
|
44
41
|
curY varchar(4);
|
45
42
|
curM varchar(2);
|
46
|
-
tbl varchar(
|
43
|
+
tbl varchar(121);
|
47
44
|
BEGIN
|
48
45
|
select cast(DATE_PART('year', new.#{parting_column}) as varchar) into curY;
|
49
46
|
select lpad(cast(DATE_PART('month', new.#{parting_column}) as varchar), 2, '0') into curM;
|
@@ -78,53 +75,6 @@ module PgPartitioner
|
|
78
75
|
|
79
76
|
execute_sql(sql)
|
80
77
|
end
|
81
|
-
|
82
|
-
def drop_partitioning_by_month_trigger_sql
|
83
|
-
sql = "DROP TRIGGER #{table_name}_insert ON #{table_name};
|
84
|
-
DROP FUNCTION #{table_name}_insert_trigger();
|
85
|
-
DROP TRIGGER #{table_name}_after_insert ON #{table_name};
|
86
|
-
DROP FUNCTION #{table_name}_delete_trigger();"
|
87
|
-
|
88
|
-
execute_sql(sql)
|
89
|
-
end
|
90
|
-
|
91
|
-
def create_partition_indexes(partition_table_name)
|
92
|
-
custom_indexes = partition_table_indexes.presence
|
93
|
-
return unless custom_indexes
|
94
|
-
|
95
|
-
custom_indexes.each { |custom_index| create_custom_index(partition_table_name, custom_index) }
|
96
|
-
end
|
97
|
-
|
98
|
-
def create_partition_named_indexes(partition_table_name)
|
99
|
-
custom_indexes = partition_table_named_indexes.presence
|
100
|
-
return unless custom_indexes
|
101
|
-
|
102
|
-
custom_indexes.map do |name, custom_index|
|
103
|
-
index_name = "index_#{partition_table_name}_#{name}"
|
104
|
-
create_custom_named_index(partition_table_name, custom_index, index_name)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def create_partition_unique_indexes(partition_table_name)
|
109
|
-
custom_unique_indexes = partition_table_unique_indexes.presence
|
110
|
-
return unless custom_unique_indexes
|
111
|
-
|
112
|
-
custom_unique_indexes.each { |custom_index| create_custom_index(partition_table_name, custom_index, true) }
|
113
|
-
end
|
114
|
-
|
115
|
-
def create_partition_named_unique_indexes(partition_table_name)
|
116
|
-
custom_indexes = partition_table_named_unique_indexes.presence
|
117
|
-
return unless custom_indexes
|
118
|
-
|
119
|
-
custom_indexes.map do |name, custom_index|
|
120
|
-
index_name = "index_#{partition_table_name}_#{name}"
|
121
|
-
create_custom_named_index(partition_table_name, custom_index, index_name, true)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def name_of_partition_table(date = Date.today)
|
126
|
-
date.strftime("#{table_name}_y%Ym%m")
|
127
|
-
end
|
128
78
|
end
|
129
79
|
end
|
130
80
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PgPartitioner
|
2
|
+
module SeparationType
|
3
|
+
module Quater
|
4
|
+
def create_current_quater_table
|
5
|
+
create_quater_table(Date.today)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_next_quater_table
|
9
|
+
create_quater_table(Date.today.next_quarter)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_quater_table(date = Date.today)
|
13
|
+
date_start = date.at_beginning_of_quarter
|
14
|
+
date_end = date.end_of_quarter.next_month.at_beginning_of_month
|
15
|
+
partition_table_name = name_of_partition_table(date, type: :quater)
|
16
|
+
return 'Already exists' if connection.table_exists? partition_table_name
|
17
|
+
|
18
|
+
sql = "CREATE TABLE IF NOT EXISTS #{partition_table_name} (
|
19
|
+
CHECK ( #{parting_column} >= DATE('#{date_start}') AND #{parting_column} < DATE('#{date_end}') )
|
20
|
+
) INHERITS (#{table_name});"
|
21
|
+
execute_sql(sql)
|
22
|
+
sql = "ALTER TABLE #{partition_table_name} ADD PRIMARY KEY (id);"
|
23
|
+
execute_sql(sql)
|
24
|
+
|
25
|
+
create_partition_indexes(partition_table_name)
|
26
|
+
create_partition_named_indexes(partition_table_name)
|
27
|
+
create_partition_unique_indexes(partition_table_name)
|
28
|
+
create_partition_named_unique_indexes(partition_table_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_partitioning_by_quater_triggers
|
32
|
+
sql = "CREATE OR REPLACE FUNCTION #{table_name}_insert_trigger() RETURNS trigger AS
|
33
|
+
$$
|
34
|
+
DECLARE
|
35
|
+
curY varchar(4);
|
36
|
+
curQ varchar(1);
|
37
|
+
tbl varchar(121);
|
38
|
+
BEGIN
|
39
|
+
select cast(DATE_PART('year', new.#{parting_column}) as varchar) into curY;
|
40
|
+
select lpad(cast(DATE_PART('quarter', new.#{parting_column}) as varchar), 2, '0') into curQ;
|
41
|
+
tbl := '#{table_name}_y' || curY || 'q' || curQ;
|
42
|
+
EXECUTE format('INSERT into %I values ($1.*);', tbl) USING NEW;
|
43
|
+
return NEW;
|
44
|
+
END;
|
45
|
+
$$
|
46
|
+
LANGUAGE plpgsql;
|
47
|
+
|
48
|
+
CREATE TRIGGER #{table_name}_insert
|
49
|
+
BEFORE INSERT ON #{table_name}
|
50
|
+
FOR EACH ROW
|
51
|
+
EXECUTE PROCEDURE #{table_name}_insert_trigger();
|
52
|
+
|
53
|
+
-- Trigger function to delete from the master table after the insert
|
54
|
+
CREATE OR REPLACE FUNCTION #{table_name}_delete_trigger() RETURNS trigger
|
55
|
+
AS $$
|
56
|
+
DECLARE
|
57
|
+
r #{table_name}%rowtype;
|
58
|
+
BEGIN
|
59
|
+
DELETE FROM ONLY #{table_name} where id = new.id returning * into r;
|
60
|
+
RETURN r;
|
61
|
+
end;
|
62
|
+
$$
|
63
|
+
LANGUAGE plpgsql;
|
64
|
+
|
65
|
+
CREATE TRIGGER #{table_name}_after_insert
|
66
|
+
AFTER INSERT ON #{table_name}
|
67
|
+
FOR EACH ROW
|
68
|
+
EXECUTE PROCEDURE #{table_name}_delete_trigger();"
|
69
|
+
|
70
|
+
execute_sql(sql)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module PgPartitioner
|
2
|
+
module SeparationType
|
3
|
+
module Week
|
4
|
+
def create_current_week_table
|
5
|
+
create_week_table(Date.today)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_next_week_table
|
9
|
+
create_week_table(Date.today.next_week)
|
10
|
+
end
|
11
|
+
|
12
|
+
def drop_old_week_table
|
13
|
+
table_name = name_of_partition_table(Date.today.prev_month.prev_month,
|
14
|
+
type: :week)
|
15
|
+
drop_month_table(table_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_week_table(date = Date.today)
|
19
|
+
date_start = date.at_beginning_of_week
|
20
|
+
date_end = date.at_beginning_of_week.next_week
|
21
|
+
partition_table_name = name_of_partition_table(date, type: :week)
|
22
|
+
return 'Already exists' if connection.table_exists? partition_table_name
|
23
|
+
|
24
|
+
sql = "CREATE TABLE IF NOT EXISTS #{partition_table_name} (
|
25
|
+
CHECK ( #{parting_column} >= DATE('#{date_start}') AND #{parting_column} < DATE('#{date_end}') )
|
26
|
+
) INHERITS (#{table_name});"
|
27
|
+
execute_sql(sql)
|
28
|
+
sql = "ALTER TABLE #{partition_table_name} ADD PRIMARY KEY (id);"
|
29
|
+
execute_sql(sql)
|
30
|
+
|
31
|
+
create_partition_indexes(partition_table_name)
|
32
|
+
create_partition_named_indexes(partition_table_name)
|
33
|
+
create_partition_unique_indexes(partition_table_name)
|
34
|
+
create_partition_named_unique_indexes(partition_table_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_partitioning_by_week_triggers
|
38
|
+
sql = "CREATE OR REPLACE FUNCTION #{table_name}_insert_trigger() RETURNS trigger AS
|
39
|
+
$$
|
40
|
+
DECLARE
|
41
|
+
curY varchar(4);
|
42
|
+
curW varchar(2);
|
43
|
+
tbl varchar(121);
|
44
|
+
BEGIN
|
45
|
+
select cast(DATE_PART('year', new.#{parting_column}) as varchar) into curY;
|
46
|
+
select lpad(cast(DATE_PART('week', new.#{parting_column}) as varchar), 2, '0') into curW;
|
47
|
+
tbl := '#{table_name}_y' || curY || 'w' || curW;
|
48
|
+
EXECUTE format('INSERT into %I values ($1.*);', tbl) USING NEW;
|
49
|
+
return NEW;
|
50
|
+
END;
|
51
|
+
$$
|
52
|
+
LANGUAGE plpgsql;
|
53
|
+
|
54
|
+
CREATE TRIGGER #{table_name}_insert
|
55
|
+
BEFORE INSERT ON #{table_name}
|
56
|
+
FOR EACH ROW
|
57
|
+
EXECUTE PROCEDURE #{table_name}_insert_trigger();
|
58
|
+
|
59
|
+
-- Trigger function to delete from the master table after the insert
|
60
|
+
CREATE OR REPLACE FUNCTION #{table_name}_delete_trigger() RETURNS trigger
|
61
|
+
AS $$
|
62
|
+
DECLARE
|
63
|
+
r #{table_name}%rowtype;
|
64
|
+
BEGIN
|
65
|
+
DELETE FROM ONLY #{table_name} where id = new.id returning * into r;
|
66
|
+
RETURN r;
|
67
|
+
end;
|
68
|
+
$$
|
69
|
+
LANGUAGE plpgsql;
|
70
|
+
|
71
|
+
CREATE TRIGGER #{table_name}_after_insert
|
72
|
+
AFTER INSERT ON #{table_name}
|
73
|
+
FOR EACH ROW
|
74
|
+
EXECUTE PROCEDURE #{table_name}_delete_trigger();"
|
75
|
+
|
76
|
+
execute_sql(sql)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/pg_partitioner.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
1
|
require 'pg_partitioner/version'
|
2
|
+
require 'pg_partitioner/separation_type/base'
|
3
|
+
require 'pg_partitioner/separation_type/week'
|
2
4
|
require 'pg_partitioner/separation_type/month'
|
5
|
+
require 'pg_partitioner/separation_type/quater'
|
3
6
|
|
4
7
|
module PgPartitioner
|
5
8
|
def self.extended(base)
|
6
|
-
base.extend(
|
9
|
+
base.extend(
|
10
|
+
PgPartitioner::SeparationType::Base,
|
11
|
+
PgPartitioner::SeparationType::Week,
|
12
|
+
PgPartitioner::SeparationType::Month,
|
13
|
+
PgPartitioner::SeparationType::Quater
|
14
|
+
)
|
7
15
|
end
|
8
16
|
|
9
17
|
# Template method
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_partitioner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ovsapyan Mishel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,7 +52,10 @@ files:
|
|
52
52
|
- bin/console
|
53
53
|
- bin/setup
|
54
54
|
- lib/pg_partitioner.rb
|
55
|
+
- lib/pg_partitioner/separation_type/base.rb
|
55
56
|
- lib/pg_partitioner/separation_type/month.rb
|
57
|
+
- lib/pg_partitioner/separation_type/quater.rb
|
58
|
+
- lib/pg_partitioner/separation_type/week.rb
|
56
59
|
- lib/pg_partitioner/version.rb
|
57
60
|
- partitioner_pg.gemspec
|
58
61
|
homepage: http://appodeal.com
|