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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -1
- data/.travis.yml +20 -5
- data/Appraisals +5 -1
- data/README.md +6 -10
- data/Rakefile +18 -2
- data/db/config.yml +2 -3
- data/db/schema.rb +6 -6
- data/gemfiles/activerecord_5.1.0.gemfile +1 -1
- data/gemfiles/activerecord_6.1.0.gemfile +8 -0
- data/jsonb_accessor.gemspec +2 -4
- data/lib/jsonb_accessor.rb +1 -0
- data/lib/jsonb_accessor/macro.rb +21 -8
- data/lib/jsonb_accessor/query_builder.rb +20 -128
- data/lib/jsonb_accessor/query_helper.rb +114 -0
- data/lib/jsonb_accessor/version.rb +1 -1
- metadata +16 -44
- data/gemfiles/activerecord_5.0.0.gemfile.lock +0 -139
- data/gemfiles/activerecord_5.1.0.gemfile.lock +0 -139
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12a9ef2a6ecf012dd86338b0962ea0338ac8950f
|
4
|
+
data.tar.gz: ffb75c6ce59fa8eeb1a6917c822853f0aa63cead
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddb76f1639699f471680602e9d3f7601eca9666e7c3c03d2f3dce80d8e810a22940712668e0190f2469bccb54f9ae10a7f0b2fb7e763ea8818da32c34893ea91
|
7
|
+
data.tar.gz: 11e77edee1f60874eb313da3301483beb5cc4a962ad14b8f202e923511a1378a10b664fcb00fb4eae161e06f73b4f3c20878871753a693cc5fd733665a0dd2c4
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,18 +1,33 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.
|
5
|
-
- 2.
|
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:
|
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
data/README.md
CHANGED
@@ -1,17 +1,13 @@
|
|
1
1
|
# JSONb Accessor
|
2
2
|
|
3
|
-
Created by [<img src="https://raw.githubusercontent.com/
|
3
|
+
Created by [<img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png" alt="Tandem Logo" />](https://www.madeintandem.com/)
|
4
4
|
|
5
|
-
[](http://badge.fury.io/rb/jsonb_accessor) [](http://badge.fury.io/rb/jsonb_accessor) [](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/
|
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
|
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](
|
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/
|
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
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
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# from scratch.
|
9
|
-
#
|
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:
|
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"
|
data/jsonb_accessor.gemspec
CHANGED
@@ -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 = "
|
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", "
|
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
|
data/lib/jsonb_accessor.rb
CHANGED
data/lib/jsonb_accessor/macro.rb
CHANGED
@@ -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,
|
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::
|
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
|
-
|
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::
|
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
|
-
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
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::
|
153
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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::
|
190
|
-
JsonbAccessor::
|
191
|
-
JsonbAccessor::
|
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
|
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.
|
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:
|
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:
|
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:
|
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/
|
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
|
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:
|
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
|