jsonb_accessor 1.0.0.beta.6 → 1.3.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: bd5842d35872b7e0a4aae6cf87b7a58b32dc7c23
4
- data.tar.gz: 74587e5629b53a1e34416e966527a59087a522d7
3
+ metadata.gz: 12a9ef2a6ecf012dd86338b0962ea0338ac8950f
4
+ data.tar.gz: ffb75c6ce59fa8eeb1a6917c822853f0aa63cead
5
5
  SHA512:
6
- metadata.gz: 9fdafe03f73b4e9b002f592b2eccac07dee6db7e236285cbc4a7ddb7394f96a74e441d25f32397e1fe210631444d06fcdea25b416cd2849623a6db1ad8974787
7
- data.tar.gz: 311f65d600e4e52ed56f1eb8412628821ff453266beebeb4045c665209c437690000beaa69d30f32c9439566f99df79e2d91b86eeae045099f365df653e8fb70
6
+ metadata.gz: ddb76f1639699f471680602e9d3f7601eca9666e7c3c03d2f3dce80d8e810a22940712668e0190f2469bccb54f9ae10a7f0b2fb7e763ea8818da32c34893ea91
7
+ data.tar.gz: 11e77edee1f60874eb313da3301483beb5cc4a962ad14b8f202e923511a1378a10b664fcb00fb4eae161e06f73b4f3c20878871753a693cc5fd733665a0dd2c4
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/.travis.yml CHANGED
@@ -1,18 +1,33 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.5
4
- - 2.3.3
5
- - 2.4.1
3
+ - 2.3.8
4
+ - 2.4.5
5
+ - 2.5.3
6
+ - 2.6.1
7
+ - 2.7.2
8
+ - 3.0.0
6
9
  addons:
7
- postgresql: '9.4'
10
+ postgresql: "9.4"
8
11
  before_install:
9
12
  - gem update --system
10
13
  - gem --version
11
- - gem install bundler
14
+ - gem install bundler:2.1.4
12
15
  before_script:
13
16
  - bundle exec rake db:create
14
17
  - bundle exec rake db:migrate
18
+ install: bundle _2.1.4_ install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
15
19
  cache: bundler
16
20
  gemfile:
17
21
  - gemfiles/activerecord_5.0.0.gemfile
18
22
  - gemfiles/activerecord_5.1.0.gemfile
23
+ - gemfiles/activerecord_6.1.0.gemfile
24
+ jobs:
25
+ exclude:
26
+ - rvm: 2.3.8
27
+ gemfile: gemfiles/activerecord_6.1.0.gemfile
28
+ - rvm: 2.4.5
29
+ gemfile: gemfiles/activerecord_6.1.0.gemfile
30
+ - rvm: 3.0.0
31
+ gemfile: gemfiles/activerecord_5.0.0.gemfile
32
+ - rvm: 3.0.0
33
+ gemfile: gemfiles/activerecord_5.1.0.gemfile
data/Appraisals CHANGED
@@ -5,5 +5,9 @@ appraise "activerecord-5.0.0" do
5
5
  end
6
6
 
7
7
  appraise "activerecord-5.1.0" do
8
- gem "activerecord", "~> 5.1.0"
8
+ gem "activerecord", "~> 5.1.3"
9
+ end
10
+
11
+ appraise "activerecord-6.1.0" do
12
+ gem "activerecord", "~> 6.1"
9
13
  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.6"
28
+ gem "jsonb_accessor", "~> 1"
33
29
  ```
34
30
 
35
31
  And then execute:
@@ -313,7 +309,7 @@ From here any attributes specific to any sub-class can be stored in the
313
309
  individual fields in an `jsonb` column.
314
310
 
315
311
  This approach was originally conceived by Joe Hirn in [this blog
316
- 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/).
317
313
 
318
314
  ## Validations
319
315
 
@@ -338,7 +334,7 @@ Run `bin/console` for an interactive prompt that will allow you to experiment.
338
334
 
339
335
  ## Contributing
340
336
 
341
- 1. [Fork it](https://github.com/devmynd/jsonb_accessor/fork)
337
+ 1. [Fork it](https://github.com/madeintandem/jsonb_accessor/fork)
342
338
  2. Create your feature branch (`git checkout -b my-new-feature`)
343
339
  3. Add tests and changes (run the tests with `rake`)
344
340
  4. Commit your changes (`git commit -am 'Add some feature'`)
data/Rakefile CHANGED
@@ -5,10 +5,26 @@ require "bundler/setup"
5
5
  require "bundler/gem_tasks"
6
6
  require "rspec/core/rake_task"
7
7
  require "rubocop/rake_task"
8
- require "standalone_migrations"
9
- StandaloneMigrations::Tasks.load_tasks
10
8
 
11
9
  RSpec::Core::RakeTask.new
12
10
  RuboCop::RakeTask.new
13
11
 
12
+ require "active_record"
13
+ include ActiveRecord::Tasks
14
+
15
+ root = File.expand_path "..", __FILE__
16
+ db_dir = File.join(root, "db")
17
+ DatabaseTasks.root = root
18
+ DatabaseTasks.db_dir = db_dir
19
+ DatabaseTasks.database_configuration = YAML.load(File.read(File.join(db_dir, "config.yml")))
20
+ DatabaseTasks.migrations_paths = [File.join(db_dir, "migrate")]
21
+ DatabaseTasks.env = "test"
22
+
23
+ task :environment do
24
+ ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
25
+ ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
26
+ end
27
+
28
+ load "active_record/railties/databases.rake"
29
+
14
30
  task(default: %i[rubocop spec])
data/db/config.yml CHANGED
@@ -1,9 +1,8 @@
1
1
  default: &default
2
2
  adapter: postgresql
3
3
  database: jsonb_accessor
4
-
5
- development:
6
- <<: *default
4
+ host: 127.0.0.1
5
+ user: postgres
7
6
 
8
7
  test:
9
8
  <<: *default
data/db/schema.rb CHANGED
@@ -2,15 +2,15 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # Note that this schema.rb definition is the authoritative source for your
6
- # database schema. If you need to create the application database on another
7
- # system, you should be using db:schema:load, not running all the migrations
8
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
- # you'll amass, the slower it'll run and the greater likelihood for issues).
5
+ # This file is the source Rails uses to define your schema when running `rails
6
+ # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20150407031737) do
13
+ ActiveRecord::Schema.define(version: 2015_04_07_031737) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -3,6 +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: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "pg"
6
+ gem "activerecord", "~> 6.1"
7
+
8
+ gemspec path: "../"
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.description = "Adds typed jsonb backed fields to your ActiveRecord models."
16
16
  spec.homepage = "https://github.com/devmynd/jsonb_accessor"
17
17
  spec.license = "MIT"
18
- spec.required_ruby_version = "~> 2.0"
18
+ spec.required_ruby_version = ">= 2"
19
19
 
20
20
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.match(/png\z/) }
21
21
  spec.bindir = "exe"
@@ -27,14 +27,12 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "pg", ">= 0.18.1"
28
28
 
29
29
  spec.add_development_dependency "appraisal", "~> 2.2.0"
30
- spec.add_development_dependency "bundler", "~> 1.9"
31
30
  spec.add_development_dependency "database_cleaner", "~> 1.6.0"
32
31
  spec.add_development_dependency "awesome_print"
33
32
  spec.add_development_dependency "pry"
34
33
  spec.add_development_dependency "pry-doc"
35
34
  spec.add_development_dependency "pry-nav"
36
- spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "rake", ">= 12.3.3"
37
36
  spec.add_development_dependency "rspec", "~> 3.6.0"
38
37
  spec.add_development_dependency "rubocop", "~> 0.48.1"
39
- spec.add_development_dependency "standalone_migrations", "~> 5.2.0"
40
38
  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,21 +92,23 @@ 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
 
@@ -1,147 +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
- CONVERT_NUMBER_RANGES = lambda do |attributes|
44
- attributes.each_with_object({}) do |(name, value), new_attributes|
45
- is_range = value.is_a?(Range)
46
-
47
- new_attributes[name] = if is_range && value.first.is_a?(Numeric) && value.exclude_end?
48
- { greater_than_or_equal_to: value.first, less_than: value.end }
49
- elsif is_range && value.first.is_a?(Numeric)
50
- { greater_than_or_equal_to: value.first, less_than_or_equal_to: value.end }
51
- else
52
- value
53
- end
54
- end
55
- end
56
-
57
- CONVERT_TIME_RANGES = lambda do |attributes|
58
- attributes.each_with_object({}) do |(name, value), new_attributes|
59
- is_range = value.is_a?(Range)
60
-
61
- if is_range && (value.first.is_a?(Time) || value.first.is_a?(Date))
62
- start_time = value.first
63
- end_time = value.end
64
- new_attributes[name] = { before: end_time, after: start_time }
65
- else
66
- new_attributes[name] = value
67
- end
68
- end
69
- end
70
-
71
- CONVERT_RANGES = lambda do |attributes|
72
- [CONVERT_NUMBER_RANGES, CONVERT_TIME_RANGES].reduce(attributes) do |new_attributes, converter|
73
- converter.call(new_attributes)
74
- end
75
- end
76
-
77
- ORDER_DIRECTIONS = [:asc, :desc, "asc", "desc"].freeze
78
-
79
4
  module QueryBuilder
80
5
  extend ActiveSupport::Concern
81
- InvalidColumnName = Class.new(StandardError)
82
- InvalidFieldName = Class.new(StandardError)
83
- InvalidDirection = Class.new(StandardError)
84
- NotSupported = Class.new(StandardError)
85
-
86
- def self.validate_column_name!(query, column_name)
87
- if query.model.columns.none? { |column| column.name == column_name.to_s }
88
- raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table"
89
- end
90
- end
91
-
92
- def self.validate_field_name!(query, column_name, field_name)
93
- store_keys = query.model.public_send("jsonb_store_key_mapping_for_#{column_name}").values
94
- if store_keys.exclude?(field_name.to_s)
95
- valid_field_names = store_keys.map { |key| "`#{key}`" }.join(", ")
96
- raise InvalidFieldName, "`#{field_name}` is not a valid field name, valid field names include: #{valid_field_names}"
97
- end
98
- end
99
-
100
- def self.validate_direction!(option)
101
- if ORDER_DIRECTIONS.exclude?(option)
102
- raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted"
103
- end
104
- end
105
-
106
- def self.convert_keys_to_store_keys(attributes, store_key_mapping)
107
- attributes.each_with_object({}) do |(name, value), new_attributes|
108
- store_key = store_key_mapping[name.to_s]
109
- new_attributes[store_key] = value
110
- end
111
- end
112
6
 
113
7
  included do
114
8
  scope(:jsonb_contains, lambda do |column_name, attributes|
115
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
9
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
116
10
  where("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
117
11
  end)
118
12
 
119
13
  scope(:jsonb_excludes, lambda do |column_name, attributes|
120
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
14
+ JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
121
15
  where.not("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
122
16
  end)
123
17
 
124
18
  scope(:jsonb_number_where, lambda do |column_name, field_name, given_operator, value|
125
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
126
- 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)
127
21
  where("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
128
22
  end)
129
23
 
130
24
  scope(:jsonb_number_where_not, lambda do |column_name, field_name, given_operator, value|
131
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
132
- 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)
133
27
  where.not("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
134
28
  end)
135
29
 
136
30
  scope(:jsonb_time_where, lambda do |column_name, field_name, given_operator, value|
137
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
138
- 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)
139
33
  where("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
140
34
  end)
141
35
 
142
36
  scope(:jsonb_time_where_not, lambda do |column_name, field_name, given_operator, value|
143
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
144
- 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)
145
39
  where.not("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
146
40
  end)
147
41
 
@@ -149,11 +43,10 @@ module JsonbAccessor
149
43
  query = all
150
44
  contains_attributes = {}
151
45
 
152
- JsonbAccessor::CONVERT_RANGES.call(attributes).each do |name, value|
153
- case value
154
- when IS_NUMBER_QUERY_ARGUMENTS
46
+ JsonbAccessor::QueryHelper.convert_ranges(attributes).each do |name, value|
47
+ if JsonbAccessor::QueryHelper.number_query_arguments?(value)
155
48
  value.each { |operator, query_value| query = query.jsonb_number_where(column_name, name, operator, query_value) }
156
- when IS_TIME_QUERY_ARGUMENTS
49
+ elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
157
50
  value.each { |operator, query_value| query = query.jsonb_time_where(column_name, name, operator, query_value) }
158
51
  else
159
52
  contains_attributes[name] = value
@@ -169,13 +62,12 @@ module JsonbAccessor
169
62
 
170
63
  attributes.each do |name, value|
171
64
  if value.is_a?(Range)
172
- raise NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field"
65
+ raise JsonbAccessor::QueryHelper::NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field"
173
66
  end
174
67
 
175
- case value
176
- when IS_NUMBER_QUERY_ARGUMENTS
68
+ if JsonbAccessor::QueryHelper.number_query_arguments?(value)
177
69
  value.each { |operator, query_value| query = query.jsonb_number_where_not(column_name, name, operator, query_value) }
178
- when IS_TIME_QUERY_ARGUMENTS
70
+ elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
179
71
  value.each { |operator, query_value| query = query.jsonb_time_where_not(column_name, name, operator, query_value) }
180
72
  else
181
73
  excludes_attributes[name] = value
@@ -186,10 +78,10 @@ module JsonbAccessor
186
78
  end)
187
79
 
188
80
  scope(:jsonb_order, lambda do |column_name, field_name, direction|
189
- JsonbAccessor::QueryBuilder.validate_column_name!(all, column_name)
190
- JsonbAccessor::QueryBuilder.validate_field_name!(all, column_name, field_name)
191
- JsonbAccessor::QueryBuilder.validate_direction!(direction)
192
- 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}"))
193
85
  end)
194
86
  end
195
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.6"
4
+ VERSION = "1.3.0"
5
5
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonb_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta.6
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Crismali
8
8
  - Joe Hirn
9
9
  - Jason Haruska
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2017-05-09 00:00:00.000000000 Z
13
+ date: 2021-05-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -68,20 +68,6 @@ dependencies:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
70
  version: 2.2.0
71
- - !ruby/object:Gem::Dependency
72
- name: bundler
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - "~>"
76
- - !ruby/object:Gem::Version
77
- version: '1.9'
78
- type: :development
79
- prerelease: false
80
- version_requirements: !ruby/object:Gem::Requirement
81
- requirements:
82
- - - "~>"
83
- - !ruby/object:Gem::Version
84
- version: '1.9'
85
71
  - !ruby/object:Gem::Dependency
86
72
  name: database_cleaner
87
73
  requirement: !ruby/object:Gem::Requirement
@@ -156,16 +142,16 @@ dependencies:
156
142
  name: rake
157
143
  requirement: !ruby/object:Gem::Requirement
158
144
  requirements:
159
- - - "~>"
145
+ - - ">="
160
146
  - !ruby/object:Gem::Version
161
- version: '10.0'
147
+ version: 12.3.3
162
148
  type: :development
163
149
  prerelease: false
164
150
  version_requirements: !ruby/object:Gem::Requirement
165
151
  requirements:
166
- - - "~>"
152
+ - - ">="
167
153
  - !ruby/object:Gem::Version
168
- version: '10.0'
154
+ version: 12.3.3
169
155
  - !ruby/object:Gem::Dependency
170
156
  name: rspec
171
157
  requirement: !ruby/object:Gem::Requirement
@@ -194,20 +180,6 @@ dependencies:
194
180
  - - "~>"
195
181
  - !ruby/object:Gem::Version
196
182
  version: 0.48.1
197
- - !ruby/object:Gem::Dependency
198
- name: standalone_migrations
199
- requirement: !ruby/object:Gem::Requirement
200
- requirements:
201
- - - "~>"
202
- - !ruby/object:Gem::Version
203
- version: 5.2.0
204
- type: :development
205
- prerelease: false
206
- version_requirements: !ruby/object:Gem::Requirement
207
- requirements:
208
- - - "~>"
209
- - !ruby/object:Gem::Version
210
- version: 5.2.0
211
183
  description: Adds typed jsonb backed fields to your ActiveRecord models.
212
184
  email:
213
185
  - michael@crismali.com
@@ -235,36 +207,36 @@ files:
235
207
  - db/migrate/20150407031737_set_up_testing_db.rb
236
208
  - db/schema.rb
237
209
  - gemfiles/activerecord_5.0.0.gemfile
238
- - gemfiles/activerecord_5.0.0.gemfile.lock
239
210
  - gemfiles/activerecord_5.1.0.gemfile
240
- - gemfiles/activerecord_5.1.0.gemfile.lock
211
+ - gemfiles/activerecord_6.1.0.gemfile
241
212
  - jsonb_accessor.gemspec
242
213
  - lib/jsonb_accessor.rb
243
214
  - lib/jsonb_accessor/macro.rb
244
215
  - lib/jsonb_accessor/query_builder.rb
216
+ - lib/jsonb_accessor/query_helper.rb
245
217
  - lib/jsonb_accessor/version.rb
246
218
  homepage: https://github.com/devmynd/jsonb_accessor
247
219
  licenses:
248
220
  - MIT
249
221
  metadata: {}
250
- post_install_message:
222
+ post_install_message:
251
223
  rdoc_options: []
252
224
  require_paths:
253
225
  - lib
254
226
  required_ruby_version: !ruby/object:Gem::Requirement
255
227
  requirements:
256
- - - "~>"
228
+ - - ">="
257
229
  - !ruby/object:Gem::Version
258
- version: '2.0'
230
+ version: '2'
259
231
  required_rubygems_version: !ruby/object:Gem::Requirement
260
232
  requirements:
261
- - - ">"
233
+ - - ">="
262
234
  - !ruby/object:Gem::Version
263
- version: 1.3.1
235
+ version: '0'
264
236
  requirements: []
265
- rubyforge_project:
237
+ rubyforge_project:
266
238
  rubygems_version: 2.6.11
267
- signing_key:
239
+ signing_key:
268
240
  specification_version: 4
269
241
  summary: Adds typed jsonb backed fields to your ActiveRecord models.
270
242
  test_files: []
@@ -1,139 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- jsonb_accessor (1.0.0.beta.6)
5
- activerecord (>= 5.0)
6
- activesupport (>= 5.0)
7
- pg (>= 0.18.1)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- actionpack (5.0.2)
13
- actionview (= 5.0.2)
14
- activesupport (= 5.0.2)
15
- rack (~> 2.0)
16
- rack-test (~> 0.6.3)
17
- rails-dom-testing (~> 2.0)
18
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
19
- actionview (5.0.2)
20
- activesupport (= 5.0.2)
21
- builder (~> 3.1)
22
- erubis (~> 2.7.0)
23
- rails-dom-testing (~> 2.0)
24
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
25
- activemodel (5.0.2)
26
- activesupport (= 5.0.2)
27
- activerecord (5.0.2)
28
- activemodel (= 5.0.2)
29
- activesupport (= 5.0.2)
30
- arel (~> 7.0)
31
- activesupport (5.0.2)
32
- concurrent-ruby (~> 1.0, >= 1.0.2)
33
- i18n (~> 0.7)
34
- minitest (~> 5.1)
35
- tzinfo (~> 1.1)
36
- appraisal (2.2.0)
37
- bundler
38
- rake
39
- thor (>= 0.14.0)
40
- arel (7.1.4)
41
- ast (2.3.0)
42
- awesome_print (1.7.0)
43
- builder (3.2.3)
44
- coderay (1.1.1)
45
- concurrent-ruby (1.0.5)
46
- database_cleaner (1.6.0)
47
- diff-lcs (1.3)
48
- erubis (2.7.0)
49
- i18n (0.8.1)
50
- loofah (2.0.3)
51
- nokogiri (>= 1.5.9)
52
- method_source (0.8.2)
53
- mini_portile2 (2.1.0)
54
- minitest (5.10.1)
55
- nokogiri (1.7.1)
56
- mini_portile2 (~> 2.1.0)
57
- parser (2.4.0.0)
58
- ast (~> 2.2)
59
- pg (0.20.0)
60
- powerpack (0.1.1)
61
- pry (0.10.4)
62
- coderay (~> 1.1.0)
63
- method_source (~> 0.8.1)
64
- slop (~> 3.4)
65
- pry-doc (0.10.0)
66
- pry (~> 0.9)
67
- yard (~> 0.9)
68
- pry-nav (0.2.4)
69
- pry (>= 0.9.10, < 0.11.0)
70
- rack (2.0.2)
71
- rack-test (0.6.3)
72
- rack (>= 1.0)
73
- rails-dom-testing (2.0.2)
74
- activesupport (>= 4.2.0, < 6.0)
75
- nokogiri (~> 1.6)
76
- rails-html-sanitizer (1.0.3)
77
- loofah (~> 2.0)
78
- railties (5.0.2)
79
- actionpack (= 5.0.2)
80
- activesupport (= 5.0.2)
81
- method_source
82
- rake (>= 0.8.7)
83
- thor (>= 0.18.1, < 2.0)
84
- rainbow (2.2.2)
85
- rake
86
- rake (10.5.0)
87
- rspec (3.6.0)
88
- rspec-core (~> 3.6.0)
89
- rspec-expectations (~> 3.6.0)
90
- rspec-mocks (~> 3.6.0)
91
- rspec-core (3.6.0)
92
- rspec-support (~> 3.6.0)
93
- rspec-expectations (3.6.0)
94
- diff-lcs (>= 1.2.0, < 2.0)
95
- rspec-support (~> 3.6.0)
96
- rspec-mocks (3.6.0)
97
- diff-lcs (>= 1.2.0, < 2.0)
98
- rspec-support (~> 3.6.0)
99
- rspec-support (3.6.0)
100
- rubocop (0.48.1)
101
- parser (>= 2.3.3.1, < 3.0)
102
- powerpack (~> 0.1)
103
- rainbow (>= 1.99.1, < 3.0)
104
- ruby-progressbar (~> 1.7)
105
- unicode-display_width (~> 1.0, >= 1.0.1)
106
- ruby-progressbar (1.8.1)
107
- slop (3.6.0)
108
- standalone_migrations (5.2.1)
109
- activerecord (>= 4.2.7, < 5.2.0)
110
- railties (>= 4.2.7, < 5.2.0)
111
- rake (~> 10.0)
112
- thor (0.19.4)
113
- thread_safe (0.3.6)
114
- tzinfo (1.2.2)
115
- thread_safe (~> 0.1)
116
- unicode-display_width (1.2.1)
117
- yard (0.9.8)
118
-
119
- PLATFORMS
120
- ruby
121
-
122
- DEPENDENCIES
123
- activerecord (~> 5.0.0)
124
- appraisal (~> 2.2.0)
125
- awesome_print
126
- bundler (~> 1.9)
127
- database_cleaner (~> 1.6.0)
128
- jsonb_accessor!
129
- pg
130
- pry
131
- pry-doc
132
- pry-nav
133
- rake (~> 10.0)
134
- rspec (~> 3.6.0)
135
- rubocop (~> 0.48.1)
136
- standalone_migrations (~> 5.2.0)
137
-
138
- BUNDLED WITH
139
- 1.14.6
@@ -1,139 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- jsonb_accessor (1.0.0.beta.6)
5
- activerecord (>= 5.0)
6
- activesupport (>= 5.0)
7
- pg (>= 0.18.1)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- actionpack (5.1.0)
13
- actionview (= 5.1.0)
14
- activesupport (= 5.1.0)
15
- rack (~> 2.0)
16
- rack-test (~> 0.6.3)
17
- rails-dom-testing (~> 2.0)
18
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
19
- actionview (5.1.0)
20
- activesupport (= 5.1.0)
21
- builder (~> 3.1)
22
- erubi (~> 1.4)
23
- rails-dom-testing (~> 2.0)
24
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
25
- activemodel (5.1.0)
26
- activesupport (= 5.1.0)
27
- activerecord (5.1.0)
28
- activemodel (= 5.1.0)
29
- activesupport (= 5.1.0)
30
- arel (~> 8.0)
31
- activesupport (5.1.0)
32
- concurrent-ruby (~> 1.0, >= 1.0.2)
33
- i18n (~> 0.7)
34
- minitest (~> 5.1)
35
- tzinfo (~> 1.1)
36
- appraisal (2.2.0)
37
- bundler
38
- rake
39
- thor (>= 0.14.0)
40
- arel (8.0.0)
41
- ast (2.3.0)
42
- awesome_print (1.7.0)
43
- builder (3.2.3)
44
- coderay (1.1.1)
45
- concurrent-ruby (1.0.5)
46
- database_cleaner (1.6.0)
47
- diff-lcs (1.3)
48
- erubi (1.6.0)
49
- i18n (0.8.1)
50
- loofah (2.0.3)
51
- nokogiri (>= 1.5.9)
52
- method_source (0.8.2)
53
- mini_portile2 (2.1.0)
54
- minitest (5.10.1)
55
- nokogiri (1.7.1)
56
- mini_portile2 (~> 2.1.0)
57
- parser (2.4.0.0)
58
- ast (~> 2.2)
59
- pg (0.20.0)
60
- powerpack (0.1.1)
61
- pry (0.10.4)
62
- coderay (~> 1.1.0)
63
- method_source (~> 0.8.1)
64
- slop (~> 3.4)
65
- pry-doc (0.10.0)
66
- pry (~> 0.9)
67
- yard (~> 0.9)
68
- pry-nav (0.2.4)
69
- pry (>= 0.9.10, < 0.11.0)
70
- rack (2.0.1)
71
- rack-test (0.6.3)
72
- rack (>= 1.0)
73
- rails-dom-testing (2.0.2)
74
- activesupport (>= 4.2.0, < 6.0)
75
- nokogiri (~> 1.6)
76
- rails-html-sanitizer (1.0.3)
77
- loofah (~> 2.0)
78
- railties (5.1.0)
79
- actionpack (= 5.1.0)
80
- activesupport (= 5.1.0)
81
- method_source
82
- rake (>= 0.8.7)
83
- thor (>= 0.18.1, < 2.0)
84
- rainbow (2.2.2)
85
- rake
86
- rake (10.5.0)
87
- rspec (3.6.0)
88
- rspec-core (~> 3.6.0)
89
- rspec-expectations (~> 3.6.0)
90
- rspec-mocks (~> 3.6.0)
91
- rspec-core (3.6.0)
92
- rspec-support (~> 3.6.0)
93
- rspec-expectations (3.6.0)
94
- diff-lcs (>= 1.2.0, < 2.0)
95
- rspec-support (~> 3.6.0)
96
- rspec-mocks (3.6.0)
97
- diff-lcs (>= 1.2.0, < 2.0)
98
- rspec-support (~> 3.6.0)
99
- rspec-support (3.6.0)
100
- rubocop (0.48.1)
101
- parser (>= 2.3.3.1, < 3.0)
102
- powerpack (~> 0.1)
103
- rainbow (>= 1.99.1, < 3.0)
104
- ruby-progressbar (~> 1.7)
105
- unicode-display_width (~> 1.0, >= 1.0.1)
106
- ruby-progressbar (1.8.1)
107
- slop (3.6.0)
108
- standalone_migrations (5.2.1)
109
- activerecord (>= 4.2.7, < 5.2.0)
110
- railties (>= 4.2.7, < 5.2.0)
111
- rake (~> 10.0)
112
- thor (0.19.4)
113
- thread_safe (0.3.6)
114
- tzinfo (1.2.3)
115
- thread_safe (~> 0.1)
116
- unicode-display_width (1.2.1)
117
- yard (0.9.9)
118
-
119
- PLATFORMS
120
- ruby
121
-
122
- DEPENDENCIES
123
- activerecord (~> 5.1.0)
124
- appraisal (~> 2.2.0)
125
- awesome_print
126
- bundler (~> 1.9)
127
- database_cleaner (~> 1.6.0)
128
- jsonb_accessor!
129
- pg
130
- pry
131
- pry-doc
132
- pry-nav
133
- rake (~> 10.0)
134
- rspec (~> 3.6.0)
135
- rubocop (~> 0.48.1)
136
- standalone_migrations (~> 5.2.0)
137
-
138
- BUNDLED WITH
139
- 1.14.6