sliding_partition 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e31845f243303eb0ddb1cf2caaa1993c74a56390
4
+ data.tar.gz: 0ac4e7ee1213d2f0392e5f1fcaba3196487bf5a5
5
+ SHA512:
6
+ metadata.gz: 14dc2a1107cad143eac55466130f65ef5ed38cb4ba75a80727ec6b56394fa63d244520a1ed5063d19324f4a2fd402e0b1cdae00ec21b9af5a35c88bda345f253
7
+ data.tar.gz: ecc06d8eee4a939fd98c1ba396ae091252896a77745a92e55bcabad4dde188e1f4bc02a013308e10a366caa5d376fd4b00af2242accd9ba478238d8b91d73308
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 []().
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,150 @@
1
+ # SlidingPartition
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/sliding_partition.svg)](http://badge.fury.io/rb/sliding_partition)
4
+ [![Code Climate GPA](https://codeclimate.com/github/paul/sliding_partition.svg)](https://codeclimate.com/github/paul/sliding_partition)
5
+ [![Code Climate Coverage](https://codeclimate.com/github/paul/sliding_partition/coverage.svg)](https://codeclimate.com/github/paul/sliding_partition)
6
+ [![Gemnasium Status](https://gemnasium.com/paul/sliding_partition.svg)](https://gemnasium.com/paul/sliding_partition)
7
+ [![Travis CI Status](https://secure.travis-ci.org/paul/sliding_partition.svg)](https://travis-ci.org/paul/sliding_partition)
8
+
9
+ <!-- Tocer[start]: Auto-generated, don't remove. -->
10
+
11
+ # Table of Contents
12
+
13
+ - [Features](#features)
14
+ - [Screencasts](#screencasts)
15
+ - [Requirements](#requirements)
16
+ - [Setup](#setup)
17
+ - [Usage](#usage)
18
+ - [Rails](#rails)
19
+ - [config/sliding_partitions.rb](#configsliding_partitionsrb)
20
+ - [Tests](#tests)
21
+ - [Versioning](#versioning)
22
+ - [Code of Conduct](#code-of-conduct)
23
+ - [Contributions](#contributions)
24
+ - [License](#license)
25
+ - [History](#history)
26
+ - [Credits](#credits)
27
+
28
+ <!-- Tocer[finish]: Auto-generated, don't remove. -->
29
+
30
+ # Features
31
+
32
+ # Screencasts
33
+
34
+ # Requirements
35
+
36
+ 0. [MRI 2.3.1](https://www.ruby-lang.org)
37
+
38
+ # Setup
39
+
40
+ For a secure install, type the following (recommended):
41
+
42
+ gem cert --add <(curl --location --silent /gem-public.pem)
43
+ gem install sliding_partition --trust-policy MediumSecurity
44
+
45
+ NOTE: A HighSecurity trust policy would be best but MediumSecurity enables signed gem verification while
46
+ allowing the installation of unsigned dependencies since they are beyond the scope of this gem.
47
+
48
+ For an insecure install, type the following (not recommended):
49
+
50
+ gem install sliding_partition
51
+
52
+ Add the following to your Gemfile:
53
+
54
+ gem "sliding_partition"
55
+
56
+ # Usage
57
+
58
+ ## Rails
59
+
60
+ Create a migration for the parent table. This table won't contain any data
61
+ itself, but gives us the skeleton that the other tables will inherit, and will
62
+ be used by the model for queries.
63
+
64
+ ```ruby
65
+ class AddEventsTable
66
+ def change
67
+ create_table :events do |t|
68
+ t.string :name
69
+ t.timestamp :event_at
70
+ t.timestamps
71
+ end
72
+
73
+ add_index :events, [:name, :event_at]
74
+ end
75
+ end
76
+ ```
77
+
78
+ Once that table exists, set up a config to tell SlidingPartition how you want it partitioned:
79
+
80
+ ```ruby
81
+ # config/sliding_partitions.rb
82
+
83
+ SlidingPartition.define(Event) do |partition|
84
+ partition.time_column = :event_at
85
+ partition.suffix = "%Y%m%d" # A strftime-formatted string, will be appended to all partition table names
86
+ partition.partition_interval = 1.month
87
+ partition.retention_interval = 6.months
88
+ end
89
+ ```
90
+
91
+ Now, have SlidingPartition manage these tables.
92
+
93
+ ```ruby
94
+ SlidingPartition.initialize!
95
+ ```
96
+
97
+ Finally, you'll want SlidingPartition to run periodically, to ensure the next
98
+ period's table is created ahead of time. We recommend that you run it several
99
+ times leading up to the next date, it does no harm to have the empty table
100
+ sitting around for future use, in case something fails and it takes it awhile
101
+ to fix it. We also recommend you put this in a background job, and trigger it
102
+ using clockwork or some other recurring job spawner. SlidingPartition comes
103
+ with an ActiveJob Job for this purpose.
104
+
105
+ ```ruby
106
+ module Clockwork
107
+
108
+ every 1.day do
109
+ SlidingPartition::Job.perform_later
110
+ end
111
+
112
+ end
113
+ ```
114
+
115
+ # Tests
116
+
117
+ To test, run:
118
+
119
+ bundle exec rake
120
+
121
+ # Versioning
122
+
123
+ Read [Semantic Versioning](http://semver.org) for details. Briefly, it means:
124
+
125
+ - Patch (x.y.Z) - Incremented for small, backwards compatible bug fixes.
126
+ - Minor (x.Y.z) - Incremented for new, backwards compatible public API enhancements and/or bug fixes.
127
+ - Major (X.y.z) - Incremented for any backwards incompatible public API changes.
128
+
129
+ # Code of Conduct
130
+
131
+ Please note that this project is released with a [CODE OF CONDUCT](CODE_OF_CONDUCT.md). By participating in this project
132
+ you agree to abide by its terms.
133
+
134
+ # Contributions
135
+
136
+ Read [CONTRIBUTING](CONTRIBUTING.md) for details.
137
+
138
+ # License
139
+
140
+ Copyright (c) 2016 []().
141
+ Read the [LICENSE](LICENSE.md) for details.
142
+
143
+ # History
144
+
145
+ Read the [CHANGELOG](CHANGELOG.md) for details.
146
+ Built with [Gemsmith](https://github.com/bkuhlmann/gemsmith).
147
+
148
+ # Credits
149
+
150
+ Developed by [Paul Sadauskas]() at []().
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sliding_partition/identity"
4
+ require "sliding_partition/definition"
5
+
6
+ require "sliding_partition/railtie" if defined?(Rails)
7
+
8
+ module SlidingPartition
9
+
10
+ def self.define(model, &config)
11
+ parititions[model] = Definition.new(model, &config)
12
+ end
13
+
14
+ def self.setup!
15
+ parititions.values.each { |p| p.setup! }
16
+ end
17
+
18
+ def self.migrate!
19
+ parititions.values.each { |p| p.migrate! }
20
+ end
21
+
22
+ def self.parititions
23
+ @@parititions ||= {}
24
+ end
25
+
26
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require_relative "partition_ddl_changer"
3
+ require_relative "table_collection"
4
+
5
+ module SlidingPartition
6
+ class Definition
7
+
8
+ attr_reader :model
9
+
10
+ attr_accessor :inherited_table_name, :time_column, :suffix,
11
+ :partition_interval, :retention_interval
12
+
13
+ def initialize(model)
14
+ @model = model
15
+ yield self if block_given?
16
+ end
17
+
18
+ def setup!(at: Time.now)
19
+ PartitionDDLChanger.new(self, at).setup!
20
+ end
21
+
22
+ def rotate!(at: Time.now)
23
+ PartitionDDLChanger.new(self, at).rotate!
24
+ end
25
+
26
+ def migrate!(at: Time.now)
27
+ PartitionDDLChanger.new(self, at).migrate!
28
+ end
29
+
30
+ def partitions(at: Time.now)
31
+ TableCollection.new(definition: self, at_time: at)
32
+ end
33
+
34
+ def inherited_table_name
35
+ @inherited_table_name ||= model.table_name
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlidingPartition
4
+ # Gem identity information.
5
+ module Identity
6
+ def self.name
7
+ "sliding_partition"
8
+ end
9
+
10
+ def self.label
11
+ "SlidingPartition"
12
+ end
13
+
14
+ def self.version
15
+ "0.1.0"
16
+ end
17
+
18
+ def self.version_label
19
+ "#{label} #{version}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,178 @@
1
+
2
+ module SlidingPartition
3
+ class PartitionDDLChanger
4
+ extend Forwardable
5
+
6
+ attr_reader :definition, :time, :partitions
7
+
8
+ delegate %i[ inherited_table_name time_column suffix
9
+ partition_interval retention_interval ] => :definition
10
+
11
+ def initialize(definition, time)
12
+ @definition, @time = definition, time
13
+ @partitions = @definition.partitions(at: time)
14
+ end
15
+
16
+ def setup!
17
+ create_tables!
18
+ update_trigger_function!
19
+ create_trigger!
20
+ end
21
+
22
+ def rotate!
23
+ create_tables!
24
+ expire_tables!
25
+ update_trigger_function!
26
+ end
27
+
28
+ def migrate!
29
+ clone_new_table!
30
+ setup!
31
+ swap_tables!
32
+ migrate_data!(from: retired_table, to: parent_table)
33
+ end
34
+
35
+ def create_tables!
36
+ partitions.each do |partition|
37
+ create_partition_table(partition) unless partition_table_exists?(partition)
38
+ end
39
+ end
40
+
41
+ def expire_tables!
42
+ candidate_tables.each do |table|
43
+ drop_partition_table(table) unless partitions.map(&:table_name).include?(table)
44
+ end
45
+ end
46
+
47
+ def clone_new_table!
48
+ connection.execute <<-SQL
49
+ CREATE TABLE #{new_table} (
50
+ LIKE #{parent_table} INCLUDING ALL
51
+ );
52
+ SQL
53
+ end
54
+
55
+ def swap_tables!
56
+ connection.execute <<-SQL
57
+ BEGIN;
58
+ ALTER TABLE #{parent_table} RENAME TO #{retired_table};
59
+ ALTER TABLE #{new_table} RENAME TO #{parent_table};
60
+ COMMIT;
61
+ SQL
62
+ create_trigger!
63
+ end
64
+
65
+ def migrate_data!(from:, to:)
66
+ partitions.each do |partition|
67
+ connection.execute <<-SQL
68
+ INSERT INTO #{to} (
69
+ SELECT * FROM #{from}
70
+ WHERE #{time_column} >= TIMESTAMP '#{partition.timestamp_floor.to_s(:db)}'
71
+ AND #{time_column} < TIMESTAMP '#{partition.timestamp_ceiling.to_s(:db)}'
72
+ );
73
+ SQL
74
+ end
75
+ end
76
+
77
+ protected
78
+
79
+ def create_partition_table(partition)
80
+ connection.execute(create_table_sql(partition))
81
+ end
82
+
83
+ def drop_partition_table(table)
84
+ connection.drop_table(table)
85
+ end
86
+
87
+ def partition_table_exists?(partition)
88
+ connection.tables.include?(partition.table_name)
89
+ end
90
+
91
+ def update_trigger_function!
92
+ connection.execute(trigger_function_sql)
93
+ end
94
+
95
+ def create_trigger!
96
+ connection.execute(<<-SQL)
97
+ BEGIN;
98
+ DROP TRIGGER IF EXISTS #{inherited_table_name}_trigger ON #{inherited_table_name};
99
+ CREATE TRIGGER #{inherited_table_name}_trigger
100
+ BEFORE INSERT ON #{inherited_table_name}
101
+ FOR EACH ROW EXECUTE PROCEDURE #{inherited_table_name}_insert_trigger();
102
+ COMMIT;
103
+ SQL
104
+
105
+ end
106
+
107
+ def trigger_function_sql
108
+ conditions = partitions.reverse_each.map do |partition|
109
+ <<-SQL
110
+ ( NEW.#{time_column} >= TIMESTAMP '#{partition.timestamp_floor.to_s(:db)}' AND
111
+ NEW.#{time_column} < TIMESTAMP '#{partition.timestamp_ceiling.to_s(:db)}'
112
+ ) THEN INSERT INTO #{partition.table_name} VALUES (NEW.*);
113
+ SQL
114
+ end
115
+
116
+ <<-SQL
117
+ CREATE OR REPLACE FUNCTION #{inherited_table_name}_insert_trigger()
118
+ RETURNS TRIGGER AS $$
119
+ BEGIN
120
+ IF #{conditions.join("\n ELSIF ")}
121
+ ELSIF (NEW.#{time_column} < TIMESTAMP '#{partitions.first_partition_timestamp.to_s(:db)}')
122
+ THEN RETURN NULL; -- Just discard pre-historic rows
123
+ ELSE
124
+ RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
125
+ END IF;
126
+ RETURN NULL;
127
+ END;
128
+ $$
129
+ LANGUAGE plpgsql;
130
+ SQL
131
+ end
132
+
133
+ def create_table_sql(partition)
134
+ <<-SQL
135
+ CREATE TABLE #{partition.table_name} (
136
+ LIKE #{inherited_table_name} INCLUDING ALL
137
+ ) INHERITS (#{inherited_table_name});
138
+
139
+ ALTER TABLE #{partition.table_name}
140
+ ADD CHECK (
141
+ #{time_column} >= TIMESTAMP '#{partition.timestamp_floor.to_s(:db)}' AND
142
+ #{time_column} < TIMESTAMP '#{partition.timestamp_ceiling.to_s(:db)}'
143
+ )
144
+ SQL
145
+ end
146
+
147
+ def candidate_tables
148
+ connection.tables.map do |candidate|
149
+ next unless candidate.starts_with?(inherited_table_name.to_s + "_")
150
+
151
+ begin
152
+ Time.strptime(candidate, [inherited_table_name, suffix].join("_"))
153
+ rescue ArgumentError
154
+ next
155
+ end
156
+
157
+ candidate
158
+ end.compact
159
+ end
160
+
161
+ def connection
162
+ definition.model.connection
163
+ end
164
+
165
+ def parent_table
166
+ @new_table_name || inherited_table_name
167
+ end
168
+
169
+ def new_table
170
+ parent_table + "_new"
171
+ end
172
+
173
+ def retired_table
174
+ parent_table + "_retired"
175
+ end
176
+
177
+ end
178
+ end
@@ -0,0 +1,42 @@
1
+
2
+ require "rounding"
3
+
4
+ module SlidingPartition
5
+ class PartitionTable
6
+ extend Forwardable
7
+
8
+ attr_reader :timestamp, :definition
9
+
10
+ delegate %i[ inherited_table_name time_column suffix
11
+ partition_interval retention_interval ] => :definition
12
+
13
+ def initialize(for_time:, definition:)
14
+ @timestamp, @definition = for_time, definition
15
+ end
16
+
17
+ def table_name
18
+ [
19
+ inherited_table_name,
20
+ timestamp_floor.strftime(suffix)
21
+ ].join("_")
22
+ end
23
+
24
+ def timestamp_floor
25
+ # rounding doesn't handle months correctly, do it ourselves
26
+ if partition_interval = 1.month
27
+ @timestamp.beginning_of_month.floor_to(1.day)
28
+ else
29
+ @timestamp.floor_to(partition_interval)
30
+ end
31
+ end
32
+
33
+ def timestamp_ceiling
34
+ if partition_interval = 1.month
35
+ @timestamp.end_of_month + 1
36
+ else
37
+ @timestamp.ceiling_to(partition_interval)
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlidingPartition
4
+ class Railtie < ::Rails::Railtie
5
+ rake_tasks do
6
+ load "tasks/sliding_partition_tasks.rake"
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,35 @@
1
+
2
+ require_relative "partition_table"
3
+
4
+ module SlidingPartition
5
+ class TableCollection
6
+ extend Forwardable
7
+ include Enumerable
8
+
9
+ attr_reader :definition, :time
10
+
11
+ delegate %i[ inherited_table_name time_column suffix
12
+ partition_interval retention_interval ] => :definition
13
+
14
+ def initialize(definition:, at_time:)
15
+ @definition, @time = definition, at_time
16
+ end
17
+
18
+ def tables
19
+ first_ts = time - retention_interval
20
+ last_ts = time + partition_interval
21
+ (first_ts.to_i...last_ts.to_i).step(partition_interval).map do |partition_time|
22
+ PartitionTable.new(for_time: Time.at(partition_time), definition: definition)
23
+ end
24
+ end
25
+
26
+ def each(&block)
27
+ tables.each(&block)
28
+ end
29
+
30
+ def first_partition_timestamp
31
+ tables.first.timestamp_floor
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sliding_partition"
4
+
5
+ namespace :partition do
6
+ desc "Setup all postgres sliding partitions"
7
+ task :setup => :environment do
8
+ SlidingPartition.setup!
9
+ end
10
+
11
+ desc "Migrate data in all partitions"
12
+ task :migrate => :environment do
13
+ SlidingPartition.migrate!
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,286 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sliding_partition
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Sadauskas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.0
20
+ - - "<="
21
+ - !ruby/object:Gem::Version
22
+ version: 6.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 4.2.0
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: 6.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: pg
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rounding
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.12'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.12'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '11.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '11.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: gemsmith
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '7.7'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '7.7'
103
+ - !ruby/object:Gem::Dependency
104
+ name: pry
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: pry-byebug
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: pry-state
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rspec
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '3.5'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '3.5'
159
+ - !ruby/object:Gem::Dependency
160
+ name: rb-fsevent
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: guard-rspec
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ - !ruby/object:Gem::Dependency
188
+ name: terminal-notifier
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: rubocop
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '0.41'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '0.41'
215
+ - !ruby/object:Gem::Dependency
216
+ name: codeclimate-test-reporter
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ - !ruby/object:Gem::Dependency
230
+ name: awesome_print
231
+ requirement: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - ">="
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
236
+ type: :development
237
+ prerelease: false
238
+ version_requirements: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: '0'
243
+ description: ''
244
+ email:
245
+ - psadauskas@gmail.com
246
+ executables: []
247
+ extensions: []
248
+ extra_rdoc_files:
249
+ - README.md
250
+ - LICENSE.md
251
+ files:
252
+ - LICENSE.md
253
+ - README.md
254
+ - lib/sliding_partition.rb
255
+ - lib/sliding_partition/definition.rb
256
+ - lib/sliding_partition/identity.rb
257
+ - lib/sliding_partition/partition_ddl_changer.rb
258
+ - lib/sliding_partition/partition_table.rb
259
+ - lib/sliding_partition/railtie.rb
260
+ - lib/sliding_partition/table_collection.rb
261
+ - lib/tasks/sliding_partition_tasks.rake
262
+ homepage: https://github.com/paul/sliding_partition
263
+ licenses:
264
+ - MIT
265
+ metadata: {}
266
+ post_install_message:
267
+ rdoc_options: []
268
+ require_paths:
269
+ - lib
270
+ required_ruby_version: !ruby/object:Gem::Requirement
271
+ requirements:
272
+ - - ">="
273
+ - !ruby/object:Gem::Version
274
+ version: '0'
275
+ required_rubygems_version: !ruby/object:Gem::Requirement
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ version: '0'
280
+ requirements: []
281
+ rubyforge_project:
282
+ rubygems_version: 2.6.6
283
+ signing_key:
284
+ specification_version: 4
285
+ summary: ''
286
+ test_files: []