brick 1.0.91 → 1.0.92
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/lib/brick/compatibility.rb +1 -0
- data/lib/brick/extensions.rb +45 -32
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +122 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bb6854dd2295476ae00996f23e801587869463aa7114d9240c0e97b1cce25b1
|
4
|
+
data.tar.gz: f174948106c6a06be049f8285fb3358813d09b9970ce484554ad3c86bc3cb8fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9384ef5db0a03fcc8fda6a3ceafc763a468f88033420d785814d657303027593c7fef64770087975d73d4041f577864c1d934629cb50083fb93d2591f719f136
|
7
|
+
data.tar.gz: e2b3e21982b9a6d132a3d9d05041759e06a3ac3ffbfdf2ea3675ee0140150f2d33b6e60cbeb0033a7f7469bba227f198a6cc6a0ef34c229ba7a1132cd1175b0d
|
data/lib/brick/compatibility.rb
CHANGED
@@ -11,6 +11,7 @@ unless ActiveRecord.respond_to?(:version)
|
|
11
11
|
end
|
12
12
|
|
13
13
|
# ActiveSupport, ActionPack, and ActionView before 4.0 didn't have #version
|
14
|
+
require 'active_support' # Needed for Rails 4.x
|
14
15
|
unless ActiveSupport.respond_to?(:version)
|
15
16
|
module ActiveSupport
|
16
17
|
def self.version
|
data/lib/brick/extensions.rb
CHANGED
@@ -407,7 +407,13 @@ module ActiveRecord
|
|
407
407
|
end
|
408
408
|
|
409
409
|
class Relation
|
410
|
-
attr_reader :
|
410
|
+
attr_reader :_arel_applied_aliases
|
411
|
+
|
412
|
+
# Links from ActiveRecord association pathing names over to real
|
413
|
+
# table correlation names built from AREL aliasing
|
414
|
+
def brick_links
|
415
|
+
@brick_links ||= {}
|
416
|
+
end
|
411
417
|
|
412
418
|
# CLASS STUFF
|
413
419
|
def _recurse_arel(piece, prefix = '')
|
@@ -448,7 +454,6 @@ module ActiveRecord
|
|
448
454
|
@_arel_applied_aliases << (alias_name = table.right)
|
449
455
|
table = table.left
|
450
456
|
end
|
451
|
-
(_brick_chains[table._arel_table_type] ||= []) << (alias_name || table.table_alias || table.name)
|
452
457
|
end
|
453
458
|
# rubocop:enable Style/IdenticalConditionalBranches
|
454
459
|
when Arel::Table # Table
|
@@ -457,12 +462,8 @@ module ActiveRecord
|
|
457
462
|
# Can get the real table name from: self._recurse_arel(piece.left)
|
458
463
|
names << [piece.left._arel_table_type, piece.right.to_s] # This is simply a string; the alias name itself
|
459
464
|
when Arel::Nodes::JoinSource # Leaving this until the end because AR < 3.2 doesn't know at all about JoinSource!
|
460
|
-
# Spin up an empty set of Brick alias name chains at the start
|
461
|
-
@_brick_chains = {}
|
462
465
|
# The left side is the "FROM" table
|
463
466
|
names << (this_name = [piece.left._arel_table_type, (piece.left.table_alias || piece.left.name)])
|
464
|
-
# # Do not currently need the root "FROM" table in our list of chains
|
465
|
-
# (_brick_chains[this_name.first] ||= []) << this_name.last
|
466
467
|
# The right side is an array of all JOINs
|
467
468
|
piece.right.each { |join| names << _recurse_arel(join) }
|
468
469
|
end
|
@@ -548,7 +549,6 @@ module ActiveRecord
|
|
548
549
|
# Without working from a duplicate, touching the AREL ast tree sets the @arel instance variable, which causes the relation to be immutable.
|
549
550
|
(rel_dupe = dup)._arel_alias_names
|
550
551
|
core_selects = selects.dup
|
551
|
-
chains = rel_dupe._brick_chains
|
552
552
|
id_for_tables = Hash.new { |h, k| h[k] = [] }
|
553
553
|
field_tbl_names = Hash.new { |h, k| h[k] = {} }
|
554
554
|
used_col_aliases = {} # Used to make sure there is not a name clash
|
@@ -569,7 +569,7 @@ module ActiveRecord
|
|
569
569
|
key_alias = nil
|
570
570
|
cc.first.each do |cc_part|
|
571
571
|
dest_klass = cc_part[0..-2].inject(klass) { |kl, cc_part_term| kl.reflect_on_association(cc_part_term).klass }
|
572
|
-
tbl_name =
|
572
|
+
tbl_name = rel_dupe.brick_links[cc_part[0..-2].map(&:to_s).join('.')]
|
573
573
|
# Deal with the conflict if there are two parts in the custom column named the same,
|
574
574
|
# "category.name" and "product.name" for instance will end up with aliases of "name"
|
575
575
|
# and "product__name".
|
@@ -606,23 +606,18 @@ module ActiveRecord
|
|
606
606
|
|
607
607
|
klass._br_bt_descrip.each do |v|
|
608
608
|
v.last.each do |k1, v1| # k1 is class, v1 is array of columns to snag
|
609
|
-
next
|
609
|
+
next unless (tbl_name = rel_dupe.brick_links[v.first.to_s]&.split('.')&.last)
|
610
610
|
|
611
|
-
tbl_name = (field_tbl_names[v.first][k1] ||= shift_or_first(chains[k1])).split('.').last
|
612
611
|
# If it's Oracle, quote any AREL aliases that had been applied
|
613
612
|
tbl_name = "\"#{tbl_name}\"" if ::Brick.is_oracle && rel_dupe._arel_applied_aliases.include?(tbl_name)
|
614
613
|
field_tbl_name = nil
|
615
|
-
v1.map { |x| [
|
616
|
-
|
617
|
-
# puts 'You might have some bogus DSL in your brick.rb file'
|
618
|
-
# next
|
619
|
-
# end
|
620
|
-
field_tbl_name = (field_tbl_names[v.first][sel_col.first] ||= shift_or_first(chains[sel_col.first])).split('.').last
|
614
|
+
v1.map { |x| [x[0..-2].map(&:to_s).join('.'), x.last] }.each_with_index do |sel_col, idx|
|
615
|
+
field_tbl_name = rel_dupe.brick_links[sel_col.first].split('.').last
|
621
616
|
# If it's Oracle, quote any AREL aliases that had been applied
|
622
617
|
field_tbl_name = "\"#{field_tbl_name}\"" if ::Brick.is_oracle && rel_dupe._arel_applied_aliases.include?(field_tbl_name)
|
623
618
|
|
624
619
|
# Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
|
625
|
-
is_xml = is_distinct && Brick.relations[
|
620
|
+
is_xml = is_distinct && Brick.relations[field_tbl_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
|
626
621
|
# If it's not unique then also include the belongs_to association name before the column name
|
627
622
|
if used_col_aliases.key?(col_alias = "br_fk_#{v.first}__#{sel_col.last}")
|
628
623
|
col_alias = "br_fk_#{v.first}__#{v1[idx][-2..-1].map(&:to_s).join('__')}"
|
@@ -659,14 +654,9 @@ module ActiveRecord
|
|
659
654
|
end
|
660
655
|
end
|
661
656
|
join_array.each do |assoc_name|
|
662
|
-
# %%% Need to support {user: :profile}
|
663
657
|
next unless assoc_name.is_a?(Symbol)
|
664
658
|
|
665
|
-
table_alias =
|
666
|
-
shift_or_first(chain)
|
667
|
-
else
|
668
|
-
klass.table_name # ActiveRecord < 4.2 can't (yet) use the cool chains thing
|
669
|
-
end
|
659
|
+
table_alias = rel_dupe.brick_links[assoc_name.to_s]
|
670
660
|
_assoc_names[assoc_name] = [table_alias, klass]
|
671
661
|
end
|
672
662
|
end
|
@@ -677,26 +667,47 @@ module ActiveRecord
|
|
677
667
|
# Build the chain of JOINs going to the final destination HMT table
|
678
668
|
# (Usually just one JOIN, but could be many.)
|
679
669
|
hmt_assoc = hm
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
670
|
+
through_sources = []
|
671
|
+
# %%% Inverse path back to the original object -- not yet used, but soon
|
672
|
+
# will be leveraged in order to build links with multi-table-hop filters.
|
673
|
+
link_back = []
|
674
|
+
# Track polymorphic type field if necessary
|
675
|
+
if hm.source_reflection.options[:as]
|
676
|
+
poly_ft = [hm.source_reflection.inverse_of.foreign_type, hmt_assoc.source_reflection.class_name]
|
677
|
+
end
|
678
|
+
# link_back << hm.source_reflection.inverse_of.name
|
679
|
+
while hmt_assoc.options[:through] && (hmt_assoc = klass.reflect_on_association(hmt_assoc.options[:through]))
|
680
|
+
through_sources.unshift(hmt_assoc)
|
681
|
+
end
|
682
|
+
# Turn the last member of link_back into a foreign key
|
683
|
+
link_back << hmt_assoc.source_reflection.foreign_key
|
684
|
+
# If it's a HMT based on a HM -> HM, must JOIN the last table into the mix at the end
|
685
|
+
through_sources.push(hm.source_reflection) unless hm.source_reflection.belongs_to?
|
686
|
+
from_clause = +"#{through_sources.first.table_name} br_t0"
|
687
|
+
fk_col = through_sources.shift.foreign_key
|
688
|
+
|
685
689
|
idx = 0
|
686
690
|
bail_out = nil
|
687
|
-
|
691
|
+
through_sources.map do |a|
|
688
692
|
from_clause << "\n LEFT OUTER JOIN #{a.table_name} br_t#{idx += 1} "
|
689
693
|
from_clause << if (src_ref = a.source_reflection).macro == :belongs_to
|
694
|
+
(nm = hmt_assoc.source_reflection.inverse_of&.name)
|
695
|
+
# binding.pry unless nm
|
696
|
+
link_back << nm
|
690
697
|
"ON br_t#{idx}.id = br_t#{idx - 1}.#{a.foreign_key}"
|
691
698
|
elsif src_ref.options[:as]
|
692
699
|
"ON br_t#{idx}.#{src_ref.type} = '#{src_ref.active_record.name}'" + # "polymorphable_type"
|
693
700
|
" AND br_t#{idx}.#{src_ref.foreign_key} = br_t#{idx - 1}.id"
|
694
701
|
elsif src_ref.options[:source_type]
|
695
|
-
print "Skipping #{hm.name} --HMT-> #{hm.source_reflection.name} as it uses source_type which is not supported"
|
702
|
+
print "Skipping #{hm.name} --HMT-> #{hm.source_reflection.name} as it uses source_type which is not yet supported"
|
696
703
|
nix << k
|
697
704
|
bail_out = true
|
698
705
|
break
|
699
706
|
else # Standard has_many
|
707
|
+
# binding.pry unless (
|
708
|
+
nm = hmt_assoc.source_reflection.inverse_of&.name
|
709
|
+
# )
|
710
|
+
link_back << nm # if nm
|
700
711
|
"ON br_t#{idx}.#{a.foreign_key} = br_t#{idx - 1}.id"
|
701
712
|
end
|
702
713
|
link_back.unshift(a.source_reflection.name)
|
@@ -704,6 +715,7 @@ module ActiveRecord
|
|
704
715
|
end
|
705
716
|
next if bail_out
|
706
717
|
|
718
|
+
# puts "LINK BACK! #{k} : #{hm.table_name} #{link_back.map(&:to_s).join('.')}"
|
707
719
|
# count_column is determined from the originating HMT member
|
708
720
|
if (src_ref = hm.source_reflection).nil?
|
709
721
|
puts "*** Warning: Could not determine destination model for this HMT association in model #{klass.name}:\n has_many :#{hm.name}, through: :#{hm.options[:through]}"
|
@@ -711,8 +723,10 @@ module ActiveRecord
|
|
711
723
|
nix << k
|
712
724
|
next
|
713
725
|
elsif src_ref.macro == :belongs_to # Traditional HMT using an associative table
|
726
|
+
# binding.pry if link_back.length > 2
|
714
727
|
"br_t#{idx}.#{hm.foreign_key}"
|
715
728
|
else # A HMT that goes HM -> HM, something like Categories -> Products -> LineItems
|
729
|
+
# binding.pry if link_back.length > 2
|
716
730
|
"br_t#{idx}.#{src_ref.active_record.primary_key}"
|
717
731
|
end
|
718
732
|
else
|
@@ -776,8 +790,7 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
776
790
|
if (v_parts = v.first.split('.')).length == 1
|
777
791
|
s[v.first] = v.last
|
778
792
|
else
|
779
|
-
|
780
|
-
tbl_name = (field_tbl_names[v_parts.first][k1] ||= shift_or_first(chains[k1])).split('.').last
|
793
|
+
tbl_name = rel_dupe.brick_links[v_parts.first].split('.').last
|
781
794
|
s["#{tbl_name}.#{v_parts.last}"] = v.last
|
782
795
|
end
|
783
796
|
end
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -1052,6 +1052,40 @@ ActiveSupport.on_load(:active_record) do
|
|
1052
1052
|
end
|
1053
1053
|
end
|
1054
1054
|
|
1055
|
+
class ActiveRecord::Associations::JoinDependency
|
1056
|
+
if JoinBase.instance_method(:initialize).arity == 2 # Older ActiveRecord 4.x?
|
1057
|
+
def initialize(base, associations, joins)
|
1058
|
+
@alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(base.connection, joins)
|
1059
|
+
@alias_tracker.aliased_table_for(base.table_name, base.table_name) # Updates the count for base.table_name to 1
|
1060
|
+
tree = self.class.make_tree associations
|
1061
|
+
|
1062
|
+
# Provide a way to find the original relation that this tree is being used for
|
1063
|
+
# (so that we can maintain a list of links for all tables used in JOINs)
|
1064
|
+
if (relation = associations.instance_variable_get(:@relation))
|
1065
|
+
tree.instance_variable_set(:@relation, relation)
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
@join_root = JoinBase.new base, build(tree, base)
|
1069
|
+
@join_root.children.each { |child| construct_tables! @join_root, child }
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
else # For ActiveRecord 5.0 - 7.1
|
1073
|
+
|
1074
|
+
def initialize(base, table, associations, join_type = nil)
|
1075
|
+
tree = self.class.make_tree associations
|
1076
|
+
|
1077
|
+
# Provide a way to find the original relation that this tree is being used for
|
1078
|
+
# (so that we can maintain a list of links for all tables used in JOINs)
|
1079
|
+
if (relation = associations.instance_variable_get(:@relation))
|
1080
|
+
tree.instance_variable_set(:@relation, relation)
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
@join_root = JoinBase.new(base, table, build(tree, base))
|
1084
|
+
@join_type = join_type if join_type
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
end
|
1088
|
+
|
1055
1089
|
# First part of arel_table_type stuff:
|
1056
1090
|
# ------------------------------------
|
1057
1091
|
# (more found below)
|
@@ -1178,7 +1212,7 @@ if ActiveRecord.version < ::Gem::Version.new('5.2')
|
|
1178
1212
|
|
1179
1213
|
module Associations
|
1180
1214
|
# Specific to AR 4.2 - 5.1:
|
1181
|
-
if
|
1215
|
+
if self.const_defined?('JoinDependency') && JoinDependency.private_instance_methods.include?(:table_aliases_for)
|
1182
1216
|
class JoinDependency
|
1183
1217
|
private
|
1184
1218
|
|
@@ -1230,4 +1264,91 @@ if ActiveRecord.version < ::Gem::Version.new('5.2')
|
|
1230
1264
|
# rubocop:enable Style/CommentedKeyword
|
1231
1265
|
end
|
1232
1266
|
|
1267
|
+
module ActiveRecord
|
1268
|
+
module QueryMethods
|
1269
|
+
private
|
1270
|
+
|
1271
|
+
if private_instance_methods.include?(:build_join_query)
|
1272
|
+
alias _brick_build_join_query build_join_query
|
1273
|
+
def build_join_query(manager, buckets, *args)
|
1274
|
+
# %%% Better way to bring relation into the mix
|
1275
|
+
if (aj = buckets.fetch(:association_join, nil))
|
1276
|
+
aj.instance_variable_set(:@relation, self)
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
_brick_build_join_query(manager, buckets, *args)
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
else
|
1283
|
+
|
1284
|
+
alias _brick_select_association_list select_association_list
|
1285
|
+
def select_association_list(associations, stashed_joins = nil)
|
1286
|
+
result = _brick_select_association_list(associations, stashed_joins)
|
1287
|
+
result.instance_variable_set(:@relation, self)
|
1288
|
+
result
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
end
|
1292
|
+
|
1293
|
+
# require 'activerecord/associations/join_dependency'
|
1294
|
+
module Associations
|
1295
|
+
# For AR >= 4.2
|
1296
|
+
if self.const_defined?('JoinDependency')
|
1297
|
+
class JoinDependency
|
1298
|
+
private
|
1299
|
+
|
1300
|
+
# %%% Pretty much have to flat-out replace this guy (I think anyway)
|
1301
|
+
# Good with Rails 5.24 and 7 on this
|
1302
|
+
def build(associations, base_klass, root = nil, path = '')
|
1303
|
+
root ||= associations
|
1304
|
+
associations.map do |name, right|
|
1305
|
+
reflection = find_reflection base_klass, name
|
1306
|
+
reflection.check_validity!
|
1307
|
+
reflection.check_eager_loadable!
|
1308
|
+
|
1309
|
+
if reflection.polymorphic?
|
1310
|
+
raise EagerLoadPolymorphicError.new(reflection)
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
# %%% The path
|
1314
|
+
link_path = path.blank? ? name.to_s : path + ".#{name}"
|
1315
|
+
ja = JoinAssociation.new(reflection, build(right, reflection.klass, root, link_path))
|
1316
|
+
ja.instance_variable_set(:@link_path, link_path) # Make note on the JoinAssociation of its AR path
|
1317
|
+
ja.instance_variable_set(:@assocs, root)
|
1318
|
+
ja
|
1319
|
+
end
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
if JoinDependency.private_instance_methods.include?(:table_aliases_for)
|
1323
|
+
# No matter if it's older or newer Rails, now extend so that we can associate AR links to table_alias names
|
1324
|
+
alias _brick_table_aliases_for table_aliases_for
|
1325
|
+
def table_aliases_for(parent, node)
|
1326
|
+
result = _brick_table_aliases_for(parent, node)
|
1327
|
+
|
1328
|
+
# Capture the table alias name that was chosen
|
1329
|
+
link_path = node.instance_variable_get(:@link_path)
|
1330
|
+
if (relation = node.instance_variable_get(:@assocs)&.instance_variable_get(:@relation))
|
1331
|
+
relation.brick_links[link_path] = result.first.table_alias || result.first.table_name
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
result
|
1335
|
+
end
|
1336
|
+
else # Same idea but for Rails 7
|
1337
|
+
alias _brick_make_constraints make_constraints
|
1338
|
+
def make_constraints(parent, child, join_type)
|
1339
|
+
result = _brick_make_constraints(parent, child, join_type)
|
1340
|
+
|
1341
|
+
# Capture the table alias name that was chosen
|
1342
|
+
link_path = child.instance_variable_get(:@link_path)
|
1343
|
+
relation = child.instance_variable_get(:@assocs)&.instance_variable_get(:@relation)
|
1344
|
+
# binding.pry if relation
|
1345
|
+
relation.brick_links[link_path] = result.first.left.table_alias || result.first.left.table_name
|
1346
|
+
result
|
1347
|
+
end
|
1348
|
+
end
|
1349
|
+
end
|
1350
|
+
end
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
|
1233
1354
|
require 'brick/extensions'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.92
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|