jsonb_accessor 1.0.0.beta.6 → 1.3.0

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: 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