sliding_partition 0.1.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.
@@ -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: []