tablature 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -8
- data/README.md +56 -1
- data/lib/tablature/adapters/postgres/partitioned_tables.rb +10 -3
- data/lib/tablature/adapters/postgres/quoting.rb +5 -1
- data/lib/tablature/adapters/postgres.rb +1 -2
- data/lib/tablature/model/partition_methods.rb +29 -0
- data/lib/tablature/model.rb +47 -0
- data/lib/tablature/partitioned_table.rb +10 -4
- data/lib/tablature/version.rb +1 -1
- data/lib/tablature.rb +7 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37da9dc068662c878b97c2f7cf95274f9893d4a34940d9511db0933d98b3597c
|
4
|
+
data.tar.gz: 261087c9165cba3aa60d4999f398889725979fa0398a5775c2408c0e41a420bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e66f6acf2ae0bbc061b92153b5f3ba798dd37f69302e2f6de5b6cf5363bdc3d8ce3bed6442017b6d85ef4aab52e96301056f72a16a393282396042c4d54334e1
|
7
|
+
data.tar.gz: 3855a566bc693bf97c7b20b2871703bb766fcd2553ef1e0043d5d18c47d7cc80eb60e779b0d2d9baf83aa2447379f9486de7104cb05945b2cc86adc9485fd537
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tablature (0.
|
4
|
+
tablature (0.2.0)
|
5
5
|
activerecord (>= 5.0.0)
|
6
6
|
railties (>= 5.0.0)
|
7
7
|
|
@@ -35,21 +35,21 @@ GEM
|
|
35
35
|
arel (9.0.0)
|
36
36
|
builder (3.2.3)
|
37
37
|
coderay (1.1.2)
|
38
|
-
concurrent-ruby (1.1.
|
38
|
+
concurrent-ruby (1.1.4)
|
39
39
|
crass (1.0.4)
|
40
40
|
database_cleaner (1.7.0)
|
41
41
|
diff-lcs (1.3)
|
42
|
-
erubi (1.
|
43
|
-
i18n (1.
|
42
|
+
erubi (1.8.0)
|
43
|
+
i18n (1.5.1)
|
44
44
|
concurrent-ruby (~> 1.0)
|
45
45
|
loofah (2.2.3)
|
46
46
|
crass (~> 1.0.2)
|
47
47
|
nokogiri (>= 1.5.9)
|
48
48
|
method_source (0.9.0)
|
49
|
-
mini_portile2 (2.
|
49
|
+
mini_portile2 (2.4.0)
|
50
50
|
minitest (5.11.3)
|
51
|
-
nokogiri (1.
|
52
|
-
mini_portile2 (~> 2.
|
51
|
+
nokogiri (1.10.0)
|
52
|
+
mini_portile2 (~> 2.4.0)
|
53
53
|
pg (0.21.0)
|
54
54
|
pry (0.12.2)
|
55
55
|
coderay (~> 1.1.0)
|
@@ -103,4 +103,4 @@ DEPENDENCIES
|
|
103
103
|
tablature!
|
104
104
|
|
105
105
|
BUNDLED WITH
|
106
|
-
1.
|
106
|
+
1.17.2
|
data/README.md
CHANGED
@@ -55,14 +55,69 @@ class CreateEvents < ActiveRecord::Migration[5.0]
|
|
55
55
|
# Create partitions with the bounds of the partition.
|
56
56
|
create_list_partition_of :events_by_list,
|
57
57
|
name: 'events_list_y2018m12', values: (Date.parse('2018-12-01')..Date.parse('2018-12-31')).to_a
|
58
|
+
|
58
59
|
end
|
59
60
|
|
60
61
|
def down
|
61
|
-
drop_table :
|
62
|
+
drop_table :events_by_range
|
63
|
+
drop_table :events_by_list
|
62
64
|
end
|
63
65
|
end
|
64
66
|
```
|
65
67
|
|
68
|
+
### Having a partition back a model
|
69
|
+
|
70
|
+
|
71
|
+
In your migration:
|
72
|
+
```ruby
|
73
|
+
# db/migrate/create_events.rb
|
74
|
+
class CreateEvents < ActiveRecord::Migration
|
75
|
+
def change
|
76
|
+
# You can use blocks when the partition key are SQL expression instead of
|
77
|
+
# being only a field.
|
78
|
+
create_range_partition :events, partition_key: -> { '(timestamp::DATE)' } do |t|
|
79
|
+
t.string :event_type, null: false
|
80
|
+
t.integer :value, null: false
|
81
|
+
t.datetime :timestamp, null: false
|
82
|
+
t.timestamps
|
83
|
+
end
|
84
|
+
|
85
|
+
create_range_partition_of :events,
|
86
|
+
name: 'events_y2018m12', range_start: '2018-12-01', range_end: '2019-01-01'
|
87
|
+
|
88
|
+
create_range_partition_of :events,
|
89
|
+
name: 'events_y2019m01', range_start: '2019-01-01', range_end: '2019-02-01'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
In your model, calling one of `range_partition` or `list_partition` to inject
|
95
|
+
methods:
|
96
|
+
```
|
97
|
+
# app/models/event.rb
|
98
|
+
class Event < ApplicationRecord
|
99
|
+
range_partition
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
Finally, you can now list the partitions :
|
104
|
+
```ruby
|
105
|
+
>> Event.partitions
|
106
|
+
# => ["events_y2018m12", "events_y2019m01"]
|
107
|
+
```
|
108
|
+
|
109
|
+
You can also create new partitions directly from the model :
|
110
|
+
```ruby
|
111
|
+
>> Event.create_range_partition(
|
112
|
+
name: 'events_y2019m02',
|
113
|
+
range_start: '2019-02-01'.to_date,
|
114
|
+
range_end: '2019-03-01'.to_date
|
115
|
+
)
|
116
|
+
# => ...
|
117
|
+
>> Event.partitions
|
118
|
+
# => ["events_y2018m12", "events_y2019m01", "events_y2019m02"]
|
119
|
+
```
|
120
|
+
|
66
121
|
## Development
|
67
122
|
|
68
123
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -25,7 +25,8 @@ module Tablature
|
|
25
25
|
c.oid,
|
26
26
|
c.relname AS table_name,
|
27
27
|
p.partstrat AS type,
|
28
|
-
(i.inhrelid::REGCLASS)::TEXT AS partition_name
|
28
|
+
(i.inhrelid::REGCLASS)::TEXT AS partition_name,
|
29
|
+
pg_get_partkeydef(c.oid) AS partition_key_definition
|
29
30
|
FROM pg_class c
|
30
31
|
INNER JOIN pg_partitioned_table p ON c.oid = p.partrelid
|
31
32
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
@@ -47,11 +48,17 @@ module Tablature
|
|
47
48
|
|
48
49
|
def to_tablature_table(table_name, rows)
|
49
50
|
result = rows.first
|
50
|
-
|
51
|
+
partitioning_method = METHOD_MAP.fetch(result['type'])
|
51
52
|
partitions = rows.map { |row| row['partition_name'] }.compact.map(&method(:unquote))
|
53
|
+
# This is very fragile code. This makes the assumption that:
|
54
|
+
# - Postgres will always have a function `pg_get_partkeydef` that returns the partition
|
55
|
+
# method with the partition key
|
56
|
+
# - Postgres will never have a partition method with two words in its name.
|
57
|
+
_, partition_key = result['partition_key_definition'].split(' ', 2)
|
52
58
|
|
53
59
|
Tablature::PartitionedTable.new(
|
54
|
-
name: table_name,
|
60
|
+
name: table_name, partitioning_method: partitioning_method,
|
61
|
+
partitions: partitions, partition_key: partition_key
|
55
62
|
)
|
56
63
|
end
|
57
64
|
|
@@ -4,7 +4,11 @@ module Tablature
|
|
4
4
|
# @api private
|
5
5
|
module Quoting
|
6
6
|
def quote_partition_key(key)
|
7
|
-
key.
|
7
|
+
if key.respond_to?(:call)
|
8
|
+
key.call.to_s
|
9
|
+
else
|
10
|
+
key.to_s.split('::').map(&method(:quote_column_name)).join('::')
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
14
|
def quote_collection(values)
|
@@ -47,7 +47,7 @@ module Tablature
|
|
47
47
|
# @param [String, Symbol] table_name The name of the table to partition.
|
48
48
|
# @param [Hash] options The options to create the partition. Keys besides +:partition_key+
|
49
49
|
# will be passed to +create_table+.
|
50
|
-
# @option options [String, Symbol] :partition_key The partition key.
|
50
|
+
# @option options [String, Symbol, #call] :partition_key The partition key.
|
51
51
|
# @yield [td] A TableDefinition object. This allows creating the table columns the same way
|
52
52
|
# as Rails's +create_table+ does.
|
53
53
|
#
|
@@ -84,7 +84,6 @@ module Tablature
|
|
84
84
|
# @param [String, Symbol] table_name The name of the table to partition.
|
85
85
|
# @param [Hash] options The options to create the partition. Keys besides +:partition_key+
|
86
86
|
# will be passed to +create_table+.
|
87
|
-
# @option options [String, Symbol] :partition_key The partition key.
|
88
87
|
# @yield [td] A TableDefinition object. This allows creating the table columns the same way
|
89
88
|
# as Rails's +create_table+ does.
|
90
89
|
#
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Tablature
|
4
|
+
module Model
|
5
|
+
module PartitionMethods
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :tablature_partition, :partitions, :partition_key, :partitioning_method
|
8
|
+
|
9
|
+
def tablature_partition
|
10
|
+
partition = Tablature.database.partitioned_tables.find do |pt|
|
11
|
+
pt.name == partition_name.to_s
|
12
|
+
end
|
13
|
+
raise Tablature::MissingPartition if partition.nil?
|
14
|
+
|
15
|
+
partition
|
16
|
+
end
|
17
|
+
|
18
|
+
def partitioned?
|
19
|
+
begin
|
20
|
+
tablature_partition
|
21
|
+
rescue Tablature::MissingPartition
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/tablature/model.rb
CHANGED
@@ -1,4 +1,51 @@
|
|
1
|
+
require 'tablature/model/partition_methods'
|
2
|
+
|
1
3
|
module Tablature
|
2
4
|
module Model
|
5
|
+
module ListPartitionMethods
|
6
|
+
def create_list_partition(options)
|
7
|
+
Tablature.database.create_list_partition_of(tablature_partition.name, options)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module RangePartitionMethods
|
12
|
+
def create_range_partition(options)
|
13
|
+
Tablature.database.create_range_partition_of(tablature_partition.name, options)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def list_partition(partition_name = table_name)
|
19
|
+
setup_partition(partition_name)
|
20
|
+
extend(PartitionMethods)
|
21
|
+
extend(ListPartitionMethods)
|
22
|
+
end
|
23
|
+
|
24
|
+
def range_partition(partition_name = table_name)
|
25
|
+
setup_partition(partition_name)
|
26
|
+
extend(PartitionMethods)
|
27
|
+
extend(RangePartitionMethods)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def inspect
|
32
|
+
return super unless partitioned?
|
33
|
+
|
34
|
+
# Copied from the Rails source.
|
35
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
|
36
|
+
"#{self}(#{attr_list})"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def setup_partition(partition_name)
|
42
|
+
class_attribute(:partition_name)
|
43
|
+
self.partition_name = partition_name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.included(klass)
|
48
|
+
klass.extend ClassMethods
|
49
|
+
end
|
3
50
|
end
|
4
51
|
end
|
@@ -13,21 +13,27 @@ module Tablature
|
|
13
13
|
|
14
14
|
# The partitioning method of the table
|
15
15
|
# @return [Symbol]
|
16
|
-
attr_reader :
|
16
|
+
attr_reader :partitioning_method
|
17
17
|
|
18
18
|
# The partitions of the table.
|
19
19
|
# @return [Array]
|
20
20
|
attr_reader :partitions
|
21
21
|
|
22
|
+
# The partition key expression.
|
23
|
+
# @return [String]
|
24
|
+
attr_reader :partition_key
|
25
|
+
|
22
26
|
# Returns a new instance of PartitionTable.
|
23
27
|
#
|
24
28
|
# @param name [String] The name of the view.
|
25
|
-
# @param
|
29
|
+
# @param partitioning_method [:symbol] One of :range, :list or :hash
|
26
30
|
# @param partitions [Array] The partitions of the table.
|
27
|
-
|
31
|
+
# @param partition_key [String] The partition key expression.
|
32
|
+
def initialize(name:, partitioning_method:, partitions: [], partition_key:)
|
28
33
|
@name = name
|
29
|
-
@
|
34
|
+
@partitioning_method = partitioning_method
|
30
35
|
@partitions = partitions
|
36
|
+
@partition_key = partition_key
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|
data/lib/tablature/version.rb
CHANGED
data/lib/tablature.rb
CHANGED
@@ -20,7 +20,7 @@ module Tablature
|
|
20
20
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.include Tablature::Statements
|
21
21
|
ActiveRecord::Migration::CommandRecorder.include Tablature::CommandRecorder
|
22
22
|
ActiveRecord::SchemaDumper.prepend Tablature::SchemaDumper
|
23
|
-
ActiveRecord::Base.
|
23
|
+
ActiveRecord::Base.include Tablature::Model
|
24
24
|
end
|
25
25
|
|
26
26
|
# The current database adapter used by Tablature.
|
@@ -29,4 +29,10 @@ module Tablature
|
|
29
29
|
def self.database
|
30
30
|
configuration.database
|
31
31
|
end
|
32
|
+
|
33
|
+
class MissingPartition < StandardError
|
34
|
+
def initialize
|
35
|
+
super('Missing partition')
|
36
|
+
end
|
37
|
+
end
|
32
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tablature
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aliou Diallo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -154,6 +154,7 @@ files:
|
|
154
154
|
- lib/tablature/command_recorder.rb
|
155
155
|
- lib/tablature/configuration.rb
|
156
156
|
- lib/tablature/model.rb
|
157
|
+
- lib/tablature/model/partition_methods.rb
|
157
158
|
- lib/tablature/partitioned_table.rb
|
158
159
|
- lib/tablature/railtie.rb
|
159
160
|
- lib/tablature/schema_dumper.rb
|