jsonb_accessor 1.0.0.beta.5 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a66f5adf90e5c66c0cacb04698102c37fbd69b27
4
- data.tar.gz: dcee9f04338256069b16e0078bbd21ee34264b7a
3
+ metadata.gz: 80ed7aa0b3f529122a97b2a00b4f81011ef18014
4
+ data.tar.gz: 407d572cea056870ce66d7b92c89d1b3e15bdb2d
5
5
  SHA512:
6
- metadata.gz: eb1b146937ec6624866dc4f8594d25889eb9fd7a92de1610242048e6c5488050b0be7cbe8e9f2f887a07ed45eeb97308071c3889023eb2a3074f8e01928c91a6
7
- data.tar.gz: f8d8fad1f5adea8b6d71b8512991a838f4a8dde52c4b9ca83b03facfab2d00f946d3a2a9e402c18d0f3f44bc2de53fa624e57e2531e2fe1b095c2766561c2ed6
6
+ metadata.gz: be4ffe5fc2318edc84b98ffee5296d30d2a9d03817540c4622f04875d0a41c19022c19c0c998357f6730cad37103ce79c43b46c5aa08a46dce8078b77f03752d
7
+ data.tar.gz: c02e7189b7354d5d112aa9414e9cb4e5329d57b97b75b4d07a7e64da1abab04c63a0419509335fd557728eb48df1183d2a2d00c9c84ed7216ac4461205ec1c4d
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  gemfiles/.bundle
11
+ gemfiles/*.gemfile.lock
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ AllCops:
5
5
  - db/**/*
6
6
  - gemfiles/**/*
7
7
  - vendor/**/*
8
- Lint/SpaceBeforeFirstArg:
8
+ Style/SpaceBeforeFirstArg:
9
9
  Enabled: false
10
10
  Lint/UnusedBlockArgument:
11
11
  Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.4.1
data/.travis.yml CHANGED
@@ -1,16 +1,19 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.5
4
- - 2.3.1
3
+ - 2.3.8
4
+ - 2.4.5
5
+ - 2.5.3
6
+ - 2.6.1
5
7
  addons:
6
- postgresql: '9.4'
8
+ postgresql: "9.4"
7
9
  before_install:
8
10
  - gem update --system
9
11
  - gem --version
10
- - gem install bundler
12
+ - gem install bundler:2.1.4
11
13
  before_script:
12
14
  - bundle exec rake db:create
13
15
  - bundle exec rake db:migrate
16
+ install: bundle _2.1.4_ install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
14
17
  cache: bundler
15
18
  gemfile:
16
19
  - gemfiles/activerecord_5.0.0.gemfile
data/Appraisals CHANGED
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  appraise "activerecord-5.0.0" do
4
- gemspec
5
4
  gem "activerecord", "~> 5.0.0"
6
5
  end
7
6
 
8
7
  appraise "activerecord-5.1.0" do
9
- gemspec
10
- gem "activerecord", "~> 5.1.0"
8
+ gem "activerecord", "~> 5.1.3"
11
9
  end
data/README.md CHANGED
@@ -1,17 +1,13 @@
1
1
  # JSONb Accessor
2
2
 
3
- Created by &nbsp;&nbsp;&nbsp; [<img src="https://raw.githubusercontent.com/devmynd/jsonb_accessor/master/devmynd-logo.png" alt="DevMynd Logo" />](https://www.devmynd.com/)
3
+ Created by &nbsp;&nbsp;&nbsp; [<img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png" alt="Tandem Logo" />](https://www.madeintandem.com/)
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) &nbsp;&nbsp;&nbsp;[![Build Status](https://travis-ci.org/devmynd/jsonb_accessor.svg)](https://travis-ci.org/devmynd/jsonb_accessor) <img src="https://raw.githubusercontent.com/devmynd/jsonb_accessor/master/json-bee.png" alt="JSONb Accessor Logo" align="right" />
5
+ [![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) &nbsp;&nbsp;&nbsp;[![Build Status](https://travis-ci.org/madeintandem/jsonb_accessor.svg)](https://travis-ci.org/madeintandem/jsonb_accessor) <img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/json-bee.png" alt="JSONb Accessor Logo" align="right" />
6
6
 
7
- Adds typed `jsonb` backed fields as first class citizens to your `ActiveRecord` models. This gem is similar in spirit to [HstoreAccessor](https://github.com/devmynd/hstore_accessor), but the `jsonb` column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.
7
+ Adds typed `jsonb` backed fields as first class citizens to your `ActiveRecord` models. This gem is similar in spirit to [HstoreAccessor](https://github.com/madeintandem/hstore_accessor), but the `jsonb` column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.
8
8
 
9
9
  It also adds generic scopes for querying `jsonb` columns.
10
10
 
11
- ## 1.0 Beta
12
-
13
- This README reflects the most recent 1.0 beta. Method names and interfaces may still change.
14
-
15
11
  ## Table of Contents
16
12
 
17
13
  * [Installation](#installation)
@@ -29,7 +25,7 @@ This README reflects the most recent 1.0 beta. Method names and interfaces may s
29
25
  Add this line to your application's `Gemfile`:
30
26
 
31
27
  ```ruby
32
- gem "jsonb_accessor", "1.0.0.beta.5"
28
+ gem "jsonb_accessor", "~> 1"
33
29
  ```
34
30
 
35
31
  And then execute:
@@ -141,6 +137,14 @@ For time related fields you can query using `before` and `after`.
141
137
  Product.all.data_where(reviewed_at: { before: Time.current.beginning_of_week, after: 4.weeks.ago })
142
138
  ```
143
139
 
140
+ If you want to search for records within a certain time, date, or number range, just pass in the range (Note: this is just shorthand for the above mentioned `before`/`after`/`less_than`/`less_than_or_equal_to`/`greater_than_or_equal_to`/etc options).
141
+
142
+ ```ruby
143
+ Product.all.data_where(price: 10..20)
144
+ Product.all.data_where(price: 10...20)
145
+ Product.all.data_where(reviewed_at: Time.current..3.days.from_now)
146
+ ```
147
+
144
148
  This scope is a convenient wrapper around the `jsonb_where` `scope` that saves you from having to convert the given keys to the store keys and from specifying the column.
145
149
 
146
150
  ### `jsonb_where`
@@ -164,6 +168,27 @@ Just the opposite of `jsonb_where`. Note that this will automatically exclude al
164
168
  Product.all.jsonb_where_not(:data, reviewed_at: { before: Time.current }, p: { greater_than: 5 })
165
169
  ```
166
170
 
171
+ ### `<jsonb_attribute>_order`
172
+
173
+ Orders your query according to values in the Jsonb Accessor fields similar to ActiveRecord's `order`.
174
+
175
+ ```ruby
176
+ Product.all.data_order(:price)
177
+ Product.all.data_order(:price, :reviewed_at)
178
+ Product.all.data_order(:price, reviewed_at: :desc)
179
+ ```
180
+
181
+ It will convert your given keys into store keys if necessary.
182
+
183
+ ### `jsonb_order`
184
+
185
+ Allows you to order by a Jsonb Accessor field.
186
+
187
+ ```ruby
188
+ Product.all.jsonb_order(:data, :price, :asc)
189
+ Product.all.jsonb_order(:data, :price, :desc)
190
+ ```
191
+
167
192
  ### `jsonb_contains`
168
193
 
169
194
  Returns all records that contain the given JSON paths.
@@ -284,7 +309,7 @@ From here any attributes specific to any sub-class can be stored in the
284
309
  individual fields in an `jsonb` column.
285
310
 
286
311
  This approach was originally conceived by Joe Hirn in [this blog
287
- post](http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination).
312
+ post](https://madeintandem.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination/).
288
313
 
289
314
  ## Validations
290
315
 
@@ -309,7 +334,7 @@ Run `bin/console` for an interactive prompt that will allow you to experiment.
309
334
 
310
335
  ## Contributing
311
336
 
312
- 1. [Fork it](https://github.com/devmynd/jsonb_accessor/fork)
337
+ 1. [Fork it](https://github.com/madeintandem/jsonb_accessor/fork)
313
338
  2. Create your feature branch (`git checkout -b my-new-feature`)
314
339
  3. Add tests and changes (run the tests with `rake`)
315
340
  4. Commit your changes (`git commit -am 'Add some feature'`)
@@ -6,4 +6,3 @@ gem "pg"
6
6
  gem "activerecord", "~> 5.0.0"
7
7
 
8
8
  gemspec path: "../"
9
- gemspec path: "../"
@@ -3,7 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "pg"
6
- gem "activerecord", "~> 5.1.0"
6
+ gem "activerecord", "~> 5.1.3"
7
7
 
8
8
  gemspec path: "../"
9
- gemspec path: "../"
@@ -23,18 +23,18 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "activerecord", ">= 5.0"
26
+ spec.add_dependency "activesupport", ">= 5.0"
26
27
  spec.add_dependency "pg", ">= 0.18.1"
27
28
 
28
- spec.add_development_dependency "appraisal"
29
- spec.add_development_dependency "bundler", "~> 1.9"
30
- spec.add_development_dependency "database_cleaner", "~> 1.5.3"
29
+ spec.add_development_dependency "appraisal", "~> 2.2.0"
30
+ spec.add_development_dependency "bundler", "~> 2.1.4"
31
+ spec.add_development_dependency "database_cleaner", "~> 1.6.0"
31
32
  spec.add_development_dependency "awesome_print"
32
33
  spec.add_development_dependency "pry"
33
34
  spec.add_development_dependency "pry-doc"
34
35
  spec.add_development_dependency "pry-nav"
35
- spec.add_development_dependency "rake", "~> 10.0"
36
- spec.add_development_dependency "rspec", "~> 3.2"
36
+ spec.add_development_dependency "rake", ">= 12.3.3"
37
+ spec.add_development_dependency "rspec", "~> 3.6.0"
37
38
  spec.add_development_dependency "rubocop", "~> 0.48.1"
38
- spec.add_development_dependency "shoulda-matchers"
39
- spec.add_development_dependency "standalone_migrations"
39
+ spec.add_development_dependency "standalone_migrations", "~> 5.2.0"
40
40
  end
@@ -6,6 +6,7 @@ require "active_record/connection_adapters/postgresql_adapter"
6
6
 
7
7
  require "jsonb_accessor/version"
8
8
  require "jsonb_accessor/macro"
9
+ require "jsonb_accessor/query_helper"
9
10
  require "jsonb_accessor/query_builder"
10
11
 
11
12
  module JsonbAccessor
@@ -11,7 +11,11 @@ module JsonbAccessor
11
11
 
12
12
  # Defines virtual attributes for each jsonb field.
13
13
  field_types.each do |name, type|
14
- attribute name, *type
14
+ next attribute name, type unless type.is_a?(Array)
15
+ next attribute name, *type unless type.last.is_a?(Hash)
16
+
17
+ *args, keyword_args = type
18
+ attribute name, *args, **keyword_args
15
19
  end
16
20
 
17
21
  store_key_mapping_method_name = "jsonb_store_key_mapping_for_#{jsonb_attribute}"
@@ -34,7 +38,7 @@ module JsonbAccessor
34
38
  end
35
39
 
36
40
  # Get store keys to default values mapping
37
- store_keys_and_defaults = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(names_and_defaults, public_send(store_key_mapping_method_name))
41
+ store_keys_and_defaults = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(names_and_defaults, public_send(store_key_mapping_method_name))
38
42
 
39
43
  # Define jsonb_defaults_mapping_for_<jsonb_attribute>
40
44
  defaults_mapping_method_name = "jsonb_defaults_mapping_for_#{jsonb_attribute}"
@@ -46,7 +50,14 @@ module JsonbAccessor
46
50
  end
47
51
 
48
52
  all_defaults_mapping = public_send(defaults_mapping_method_name)
49
- attribute jsonb_attribute, :jsonb, default: all_defaults_mapping if all_defaults_mapping.present?
53
+ # Fields may have procs as default value. This means `all_defaults_mapping` may contain procs as values. To make this work
54
+ # with the attributes API, we need to wrap `all_defaults_mapping` with a proc itself, making sure it returns a plain hash
55
+ # each time it is evaluated.
56
+ all_defaults_mapping_proc =
57
+ if all_defaults_mapping.present?
58
+ -> { all_defaults_mapping.map { |key, value| [key, value.respond_to?(:call) ? value.call : value] }.to_h }
59
+ end
60
+ attribute jsonb_attribute, :jsonb, default: all_defaults_mapping_proc if all_defaults_mapping_proc.present?
50
61
 
51
62
  # Setters are in a module to allow users to override them and still be able to use `super`.
52
63
  setters = Module.new do
@@ -67,7 +78,7 @@ module JsonbAccessor
67
78
  empty_store_key_attributes = names_to_store_keys.values.each_with_object({}) { |name, defaults| defaults[name] = nil }
68
79
  empty_named_attributes = names_to_store_keys.keys.each_with_object({}) { |name, defaults| defaults[name] = nil }
69
80
 
70
- store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(value, names_to_store_keys)
81
+ store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(value, names_to_store_keys)
71
82
  write_attribute(jsonb_attribute, empty_store_key_attributes.merge(store_key_attributes))
72
83
 
73
84
  empty_named_attributes.merge(value).each { |name, attribute_value| write_attribute(name, attribute_value) }
@@ -81,28 +92,37 @@ module JsonbAccessor
81
92
  jsonb_values = public_send(jsonb_attribute) || {}
82
93
  jsonb_values.each do |store_key, value|
83
94
  name = names_and_store_keys.key(store_key)
84
- write_attribute(name, value) if name
95
+ next unless name
96
+
97
+ write_attribute(name, value)
98
+ clear_attribute_change(name) if persisted?
85
99
  end
86
- clear_changes_information if persisted?
87
100
  end
88
101
  end
89
102
 
90
103
  # <jsonb_attribute>_where scope
91
104
  scope("#{jsonb_attribute}_where", lambda do |attributes|
92
- store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
105
+ store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
93
106
  jsonb_where(jsonb_attribute, store_key_attributes)
94
107
  end)
95
108
 
96
109
  # <jsonb_attribute>_where_not scope
97
110
  scope("#{jsonb_attribute}_where_not", lambda do |attributes|
98
- store_key_attributes = ::JsonbAccessor::QueryBuilder.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
111
+ store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
99
112
  jsonb_where_not(jsonb_attribute, store_key_attributes)
100
113
  end)
101
114
 
102
115
  # <jsonb_attribute>_order scope
103
- scope("#{jsonb_attribute}_order", lambda do |attribute, direction = nil|
104
- key = all.model.public_send(store_key_mapping_method_name)[attribute.to_s]
105
- jsonb_order(jsonb_attribute, key, direction || :asc)
116
+ scope("#{jsonb_attribute}_order", lambda do |*args|
117
+ ordering_options = args.extract_options!
118
+ order_by_defaults = args.each_with_object({}) { |attribute, config| config[attribute] = :asc }
119
+ store_key_mapping = all.model.public_send(store_key_mapping_method_name)
120
+
121
+ order_by_defaults.merge(ordering_options).reduce(all) do |query, (name, direction)|
122
+ key = store_key_mapping[name.to_s]
123
+ order_query = jsonb_order(jsonb_attribute, key, direction)
124
+ query.merge(order_query)
125
+ end
106
126
  end)
107
127
  end
108
128
  end
@@ -1,112 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonbAccessor
4
- GREATER_THAN = ">"
5
- GREATER_THAN_OR_EQUAL_TO = ">="
6
- LESS_THAN = "<"
7
- LESS_THAN_OR_EQUAL_TO = "<="
8
-
9
- NUMBER_OPERATORS_MAP = {
10
- GREATER_THAN => GREATER_THAN,
11
- "greater_than" => GREATER_THAN,
12
- "gt" => GREATER_THAN,
13
- GREATER_THAN_OR_EQUAL_TO => GREATER_THAN_OR_EQUAL_TO,
14
- "greater_than_or_equal_to" => GREATER_THAN_OR_EQUAL_TO,
15
- "gte" => GREATER_THAN_OR_EQUAL_TO,
16
- LESS_THAN => LESS_THAN,
17
- "less_than" => LESS_THAN,
18
- "lt" => LESS_THAN,
19
- LESS_THAN_OR_EQUAL_TO => LESS_THAN_OR_EQUAL_TO,
20
- "less_than_or_equal_to" => LESS_THAN_OR_EQUAL_TO,
21
- "lte" => LESS_THAN_OR_EQUAL_TO
22
- }.freeze
23
-
24
- NUMBER_OPERATORS = NUMBER_OPERATORS_MAP.keys.freeze
25
-
26
- TIME_OPERATORS_MAP = {
27
- "after" => GREATER_THAN,
28
- "before" => LESS_THAN
29
- }.freeze
30
-
31
- TIME_OPERATORS = TIME_OPERATORS_MAP.keys.freeze
32
-
33
- IS_NUMBER_QUERY_ARGUMENTS = lambda do |arg|
34
- arg.is_a?(Hash) &&
35
- arg.keys.map(&:to_s).all? { |key| JsonbAccessor::NUMBER_OPERATORS.include?(key) }
36
- end
37
-
38
- IS_TIME_QUERY_ARGUMENTS = lambda do |arg|
39
- arg.is_a?(Hash) &&
40
- arg.keys.map(&:to_s).all? { |key| JsonbAccessor::TIME_OPERATORS.include?(key) }
41
- end
42
-
43
- ORDER_DIRECTIONS = [:asc, :desc, "asc", "desc"].freeze
44
-
45
4
  module QueryBuilder
46
5
  extend ActiveSupport::Concern
47
- InvalidColumnName = Class.new(StandardError)
48
- InvalidFieldName = Class.new(StandardError)
49
- InvalidDirection = Class.new(StandardError)
50
-
51
- def self.validate_column_name!(query, column_name)
52
- if query.model.columns.none? { |column| column.name == column_name.to_s }
53
- raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table"
54
- end
55
- end
56
-
57
- def self.validate_field_name!(query, column_name, field_name)
58
- store_keys = query.model.public_send("jsonb_store_key_mapping_for_#{column_name}").values
59
- if store_keys.exclude?(field_name.to_s)
60
- valid_field_names = store_keys.map { |key| "`#{key}`" }.join(", ")
61
- raise InvalidFieldName, "`#{field_name}` is not a valid field name, valid field names include: #{valid_field_names}"
62
- end
63
- end
64
-
65
- def self.validate_direction!(option)
66
- if ORDER_DIRECTIONS.exclude?(option)
67
- raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted"
68
- end
69
- end
70
-
71
- def self.convert_keys_to_store_keys(attributes, store_key_mapping)
72
- attributes.each_with_object({}) do |(name, value), new_attributes|
73
- store_key = store_key_mapping[name.to_s]
74
- new_attributes[store_key] = value
75
- end
76
- end
77
6
 
78
7
  included do
79
8
  scope(:jsonb_contains, lambda do |column_name, attributes|
80
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
9
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
81
10
  where("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
82
11
  end)
83
12
 
84
13
  scope(:jsonb_excludes, lambda do |column_name, attributes|
85
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
14
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
86
15
  where.not("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
87
16
  end)
88
17
 
89
18
  scope(:jsonb_number_where, lambda do |column_name, field_name, given_operator, value|
90
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
91
- operator = JsonbAccessor::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
19
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
20
+ operator = JsonbAccessor::QueryHelper::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
92
21
  where("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
93
22
  end)
94
23
 
95
24
  scope(:jsonb_number_where_not, lambda do |column_name, field_name, given_operator, value|
96
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
97
- operator = JsonbAccessor::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
25
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
26
+ operator = JsonbAccessor::QueryHelper::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
98
27
  where.not("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
99
28
  end)
100
29
 
101
30
  scope(:jsonb_time_where, lambda do |column_name, field_name, given_operator, value|
102
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
103
- operator = JsonbAccessor::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
31
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
32
+ operator = JsonbAccessor::QueryHelper::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
104
33
  where("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
105
34
  end)
106
35
 
107
36
  scope(:jsonb_time_where_not, lambda do |column_name, field_name, given_operator, value|
108
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
109
- operator = JsonbAccessor::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
37
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
38
+ operator = JsonbAccessor::QueryHelper::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
110
39
  where.not("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
111
40
  end)
112
41
 
@@ -114,11 +43,10 @@ module JsonbAccessor
114
43
  query = all
115
44
  contains_attributes = {}
116
45
 
117
- attributes.each do |name, value|
118
- case value
119
- when IS_NUMBER_QUERY_ARGUMENTS
46
+ JsonbAccessor::QueryHelper.convert_ranges(attributes).each do |name, value|
47
+ if JsonbAccessor::QueryHelper.number_query_arguments?(value)
120
48
  value.each { |operator, query_value| query = query.jsonb_number_where(column_name, name, operator, query_value) }
121
- when IS_TIME_QUERY_ARGUMENTS
49
+ elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
122
50
  value.each { |operator, query_value| query = query.jsonb_time_where(column_name, name, operator, query_value) }
123
51
  else
124
52
  contains_attributes[name] = value
@@ -133,10 +61,13 @@ module JsonbAccessor
133
61
  excludes_attributes = {}
134
62
 
135
63
  attributes.each do |name, value|
136
- case value
137
- when IS_NUMBER_QUERY_ARGUMENTS
64
+ if value.is_a?(Range)
65
+ raise JsonbAccessor::QueryHelper::NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field"
66
+ end
67
+
68
+ if JsonbAccessor::QueryHelper.number_query_arguments?(value)
138
69
  value.each { |operator, query_value| query = query.jsonb_number_where_not(column_name, name, operator, query_value) }
139
- when IS_TIME_QUERY_ARGUMENTS
70
+ elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
140
71
  value.each { |operator, query_value| query = query.jsonb_time_where_not(column_name, name, operator, query_value) }
141
72
  else
142
73
  excludes_attributes[name] = value
@@ -147,10 +78,10 @@ module JsonbAccessor
147
78
  end)
148
79
 
149
80
  scope(:jsonb_order, lambda do |column_name, field_name, direction|
150
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
151
- JsonbAccessor::QueryBuilder.validate_field_name!(all, column_name, field_name)
152
- JsonbAccessor::QueryBuilder.validate_direction!(direction)
153
- order("(#{table_name}.#{column_name} -> '#{field_name}') #{direction}")
81
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
82
+ JsonbAccessor::QueryHelper.validate_field_name!(all, column_name, field_name)
83
+ JsonbAccessor::QueryHelper.validate_direction!(direction)
84
+ order(Arel.sql("(#{table_name}.#{column_name} -> '#{field_name}') #{direction}"))
154
85
  end)
155
86
  end
156
87
  end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonbAccessor
4
+ module QueryHelper
5
+ # Errors
6
+ InvalidColumnName = Class.new(StandardError)
7
+ InvalidFieldName = Class.new(StandardError)
8
+ InvalidDirection = Class.new(StandardError)
9
+ NotSupported = Class.new(StandardError)
10
+
11
+ # Constants
12
+ GREATER_THAN = ">"
13
+ GREATER_THAN_OR_EQUAL_TO = ">="
14
+ LESS_THAN = "<"
15
+ LESS_THAN_OR_EQUAL_TO = "<="
16
+
17
+ NUMBER_OPERATORS_MAP = {
18
+ GREATER_THAN => GREATER_THAN,
19
+ "greater_than" => GREATER_THAN,
20
+ "gt" => GREATER_THAN,
21
+ GREATER_THAN_OR_EQUAL_TO => GREATER_THAN_OR_EQUAL_TO,
22
+ "greater_than_or_equal_to" => GREATER_THAN_OR_EQUAL_TO,
23
+ "gte" => GREATER_THAN_OR_EQUAL_TO,
24
+ LESS_THAN => LESS_THAN,
25
+ "less_than" => LESS_THAN,
26
+ "lt" => LESS_THAN,
27
+ LESS_THAN_OR_EQUAL_TO => LESS_THAN_OR_EQUAL_TO,
28
+ "less_than_or_equal_to" => LESS_THAN_OR_EQUAL_TO,
29
+ "lte" => LESS_THAN_OR_EQUAL_TO
30
+ }.freeze
31
+
32
+ NUMBER_OPERATORS = NUMBER_OPERATORS_MAP.keys.freeze
33
+
34
+ TIME_OPERATORS_MAP = {
35
+ "after" => GREATER_THAN,
36
+ "before" => LESS_THAN
37
+ }.freeze
38
+
39
+ TIME_OPERATORS = TIME_OPERATORS_MAP.keys.freeze
40
+
41
+ ORDER_DIRECTIONS = [:asc, :desc, "asc", "desc"].freeze
42
+
43
+ class << self
44
+ def validate_column_name!(query, column_name)
45
+ if query.model.columns.none? { |column| column.name == column_name.to_s }
46
+ raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table"
47
+ end
48
+ end
49
+
50
+ def validate_field_name!(query, column_name, field_name)
51
+ store_keys = query.model.public_send("jsonb_store_key_mapping_for_#{column_name}").values
52
+ if store_keys.exclude?(field_name.to_s)
53
+ valid_field_names = store_keys.map { |key| "`#{key}`" }.join(", ")
54
+ raise InvalidFieldName, "`#{field_name}` is not a valid field name, valid field names include: #{valid_field_names}"
55
+ end
56
+ end
57
+
58
+ def validate_direction!(option)
59
+ if ORDER_DIRECTIONS.exclude?(option)
60
+ raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted"
61
+ end
62
+ end
63
+
64
+ def convert_keys_to_store_keys(attributes, store_key_mapping)
65
+ attributes.each_with_object({}) do |(name, value), new_attributes|
66
+ store_key = store_key_mapping[name.to_s]
67
+ new_attributes[store_key] = value
68
+ end
69
+ end
70
+
71
+ def number_query_arguments?(arg)
72
+ arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| NUMBER_OPERATORS.include?(key) }
73
+ end
74
+
75
+ def time_query_arguments?(arg)
76
+ arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| TIME_OPERATORS.include?(key) }
77
+ end
78
+
79
+ def convert_number_ranges(attributes)
80
+ attributes.each_with_object({}) do |(name, value), new_attributes|
81
+ is_range = value.is_a?(Range)
82
+
83
+ new_attributes[name] = if is_range && value.first.is_a?(Numeric) && value.exclude_end?
84
+ { greater_than_or_equal_to: value.first, less_than: value.end }
85
+ elsif is_range && value.first.is_a?(Numeric)
86
+ { greater_than_or_equal_to: value.first, less_than_or_equal_to: value.end }
87
+ else
88
+ value
89
+ end
90
+ end
91
+ end
92
+
93
+ def convert_time_ranges(attributes)
94
+ attributes.each_with_object({}) do |(name, value), new_attributes|
95
+ is_range = value.is_a?(Range)
96
+
97
+ if is_range && (value.first.is_a?(Time) || value.first.is_a?(Date))
98
+ start_time = value.first
99
+ end_time = value.end
100
+ new_attributes[name] = { before: end_time, after: start_time }
101
+ else
102
+ new_attributes[name] = value
103
+ end
104
+ end
105
+ end
106
+
107
+ def convert_ranges(attributes)
108
+ %i[convert_number_ranges convert_time_ranges].reduce(attributes) do |new_attributes, converter_method|
109
+ public_send(converter_method, new_attributes)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonbAccessor
4
- VERSION = "1.0.0.beta.5"
4
+ VERSION = "1.2.0"
5
5
  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.5
4
+ version: 1.2.0
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: 2017-05-03 00:00:00.000000000 Z
13
+ date: 2021-05-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -26,6 +26,20 @@ dependencies:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: '5.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: activesupport
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '5.0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '5.0'
29
43
  - !ruby/object:Gem::Dependency
30
44
  name: pg
31
45
  requirement: !ruby/object:Gem::Requirement
@@ -44,44 +58,44 @@ dependencies:
44
58
  name: appraisal
45
59
  requirement: !ruby/object:Gem::Requirement
46
60
  requirements:
47
- - - ">="
61
+ - - "~>"
48
62
  - !ruby/object:Gem::Version
49
- version: '0'
63
+ version: 2.2.0
50
64
  type: :development
51
65
  prerelease: false
52
66
  version_requirements: !ruby/object:Gem::Requirement
53
67
  requirements:
54
- - - ">="
68
+ - - "~>"
55
69
  - !ruby/object:Gem::Version
56
- version: '0'
70
+ version: 2.2.0
57
71
  - !ruby/object:Gem::Dependency
58
72
  name: bundler
59
73
  requirement: !ruby/object:Gem::Requirement
60
74
  requirements:
61
75
  - - "~>"
62
76
  - !ruby/object:Gem::Version
63
- version: '1.9'
77
+ version: 2.1.4
64
78
  type: :development
65
79
  prerelease: false
66
80
  version_requirements: !ruby/object:Gem::Requirement
67
81
  requirements:
68
82
  - - "~>"
69
83
  - !ruby/object:Gem::Version
70
- version: '1.9'
84
+ version: 2.1.4
71
85
  - !ruby/object:Gem::Dependency
72
86
  name: database_cleaner
73
87
  requirement: !ruby/object:Gem::Requirement
74
88
  requirements:
75
89
  - - "~>"
76
90
  - !ruby/object:Gem::Version
77
- version: 1.5.3
91
+ version: 1.6.0
78
92
  type: :development
79
93
  prerelease: false
80
94
  version_requirements: !ruby/object:Gem::Requirement
81
95
  requirements:
82
96
  - - "~>"
83
97
  - !ruby/object:Gem::Version
84
- version: 1.5.3
98
+ version: 1.6.0
85
99
  - !ruby/object:Gem::Dependency
86
100
  name: awesome_print
87
101
  requirement: !ruby/object:Gem::Requirement
@@ -142,30 +156,30 @@ dependencies:
142
156
  name: rake
143
157
  requirement: !ruby/object:Gem::Requirement
144
158
  requirements:
145
- - - "~>"
159
+ - - ">="
146
160
  - !ruby/object:Gem::Version
147
- version: '10.0'
161
+ version: 12.3.3
148
162
  type: :development
149
163
  prerelease: false
150
164
  version_requirements: !ruby/object:Gem::Requirement
151
165
  requirements:
152
- - - "~>"
166
+ - - ">="
153
167
  - !ruby/object:Gem::Version
154
- version: '10.0'
168
+ version: 12.3.3
155
169
  - !ruby/object:Gem::Dependency
156
170
  name: rspec
157
171
  requirement: !ruby/object:Gem::Requirement
158
172
  requirements:
159
173
  - - "~>"
160
174
  - !ruby/object:Gem::Version
161
- version: '3.2'
175
+ version: 3.6.0
162
176
  type: :development
163
177
  prerelease: false
164
178
  version_requirements: !ruby/object:Gem::Requirement
165
179
  requirements:
166
180
  - - "~>"
167
181
  - !ruby/object:Gem::Version
168
- version: '3.2'
182
+ version: 3.6.0
169
183
  - !ruby/object:Gem::Dependency
170
184
  name: rubocop
171
185
  requirement: !ruby/object:Gem::Requirement
@@ -180,34 +194,20 @@ dependencies:
180
194
  - - "~>"
181
195
  - !ruby/object:Gem::Version
182
196
  version: 0.48.1
183
- - !ruby/object:Gem::Dependency
184
- name: shoulda-matchers
185
- requirement: !ruby/object:Gem::Requirement
186
- requirements:
187
- - - ">="
188
- - !ruby/object:Gem::Version
189
- version: '0'
190
- type: :development
191
- prerelease: false
192
- version_requirements: !ruby/object:Gem::Requirement
193
- requirements:
194
- - - ">="
195
- - !ruby/object:Gem::Version
196
- version: '0'
197
197
  - !ruby/object:Gem::Dependency
198
198
  name: standalone_migrations
199
199
  requirement: !ruby/object:Gem::Requirement
200
200
  requirements:
201
- - - ">="
201
+ - - "~>"
202
202
  - !ruby/object:Gem::Version
203
- version: '0'
203
+ version: 5.2.0
204
204
  type: :development
205
205
  prerelease: false
206
206
  version_requirements: !ruby/object:Gem::Requirement
207
207
  requirements:
208
- - - ">="
208
+ - - "~>"
209
209
  - !ruby/object:Gem::Version
210
- version: '0'
210
+ version: 5.2.0
211
211
  description: Adds typed jsonb backed fields to your ActiveRecord models.
212
212
  email:
213
213
  - michael@crismali.com
@@ -235,13 +235,12 @@ files:
235
235
  - db/migrate/20150407031737_set_up_testing_db.rb
236
236
  - db/schema.rb
237
237
  - gemfiles/activerecord_5.0.0.gemfile
238
- - gemfiles/activerecord_5.0.0.gemfile.lock
239
238
  - gemfiles/activerecord_5.1.0.gemfile
240
- - gemfiles/activerecord_5.1.0.gemfile.lock
241
239
  - jsonb_accessor.gemspec
242
240
  - lib/jsonb_accessor.rb
243
241
  - lib/jsonb_accessor/macro.rb
244
242
  - lib/jsonb_accessor/query_builder.rb
243
+ - lib/jsonb_accessor/query_helper.rb
245
244
  - lib/jsonb_accessor/version.rb
246
245
  homepage: https://github.com/devmynd/jsonb_accessor
247
246
  licenses:
@@ -258,12 +257,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
258
257
  version: '2.0'
259
258
  required_rubygems_version: !ruby/object:Gem::Requirement
260
259
  requirements:
261
- - - ">"
260
+ - - ">="
262
261
  - !ruby/object:Gem::Version
263
- version: 1.3.1
262
+ version: '0'
264
263
  requirements: []
265
264
  rubyforge_project:
266
- rubygems_version: 2.5.1
265
+ rubygems_version: 2.6.11
267
266
  signing_key:
268
267
  specification_version: 4
269
268
  summary: Adds typed jsonb backed fields to your ActiveRecord models.
@@ -1,141 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- jsonb_accessor (1.0.0.beta.5)
5
- activerecord (>= 5.0)
6
- pg (>= 0.18.1)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- actionpack (5.0.2)
12
- actionview (= 5.0.2)
13
- activesupport (= 5.0.2)
14
- rack (~> 2.0)
15
- rack-test (~> 0.6.3)
16
- rails-dom-testing (~> 2.0)
17
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
18
- actionview (5.0.2)
19
- activesupport (= 5.0.2)
20
- builder (~> 3.1)
21
- erubis (~> 2.7.0)
22
- rails-dom-testing (~> 2.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
- arel (~> 7.0)
30
- activesupport (5.0.2)
31
- concurrent-ruby (~> 1.0, >= 1.0.2)
32
- i18n (~> 0.7)
33
- minitest (~> 5.1)
34
- tzinfo (~> 1.1)
35
- appraisal (2.1.0)
36
- bundler
37
- rake
38
- thor (>= 0.14.0)
39
- arel (7.1.4)
40
- ast (2.3.0)
41
- awesome_print (1.7.0)
42
- builder (3.2.3)
43
- coderay (1.1.1)
44
- concurrent-ruby (1.0.5)
45
- database_cleaner (1.5.3)
46
- diff-lcs (1.3)
47
- erubis (2.7.0)
48
- i18n (0.8.1)
49
- loofah (2.0.3)
50
- nokogiri (>= 1.5.9)
51
- method_source (0.8.2)
52
- mini_portile2 (2.1.0)
53
- minitest (5.10.1)
54
- nokogiri (1.7.0.1)
55
- mini_portile2 (~> 2.1.0)
56
- parser (2.4.0.0)
57
- ast (~> 2.2)
58
- pg (0.20.0)
59
- powerpack (0.1.1)
60
- pry (0.10.4)
61
- coderay (~> 1.1.0)
62
- method_source (~> 0.8.1)
63
- slop (~> 3.4)
64
- pry-doc (0.10.0)
65
- pry (~> 0.9)
66
- yard (~> 0.9)
67
- pry-nav (0.2.4)
68
- pry (>= 0.9.10, < 0.11.0)
69
- rack (2.0.1)
70
- rack-test (0.6.3)
71
- rack (>= 1.0)
72
- rails-dom-testing (2.0.2)
73
- activesupport (>= 4.2.0, < 6.0)
74
- nokogiri (~> 1.6)
75
- rails-html-sanitizer (1.0.3)
76
- loofah (~> 2.0)
77
- railties (5.0.2)
78
- actionpack (= 5.0.2)
79
- activesupport (= 5.0.2)
80
- method_source
81
- rake (>= 0.8.7)
82
- thor (>= 0.18.1, < 2.0)
83
- rainbow (2.2.2)
84
- rake
85
- rake (10.5.0)
86
- rspec (3.5.0)
87
- rspec-core (~> 3.5.0)
88
- rspec-expectations (~> 3.5.0)
89
- rspec-mocks (~> 3.5.0)
90
- rspec-core (3.5.4)
91
- rspec-support (~> 3.5.0)
92
- rspec-expectations (3.5.0)
93
- diff-lcs (>= 1.2.0, < 2.0)
94
- rspec-support (~> 3.5.0)
95
- rspec-mocks (3.5.0)
96
- diff-lcs (>= 1.2.0, < 2.0)
97
- rspec-support (~> 3.5.0)
98
- rspec-support (3.5.0)
99
- rubocop (0.48.1)
100
- parser (>= 2.3.3.1, < 3.0)
101
- powerpack (~> 0.1)
102
- rainbow (>= 1.99.1, < 3.0)
103
- ruby-progressbar (~> 1.7)
104
- unicode-display_width (~> 1.0, >= 1.0.1)
105
- ruby-progressbar (1.8.1)
106
- shoulda-matchers (3.1.1)
107
- activesupport (>= 4.0.0)
108
- slop (3.6.0)
109
- standalone_migrations (5.0.0)
110
- activerecord (>= 4.2.7, < 5.1.0)
111
- railties (>= 4.2.7, < 5.1.0)
112
- rake (~> 10.0)
113
- thor (0.19.4)
114
- thread_safe (0.3.6)
115
- tzinfo (1.2.2)
116
- thread_safe (~> 0.1)
117
- unicode-display_width (1.2.1)
118
- yard (0.9.8)
119
-
120
- PLATFORMS
121
- ruby
122
-
123
- DEPENDENCIES
124
- activerecord (~> 5.0.0)
125
- appraisal
126
- awesome_print
127
- bundler (~> 1.9)
128
- database_cleaner (~> 1.5.3)
129
- jsonb_accessor!
130
- pg
131
- pry
132
- pry-doc
133
- pry-nav
134
- rake (~> 10.0)
135
- rspec (~> 3.2)
136
- rubocop (~> 0.48.1)
137
- shoulda-matchers
138
- standalone_migrations
139
-
140
- BUNDLED WITH
141
- 1.14.6
@@ -1,141 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- jsonb_accessor (1.0.0.beta.5)
5
- activerecord (>= 5.0)
6
- pg (>= 0.18.1)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- actionpack (5.1.0)
12
- actionview (= 5.1.0)
13
- activesupport (= 5.1.0)
14
- rack (~> 2.0)
15
- rack-test (~> 0.6.3)
16
- rails-dom-testing (~> 2.0)
17
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
18
- actionview (5.1.0)
19
- activesupport (= 5.1.0)
20
- builder (~> 3.1)
21
- erubi (~> 1.4)
22
- rails-dom-testing (~> 2.0)
23
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
24
- activemodel (5.1.0)
25
- activesupport (= 5.1.0)
26
- activerecord (5.1.0)
27
- activemodel (= 5.1.0)
28
- activesupport (= 5.1.0)
29
- arel (~> 8.0)
30
- activesupport (5.1.0)
31
- concurrent-ruby (~> 1.0, >= 1.0.2)
32
- i18n (~> 0.7)
33
- minitest (~> 5.1)
34
- tzinfo (~> 1.1)
35
- appraisal (2.2.0)
36
- bundler
37
- rake
38
- thor (>= 0.14.0)
39
- arel (8.0.0)
40
- ast (2.3.0)
41
- awesome_print (1.7.0)
42
- builder (3.2.3)
43
- coderay (1.1.1)
44
- concurrent-ruby (1.0.5)
45
- database_cleaner (1.5.3)
46
- diff-lcs (1.3)
47
- erubi (1.6.0)
48
- i18n (0.8.1)
49
- loofah (2.0.3)
50
- nokogiri (>= 1.5.9)
51
- method_source (0.8.2)
52
- mini_portile2 (2.1.0)
53
- minitest (5.10.1)
54
- nokogiri (1.7.1)
55
- mini_portile2 (~> 2.1.0)
56
- parser (2.4.0.0)
57
- ast (~> 2.2)
58
- pg (0.20.0)
59
- powerpack (0.1.1)
60
- pry (0.10.4)
61
- coderay (~> 1.1.0)
62
- method_source (~> 0.8.1)
63
- slop (~> 3.4)
64
- pry-doc (0.10.0)
65
- pry (~> 0.9)
66
- yard (~> 0.9)
67
- pry-nav (0.2.4)
68
- pry (>= 0.9.10, < 0.11.0)
69
- rack (2.0.1)
70
- rack-test (0.6.3)
71
- rack (>= 1.0)
72
- rails-dom-testing (2.0.2)
73
- activesupport (>= 4.2.0, < 6.0)
74
- nokogiri (~> 1.6)
75
- rails-html-sanitizer (1.0.3)
76
- loofah (~> 2.0)
77
- railties (5.1.0)
78
- actionpack (= 5.1.0)
79
- activesupport (= 5.1.0)
80
- method_source
81
- rake (>= 0.8.7)
82
- thor (>= 0.18.1, < 2.0)
83
- rainbow (2.2.2)
84
- rake
85
- rake (10.5.0)
86
- rspec (3.5.0)
87
- rspec-core (~> 3.5.0)
88
- rspec-expectations (~> 3.5.0)
89
- rspec-mocks (~> 3.5.0)
90
- rspec-core (3.5.4)
91
- rspec-support (~> 3.5.0)
92
- rspec-expectations (3.5.0)
93
- diff-lcs (>= 1.2.0, < 2.0)
94
- rspec-support (~> 3.5.0)
95
- rspec-mocks (3.5.0)
96
- diff-lcs (>= 1.2.0, < 2.0)
97
- rspec-support (~> 3.5.0)
98
- rspec-support (3.5.0)
99
- rubocop (0.48.1)
100
- parser (>= 2.3.3.1, < 3.0)
101
- powerpack (~> 0.1)
102
- rainbow (>= 1.99.1, < 3.0)
103
- ruby-progressbar (~> 1.7)
104
- unicode-display_width (~> 1.0, >= 1.0.1)
105
- ruby-progressbar (1.8.1)
106
- shoulda-matchers (3.1.1)
107
- activesupport (>= 4.0.0)
108
- slop (3.6.0)
109
- standalone_migrations (5.2.1)
110
- activerecord (>= 4.2.7, < 5.2.0)
111
- railties (>= 4.2.7, < 5.2.0)
112
- rake (~> 10.0)
113
- thor (0.19.4)
114
- thread_safe (0.3.6)
115
- tzinfo (1.2.3)
116
- thread_safe (~> 0.1)
117
- unicode-display_width (1.2.1)
118
- yard (0.9.9)
119
-
120
- PLATFORMS
121
- ruby
122
-
123
- DEPENDENCIES
124
- activerecord (~> 5.1.0)
125
- appraisal
126
- awesome_print
127
- bundler (~> 1.9)
128
- database_cleaner (~> 1.5.3)
129
- jsonb_accessor!
130
- pg
131
- pry
132
- pry-doc
133
- pry-nav
134
- rake (~> 10.0)
135
- rspec (~> 3.2)
136
- rubocop (~> 0.48.1)
137
- shoulda-matchers
138
- standalone_migrations
139
-
140
- BUNDLED WITH
141
- 1.14.6