jsonb_accessor 1.3.7-java
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 +7 -0
- data/.github/workflows/ci.yml +153 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +62 -0
- data/.ruby-version +1 -0
- data/Appraisals +25 -0
- data/CHANGELOG.md +28 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Dockerfile +12 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +355 -0
- data/Rakefile +33 -0
- data/UPGRADE_GUIDE.md +67 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/db/config.yml +8 -0
- data/db/migrate/20150407031737_set_up_testing_db.rb +24 -0
- data/db/schema.rb +36 -0
- data/docker-compose.yml +29 -0
- data/gemfiles/activerecord_5.0.0.gemfile +7 -0
- data/gemfiles/activerecord_5.1.0.gemfile +7 -0
- data/gemfiles/activerecord_5.2.0.gemfile +7 -0
- data/gemfiles/activerecord_6.0.0.gemfile +7 -0
- data/gemfiles/activerecord_6.1.0.gemfile +7 -0
- data/gemfiles/activerecord_7.0.1.gemfile +7 -0
- data/jsonb_accessor.gemspec +45 -0
- data/lib/jsonb_accessor/attribute_query_methods.rb +42 -0
- data/lib/jsonb_accessor/helpers.rb +37 -0
- data/lib/jsonb_accessor/macro.rb +124 -0
- data/lib/jsonb_accessor/query_builder.rb +86 -0
- data/lib/jsonb_accessor/query_helper.rb +103 -0
- data/lib/jsonb_accessor/version.rb +5 -0
- data/lib/jsonb_accessor.rb +22 -0
- metadata +263 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonbAccessor
|
4
|
+
class AttributeQueryMethods
|
5
|
+
def initialize(klass)
|
6
|
+
@klass = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def define(store_key_mapping_method_name, jsonb_attribute)
|
10
|
+
return if klass.superclass.respond_to? store_key_mapping_method_name
|
11
|
+
|
12
|
+
# <jsonb_attribute>_where scope
|
13
|
+
klass.define_singleton_method "#{jsonb_attribute}_where" do |attributes|
|
14
|
+
store_key_attributes = JsonbAccessor::Helpers.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
|
15
|
+
jsonb_where(jsonb_attribute, store_key_attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
# <jsonb_attribute>_where_not scope
|
19
|
+
klass.define_singleton_method "#{jsonb_attribute}_where_not" do |attributes|
|
20
|
+
store_key_attributes = JsonbAccessor::Helpers.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
|
21
|
+
jsonb_where_not(jsonb_attribute, store_key_attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
# <jsonb_attribute>_order scope
|
25
|
+
klass.define_singleton_method "#{jsonb_attribute}_order" do |*args|
|
26
|
+
ordering_options = args.extract_options!
|
27
|
+
order_by_defaults = args.each_with_object({}) { |attribute, config| config[attribute] = :asc }
|
28
|
+
store_key_mapping = all.model.public_send(store_key_mapping_method_name)
|
29
|
+
|
30
|
+
order_by_defaults.merge(ordering_options).reduce(all) do |query, (name, direction)|
|
31
|
+
key = store_key_mapping[name.to_s]
|
32
|
+
order_query = jsonb_order(jsonb_attribute, key, direction)
|
33
|
+
query.merge(order_query)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :klass
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonbAccessor
|
4
|
+
module Helpers
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def active_record_default_timezone
|
8
|
+
ActiveRecord.try(:default_timezone) || ActiveRecord::Base.default_timezone
|
9
|
+
end
|
10
|
+
|
11
|
+
# Replaces all keys in `attributes` that have a defined store_key with the store_key
|
12
|
+
def convert_keys_to_store_keys(attributes, store_key_mapping)
|
13
|
+
attributes.stringify_keys.transform_keys do |key|
|
14
|
+
store_key_mapping[key] || key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Replaces all keys in `attributes` that have a defined store_key with the named key (alias)
|
19
|
+
def convert_store_keys_to_keys(attributes, store_key_mapping)
|
20
|
+
convert_keys_to_store_keys(attributes, store_key_mapping.invert)
|
21
|
+
end
|
22
|
+
|
23
|
+
def deserialize_value(value, attribute_type)
|
24
|
+
return value if value.blank?
|
25
|
+
|
26
|
+
if attribute_type == :datetime
|
27
|
+
value = if active_record_default_timezone == :utc
|
28
|
+
Time.find_zone("UTC").parse(value).in_time_zone
|
29
|
+
else
|
30
|
+
Time.zone.parse(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonbAccessor
|
4
|
+
module Macro
|
5
|
+
module ClassMethods
|
6
|
+
def jsonb_accessor(jsonb_attribute, field_types)
|
7
|
+
names_and_store_keys = field_types.each_with_object({}) do |(name, type), mapping|
|
8
|
+
_type, options = Array(type)
|
9
|
+
mapping[name.to_s] = (options.try(:delete, :store_key) || name).to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
# Defines virtual attributes for each jsonb field.
|
13
|
+
field_types.each do |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
|
19
|
+
end
|
20
|
+
|
21
|
+
store_key_mapping_method_name = "jsonb_store_key_mapping_for_#{jsonb_attribute}"
|
22
|
+
# Defines methods on the model class
|
23
|
+
class_methods = Module.new do
|
24
|
+
# Allows us to get a mapping of field names to store keys scoped to the column
|
25
|
+
define_method(store_key_mapping_method_name) do
|
26
|
+
superclass_mapping = superclass.try(store_key_mapping_method_name) || {}
|
27
|
+
superclass_mapping.merge(names_and_store_keys)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# We extend with class methods here so we can use the results of methods it defines to define more useful methods later
|
31
|
+
extend class_methods
|
32
|
+
|
33
|
+
# Get field names to default values mapping
|
34
|
+
names_and_defaults = field_types.each_with_object({}) do |(name, type), mapping|
|
35
|
+
_type, options = Array(type)
|
36
|
+
field_default = options.try(:delete, :default)
|
37
|
+
mapping[name.to_s] = field_default unless field_default.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get store keys to default values mapping
|
41
|
+
store_keys_and_defaults = JsonbAccessor::Helpers.convert_keys_to_store_keys(names_and_defaults, public_send(store_key_mapping_method_name))
|
42
|
+
|
43
|
+
# Define jsonb_defaults_mapping_for_<jsonb_attribute>
|
44
|
+
defaults_mapping_method_name = "jsonb_defaults_mapping_for_#{jsonb_attribute}"
|
45
|
+
class_methods.instance_eval do
|
46
|
+
define_method(defaults_mapping_method_name) do
|
47
|
+
superclass_mapping = superclass.try(defaults_mapping_method_name) || {}
|
48
|
+
superclass_mapping.merge(store_keys_and_defaults)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
all_defaults_mapping = public_send(defaults_mapping_method_name)
|
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.transform_values { |value| value.respond_to?(:call) ? value.call : value }.to_h.compact }
|
59
|
+
end
|
60
|
+
attribute jsonb_attribute, :jsonb, default: all_defaults_mapping_proc if all_defaults_mapping_proc.present?
|
61
|
+
|
62
|
+
# Setters are in a module to allow users to override them and still be able to use `super`.
|
63
|
+
setters = Module.new do
|
64
|
+
# Overrides the setter created by `attribute` above to make sure the jsonb attribute is kept in sync.
|
65
|
+
names_and_store_keys.each do |name, store_key|
|
66
|
+
define_method("#{name}=") do |value|
|
67
|
+
super(value)
|
68
|
+
|
69
|
+
attribute_value = public_send(name)
|
70
|
+
# Rails always saves time based on `default_timezone`. Since #as_json considers timezone, manual conversion is needed
|
71
|
+
if attribute_value.acts_like?(:time)
|
72
|
+
attribute_value = (JsonbAccessor::Helpers.active_record_default_timezone == :utc ? attribute_value.utc : attribute_value.in_time_zone).strftime("%F %R:%S.%L")
|
73
|
+
end
|
74
|
+
|
75
|
+
new_values = (public_send(jsonb_attribute) || {}).merge(store_key => attribute_value)
|
76
|
+
write_attribute(jsonb_attribute, new_values)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Overrides the jsonb attribute setter to make sure the jsonb fields are kept in sync.
|
81
|
+
define_method("#{jsonb_attribute}=") do |value|
|
82
|
+
value ||= {}
|
83
|
+
names_to_store_keys = self.class.public_send(store_key_mapping_method_name)
|
84
|
+
|
85
|
+
# this is the raw hash we want to save in the jsonb_attribute
|
86
|
+
value_with_store_keys = JsonbAccessor::Helpers.convert_keys_to_store_keys(value, names_to_store_keys)
|
87
|
+
write_attribute(jsonb_attribute, value_with_store_keys)
|
88
|
+
|
89
|
+
# this maps attributes to values
|
90
|
+
value_with_named_keys = JsonbAccessor::Helpers.convert_store_keys_to_keys(value, names_to_store_keys)
|
91
|
+
|
92
|
+
empty_named_attributes = names_to_store_keys.transform_values { nil }
|
93
|
+
empty_named_attributes.merge(value_with_named_keys).each do |name, attribute_value|
|
94
|
+
# Only proceed if this attribute has been defined using `jsonb_accessor`.
|
95
|
+
next unless names_to_store_keys.key?(name)
|
96
|
+
|
97
|
+
write_attribute(name, attribute_value)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
include setters
|
102
|
+
|
103
|
+
# Makes sure new objects have the appropriate values in their jsonb fields.
|
104
|
+
after_initialize do
|
105
|
+
next unless has_attribute? jsonb_attribute
|
106
|
+
|
107
|
+
jsonb_values = public_send(jsonb_attribute) || {}
|
108
|
+
jsonb_values.each do |store_key, value|
|
109
|
+
name = names_and_store_keys.key(store_key)
|
110
|
+
next unless name
|
111
|
+
|
112
|
+
write_attribute(
|
113
|
+
name,
|
114
|
+
JsonbAccessor::Helpers.deserialize_value(value, self.class.type_for_attribute(name).type)
|
115
|
+
)
|
116
|
+
clear_attribute_change(name) if persisted?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
JsonbAccessor::AttributeQueryMethods.new(self).define(store_key_mapping_method_name, jsonb_attribute)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonbAccessor
|
4
|
+
module QueryBuilder
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
scope(:jsonb_contains, lambda do |column_name, attributes|
|
9
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
10
|
+
where("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
|
11
|
+
end)
|
12
|
+
|
13
|
+
scope(:jsonb_excludes, lambda do |column_name, attributes|
|
14
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
15
|
+
where.not("#{table_name}.#{column_name} @> (?)::jsonb", attributes.to_json)
|
16
|
+
end)
|
17
|
+
|
18
|
+
scope(:jsonb_number_where, lambda do |column_name, field_name, given_operator, value|
|
19
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
20
|
+
operator = JsonbAccessor::QueryHelper::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
|
21
|
+
where("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
|
22
|
+
end)
|
23
|
+
|
24
|
+
scope(:jsonb_number_where_not, lambda do |column_name, field_name, given_operator, value|
|
25
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
26
|
+
operator = JsonbAccessor::QueryHelper::NUMBER_OPERATORS_MAP.fetch(given_operator.to_s)
|
27
|
+
where.not("(#{table_name}.#{column_name} ->> ?)::float #{operator} ?", field_name, value)
|
28
|
+
end)
|
29
|
+
|
30
|
+
scope(:jsonb_time_where, lambda do |column_name, field_name, given_operator, value|
|
31
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
32
|
+
operator = JsonbAccessor::QueryHelper::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
|
33
|
+
where("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
|
34
|
+
end)
|
35
|
+
|
36
|
+
scope(:jsonb_time_where_not, lambda do |column_name, field_name, given_operator, value|
|
37
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
38
|
+
operator = JsonbAccessor::QueryHelper::TIME_OPERATORS_MAP.fetch(given_operator.to_s)
|
39
|
+
where.not("(#{table_name}.#{column_name} ->> ?)::timestamp #{operator} ?", field_name, value)
|
40
|
+
end)
|
41
|
+
|
42
|
+
scope(:jsonb_where, lambda do |column_name, attributes|
|
43
|
+
query = all
|
44
|
+
contains_attributes = {}
|
45
|
+
|
46
|
+
JsonbAccessor::QueryHelper.convert_ranges(attributes).each do |name, value|
|
47
|
+
if JsonbAccessor::QueryHelper.number_query_arguments?(value)
|
48
|
+
value.each { |operator, query_value| query = query.jsonb_number_where(column_name, name, operator, query_value) }
|
49
|
+
elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
|
50
|
+
value.each { |operator, query_value| query = query.jsonb_time_where(column_name, name, operator, query_value) }
|
51
|
+
else
|
52
|
+
contains_attributes[name] = value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
query.jsonb_contains(column_name, contains_attributes)
|
57
|
+
end)
|
58
|
+
|
59
|
+
scope(:jsonb_where_not, lambda do |column_name, attributes|
|
60
|
+
query = all
|
61
|
+
excludes_attributes = {}
|
62
|
+
|
63
|
+
attributes.each do |name, value|
|
64
|
+
raise JsonbAccessor::QueryHelper::NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field" if value.is_a?(Range)
|
65
|
+
|
66
|
+
if JsonbAccessor::QueryHelper.number_query_arguments?(value)
|
67
|
+
value.each { |operator, query_value| query = query.jsonb_number_where_not(column_name, name, operator, query_value) }
|
68
|
+
elsif JsonbAccessor::QueryHelper.time_query_arguments?(value)
|
69
|
+
value.each { |operator, query_value| query = query.jsonb_time_where_not(column_name, name, operator, query_value) }
|
70
|
+
else
|
71
|
+
excludes_attributes[name] = value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
excludes_attributes.empty? ? query : query.jsonb_excludes(column_name, excludes_attributes)
|
76
|
+
end)
|
77
|
+
|
78
|
+
scope(:jsonb_order, lambda do |column_name, field_name, direction|
|
79
|
+
JsonbAccessor::QueryHelper.validate_column_name!(all, column_name)
|
80
|
+
JsonbAccessor::QueryHelper.validate_field_name!(all, column_name, field_name)
|
81
|
+
JsonbAccessor::QueryHelper.validate_direction!(direction)
|
82
|
+
order(Arel.sql("(#{table_name}.#{column_name} -> '#{field_name}') #{direction}"))
|
83
|
+
end)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,103 @@
|
|
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
|
+
raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table" if query.model.columns.none? { |column| column.name == column_name.to_s }
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_field_name!(query, column_name, field_name)
|
49
|
+
store_keys = query.model.public_send("jsonb_store_key_mapping_for_#{column_name}").values
|
50
|
+
if store_keys.exclude?(field_name.to_s)
|
51
|
+
valid_field_names = store_keys.map { |key| "`#{key}`" }.join(", ")
|
52
|
+
raise InvalidFieldName, "`#{field_name}` is not a valid field name, valid field names include: #{valid_field_names}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_direction!(option)
|
57
|
+
raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted" if ORDER_DIRECTIONS.exclude?(option)
|
58
|
+
end
|
59
|
+
|
60
|
+
def number_query_arguments?(arg)
|
61
|
+
arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| NUMBER_OPERATORS.include?(key) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def time_query_arguments?(arg)
|
65
|
+
arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| TIME_OPERATORS.include?(key) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def convert_number_ranges(attributes)
|
69
|
+
attributes.each_with_object({}) do |(name, value), new_attributes|
|
70
|
+
is_range = value.is_a?(Range)
|
71
|
+
|
72
|
+
new_attributes[name] = if is_range && value.first.is_a?(Numeric) && value.exclude_end?
|
73
|
+
{ greater_than_or_equal_to: value.first, less_than: value.end }
|
74
|
+
elsif is_range && value.first.is_a?(Numeric)
|
75
|
+
{ greater_than_or_equal_to: value.first, less_than_or_equal_to: value.end }
|
76
|
+
else
|
77
|
+
value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def convert_time_ranges(attributes)
|
83
|
+
attributes.each_with_object({}) do |(name, value), new_attributes|
|
84
|
+
is_range = value.is_a?(Range)
|
85
|
+
|
86
|
+
if is_range && (value.first.is_a?(Time) || value.first.is_a?(Date))
|
87
|
+
start_time = value.first
|
88
|
+
end_time = value.end
|
89
|
+
new_attributes[name] = { before: end_time, after: start_time }
|
90
|
+
else
|
91
|
+
new_attributes[name] = value
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_ranges(attributes)
|
97
|
+
%i[convert_number_ranges convert_time_ranges].reduce(attributes) do |new_attributes, converter_method|
|
98
|
+
public_send(converter_method, new_attributes)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
6
|
+
|
7
|
+
require "jsonb_accessor/version"
|
8
|
+
require "jsonb_accessor/helpers"
|
9
|
+
require "jsonb_accessor/macro"
|
10
|
+
require "jsonb_accessor/query_helper"
|
11
|
+
require "jsonb_accessor/query_builder"
|
12
|
+
require "jsonb_accessor/attribute_query_methods"
|
13
|
+
|
14
|
+
module JsonbAccessor
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
include Macro
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveSupport.on_load(:active_record) do
|
20
|
+
ActiveRecord::Base.include JsonbAccessor
|
21
|
+
ActiveRecord::Base.include JsonbAccessor::QueryBuilder
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jsonb_accessor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.3.7
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Michael Crismali
|
8
|
+
- Joe Hirn
|
9
|
+
- Jason Haruska
|
10
|
+
autorequire:
|
11
|
+
bindir: exe
|
12
|
+
cert_chain: []
|
13
|
+
date: 2022-12-29 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '5.0'
|
21
|
+
name: activerecord
|
22
|
+
prerelease: false
|
23
|
+
type: :runtime
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '5.0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '5.0'
|
35
|
+
name: activesupport
|
36
|
+
prerelease: false
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '5.0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '50.0'
|
49
|
+
name: activerecord-jdbcpostgresql-adapter
|
50
|
+
prerelease: false
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '50.0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.2.0
|
63
|
+
name: appraisal
|
64
|
+
prerelease: false
|
65
|
+
type: :development
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.2.0
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
name: awesome_print
|
78
|
+
prerelease: false
|
79
|
+
type: :development
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.6.0
|
91
|
+
name: database_cleaner
|
92
|
+
prerelease: false
|
93
|
+
type: :development
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 1.6.0
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
name: pry
|
106
|
+
prerelease: false
|
107
|
+
type: :development
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
name: pry-doc
|
120
|
+
prerelease: false
|
121
|
+
type: :development
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
name: pry-nav
|
134
|
+
prerelease: false
|
135
|
+
type: :development
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '3'
|
147
|
+
name: psych
|
148
|
+
prerelease: false
|
149
|
+
type: :development
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - "~>"
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '3'
|
155
|
+
- !ruby/object:Gem::Dependency
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 12.3.3
|
161
|
+
name: rake
|
162
|
+
prerelease: false
|
163
|
+
type: :development
|
164
|
+
version_requirements: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: 12.3.3
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 3.6.0
|
175
|
+
name: rspec
|
176
|
+
prerelease: false
|
177
|
+
type: :development
|
178
|
+
version_requirements: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - "~>"
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 3.6.0
|
183
|
+
- !ruby/object:Gem::Dependency
|
184
|
+
requirement: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - "~>"
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '1'
|
189
|
+
name: rubocop
|
190
|
+
prerelease: false
|
191
|
+
type: :development
|
192
|
+
version_requirements: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - "~>"
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '1'
|
197
|
+
description: Adds typed jsonb backed fields to your ActiveRecord models.
|
198
|
+
email:
|
199
|
+
- michael@crismali.com
|
200
|
+
- joe@devmynd.com
|
201
|
+
- jason@haruska.com
|
202
|
+
executables: []
|
203
|
+
extensions: []
|
204
|
+
extra_rdoc_files: []
|
205
|
+
files:
|
206
|
+
- ".github/workflows/ci.yml"
|
207
|
+
- ".gitignore"
|
208
|
+
- ".rspec"
|
209
|
+
- ".rubocop.yml"
|
210
|
+
- ".ruby-version"
|
211
|
+
- Appraisals
|
212
|
+
- CHANGELOG.md
|
213
|
+
- CODE_OF_CONDUCT.md
|
214
|
+
- Dockerfile
|
215
|
+
- Gemfile
|
216
|
+
- LICENSE.txt
|
217
|
+
- README.md
|
218
|
+
- Rakefile
|
219
|
+
- UPGRADE_GUIDE.md
|
220
|
+
- bin/console
|
221
|
+
- bin/setup
|
222
|
+
- db/config.yml
|
223
|
+
- db/migrate/20150407031737_set_up_testing_db.rb
|
224
|
+
- db/schema.rb
|
225
|
+
- docker-compose.yml
|
226
|
+
- gemfiles/activerecord_5.0.0.gemfile
|
227
|
+
- gemfiles/activerecord_5.1.0.gemfile
|
228
|
+
- gemfiles/activerecord_5.2.0.gemfile
|
229
|
+
- gemfiles/activerecord_6.0.0.gemfile
|
230
|
+
- gemfiles/activerecord_6.1.0.gemfile
|
231
|
+
- gemfiles/activerecord_7.0.1.gemfile
|
232
|
+
- jsonb_accessor.gemspec
|
233
|
+
- lib/jsonb_accessor.rb
|
234
|
+
- lib/jsonb_accessor/attribute_query_methods.rb
|
235
|
+
- lib/jsonb_accessor/helpers.rb
|
236
|
+
- lib/jsonb_accessor/macro.rb
|
237
|
+
- lib/jsonb_accessor/query_builder.rb
|
238
|
+
- lib/jsonb_accessor/query_helper.rb
|
239
|
+
- lib/jsonb_accessor/version.rb
|
240
|
+
homepage: https://github.com/devmynd/jsonb_accessor
|
241
|
+
licenses:
|
242
|
+
- MIT
|
243
|
+
metadata: {}
|
244
|
+
post_install_message:
|
245
|
+
rdoc_options: []
|
246
|
+
require_paths:
|
247
|
+
- lib
|
248
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - ">="
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: '2'
|
253
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
requirements: []
|
259
|
+
rubygems_version: 3.2.33
|
260
|
+
signing_key:
|
261
|
+
specification_version: 4
|
262
|
+
summary: Adds typed jsonb backed fields to your ActiveRecord models.
|
263
|
+
test_files: []
|