pg_online_schema_change 0.9.4 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01d9f8568b13763a56446a47e4d1c9f8d04b4d29cfd5eec3f6bdafd4355ce163
4
- data.tar.gz: c14d2ce856b0023484864559a8d39de9f05510b7123125df12028be5d4a280ea
3
+ metadata.gz: 839fe414842291d9118a4115a56e06f1e0308ab3b7a740cafd9994314ded2d76
4
+ data.tar.gz: 22e9639093bf386f8a1e554e15e8d83df5e3c6de340c372f181fa3b280aee98d
5
5
  SHA512:
6
- metadata.gz: bcf50ee7f529ce49c922ad5ff514233992ef5b3dcbe58fea8766efcb5ee0cce24798448e5d825a9b24a5f97a8e8864cd423dbb81898ebf3ab165a8e905745c58
7
- data.tar.gz: 045a92a13bebe1e4ebdc8a09411b5c7536f12df800a1a66f4ad4709fdb1ec31a57ef98db136643042d87bda13945d46a52c228b3e9650e3a0a63efb4f2e1c186
6
+ metadata.gz: a160d19b3f1cb6655f70e0481b3293110deaee04d7a017ff9fe0c2b4d6100fd7d475520092db1b3bb5e068df5cb70243a00397a5cb1c2c259f2fe5b776b7e405
7
+ data.tar.gz: 9e4543fde48359fdc12046ff019420aafe51732f5cd1332285b3762fac3dcb198acc7be4f5fc6f6f90b910532758eb4a5752a8c9835d1f394774e6f77eda3898
data/CHANGELOG.md CHANGED
@@ -1,7 +1,24 @@
1
+ ## [0.9.5] - 2023-10-15
2
+
3
+ - Validate one constraint at a time in #124
4
+ - Introduce --skip-foreign-key-validation in #125
5
+
6
+ ## [0.9.4] - 2023-09-17
7
+
8
+ - Resolving gem push and sync glitch in 0.9.3
9
+
10
+ ## [0.9.3] - 2023-09-17
11
+
12
+ - Dependency updates
13
+ - Adding support for showing the gem version with -v or --version by @brycethornton #101
14
+ - Fix for INSERT's failing for long table names by @ahilmer #116
15
+ - Get view definition of a view from dedicated schema by @shayonj #117
16
+
1
17
  ## [0.9.2] - 2023-07-03
2
18
 
3
19
  - Dependency updates
4
20
  - Create shadow and audit with auatovacuum default turned off. Should avoid lock queues when disabling vacuum on audit table. #97
21
+
5
22
  ## [0.9.1] - 2023-06-24
6
23
 
7
24
  - Dependency updates and refresh docker release process with multi-platform build
data/Gemfile.lock CHANGED
@@ -1,21 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pg_online_schema_change (0.9.4)
4
+ pg_online_schema_change (0.9.6)
5
5
  ougai (~> 2.0.0)
6
6
  pg (>= 1.3.2, < 1.6.0)
7
7
  pg_query (>= 2.1.3, < 4.3.0)
8
- thor (~> 1.2.1)
8
+ thor (>= 1.2.1, < 1.4.0)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
13
  ast (2.4.2)
14
- base64 (0.1.1)
15
14
  coderay (1.1.3)
16
15
  diff-lcs (1.5.0)
17
- google-protobuf (3.24.3-arm64-darwin)
18
- google-protobuf (3.24.3-x86_64-linux)
16
+ google-protobuf (3.25.0-arm64-darwin)
19
17
  haml (6.1.1)
20
18
  temple (>= 0.8.2)
21
19
  thor
@@ -27,7 +25,7 @@ GEM
27
25
  ougai (2.0.0)
28
26
  oj (~> 3.10)
29
27
  parallel (1.23.0)
30
- parser (3.2.2.3)
28
+ parser (3.2.2.4)
31
29
  ast (~> 2.4.1)
32
30
  racc
33
31
  pg (1.5.4)
@@ -39,9 +37,9 @@ GEM
39
37
  method_source (~> 1.0)
40
38
  racc (1.7.1)
41
39
  rainbow (3.1.1)
42
- rake (13.0.6)
40
+ rake (13.1.0)
43
41
  rbs (3.1.0)
44
- regexp_parser (2.8.1)
42
+ regexp_parser (2.8.2)
45
43
  rexml (3.2.6)
46
44
  rspec (3.12.0)
47
45
  rspec-core (~> 3.12.0)
@@ -56,19 +54,18 @@ GEM
56
54
  diff-lcs (>= 1.2.0, < 2.0)
57
55
  rspec-support (~> 3.12.0)
58
56
  rspec-support (3.12.0)
59
- rubocop (1.56.3)
60
- base64 (~> 0.1.1)
57
+ rubocop (1.57.2)
61
58
  json (~> 2.3)
62
59
  language_server-protocol (>= 3.17.0)
63
60
  parallel (~> 1.10)
64
- parser (>= 3.2.2.3)
61
+ parser (>= 3.2.2.4)
65
62
  rainbow (>= 2.2.2, < 4.0)
66
63
  regexp_parser (>= 1.8, < 3.0)
67
64
  rexml (>= 3.2.5, < 4.0)
68
65
  rubocop-ast (>= 1.28.1, < 2.0)
69
66
  ruby-progressbar (~> 1.7)
70
67
  unicode-display_width (>= 2.4.0, < 3.0)
71
- rubocop-ast (1.29.0)
68
+ rubocop-ast (1.30.0)
72
69
  parser (>= 3.2.1.0)
73
70
  rubocop-capybara (2.18.0)
74
71
  rubocop (~> 1.41)
@@ -76,7 +73,7 @@ GEM
76
73
  rubocop (~> 1.33)
77
74
  rubocop-packaging (0.5.2)
78
75
  rubocop (>= 1.33, < 2.0)
79
- rubocop-performance (1.19.0)
76
+ rubocop-performance (1.19.1)
80
77
  rubocop (>= 1.7.0, < 2.0)
81
78
  rubocop-ast (>= 0.4.0)
82
79
  rubocop-rake (0.6.0)
@@ -86,7 +83,7 @@ GEM
86
83
  rubocop-capybara (~> 2.17)
87
84
  rubocop-factory_bot (~> 2.22)
88
85
  ruby-progressbar (1.13.0)
89
- syntax_tree (6.1.1)
86
+ syntax_tree (6.2.0)
90
87
  prettier_print (>= 1.2.0)
91
88
  syntax_tree-haml (4.0.3)
92
89
  haml (>= 5.2)
@@ -97,9 +94,9 @@ GEM
97
94
  rbs
98
95
  syntax_tree (>= 2.0.1)
99
96
  temple (0.10.0)
100
- thor (1.2.2)
97
+ thor (1.3.0)
101
98
  tilt (2.1.0)
102
- unicode-display_width (2.4.2)
99
+ unicode-display_width (2.5.0)
103
100
 
104
101
  PLATFORMS
105
102
  arm64-darwin-20
data/README.md CHANGED
@@ -9,12 +9,11 @@ pg-online-schema-change (`pg-osc`) is a tool for making schema changes (any `ALT
9
9
 
10
10
  `pg-osc` uses the concept of shadow table to perform schema changes. At a high level, it creates a shadow table that looks structurally the same as the primary table, performs the schema change on the shadow table, copies contents from the primary table to the shadow table and swaps the table names in the end while preserving all changes to the primary table using triggers (via audit table).
11
11
 
12
- `pg-osc` is inspired by the design and workings of tools like `pg_repack` and `pt-online-schema-change` (MySQL). Read more below on [how does it work](#how-does-it-work), [prominent features](#prominent-features), the [caveats](#caveats) and [examples](#examples)
13
-
14
- ⚠️ Proceed with caution when using this on production like workloads. Best to try on similar setup or staging like environment first. Read on below for some examples and caveats.
12
+ `pg-osc` is inspired by the design and workings of tools like `pg_repack` and `pt-online-schema-change` (MySQL). Read more below on [how does it work](#how-does-it-work), [prominent features](#prominent-features), the [caveats](#few-things-to-keep-in-mind) and [examples](#examples)
15
13
 
16
14
  ## Table of Contents
17
15
 
16
+ - [Table of Contents](#table-of-contents)
18
17
  - [Installation](#installation)
19
18
  - [Requirements](#requirements)
20
19
  - [Usage](#usage)
@@ -24,15 +23,15 @@ pg-online-schema-change (`pg-osc`) is a tool for making schema changes (any `ALT
24
23
  - [Renaming a column](#renaming-a-column)
25
24
  - [Multiple ALTER statements](#multiple-alter-statements)
26
25
  - [Kill other backends after 5s](#kill-other-backends-after-5s)
26
+ - [Replaying larger workloads](#replaying-larger-workloads)
27
27
  - [Backfill data](#backfill-data)
28
28
  - [Running using Docker](#running-using-docker)
29
- - [Caveats](#caveats)
29
+ - [Few things to keep in mind](#few-things-to-keep-in-mind)
30
30
  - [How does it work](#how-does-it-work)
31
31
  - [Development](#development)
32
+ - [Local testing](#local-testing)
32
33
  - [Releasing](#releasing)
33
34
  - [Contributing](#contributing)
34
- - [License](#license)
35
- - [Code of Conduct](#code-of-conduct)
36
35
 
37
36
  ## Installation
38
37
 
@@ -70,28 +69,29 @@ https://hub.docker.com/r/shayonj/pg-osc
70
69
  pg-online-schema-change help perform
71
70
 
72
71
  Usage:
73
- pg-online-schema-change perform -a, --alter-statement=ALTER_STATEMENT -d, --dbname=DBNAME -h, --host=HOST -p, --port=N -s, --schema=SCHEMA -u, --username=USERNAME -w, --password=PASSWORD
72
+ pg-online-schema-change perform -a, --alter-statement=ALTER_STATEMENT -d, --dbname=DBNAME -h, --host=HOST -p, --port=N -s, --schema=SCHEMA -u, --username=USERNAME
74
73
 
75
74
  Options:
76
- -a, --alter-statement=ALTER_STATEMENT # The ALTER statement to perform the schema change
77
- -s, --schema=SCHEMA # The schema in which the table is
78
- # Default: public
79
- -d, --dbname=DBNAME # Name of the database
80
- -h, --host=HOST # Server host where the Database is located
81
- -u, --username=USERNAME # Username for the Database
82
- -p, --port=N # Port for the Database
83
- # Default: 5432
84
- -w, --password=PASSWORD # DEPRECATED: Password for the Database. Please pass PGPASSWORD environment variable instead.
85
- -v, [--verbose], [--no-verbose] # Emit logs in debug mode
86
- -f, [--drop], [--no-drop] # Drop the original table in the end after the swap
87
- -k, [--kill-backends], [--no-kill-backends] # Kill other competing queries/backends when trying to acquire lock for the shadow table creation and swap. It will wait for --wait-time-for-lock duration before killing backends and try upto 3 times.
88
- -w, [--wait-time-for-lock=N] # Time to wait before killing backends to acquire lock and/or retrying upto 3 times. It will kill backends if --kill-backends is true, otherwise try upto 3 times and exit if it cannot acquire a lock.
89
- # Default: 10
90
- -c, [--copy-statement=COPY_STATEMENT] # Takes a .sql file location where you can provide a custom query to be played (ex: backfills) when pgosc copies data from the primary to the shadow table. More examples in README.
91
- -b, [--pull-batch-count=N] # Number of rows to be replayed on each iteration after copy. This can be tuned for faster catch up and swap. Best used with delta-count.
92
- # Default: 1000
93
- -e, [--delta-count=N] # Indicates how many rows should be remaining before a swap should be performed. This can be tuned for faster catch up and swap, especially on highly volume tables. Best used with pull-batch-count.
94
- # Default: 20
75
+ -a, --alter-statement=ALTER_STATEMENT # The ALTER statement to perform the schema change
76
+ -s, --schema=SCHEMA # The schema in which the table is
77
+ # Default: public
78
+ -d, --dbname=DBNAME # Name of the database
79
+ -h, --host=HOST # Server host where the Database is located
80
+ -u, --username=USERNAME # Username for the Database
81
+ -p, --port=N # Port for the Database
82
+ # Default: 5432
83
+ -w, [--password=PASSWORD] # DEPRECATED: Password for the Database. Please pass PGPASSWORD environment variable instead.
84
+ -v, [--verbose], [--no-verbose] # Emit logs in debug mode
85
+ -f, [--drop], [--no-drop] # Drop the original table in the end after the swap
86
+ -k, [--kill-backends], [--no-kill-backends] # Kill other competing queries/backends when trying to acquire lock for the shadow table creation and swap. It will wait for --wait-time-for-lock duration before killing backends and try upto 3 times.
87
+ -w, [--wait-time-for-lock=N] # Time to wait before killing backends to acquire lock and/or retrying upto 3 times. It will kill backends if --kill-backends is true, otherwise try upto 3 times and exit if it cannot acquire a lock.
88
+ # Default: 10
89
+ -c, [--copy-statement=COPY_STATEMENT] # Takes a .sql file location where you can provide a custom query to be played (ex: backfills) when pgosc copies data from the primary to the shadow table. More examples in README.
90
+ -b, [--pull-batch-count=N] # Number of rows to be replayed on each iteration after copy. This can be tuned for faster catch up and swap. Best used with delta-count.
91
+ # Default: 1000
92
+ -e, [--delta-count=N] # Indicates how many rows should be remaining before a swap should be performed. This can be tuned for faster catch up and swap, especially on highly volume tables. Best used with pull-batch-count.
93
+ # Default: 20
94
+ -o, [--skip-foreign-key-validation], [--no-skip-foreign-key-validation] # Skip foreign key validation after swap. You shouldn't need this unless you have a very specific use case, like manually validating foreign key constraints after swap.
95
95
  ```
96
96
 
97
97
  ```
@@ -104,7 +104,7 @@ print the version
104
104
  ## Prominent features
105
105
 
106
106
  - `pg-osc` supports when a column is being added, dropped or renamed with no data loss.
107
- - `pg-osc` acquires minimal locks throughout the process (read more below on the caveats).
107
+ - `pg-osc` acquires minimal locks throughout the process (read more below on the [caveats](#few-things-to-keep-in-mind)).
108
108
  - Copies over indexes and Foreign keys.
109
109
  - Optionally drop or retain old tables in the end.
110
110
  - Tune how slow or fast should replays be from the audit/log table ([Replaying larger workloads](#replaying-larger-workloads)).
@@ -217,7 +217,7 @@ docker run --network host -it --rm shayonj/pg-osc:latest \
217
217
  --drop
218
218
  ```
219
219
 
220
- ## Caveats
220
+ ## Few things to keep in mind
221
221
 
222
222
  - Partitioned tables are not supported as of yet. Pull requests and ideas welcome.
223
223
  - A primary key should exist on the table; without it, `pg-osc` will raise an exception
@@ -230,8 +230,6 @@ docker run --network host -it --rm shayonj/pg-osc:latest \
230
230
  - Due to the nature of duplicating a table, there needs to be enough space on the disk to support the operation.
231
231
  - Index, constraints and sequence names will be altered and lose their original naming.
232
232
  - Can be fixed in future releases. Feel free to open a feature req.
233
- - Triggers are not carried over.
234
- - Can be fixed in future releases. Feel free to open a feature req.
235
233
  - Foreign keys are dropped & re-added to referencing tables with a `NOT VALID`. A follow on `VALIDATE CONSTRAINT` is run.
236
234
  - Ensures that integrity is maintained and re-introducing FKs doesn't acquire additional locks, hence the `NOT VALID`.
237
235
 
@@ -298,11 +296,3 @@ bundle exec bin/pg-online-schema-change perform -a 'ALTER TABLE pgbench_accounts
298
296
  ## Contributing
299
297
 
300
298
  Bug reports and pull requests are welcome on GitHub at https://github.com/shayonj/pg-osc.
301
-
302
- ## License
303
-
304
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
305
-
306
- ## Code of Conduct
307
-
308
- Everyone interacting in the PgOnlineSchemaChange project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/shayonj/pg-osc/blob/main/CODE_OF_CONDUCT.md).
@@ -89,6 +89,13 @@ module PgOnlineSchemaChange
89
89
  default: DELTA_COUNT,
90
90
  desc:
91
91
  "Indicates how many rows should be remaining before a swap should be performed. This can be tuned for faster catch up and swap, especially on highly volume tables. Best used with pull-batch-count."
92
+ method_option :skip_foreign_key_validation,
93
+ aliases: "-o",
94
+ type: :boolean,
95
+ required: false,
96
+ default: false,
97
+ desc:
98
+ "Skip foreign key validation after swap. You shouldn't need this unless you have a very specific use case, like manually validating foreign key constraints after swap."
92
99
 
93
100
  def perform
94
101
  client_options = Struct.new(*options.keys.map(&:to_sym)).new(*options.values)
@@ -19,7 +19,8 @@ module PgOnlineSchemaChange
19
19
  :wait_time_for_lock,
20
20
  :copy_statement,
21
21
  :pull_batch_count,
22
- :delta_count
22
+ :delta_count,
23
+ :skip_foreign_key_validation
23
24
 
24
25
  def initialize(options)
25
26
  @alter_statement = options.alter_statement
@@ -34,6 +35,7 @@ module PgOnlineSchemaChange
34
35
  @wait_time_for_lock = options.wait_time_for_lock
35
36
  @pull_batch_count = options.pull_batch_count
36
37
  @delta_count = options.delta_count
38
+ @skip_foreign_key_validation = options.skip_foreign_key_validation
37
39
 
38
40
  handle_copy_statement(options.copy_statement)
39
41
  handle_validations
@@ -54,7 +56,7 @@ module PgOnlineSchemaChange
54
56
 
55
57
  return if Query.same_table?(@alter_statement)
56
58
 
57
- raise Error("All statements should belong to the same table: #{@alter_statement}")
59
+ raise Error, "All statements should belong to the same table: #{@alter_statement}"
58
60
  end
59
61
 
60
62
  def handle_copy_statement(statement)
@@ -36,7 +36,10 @@ module PgOnlineSchemaChange
36
36
  Store.set(:trigger_time_column, "trigger_time_#{pgosc_identifier}")
37
37
  Store.set(:audit_table_pk, "at_#{pgosc_identifier}_id")
38
38
  Store.set(:shadow_table, "pgosc_st_#{client.table.downcase}_#{pgosc_identifier}")
39
- Store.set(:primary_table_storage_parameters, Query.storage_parameters_for(client, client.table_name, true) || "")
39
+ Store.set(
40
+ :primary_table_storage_parameters,
41
+ Query.storage_parameters_for(client, client.table_name, true) || "",
42
+ )
40
43
 
41
44
  Store.set(
42
45
  :referential_foreign_key_statements,
@@ -109,7 +112,10 @@ module PgOnlineSchemaChange
109
112
 
110
113
  Query.run(client.connection, sql)
111
114
 
112
- Store.set(:audit_table_pk_sequence, Query.get_sequence_name(client, audit_table, audit_table_pk))
115
+ Store.set(
116
+ :audit_table_pk_sequence,
117
+ Query.get_sequence_name(client, audit_table, audit_table_pk),
118
+ )
113
119
  end
114
120
 
115
121
  def setup_trigger!
@@ -270,11 +276,14 @@ module PgOnlineSchemaChange
270
276
  end
271
277
 
272
278
  def validate_constraints!
273
- logger.info("Validating constraints!")
274
-
275
- validate_statements = Query.get_foreign_keys_to_validate(client, client.table_name)
279
+ return if client.skip_foreign_key_validation
276
280
 
277
- Query.run(client.connection, validate_statements)
281
+ Query
282
+ .get_foreign_keys_to_validate(client, client.table_name)
283
+ .each do |statement|
284
+ logger.info("Validating constraints!", statement: statement)
285
+ Query.run(client.connection, statement)
286
+ end
278
287
  end
279
288
 
280
289
  def replace_views!
@@ -140,10 +140,9 @@ module PgOnlineSchemaChange
140
140
  SELECT pg_get_serial_sequence('#{table}', '#{column}');
141
141
  SQL
142
142
 
143
- run(client.connection, query) { |result| result.map { |row|
144
- row["pg_get_serial_sequence"]
145
- }
146
- }.first
143
+ run(client.connection, query) do |result|
144
+ result.map { |row| row["pg_get_serial_sequence"] }
145
+ end.first
147
146
  end
148
147
 
149
148
  def get_triggers_for(client, table)
@@ -238,11 +237,9 @@ module PgOnlineSchemaChange
238
237
  self_foreign_keys =
239
238
  constraints.select { |row| row["table_on"] == table && row["constraint_type"] == "f" }
240
239
 
241
- [referential_foreign_keys, self_foreign_keys].flatten
242
- .map do |row|
243
- "ALTER TABLE #{row["table_on"]} VALIDATE CONSTRAINT #{row["constraint_name"]};"
244
- end
245
- .join
240
+ [referential_foreign_keys, self_foreign_keys].flatten.map do |row|
241
+ "ALTER TABLE #{row["table_on"]} VALIDATE CONSTRAINT #{row["constraint_name"]};"
242
+ end
246
243
  end
247
244
 
248
245
  def dropped_columns(client)
@@ -314,20 +311,25 @@ module PgOnlineSchemaChange
314
311
 
315
312
  def view_definitions_for(client, table)
316
313
  query = <<~SQL
317
- SELECT DISTINCT dependent_view.relname as view_name, pg_get_viewdef(format('%I.%I', '#{client.schema}', dependent_view.relname)::regclass) as view_definition
318
- FROM pg_depend
319
- JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
320
- JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid
321
- JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid
322
- JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace
323
- WHERE
324
- source_ns.nspname = '#{client.schema}'
325
- AND source_table.relname = '#{table}'
314
+ SELECT DISTINCT
315
+ dependent_view.relname AS view_name,
316
+ pg_get_viewdef(dependent_view.oid) AS view_definition,
317
+ view_ns.nspname AS schema_name
318
+ FROM pg_class AS source_table
319
+ JOIN pg_depend ON pg_depend.refobjid = source_table.oid
320
+ JOIN pg_rewrite ON pg_rewrite.oid = pg_depend.objid
321
+ JOIN pg_class AS dependent_view ON dependent_view.oid = pg_rewrite.ev_class
322
+ JOIN pg_namespace AS view_ns ON dependent_view.relnamespace = view_ns.oid
323
+ AND dependent_view.relkind = 'v'
324
+ AND source_table.relname = '#{table}';
326
325
  SQL
327
326
 
328
327
  definitions = []
329
328
  run(client.connection, query) do |result|
330
- definitions = result.map { |row| {row["view_name"] => row["view_definition"].strip} }
329
+ definitions =
330
+ result.map do |row|
331
+ { "#{row["schema_name"]}.#{row["view_name"]}" => row["view_definition"].strip }
332
+ end
331
333
  end
332
334
 
333
335
  definitions
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgOnlineSchemaChange
4
- VERSION = "0.9.4"
4
+ VERSION = "0.9.6"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_online_schema_change
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shayon Mukherjee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-17 00:00:00.000000000 Z
11
+ date: 2023-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ougai
@@ -68,16 +68,22 @@ dependencies:
68
68
  name: thor
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
- - - "~>"
71
+ - - ">="
72
72
  - !ruby/object:Gem::Version
73
73
  version: 1.2.1
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: 1.4.0
74
77
  type: :runtime
75
78
  prerelease: false
76
79
  version_requirements: !ruby/object:Gem::Requirement
77
80
  requirements:
78
- - - "~>"
81
+ - - ">="
79
82
  - !ruby/object:Gem::Version
80
83
  version: 1.2.1
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: 1.4.0
81
87
  - !ruby/object:Gem::Dependency
82
88
  name: prettier_print
83
89
  requirement: !ruby/object:Gem::Requirement