jsonb_accessor 1.0.0.beta.2 → 1.0.0.beta.3

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
  SHA1:
3
- metadata.gz: d6f16bfcb008ed0dabf95cb479829414652c0fb5
4
- data.tar.gz: 9aec106f0ba84f640710bb8181da1d2d329e38ce
3
+ metadata.gz: daa3bf1bf3902f9507356358bb715623a66f622a
4
+ data.tar.gz: b6f917cb7dab2ad61077a23a2b94d8a65545b6f5
5
5
  SHA512:
6
- metadata.gz: 6bac196bd2d23e96576d8893a320f4fc006860164ef5ca56fde49ee7591b603f3f1d876de857231c3e4a2e07ecdd9170567f9b74e17c1c97ea44a6c514cb81a5
7
- data.tar.gz: 4670f4f4dda76182a874f9ffa3c279487a4b8aff250660575df49aab1a84b5dd0b11971142c76a8cc50dbccd935bdd814b18646838a100a9cef927bd487a5011
6
+ metadata.gz: 1d3f263eb28a0b7f2d0b1f813cc0a9d24b2b1fd0814eca2916ca474d150eb751287e064b82464f541224a53a4b6576bffc35012a56a4ea84bf240646e5c3a288
7
+ data.tar.gz: 5a41d9c6cd1b5d45b3d8f76b974493c668a28453575d0247fb896cc842edfcc898d4d3aedc6158c54e8786cdcb0b962c7bf7be942b169699951aa4695fb561c3
data/.rubocop.yml CHANGED
@@ -23,9 +23,11 @@ Metrics/MethodLength:
23
23
  Enabled: false
24
24
  Metrics/ModuleLength:
25
25
  Enabled: false
26
+ Metrics/PerceivedComplexity:
27
+ Enabled: false
26
28
  Metrics/BlockLength:
27
29
  Enabled: false
28
- Metrics/PerceivedComplexity:
30
+ Security/YAMLLoad:
29
31
  Enabled: false
30
32
  Style/AlignParameters:
31
33
  Enabled: false
data/Appraisals CHANGED
@@ -1,4 +1,4 @@
1
1
  appraise "activerecord-5.0.0" do
2
2
  gemspec
3
- gem "activerecord", "5.0.0"
3
+ gem "activerecord", "~> 5.0.0"
4
4
  end
data/README.md CHANGED
@@ -27,7 +27,7 @@ This README reflects the most recent 1.0 beta. Method names and interfaces may s
27
27
  Add this line to your application's `Gemfile`:
28
28
 
29
29
  ```ruby
30
- gem "jsonb_accessor", "1.0.0.beta.2"
30
+ gem "jsonb_accessor", "1.0.0.beta.3"
31
31
  ```
32
32
 
33
33
  And then execute:
@@ -71,6 +71,8 @@ class Product < ActiveRecord::Base
71
71
  end
72
72
  ```
73
73
 
74
+ A brief note about defaults: `default` works pretty much as you would expect in practice, but it actually becomes part of a defaults hash that is the `default` value for the jsonb column (in the above example it would be `:data`).
75
+
74
76
  You can also pass in a `store_key` option.
75
77
 
76
78
  ```ruby
@@ -103,12 +105,18 @@ class Product < ActiveRecord::Base
103
105
  end
104
106
  ```
105
107
 
106
- Jsonb Accessor will add a `scope` to `Product` called `data_where`.
108
+ Jsonb Accessor will add a `scope` to `Product` called like the json column with `_where` suffix, in our case `data_where`.
107
109
 
108
110
  ```ruby
109
111
  Product.all.data_where(name: "Granite Towel", price: 17)
110
112
  ```
111
113
 
114
+ Similarly, it will also add a `data_where_not` `scope` to `Product`.
115
+
116
+ ```ruby
117
+ Product.all.data_where_not(name: "Plasma Fork")
118
+ ```
119
+
112
120
  For number fields you can query using `<` or `>`or use plain english if that's what you prefer.
113
121
 
114
122
  ```ruby
@@ -157,6 +165,15 @@ Product.all.jsonb_contains(:data, reviewed_at: 10.minutes.ago, p: 12) # Using th
157
165
 
158
166
  **Note:** Under the hood, `jsonb_contains` uses the [`@>` operator in Postgres](https://www.postgresql.org/docs/9.5/static/functions-json.html) so when you include an array query, the stored array and the array used for the query do not need to match exactly. For example, when queried with `[1, 2]`, records that have arrays of `[2, 1, 3]` will be returned.
159
167
 
168
+ ### `jsonb_excludes`
169
+
170
+ Returns all records that exclude the given JSON paths. Pretty much the opposite of `jsonb_contains`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
171
+
172
+ ```ruby
173
+ Product.all.jsonb_excludes(:data, title: "foo")
174
+ Product.all.jsonb_excludes(:data, reviewed_at: 10.minutes.ago, p: 12) # Using the store key
175
+ ```
176
+
160
177
  ### `jsonb_number_where`
161
178
 
162
179
  Returns all records that match the given criteria.
@@ -178,6 +195,14 @@ It supports:
178
195
 
179
196
  and it is indifferent to strings/symbols.
180
197
 
198
+ ### `jsonb_number_where_not`
199
+
200
+ Returns all records that do not match the given criteria. It's the opposite of `jsonb_number_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
201
+
202
+ ```ruby
203
+ Product.all.jsonb_number_where_not(:data, :price_in_cents, :greater_than, 300)
204
+ ```
205
+
181
206
  ### `jsonb_time_where`
182
207
 
183
208
  Returns all records that match the given criteria.
@@ -188,6 +213,14 @@ Product.all.jsonb_time_where(:data, :reviewed_at, :before, 2.days.ago)
188
213
 
189
214
  It supports `before` and `after` and is indifferent to strings/symbols.
190
215
 
216
+ ### `jsonb_time_where_not`
217
+
218
+ Returns all records that match the given criteria. The opposite of `jsonb_time_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).
219
+
220
+ ```ruby
221
+ Product.all.jsonb_time_where_not(:data, :reviewed_at, :before, 2.days.ago)
222
+ ```
223
+
191
224
  ## Single-Table Inheritance
192
225
 
193
226
  One of the big issues with `ActiveRecord` single-table inheritance (STI)
@@ -1,4 +1,4 @@
1
- class SetUpTestingDb < ActiveRecord::Migration
1
+ class SetUpTestingDb < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :products do |t|
4
4
  t.jsonb :options
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "pg"
6
- gem "activerecord", "5.0.0"
6
+ gem "activerecord", "~> 5.0.0"
7
7
 
8
8
  gemspec :path => "../"
@@ -1,33 +1,33 @@
1
1
  PATH
2
- remote: ../
2
+ remote: ..
3
3
  specs:
4
- jsonb_accessor (1.0.0.beta.2)
5
- activerecord (>= 5.0.0)
4
+ jsonb_accessor (1.0.0.beta.3)
5
+ activerecord (>= 5.0)
6
6
  pg (>= 0.18.1)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actionpack (5.0.0)
12
- actionview (= 5.0.0)
13
- activesupport (= 5.0.0)
11
+ actionpack (5.0.2)
12
+ actionview (= 5.0.2)
13
+ activesupport (= 5.0.2)
14
14
  rack (~> 2.0)
15
15
  rack-test (~> 0.6.3)
16
16
  rails-dom-testing (~> 2.0)
17
17
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
18
- actionview (5.0.0)
19
- activesupport (= 5.0.0)
18
+ actionview (5.0.2)
19
+ activesupport (= 5.0.2)
20
20
  builder (~> 3.1)
21
21
  erubis (~> 2.7.0)
22
22
  rails-dom-testing (~> 2.0)
23
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
24
- activemodel (5.0.0)
25
- activesupport (= 5.0.0)
26
- activerecord (5.0.0)
27
- activemodel (= 5.0.0)
28
- activesupport (= 5.0.0)
23
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
24
+ activemodel (5.0.2)
25
+ activesupport (= 5.0.2)
26
+ activerecord (5.0.2)
27
+ activemodel (= 5.0.2)
28
+ activesupport (= 5.0.2)
29
29
  arel (~> 7.0)
30
- activesupport (5.0.0)
30
+ activesupport (5.0.2)
31
31
  concurrent-ruby (~> 1.0, >= 1.0.2)
32
32
  i18n (~> 0.7)
33
33
  minitest (~> 5.1)
@@ -39,48 +39,48 @@ GEM
39
39
  arel (7.1.4)
40
40
  ast (2.3.0)
41
41
  awesome_print (1.7.0)
42
- builder (3.2.2)
42
+ builder (3.2.3)
43
43
  coderay (1.1.1)
44
- concurrent-ruby (1.0.2)
44
+ concurrent-ruby (1.0.5)
45
45
  database_cleaner (1.5.3)
46
- diff-lcs (1.2.5)
46
+ diff-lcs (1.3)
47
47
  erubis (2.7.0)
48
- i18n (0.7.0)
48
+ i18n (0.8.1)
49
49
  loofah (2.0.3)
50
50
  nokogiri (>= 1.5.9)
51
51
  method_source (0.8.2)
52
52
  mini_portile2 (2.1.0)
53
- minitest (5.9.1)
54
- nokogiri (1.6.8.1)
53
+ minitest (5.10.1)
54
+ nokogiri (1.7.0.1)
55
55
  mini_portile2 (~> 2.1.0)
56
- parser (2.3.1.4)
56
+ parser (2.4.0.0)
57
57
  ast (~> 2.2)
58
- pg (0.19.0)
58
+ pg (0.20.0)
59
59
  powerpack (0.1.1)
60
60
  pry (0.10.4)
61
61
  coderay (~> 1.1.0)
62
62
  method_source (~> 0.8.1)
63
63
  slop (~> 3.4)
64
- pry-doc (0.9.0)
64
+ pry-doc (0.10.0)
65
65
  pry (~> 0.9)
66
- yard (~> 0.8)
66
+ yard (~> 0.9)
67
67
  pry-nav (0.2.4)
68
68
  pry (>= 0.9.10, < 0.11.0)
69
69
  rack (2.0.1)
70
70
  rack-test (0.6.3)
71
71
  rack (>= 1.0)
72
- rails-dom-testing (2.0.1)
72
+ rails-dom-testing (2.0.2)
73
73
  activesupport (>= 4.2.0, < 6.0)
74
- nokogiri (~> 1.6.0)
74
+ nokogiri (~> 1.6)
75
75
  rails-html-sanitizer (1.0.3)
76
76
  loofah (~> 2.0)
77
- railties (5.0.0)
78
- actionpack (= 5.0.0)
79
- activesupport (= 5.0.0)
77
+ railties (5.0.2)
78
+ actionpack (= 5.0.2)
79
+ activesupport (= 5.0.2)
80
80
  method_source
81
81
  rake (>= 0.8.7)
82
82
  thor (>= 0.18.1, < 2.0)
83
- rainbow (2.1.0)
83
+ rainbow (2.2.1)
84
84
  rake (10.5.0)
85
85
  rspec (3.5.0)
86
86
  rspec-core (~> 3.5.0)
@@ -95,8 +95,8 @@ GEM
95
95
  diff-lcs (>= 1.2.0, < 2.0)
96
96
  rspec-support (~> 3.5.0)
97
97
  rspec-support (3.5.0)
98
- rubocop (0.44.1)
99
- parser (>= 2.3.1.1, < 3.0)
98
+ rubocop (0.47.1)
99
+ parser (>= 2.3.3.1, < 3.0)
100
100
  powerpack (~> 0.1)
101
101
  rainbow (>= 1.99.1, < 3.0)
102
102
  ruby-progressbar (~> 1.7)
@@ -109,18 +109,18 @@ GEM
109
109
  activerecord (>= 4.2.7, < 5.1.0)
110
110
  railties (>= 4.2.7, < 5.1.0)
111
111
  rake (~> 10.0)
112
- thor (0.19.1)
113
- thread_safe (0.3.5)
112
+ thor (0.19.4)
113
+ thread_safe (0.3.6)
114
114
  tzinfo (1.2.2)
115
115
  thread_safe (~> 0.1)
116
- unicode-display_width (1.1.1)
117
- yard (0.9.5)
116
+ unicode-display_width (1.1.3)
117
+ yard (0.9.8)
118
118
 
119
119
  PLATFORMS
120
120
  ruby
121
121
 
122
122
  DEPENDENCIES
123
- activerecord (= 5.0.0)
123
+ activerecord (~> 5.0.0)
124
124
  appraisal
125
125
  awesome_print
126
126
  bundler (~> 1.9)
@@ -137,4 +137,4 @@ DEPENDENCIES
137
137
  standalone_migrations
138
138
 
139
139
  BUNDLED WITH
140
- 1.13.6
140
+ 1.14.6
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_dependency "activerecord", ">= 5.0.0"
23
+ spec.add_dependency "activerecord", ">= 5.0"
24
24
  spec.add_dependency "pg", ">= 0.18.1"
25
25
 
26
26
  spec.add_development_dependency "appraisal"
@@ -3,16 +3,50 @@ module JsonbAccessor
3
3
  module Macro
4
4
  module ClassMethods
5
5
  def jsonb_accessor(jsonb_attribute, field_types)
6
- field_names = field_types.keys
7
6
  names_and_store_keys = field_types.each_with_object({}) do |(name, type), mapping|
8
7
  _type, options = Array(type)
9
8
  mapping[name.to_s] = (options.try(:delete, :store_key) || name).to_s
10
9
  end
10
+
11
11
  # Defines virtual attributes for each jsonb field.
12
12
  field_types.each do |name, type|
13
13
  attribute name, *type
14
14
  end
15
15
 
16
+ store_key_mapping_method_name = "jsonb_store_key_mapping_for_#{jsonb_attribute}"
17
+ # Defines methods on the model class
18
+ class_methods = Module.new do
19
+ # Allows us to get a mapping of field names to store keys scoped to the column
20
+ define_method(store_key_mapping_method_name) do
21
+ superclass_mapping = superclass.try(store_key_mapping_method_name) || {}
22
+ superclass_mapping.merge(names_and_store_keys)
23
+ end
24
+ end
25
+ # We extend with class methods here so we can use the results of methods it defines to define more useful methods later
26
+ extend class_methods
27
+
28
+ # Get field names to default values mapping
29
+ names_and_defaults = field_types.each_with_object({}) do |(name, type), mapping|
30
+ _type, options = Array(type)
31
+ field_default = options.try(:delete, :default)
32
+ mapping[name.to_s] = field_default if field_default
33
+ end
34
+
35
+ # Get store keys to default values mapping
36
+ store_keys_and_defaults = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(names_and_defaults, public_send(store_key_mapping_method_name))
37
+
38
+ # Define jsonb_defaults_mapping_for_<jsonb_attribute>
39
+ defaults_mapping_method_name = "jsonb_defaults_mapping_for_#{jsonb_attribute}"
40
+ class_methods.instance_eval do
41
+ define_method(defaults_mapping_method_name) do
42
+ superclass_mapping = superclass.try(defaults_mapping_method_name) || {}
43
+ superclass_mapping.merge(store_keys_and_defaults)
44
+ end
45
+ end
46
+
47
+ all_defaults_mapping = public_send(defaults_mapping_method_name)
48
+ attribute jsonb_attribute, :jsonb, default: all_defaults_mapping if all_defaults_mapping.present?
49
+
16
50
  # Setters are in a module to allow users to override them and still be able to use `super`.
17
51
  setters = Module.new do
18
52
  # Overrides the setter created by `attribute` above to make sure the jsonb attribute is kept in sync.
@@ -25,16 +59,17 @@ module JsonbAccessor
25
59
  end
26
60
 
27
61
  # Overrides the jsonb attribute setter to make sure the jsonb fields are kept in sync.
28
- define_method("#{jsonb_attribute}=") do |value|
29
- indifferent_value = value.try(:with_indifferent_access) || {}
30
- value_with_store_keys = names_and_store_keys.each_with_object({}) do |(name, store_key), new_value|
31
- new_value[store_key] = indifferent_value[name]
32
- end
62
+ define_method("#{jsonb_attribute}=") do |given_value|
63
+ value = given_value || {}
64
+ names_to_store_keys = self.class.public_send(store_key_mapping_method_name)
33
65
 
34
- super(value_with_store_keys)
66
+ empty_store_key_attributes = names_to_store_keys.values.each_with_object({}) { |name, defaults| defaults[name] = nil }
67
+ empty_named_attributes = names_to_store_keys.keys.each_with_object({}) { |name, defaults| defaults[name] = nil }
35
68
 
36
- new_attributes = field_names.each_with_object({}) { |name, defaults| defaults[name] = nil }.merge(value || {})
37
- new_attributes.each { |name, new_value| write_attribute(name, new_value) }
69
+ store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(value, names_to_store_keys)
70
+ write_attribute(jsonb_attribute, empty_store_key_attributes.merge(store_key_attributes))
71
+
72
+ empty_named_attributes.merge(value).each { |name, attribute_value| write_attribute(name, attribute_value) }
38
73
  end
39
74
  end
40
75
  include setters
@@ -51,12 +86,15 @@ module JsonbAccessor
51
86
 
52
87
  # <jsonb_attribute>_where scope
53
88
  scope("#{jsonb_attribute}_where", lambda do |attributes|
54
- store_key_attributes = attributes.each_with_object({}) do |(name, value), new_attributes|
55
- store_key = names_and_store_keys[name.to_s]
56
- new_attributes[store_key] = value
57
- end
89
+ store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
58
90
  jsonb_where(jsonb_attribute, store_key_attributes)
59
91
  end)
92
+
93
+ # <jsonb_attribute>_where_not scope
94
+ scope("#{jsonb_attribute}_where_not", lambda do |attributes|
95
+ store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
96
+ jsonb_where_not(jsonb_attribute, store_key_attributes)
97
+ end)
60
98
  end
61
99
  end
62
100
  end
@@ -41,21 +41,56 @@ module JsonbAccessor
41
41
 
42
42
  module QueryBuilder
43
43
  extend ActiveSupport::Concern
44
+ InvalidColumnName = Class.new(StandardError)
45
+
46
+ def self.validate_column_name!(query, column_name)
47
+ if query.model.columns.none? { |column| column.name == column_name.to_s }
48
+ raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table"
49
+ end
50
+ end
51
+
52
+ def self.convert_keys_to_store_keys(attributes, store_key_mapping)
53
+ attributes.each_with_object({}) do |(name, value), new_attributes|
54
+ store_key = store_key_mapping[name.to_s]
55
+ new_attributes[store_key] = value
56
+ end
57
+ end
44
58
 
45
59
  included do
46
- scope(:jsonb_contains,
47
- -> (column_name, attributes) { where("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json) })
60
+ scope(:jsonb_contains, lambda do |column_name, attributes|
61
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
62
+ where("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
63
+ end)
64
+
65
+ scope(:jsonb_excludes, lambda do |column_name, attributes|
66
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
67
+ where.not("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
68
+ end)
48
69
 
49
70
  scope(:jsonb_number_where, lambda do |column_name, field_name, given_operator, value|
71
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
50
72
  operator = JsonbAccessor::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
51
73
  where("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
52
74
  end)
53
75
 
76
+ scope(:jsonb_number_where_not, lambda do |column_name, field_name, given_operator, value|
77
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
78
+ operator = JsonbAccessor::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
79
+ where.not("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
80
+ end)
81
+
54
82
  scope(:jsonb_time_where, lambda do |column_name, field_name, given_operator, value|
83
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
55
84
  operator = JsonbAccessor::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
56
85
  where("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
57
86
  end)
58
87
 
88
+ scope(:jsonb_time_where_not, lambda do |column_name, field_name, given_operator, value|
89
+ JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
90
+ operator = JsonbAccessor::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
91
+ where.not("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
92
+ end)
93
+
59
94
  scope(:jsonb_where, lambda do |column_name, attributes|
60
95
  query = all
61
96
  contains_attributes = {}
@@ -73,6 +108,24 @@ module JsonbAccessor
73
108
 
74
109
  query.jsonb_contains(column_name, contains_attributes)
75
110
  end)
111
+
112
+ scope(:jsonb_where_not, lambda do |column_name, attributes|
113
+ query = all
114
+ excludes_attributes = {}
115
+
116
+ attributes.each do |name, value|
117
+ case value
118
+ when IS_NUMBER_QUERY_ARGUMENTS
119
+ value.each { |operator, query_value| query = query.jsonb_number_where_not(column_name, name, operator, query_value) }
120
+ when IS_TIME_QUERY_ARGUMENTS
121
+ value.each { |operator, query_value| query = query.jsonb_time_where_not(column_name, name, operator, query_value) }
122
+ else
123
+ excludes_attributes[name] = value
124
+ end
125
+ end
126
+
127
+ excludes_attributes.empty? ? query : query.jsonb_excludes(column_name, excludes_attributes)
128
+ end)
76
129
  end
77
130
  end
78
131
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module JsonbAccessor
3
- VERSION = "1.0.0.beta.2"
3
+ VERSION = "1.0.0.beta.3"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonb_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta.2
4
+ version: 1.0.0.beta.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Crismali
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2016-11-10 00:00:00.000000000 Z
13
+ date: 2017-03-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 5.0.0
21
+ version: '5.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 5.0.0
28
+ version: '5.0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: pg
31
31
  requirement: !ruby/object:Gem::Requirement