tablature 0.1.1 → 0.2.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/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
|