associate_jsonb 0.0.10 → 6.1.4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 847b6c8d5410dca5511a9ab2537ea3d2d9ba5c40e681ad42a63f0e752604d1ff
4
- data.tar.gz: 935adff8c21a94b4d7593a236c9e56eec29c31340a897c82851b3662b0da880e
3
+ metadata.gz: f26470e30b277fe8ef0189ca4bef7eacf8cf7d4fa22008a879f5c1b187f9c476
4
+ data.tar.gz: 28ca2bd98358795e4e9d6a59e14738536e7a2696e0b4eacb11612e5bc33840a6
5
5
  SHA512:
6
- metadata.gz: c614936df446af3b0bd1301037954214e973cc4522637c3578f47f775065eb9085f08b668b11bf619ba3ca7968b14c078e192579be56eee489d5bf0780097552
7
- data.tar.gz: 5243289a848da4cc15d03204a6d5bc6a502d810e6f839fb2b26aabc264bea63553b040a8508cf6f6d0722d82be5ea905c9bb75caa5e9ac1038b2e9d85e535122
6
+ metadata.gz: 6475d5e18d9c67d1b4b13a4770640ba79031357317dd185d77b8c959b8fdf1f59b52d6ee12fe1bed2e18652ed36747ce22c33af390bd63a3dbb87249c81479d2
7
+ data.tar.gz: 300b6fb1c2385bab73823765ee42d27e2b0a047efcf10b58727ad5e2973672910ca07a57ae76b64ff4ab32f006bf934d6376ddd975b9380600404d6264860955
@@ -1,28 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- # module AssociateJsonb
5
- # module ArelNodes
6
- # class SqlCastedEquality < ::Arel::Nodes::Equality
7
- # attr_reader :original_left
8
- # def initialize(left, cast_as, right)
9
- # @original_left = left
10
- # super(
11
- # ::Arel::Nodes::NamedFunction.new(
12
- # "CAST",
13
- # [ left.as(cast_as) ]
14
- # ),
15
- # right
16
- # )
17
- # end
18
- # end
19
- # end
20
- # end
21
-
22
-
23
- # encoding: utf-8
24
- # frozen_string_literal: true
25
-
26
4
  module AssociateJsonb
27
5
  module ArelNodes
28
6
  class SqlCastedEquality < AssociateJsonb::ArelNodes::SqlCastedBinary
@@ -5,8 +5,8 @@ require "active_support/core_ext/string/conversions"
5
5
  module AssociateJsonb
6
6
  module Associations
7
7
  module AliasTracker # :nodoc:
8
- def aliased_table_for(table_name, aliased_name, type_caster, store_tracker = nil)
9
- super(table_name, aliased_name, type_caster).with_store_tracker(store_tracker)
8
+ def aliased_table_for(arel_table, table_name = nil, store_tracker: nil)
9
+ super(arel_table, table_name).with_store_tracker(store_tracker)
10
10
  end
11
11
  end
12
12
  end
@@ -12,28 +12,14 @@ module AssociateJsonb
12
12
  assigned_keys = record.changed_attribute_names_to_save
13
13
  assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
14
14
  attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
15
+
15
16
  if attributes.key?(reflection.foreign_store_key.to_s)
16
- v = attributes.delete(reflection.foreign_store_key.to_s)
17
- attributes[reflection.foreign_key.to_s] = v
17
+ attributes[reflection.foreign_key.to_s] = attributes.delete(reflection.foreign_store_key.to_s)
18
18
  end
19
+
19
20
  record.send(:_assign_attributes, attributes) if attributes.any?
20
21
  set_inverse_instance(record)
21
22
  end
22
-
23
- private
24
- def creation_attributes
25
- return super if reflection.belongs_to?
26
- return super unless reflection.foreign_store?
27
-
28
- attributes = {}
29
-
30
- jsonb_store = reflection.foreign_store_attr
31
- attributes[jsonb_store] ||= {}
32
- attributes[jsonb_store][reflection.foreign_store_key] =
33
- owner[reflection.active_record_primary_key]
34
-
35
- attributes
36
- end
37
23
  end
38
24
  end
39
25
  end
@@ -4,17 +4,13 @@
4
4
  module AssociateJsonb
5
5
  module Associations
6
6
  module AssociationScope #:nodoc:
7
-
8
7
  def get_chain(reflection, association, tracker)
9
8
  name = reflection.name
10
9
  chain = [ActiveRecord::Reflection::RuntimeReflection.new(reflection, association)]
11
10
  reflection.chain.drop(1).each do |refl|
12
- aliased_table = tracker.aliased_table_for(
13
- refl.table_name,
14
- refl.alias_candidate(name),
15
- refl.klass.type_caster,
16
- refl.klass.store_column_attribute_tracker
17
- )
11
+ aliased_table = tracker.aliased_table_for(refl.klass.arel_table, store_tracker: refl.klass.store_column_attribute_tracker) do
12
+ refl.alias_candidate(name)
13
+ end
18
14
  chain << ActiveRecord::Associations::AssociationScope::ReflectionProxy.new(refl, aliased_table)
19
15
  end
20
16
  chain
@@ -25,18 +21,19 @@ module AssociateJsonb
25
21
  reflection = owner_reflection.instance_variable_get(:@reflection)
26
22
  return super unless reflection&.foreign_store?
27
23
 
24
+ primary_key = reflection.join_primary_key
25
+ foreign_key = reflection.join_foreign_key
26
+ store_key = reflection.foreign_store_key || primary_key
28
27
 
29
- join_keys = owner_reflection.join_keys
30
28
  table = owner_reflection.aliased_table
31
- key = reflection.foreign_store_key || join_keys.key
32
- value = transform_value(owner[join_keys.foreign_key])
29
+ value = transform_value(owner[foreign_key])
33
30
 
34
31
  apply_jsonb_equality(
35
32
  scope,
36
33
  table,
37
34
  reflection.foreign_store_attr,
38
- key.to_s,
39
- join_keys.foreign_key,
35
+ store_key.to_s,
36
+ owner_reflection.join_foreign_key,
40
37
  value,
41
38
  reflection.active_record
42
39
  )
@@ -5,6 +5,29 @@ module AssociateJsonb
5
5
  module Associations
6
6
  module Builder
7
7
  module BelongsTo #:nodoc:
8
+ # Maybe convert to builder callbacks here in next iteration
9
+ # def define_callbacks(model, reflection)
10
+ # super
11
+ # add_after_jsonb_initialize_callbacks(model, reflection) if reflection.jsonb_store?
12
+ # add_after_foreign_store_initialize_callbacks(model, reflection) if reflection.foreign_store?
13
+ # end
14
+ #
15
+ # def add_after_jsonb_initialize_callbacks(model, reflection)
16
+ # model.after_initialize lambda {|record|
17
+ # association = association(reflection.name)
18
+ # p model, reflection.join_primary_key, reflection.join_foreign_key, reflection.options
19
+ # p record.attributes
20
+ # # record.attributes._write_attribute()
21
+ # }
22
+ # end
23
+ #
24
+ # def add_after_foreign_store_initialize_callbacks(model, reflection)
25
+ # model.after_initialize lambda {|record|
26
+ # association = association(reflection.name)
27
+ # # record.attributes._write_attribute()
28
+ # }
29
+ # end
30
+
8
31
  def valid_options(options)
9
32
  super + %i[ store store_key ]
10
33
  end
@@ -18,7 +41,7 @@ module AssociateJsonb
18
41
  end
19
42
 
20
43
  def add_association_accessor_methods(mixin, reflection)
21
- foreign_key = reflection.foreign_key.to_s
44
+ foreign_key = reflection.join_foreign_key.to_s
22
45
  key = (reflection.jsonb_store_key || foreign_key).to_s
23
46
  store = reflection.jsonb_store_attr
24
47
 
@@ -35,8 +58,8 @@ module AssociateJsonb
35
58
  foreign_type = :integer
36
59
  sql_type = "numeric"
37
60
  begin
38
- primary_key = reflection.active_record_primary_key.to_s
39
- primary_column = reflection.klass.columns.find {|col| col.name == primary_key }
61
+ primary_key = reflection.join_primary_key.to_s
62
+ primary_column = reflection.klass.columns_hash[primary_key]
40
63
 
41
64
  if primary_column
42
65
  foreign_type = primary_column.type
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module AssociateJsonb
5
+ module Associations
6
+ module ForeignAssociation # :nodoc:
7
+ private
8
+ # Sets the owner attributes on the given record
9
+ def set_owner_attributes(record)
10
+ return if options[:through]
11
+ return super unless reflection.foreign_store?
12
+
13
+ jsonb_store = reflection.foreign_store_attr.to_s
14
+ value = record._read_attribute(jsonb_store).presence || {}
15
+ fk_value = owner._read_attribute(reflection.join_foreign_key)
16
+ value[reflection.foreign_store_key] = fk_value
17
+
18
+ record._write_attribute(reflection.join_primary_key, fk_value)
19
+ record._write_attribute(jsonb_store, value)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -6,15 +6,28 @@ module AssociateJsonb
6
6
  module Associations
7
7
  module JoinDependency # :nodoc:
8
8
  private
9
- def table_aliases_for(parent, node)
10
- node.reflection.chain.map { |reflection|
11
- alias_tracker.aliased_table_for(
12
- reflection.table_name,
13
- table_alias_for(reflection, parent, reflection != node.reflection),
14
- reflection.klass.type_caster,
15
- reflection.klass.store_column_attribute_tracker
16
- )
17
- }
9
+ def make_constraints(parent, child, join_type)
10
+ foreign_table = parent.table
11
+ foreign_klass = parent.base_klass
12
+ child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection|
13
+ table, terminated = @joined_tables[reflection]
14
+ root = reflection == child.reflection
15
+
16
+ if table && (!root || !terminated)
17
+ @joined_tables[reflection] = [table, root] if root
18
+ next table, true
19
+ end
20
+
21
+ table_name = @references[reflection.name.to_sym]&.to_s
22
+
23
+ table = alias_tracker.aliased_table_for(reflection.klass.arel_table, table_name, store_tracker: reflection.klass.store_column_attribute_tracker) do
24
+ name = reflection.alias_candidate(parent.table_name)
25
+ root ? name : "#{name}_join"
26
+ end
27
+
28
+ @joined_tables[reflection] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
29
+ table
30
+ end.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
18
31
  end
19
32
  end
20
33
  end
@@ -18,6 +18,30 @@ module AssociateJsonb
18
18
  ).intersects_with(ids)
19
19
  )
20
20
  end
21
+
22
+ private
23
+ def load_records
24
+ return super unless reflection.foreign_store?
25
+ # owners can be duplicated when a relation has a collection association join
26
+ # #compare_by_identity makes such owners different hash keys
27
+ @records_by_owner = {}.compare_by_identity
28
+ raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
29
+
30
+ @preloaded_records = raw_records.select do |record|
31
+ assignments = false
32
+
33
+ owners_by_key[convert_key(record[association_key_name])].each do |owner|
34
+ entries = (@records_by_owner[owner] ||= [])
35
+
36
+ if reflection.collection? || entries.empty?
37
+ entries << record
38
+ assignments = true
39
+ end
40
+ end
41
+
42
+ assignments
43
+ end
44
+ end
21
45
  end
22
46
  end
23
47
  end
@@ -11,8 +11,8 @@ module AssociateJsonb
11
11
 
12
12
  private
13
13
  def attributes_with_info(attribute_names)
14
- attribute_names.each_with_object({}) do |name, attrs|
15
- attrs[name] = _fetch_attribute(name)
14
+ attribute_names.index_with do |name|
15
+ _fetch_attribute(name)
16
16
  end
17
17
  end
18
18
  end
@@ -30,7 +30,7 @@ module AssociateJsonb
30
30
  end
31
31
 
32
32
  create_sql << "(#{statements.join(', ')})" if statements.present?
33
- add_table_options!(create_sql, table_options(o))
33
+ add_table_options!(create_sql, o)
34
34
  create_sql << " AS #{to_sql(o.as)}" if o.as
35
35
  create_sql
36
36
  end
@@ -12,38 +12,43 @@ module AssociateJsonb
12
12
  execute schema_creation.accept(AddJsonbForeignKeyFunction.new)
13
13
  end
14
14
 
15
- def create_table(table_name, **options)
16
- td = create_table_definition(table_name, **options)
15
+ def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
16
+ td = create_table_definition(table_name, **extract_table_options!(options))
17
17
 
18
- if options[:id] != false && !options[:as]
19
- pk = options.fetch(:primary_key) do
20
- ActiveRecord::Base.get_primary_key table_name.to_s.singularize
18
+ if id && !td.as
19
+ pk = primary_key || ActiveRecord::Base.get_primary_key(table_name.to_s.singularize)
20
+
21
+ if id.is_a?(Hash)
22
+ options.merge!(id.except(:type))
23
+ id = id.fetch(:type, :primary_key)
21
24
  end
22
25
 
23
26
  if pk.is_a?(Array)
24
27
  td.primary_keys pk
25
28
  else
26
- td.primary_key pk, options.fetch(:id, :primary_key), **options.except(:comment)
29
+ td.primary_key pk, id, **options
27
30
  end
28
31
  end
29
32
 
30
33
  yield td if block_given?
31
34
 
32
- if options[:force]
33
- drop_table(table_name, **options, if_exists: true)
35
+ if force
36
+ drop_table(table_name, force: force, if_exists: true)
37
+ else
38
+ schema_cache.clear_data_source_cache!(table_name.to_s)
34
39
  end
35
40
 
36
41
  result = execute schema_creation.accept td
37
42
 
38
43
  td.indexes.each do |column_name, index_options|
39
- add_index(table_name, column_name, index_options)
44
+ add_index(table_name, column_name, **index_options, if_not_exists: td.if_not_exists)
40
45
  end
41
46
 
42
47
  td.constraints.each do |ct|
43
48
  add_constraint(table_name, **ct)
44
49
  end
45
50
 
46
- if table_comment = options[:comment].presence
51
+ if table_comment = td.comment.presence
47
52
  change_table_comment(table_name, table_comment)
48
53
  end
49
54
 
@@ -18,7 +18,7 @@ module AssociateJsonb
18
18
  end
19
19
 
20
20
  def jsonb_store_key
21
- options[:store_key].presence || join_keys.foreign_key
21
+ options[:store_key].presence || join_foreign_key
22
22
  end
23
23
 
24
24
  def foreign_store?
@@ -36,7 +36,7 @@ module AssociateJsonb
36
36
  end
37
37
 
38
38
  def foreign_store_key
39
- options[:foreign_store_key].presence || join_keys.key
39
+ options[:foreign_store_key].presence || join_primary_key
40
40
  end
41
41
 
42
42
  def join_scope(table, foreign_table, foreign_klass)
@@ -52,8 +52,8 @@ module AssociateJsonb
52
52
 
53
53
  scope_chain_items.inject(klass_scope, &:merge!)
54
54
 
55
- key = join_keys.key
56
- foreign_key = join_keys.foreign_key
55
+ key = join_primary_key
56
+ foreign_key = join_foreign_key
57
57
 
58
58
  if foreign_store?
59
59
  klass_scope.where!(
@@ -4,36 +4,14 @@
4
4
  module AssociateJsonb
5
5
  module Relation
6
6
  module WhereClause
7
- def to_h(table_name = nil)
8
- equalities = equalities(predicates)
9
- if table_name
10
- equalities = equalities.select do |node|
11
- node.original_left.relation.name == table_name
12
- end
13
- end
14
-
15
- equalities.map { |node|
7
+ def to_h(table_name = nil, equality_only: false)
8
+ equalities(predicates, equality_only).each_with_object({}) do |node, hash|
9
+ next if table_name&.!= node.original_left.relation.name
16
10
  name = node.original_left.name.to_s
17
11
  value = extract_node_value(node.right)
18
- [name, value]
19
- }.to_h
20
- end
21
-
22
- private
23
- def equalities(predicates)
24
- equalities = []
25
-
26
- predicates.each do |node|
27
- case node
28
- when Arel::Nodes::Equality, Arel::Nodes::SqlCastedEquality
29
- equalities << node
30
- when Arel::Nodes::And
31
- equalities.concat equalities(node.children)
32
- end
33
- end
34
-
35
- equalities
12
+ hash[name] = value
36
13
  end
14
+ end
37
15
  end
38
16
  end
39
17
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module AssociateJsonb
5
- SUPPORTED_RAILS_VERSION = "6.0.3.2"
5
+ SUPPORTED_RAILS_VERSION = "6.1.4.1"
6
6
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module AssociateJsonb
5
- VERSION = "0.0.10"
5
+ VERSION = "6.1.4.1.1"
6
6
  end
@@ -99,15 +99,15 @@ module AssociateJsonb
99
99
  end
100
100
 
101
101
  def store_column_attribute(store, attr, cast_type = ActiveRecord::Type::Value.new, sql_type: nil, key: nil, **attribute_opts)
102
- store = store.to_sym
103
- attr = attr.to_sym
102
+ store = store.to_s
103
+ attr = attr.to_s
104
104
  key ||= attr
105
105
  key = key.to_s
106
106
  array = attribute_opts[:array]
107
107
  attribute attr, cast_type, **attribute_opts
108
108
 
109
109
  instance_eval <<~CODE, __FILE__, __LINE__ + 1
110
- add_store_column_attribute_name("#{attr}", :#{store}, "#{key}", { sql_type: sql_type, type: cast_type, opts: attribute_opts })
110
+ add_store_column_attribute_name(attr, store, key, { sql_type: sql_type, type: cast_type, opts: attribute_opts })
111
111
  CODE
112
112
 
113
113
  include WithStoreAttribute::InstanceMethodsOnActivation.new(self, store, attr, key, array)
@@ -120,9 +120,9 @@ module AssociateJsonb
120
120
 
121
121
  array_or_attr = ->(value) {
122
122
  is_array \
123
- ? %Q(Array(#{value})) \
124
- : %Q(#{value})
125
- }
123
+ ? %Q(Array(#{value})) \
124
+ : %Q(#{value})
125
+ }
126
126
 
127
127
  on_store_change = "_write_attribute(:#{attribute}, #{array_or_attr.call %Q(#{store}["#{key}"])})"
128
128
  on_attr_change = "super(#{array_or_attr.call %Q(given)})"
@@ -36,7 +36,7 @@ module AssociateJsonb
36
36
  ##
37
37
  # Enables the use of `jsonb_nested_set` for hash updates
38
38
  #
39
- # if passed a class, or a list of classes, those classes will be added todo
39
+ # if passed a class, or a list of classes, those classes will be added to
40
40
  # the enabled classes. if no argument is given, and the enabled class list is
41
41
  # empty, `ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Jsonb` is added
42
42
  # to the list of enabled classes
@@ -187,6 +187,10 @@ ActiveSupport.on_load :active_record do
187
187
  AssociateJsonb::Associations::Preloader::Association
188
188
  )
189
189
 
190
+ ActiveRecord::Associations::ForeignAssociation.prepend(
191
+ AssociateJsonb::Associations::ForeignAssociation
192
+ )
193
+
190
194
  %i[
191
195
  AlterTable
192
196
  ConstraintDefinition
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: associate_jsonb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 6.1.4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sampson Crowley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-24 00:00:00.000000000 Z
11
+ date: 2021-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.3
19
+ version: 6.1.4
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 6.0.3.2
22
+ version: 6.1.4.1
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: 6.0.3
29
+ version: 6.1.4
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 6.0.3.2
32
+ version: 6.1.4.1
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: pg
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +149,7 @@ files:
149
149
  - lib/associate_jsonb/associations/builder/has_many.rb
150
150
  - lib/associate_jsonb/associations/builder/has_one.rb
151
151
  - lib/associate_jsonb/associations/conflicting_association.rb
152
+ - lib/associate_jsonb/associations/foreign_association.rb
152
153
  - lib/associate_jsonb/associations/has_many_association.rb
153
154
  - lib/associate_jsonb/associations/join_dependency.rb
154
155
  - lib/associate_jsonb/associations/preloader/association.rb
@@ -190,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
190
191
  - !ruby/object:Gem::Version
191
192
  version: '0'
192
193
  requirements: []
193
- rubygems_version: 3.1.4
194
+ rubygems_version: 3.1.6
194
195
  signing_key:
195
196
  specification_version: 4
196
197
  summary: Store database references in PostgreSQL Jsonb columns