brick 1.0.36 → 1.0.39

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: 6ef930474d4e1496812af0a626f57a2db1b05396c2dc46eb8f117c6fbf2f4df5
4
- data.tar.gz: 8847971321e1a6178b340ef6929298d2d33edb1a1918584c43d67edc5b844a39
3
+ metadata.gz: 965d31143248d85fd47cf2445a266fb9d26cc5eb814330cbdbfb37d50570b5a0
4
+ data.tar.gz: d4f070e1c01b3922a610a4385fde6f6b4f345892d68d6b872e1294a33f4b1e61
5
5
  SHA512:
6
- metadata.gz: cba480c932d00067c122b99d22f2633d8b26795295a4039a4c6ac014893ed0e4313ac33571cad06a880d9cbf426627e766c2b13514e7bf7b81093acc723aa425
7
- data.tar.gz: 75aa1e29cd0619bf9654df74a4f36625b1b703bd307b9f72439e4ce9e25f0b80bd9fb10b4fe6f2eadf70effcf28849e1a513c1745d48b31000d33e8948ab555c
6
+ metadata.gz: 70ea705efad428abb335e05569284caabe908c65efd679fffcd044894083626ca432366a65305bcd50506a7ca13169bac9cc2f7354728c3b8f23e4ed0aba7094
7
+ data.tar.gz: b61096e6deadf323cc8784bcf93ae5faf72eae02fef3059b002c57bac035b30858da73bb59bd2f0572168a90b39062645580cd120e1d78665f5c909258727ad8
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_record/version'
4
-
5
4
  # ActiveRecord before 4.0 didn't have #version
6
5
  unless ActiveRecord.respond_to?(:version)
7
6
  module ActiveRecord
@@ -11,6 +10,16 @@ unless ActiveRecord.respond_to?(:version)
11
10
  end
12
11
  end
13
12
 
13
+ require 'action_view'
14
+ # Older ActionView didn't have #version
15
+ unless ActionView.respond_to?(:version)
16
+ module ActionView
17
+ def self.version
18
+ ActionPack.version
19
+ end
20
+ end
21
+ end
22
+
14
23
  # In ActiveSupport older than 5.0, the duplicable? test tries to new up a BigDecimal,
15
24
  # and Ruby 2.6 and later deprecates #new. This removes the warning from BigDecimal.
16
25
  # This compatibility needs to be put into place in the application's "config/boot.rb"
@@ -204,7 +204,7 @@ module ActiveRecord
204
204
  assoc_name = CGI.escapeHTML(assoc_name.to_s)
205
205
  model_path = Rails.application.routes.url_helpers.send("#{model_underscore.tr('/', '_').pluralize}_path".to_sym)
206
206
  av_class = Class.new.extend(ActionView::Helpers::UrlHelper)
207
- av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('6.1')
207
+ av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('7')
208
208
  link = av_class.link_to(name, model_path)
209
209
  model_underscore == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
210
210
  end
@@ -552,7 +552,7 @@ Module.class_exec do
552
552
  # return my_const
553
553
  end
554
554
 
555
- relations = ::Brick.instance_variable_get(:@relations)[ActiveRecord::Base.connection_pool.object_id] || {}
555
+ relations = ::Brick.relations
556
556
  # puts "ON OBJECT: #{args.inspect}" if self.module_parent == Object
557
557
  result = if ::Brick.enable_controllers? && class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
558
558
  # Otherwise now it's up to us to fill in the gaps
@@ -627,8 +627,8 @@ Module.class_exec do
627
627
  # module_prefixes.unshift('') unless module_prefixes.first.blank?
628
628
  # candidate_file = Rails.root.join('app/models' + module_prefixes.map(&:underscore).join('/') + '.rb')
629
629
  self._brick_const_missing(*args)
630
- elsif self != Object
631
- module_parent.const_missing(*args)
630
+ # elsif self != Object
631
+ # module_parent.const_missing(*args)
632
632
  else
633
633
  puts "MISSING! #{self.name} #{args.inspect} #{table_name}"
634
634
  self._brick_const_missing(*args)
@@ -1188,8 +1188,13 @@ module ActiveRecord::ConnectionHandling
1188
1188
  case ActiveRecord::Base.connection.adapter_name
1189
1189
  when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
1190
1190
  # schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1191
+ ar_smtn = if ActiveRecord::Base.respond_to?(:schema_migrations_table_name)
1192
+ ActiveRecord::Base.schema_migrations_table_name
1193
+ else
1194
+ 'schema_migrations'
1195
+ end
1191
1196
  ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1192
- ActiveRecord::Base.execute_sql(sql, ActiveRecord::Base.schema_migrations_table_name, ar_imtn).each do |r|
1197
+ ActiveRecord::Base.execute_sql(sql, ar_smtn, ar_imtn).each do |r|
1193
1198
  # If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
1194
1199
  # is the default schema, usually 'public'.
1195
1200
  schema_name = if ::Brick.config.schema_behavior[:multitenant]
@@ -50,23 +50,26 @@ module Brick
50
50
  # ====================================
51
51
  if ::Brick.enable_views?
52
52
  ActionView::LookupContext.class_exec do
53
+ # Used by Rails 5.0 and above
53
54
  alias :_brick_template_exists? :template_exists?
54
55
  def template_exists?(*args, **options)
55
- unless (is_template_exists = _brick_template_exists?(*args, **options))
56
- # Need to return true if we can fill in the blanks for a missing one
57
- # args will be something like: ["index", ["categories"]]
58
- args[1] = args[1].each_with_object([]) { |a, s| s.concat(a.split('/')) }
59
- args[1][args[1].length - 1] = args[1].last.singularize # Make sure the last item, defining the class name, is singular
60
- model = args[1].map(&:camelize).join('::').constantize
61
- if is_template_exists = model && (
62
- ['index', 'show'].include?(args.first) || # Everything has index and show
56
+ _brick_template_exists?(*args, **options) || set_brick_model(args)
57
+ end
58
+
59
+ def set_brick_model(find_args)
60
+ # Need to return true if we can fill in the blanks for a missing one
61
+ # args will be something like: ["index", ["categories"]]
62
+ find_args[1] = find_args[1].each_with_object([]) { |a, s| s.concat(a.split('/')) }
63
+ if (class_name = find_args[1].last&.singularize)
64
+ find_args[1][find_args[1].length - 1] = class_name # Make sure the last item, defining the class name, is singular
65
+ if (model = find_args[1].map(&:camelize).join('::').constantize) && (
66
+ ['index', 'show'].include?(find_args.first) || # Everything has index and show
63
67
  # Only CUD stuff has create / update / destroy
64
- (!model.is_view? && ['new', 'create', 'edit', 'update', 'destroy'].include?(args.first))
68
+ (!model.is_view? && ['new', 'create', 'edit', 'update', 'destroy'].include?(find_args.first))
65
69
  )
66
70
  @_brick_model = model
67
71
  end
68
72
  end
69
- is_template_exists
70
73
  end
71
74
 
72
75
  def path_keys(hm_assoc, fk_name, obj_name, pk)
@@ -82,9 +85,13 @@ module Brick
82
85
 
83
86
  alias :_brick_find_template :find_template
84
87
  def find_template(*args, **options)
85
- return _brick_find_template(*args, **options) unless @_brick_model
88
+ unless (model_name = (
89
+ @_brick_model ||
90
+ (ActionView.version < ::Gem::Version.new('5.0') && args[1].is_a?(Array) ? set_brick_model(args) : nil)
91
+ )&.name)
92
+ return _brick_find_template(*args, **options)
93
+ end
86
94
 
87
- model_name = @_brick_model.name
88
95
  pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(model_name, nil))
89
96
  obj_name = model_name.split('::').last.underscore
90
97
  path_obj_name = model_name.underscore.tr('/', '_')
@@ -141,9 +148,14 @@ module Brick
141
148
  display: none;
142
149
  }
143
150
 
151
+ #headerTop {
152
+ position: sticky;
153
+ top: 0px;
154
+ background-color: white;
155
+ z-index: 1;
156
+ }
144
157
  table {
145
158
  border-collapse: collapse;
146
- margin: 25px 0;
147
159
  font-size: 0.9em;
148
160
  font-family: sans-serif;
149
161
  min-width: 400px;
@@ -255,6 +267,7 @@ end %>"
255
267
  var schemaSelect = document.getElementById(\"schema\");
256
268
  var tblSelect = document.getElementById(\"tbl\");
257
269
  var brickSchema;
270
+ var #{table_name}HtColumns;
258
271
 
259
272
  // This PageTransitionEvent fires when the page first loads, as well as after any other history
260
273
  // transition such as when using the browser's Back and Forward buttons.
@@ -316,6 +329,42 @@ function changeout(href, param, value, trimAfter) {
316
329
  params[param] = value;
317
330
  return hrefParts[0] + \"?\" + Object.keys(params).reduce(function (s, v) { s.push(v + \"=\" + params[v]); return s; }, []).join(\"&\");
318
331
  }
332
+
333
+ // Snag first TR for sticky header
334
+ var grid = document.getElementById(\"#{table_name}\");
335
+ #{table_name}HtColumns = grid && [grid.getElementsByTagName(\"TR\")[0]];
336
+ var headerTop = document.getElementById(\"headerTop\");
337
+ function setHeaderSizes() {
338
+ // console.log(\"start\");
339
+ // See if the headerTop is already populated
340
+ // %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
341
+ headerTop.innerHTML = \"\"; // %%% Would love to not have to clear it out like this every time! (Currently doing this to support resize events.)
342
+ var isEmpty = headerTop.childElementCount === 0;
343
+ // Set up proper sizings of sticky column header
344
+ var node;
345
+ for (var j = 0; j < #{table_name}HtColumns.length; ++j) {
346
+ var row = #{table_name}HtColumns[j];
347
+ var tr = isEmpty ? document.createElement(\"TR\") : headerTop.childNodes[j];
348
+ tr.innerHTML = row.innerHTML.trim();
349
+ // Match up widths from the original column headers
350
+ for (var i = 0; i < row.childNodes.length; ++i) {
351
+ node = row.childNodes[i];
352
+ if (node.nodeType === 1) {
353
+ var style = tr.childNodes[i].style;
354
+ style.minWidth = style.maxWidth = getComputedStyle(node).width;
355
+ }
356
+ }
357
+ if (isEmpty) headerTop.appendChild(tr);
358
+ }
359
+ grid.style.marginTop = \"-\" + getComputedStyle(headerTop).height;
360
+ // console.log(\"end\");
361
+ }
362
+ if (headerTop) {
363
+ setHeaderSizes();
364
+ window.addEventListener('resize', function(event) {
365
+ setHeaderSizes();
366
+ }, true);
367
+ }
319
368
  </script>"
320
369
  inline = case args.first
321
370
  when 'index'
@@ -415,13 +464,13 @@ function changeout(href, param, value, trimAfter) {
415
464
  end
416
465
  # %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
417
466
  # (where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %>)
418
- x = "#{css}
467
+ "#{css}
419
468
  <p style=\"color: green\"><%= notice %></p>#{"
420
469
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
421
470
  <select id=\"tbl\">#{table_options}</select>
422
471
  <h1>#{model_plural = model_name.pluralize}</h1>#{template_link}<%
423
- if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
424
- relation.fetch(:description, nil) %><br><%
472
+ if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
473
+ description %><br><%
425
474
  end
426
475
  if @_brick_params&.present? %>
427
476
  <% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
@@ -435,16 +484,18 @@ x = "#{css}
435
484
  end %>
436
485
  (<%= link_to 'See all #{model_plural.split('::').last}', #{path_obj_name.pluralize}_path %>)
437
486
  <% end %>
487
+ <br>
488
+ <table id=\"headerTop\">
438
489
  <table id=\"#{table_name}\">
439
- <thead><tr>#{'<th></th>' if pk.present?}
440
- <% col_order = []
490
+ <thead><tr>#{'<th></th>' if pk.present?}<%
491
+ col_order = []
441
492
  @#{table_name}.columns.each do |col|
442
493
  col_name = col.name
443
494
  next if (#{(pk || []).inspect}.include?(col_name) && col.type == :integer && !bts.key?(col_name)) ||
444
495
  ::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
445
496
 
446
- col_order << col_name %>
447
- <th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>><%
497
+ col_order << col_name
498
+ %><th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>><%
448
499
  if (bt = bts[col_name]) %>
449
500
  BT <%
450
501
  bt[1].each do |bt_pair| %><%=
@@ -453,11 +504,11 @@ x = "#{css}
453
504
  else %><%=
454
505
  col_name %><%
455
506
  end
456
- %></th>
457
- <% end %>
458
- <%# Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name %>
459
- #{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>\n" }.join}
460
- </tr></thead>
507
+ %></th><%
508
+ end
509
+ # Consider getting the name from the association -- h.first.name -- if a more \"friendly\" alias should be used for a screwy table name
510
+ %>#{hms_headers.map { |h| "<th>#{h[1]} <%= link_to('#{h[2]}', #{h.first.klass.name.underscore.tr('/', '_').pluralize}_path) %></th>" }.join
511
+ }</tr></thead>
461
512
 
462
513
  <tbody>
463
514
  <% @#{table_name}.each do |#{obj_name}| %>
@@ -495,19 +546,18 @@ x = "#{css}
495
546
 
496
547
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
497
548
  #{script}"
498
- puts x
499
- x
500
549
  when 'show', 'update'
501
550
  "#{css}
502
551
  <p style=\"color: green\"><%= notice %></p>#{"
503
552
  <select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
504
553
  <select id=\"tbl\">#{table_options}</select>
505
554
  <h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
506
- if (relation = Brick.relations[#{model_name}.table_name])[:description] %><%=
507
- relation.fetch(:description, nil) %><br><%
555
+ if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
556
+ description %><br><%
508
557
  end
509
558
  %><%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
510
559
  <% if obj %>
560
+ <br><br>
511
561
  <%= # path_options = [obj.#{pk}]
512
562
  # path_options << { '_brick_schema': } if
513
563
  # url = send(:#{model_name.underscore}_path, obj.#{pk})
@@ -519,7 +569,7 @@ end
519
569
  <tr>
520
570
  <% next if (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
521
571
  ::Brick.config.metadata_columns.include?(k) %>
522
- <th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe unless col.comment.blank? %>>
572
+ <th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>>
523
573
  <% has_fields = true
524
574
  if (bt = bts[k])
525
575
  # Add a final member in this array with descriptive options to be used in <select> drop-downs
data/lib/brick/util.rb CHANGED
@@ -5,7 +5,7 @@ module Brick
5
5
  module Util
6
6
  # ===================================
7
7
  # Epic require patch
8
- def self._patch_require(module_filename, folder_matcher, search_text, replacement_text, autoload_symbol = nil, is_bundler = false)
8
+ def self._patch_require(module_filename, folder_matcher, replacements, autoload_symbol = nil, is_bundler = false)
9
9
  mod_name_parts = module_filename.split('.')
10
10
  extension = case mod_name_parts.last
11
11
  when 'rb', 'so', 'o'
@@ -28,10 +28,13 @@ module Brick
28
28
  Dir.mkdir(new_part) unless Dir.exist?(new_part)
29
29
  new_part
30
30
  end
31
- if ::Brick::Util._write_patched(folder_matcher, module_filename, extension, custom_require_dir, nil, search_text, replacement_text) &&
31
+ if ::Brick::Util._write_patched(folder_matcher, module_filename, extension, custom_require_dir, nil, replacements) &&
32
32
  !alp.include?(custom_require_dir)
33
33
  alp.unshift(custom_require_dir)
34
34
  end
35
+ # require 'pry-byebug'
36
+ # binding.pry
37
+ # z = 10
35
38
  elsif is_bundler
36
39
  puts "Bundler hack"
37
40
  require 'pry-byebug'
@@ -56,13 +59,13 @@ module Brick
56
59
  define_method(:require) do |name|
57
60
  puts name if name.to_s.include?('cucu')
58
61
  if (require_override = ::Brick::Util.instance_variable_get(:@_require_overrides)[name])
59
- extension, folder_matcher, search_text, replacement_text, autoload_symbol = require_override
62
+ extension, folder_matcher, replacements, autoload_symbol = require_override
60
63
  patched_filename = "/patched_#{name.tr('/', '_')}#{extension}"
61
64
  if $LOADED_FEATURES.find { |f| f.end_with?(patched_filename) }
62
65
  false
63
66
  else
64
67
  is_replaced = false
65
- if (replacement_path = ::Brick::Util._write_patched(folder_matcher, name, extension, ::Brick::Util._custom_require_dir, patched_filename, search_text, replacement_text))
68
+ if (replacement_path = ::Brick::Util._write_patched(folder_matcher, name, extension, ::Brick::Util._custom_require_dir, patched_filename, replacements))
66
69
  is_replaced = Kernel.send(:orig_require, replacement_path)
67
70
  elsif replacement_path.nil?
68
71
  puts "Couldn't find #{name} to require it!"
@@ -75,7 +78,7 @@ module Brick
75
78
  end
76
79
  end
77
80
  end
78
- require_overrides[module_filename] = [extension, folder_matcher, search_text, replacement_text, autoload_symbol]
81
+ require_overrides[module_filename] = [extension, folder_matcher, replacements, autoload_symbol]
79
82
  end
80
83
  end
81
84
 
@@ -94,7 +97,7 @@ module Brick
94
97
 
95
98
  # Returns the full path to the replaced filename, or
96
99
  # false if the file already exists, and nil if it was unable to write anything.
97
- def self._write_patched(folder_matcher, name, extension, dir, patched_filename, search_text, replacement_text)
100
+ def self._write_patched(folder_matcher, name, extension, dir, patched_filename, replacements)
98
101
  # See if our replacement file might already exist for some reason
99
102
  name = +"/#{name}" unless name.start_with?('/')
100
103
  name << extension unless name.end_with?(extension)
@@ -111,9 +114,13 @@ module Brick
111
114
  break if path.include?(folder_matcher) && (orig_as = File.open(orig_path))
112
115
  end
113
116
  puts [folder_matcher, name].inspect
114
- if (orig_text = orig_as&.read)
115
- File.open(replacement_path, 'w') do |replacement|
116
- num_written = replacement.write(orig_text.gsub(search_text, replacement_text))
117
+ if (updated_text = orig_as&.read)
118
+ File.open(replacement_path, 'w') do |replaced_file|
119
+ replacements = [replacements] unless replacements.first.is_a?(Array)
120
+ replacements.each do |search_text, replacement_text|
121
+ updated_text.gsub!(search_text, replacement_text)
122
+ end
123
+ num_written = replaced_file.write(updated_text)
117
124
  end
118
125
  orig_as.close
119
126
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 36
8
+ TINY = 39
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'brick/compatibility'
4
4
 
5
- # Allow ActiveRecord 4.0 and 4.1 to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep"
5
+ # Allow ActiveRecord 4.2.7 and older to work with newer Ruby (>= 2.4) by avoiding a "stack level too deep"
6
6
  # error when ActiveSupport tries to smarten up Numeric by messing with Fixnum and Bignum at the end of:
7
7
  # activesupport-4.0.13/lib/active_support/core_ext/numeric/conversions.rb
8
- if ActiveRecord.version < ::Gem::Version.new('4.2') &&
8
+ if ActiveRecord.version < ::Gem::Version.new('4.2.8') &&
9
9
  ActiveRecord.version > ::Gem::Version.new('3.2') &&
10
10
  Object.const_defined?('Integer') && Integer.superclass.name == 'Numeric'
11
11
  class OurFixnum < Integer; end
@@ -31,25 +31,78 @@ if (ruby_version = ::Gem::Version.new(RUBY_VERSION)) >= ::Gem::Version.new('2.7'
31
31
  # Remove circular reference for "now"
32
32
  ::Brick::Util._patch_require(
33
33
  'active_support/values/time_zone.rb', '/activesupport',
34
- ' def parse(str, now=now)',
35
- ' def parse(str, now=now())'
34
+ [' def parse(str, now=now)',
35
+ ' def parse(str, now=now())']
36
36
  )
37
37
  # Remove circular reference for "reflection" for ActiveRecord 3.1
38
38
  if ActiveRecord.version >= ::Gem::Version.new('3.1')
39
39
  ::Brick::Util._patch_require(
40
40
  'active_record/associations/has_many_association.rb', '/activerecord',
41
- 'reflection = reflection)',
42
- 'reflection = reflection())',
41
+ ['reflection = reflection)',
42
+ 'reflection = reflection())'],
43
43
  :HasManyAssociation # Make sure the path for this guy is available to be autoloaded
44
44
  )
45
45
  end
46
46
  end
47
47
 
48
+ # Add left_outer_join! to Associations::JoinDependency and Relation::QueryMethods
49
+ if ActiveRecord.version < ::Gem::Version.new('5')
50
+ is_add_left_outer_join = true
51
+ ::Brick::Util._patch_require(
52
+ 'active_record/associations/join_dependency.rb', '/activerecord', # /associations
53
+ ["def join_constraints(outer_joins)
54
+ joins = join_root.children.flat_map { |child|
55
+ make_inner_joins join_root, child
56
+ }",
57
+ "def join_constraints(outer_joins, join_type)
58
+ joins = join_root.children.flat_map { |child|
59
+
60
+ if join_type == Arel::Nodes::OuterJoin
61
+ make_left_outer_joins join_root, child
62
+ else
63
+ make_inner_joins join_root, child
64
+ end
65
+ }"],
66
+ :JoinDependency # This one is in an "eager_autoload do" -- so how to handle it?
67
+ )
68
+
69
+ # Three changes all in the same file, query_methods.rb:
70
+ ::Brick::Util._patch_require(
71
+ 'active_record/relation/query_methods.rb', '/activerecord',
72
+ [
73
+ # Change 1 - Line 904
74
+ ['build_joins(arel, joins_values.flatten) unless joins_values.empty?',
75
+ "build_joins(arel, joins_values.flatten) unless joins_values.empty?
76
+ build_left_outer_joins(arel, left_outer_joins_values.flatten) unless left_outer_joins_values.empty?"
77
+ ],
78
+ # Change 2 - Line 992
79
+ ["raise 'unknown class: %s' % join.class.name
80
+ end
81
+ end",
82
+ "raise 'unknown class: %s' % join.class.name
83
+ end
84
+ end
85
+
86
+ build_join_query(manager, buckets, Arel::Nodes::InnerJoin)
87
+ end
88
+
89
+ def build_join_query(manager, buckets, join_type)"
90
+ ],
91
+ # Change 3 - Line 1012
92
+ ['join_infos = join_dependency.join_constraints stashed_association_joins',
93
+ 'join_infos = join_dependency.join_constraints stashed_association_joins, join_type'
94
+ ]
95
+ ],
96
+ :QueryMethods
97
+ )
98
+ end
99
+
100
+
48
101
  # puts ::Brick::Util._patch_require(
49
102
  # 'cucumber/cli/options.rb', '/cucumber/cli/options', # /cli/options
50
- # ' def extract_environment_variables',
51
- # " def extract_environment_variables\n
52
- # puts 'Patch test!'"
103
+ # [' def extract_environment_variables',
104
+ # " def extract_environment_variables\n
105
+ # puts 'Patch test!'"]
53
106
  # ).inspect
54
107
 
55
108
  # An ActiveRecord extension that uses INFORMATION_SCHEMA views to reflect on all
@@ -295,10 +348,11 @@ module Brick
295
348
 
296
349
  relations = ::Brick.relations
297
350
  if (ars = ::Brick.config.additional_references) || ::Brick.config.polymorphics
351
+ is_optional = ActiveRecord.version >= ::Gem::Version.new('5.0')
298
352
  if ars
299
353
  ars.each do |ar|
300
354
  fk = ar.length < 5 ? [nil, +ar[0], ar[1], nil, +ar[2]] : [ar[0], +ar[1], ar[2], ar[3], +ar[4], ar[5]]
301
- ::Brick._add_bt_and_hm(fk, relations, false, true)
355
+ ::Brick._add_bt_and_hm(fk, relations, false, is_optional)
302
356
  end
303
357
  end
304
358
  if (polys = ::Brick.config.polymorphics)
@@ -311,7 +365,7 @@ module Brick
311
365
  v ||= ActiveRecord::Base.execute_sql("SELECT DISTINCT #{poly}_type AS typ FROM #{table_name}").each_with_object([]) { |result, s| s << result['typ'] if result['typ'] }
312
366
  v.each do |type|
313
367
  if relations.key?(primary_table = type.underscore.pluralize)
314
- ::Brick._add_bt_and_hm([nil, table_name, poly, nil, primary_table, "(brick) #{table_name}_#{poly}"], relations, true, true)
368
+ ::Brick._add_bt_and_hm([nil, table_name, poly, nil, primary_table, "(brick) #{table_name}_#{poly}"], relations, true, is_optional)
315
369
  else
316
370
  missing_stis[primary_table] = type unless ::Brick.existing_stis.key?(type)
317
371
  end
@@ -414,7 +468,19 @@ end
414
468
 
415
469
  require 'brick/version_number'
416
470
 
471
+ # Older versions of ActiveRecord would only show more serious error information from "panic" level, which is
472
+ # a level only available in Postgres 12 and older. This patch will allow older and newer versions of Postgres
473
+ # to work along with fairly old versions of Rails.
474
+ if Object.const_defined?('PG::VERSION') && ActiveRecord.version < ::Gem::Version.new('4.2.6')
475
+ ::Brick::Util._patch_require(
476
+ 'active_record/connection_adapters/postgresql_adapter.rb', '/activerecord', ["'panic'", "'error'"]
477
+ )
478
+ end
479
+
417
480
  require 'active_record'
481
+ require 'active_record/relation'
482
+ require 'active_record/relation/query_methods' if is_add_left_outer_join
483
+
418
484
  # Major compatibility fixes for ActiveRecord < 4.2
419
485
  # ================================================
420
486
  ActiveSupport.on_load(:active_record) do
@@ -633,6 +699,62 @@ ActiveSupport.on_load(:active_record) do
633
699
  end
634
700
  end
635
701
  end
702
+
703
+ if is_add_left_outer_join
704
+ # Final pieces for left_outer_joins support, which was derived from this commit:
705
+ # https://github.com/rails/rails/commit/3f46ef1ddab87482b730a3f53987e04308783d8b
706
+ module Associations
707
+ class JoinDependency
708
+ def make_left_outer_joins(parent, child)
709
+ tables = child.tables
710
+ join_type = Arel::Nodes::OuterJoin
711
+ info = make_constraints parent, child, tables, join_type
712
+
713
+ [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
714
+ end
715
+ end
716
+ end
717
+ module Querying
718
+ delegate :left_outer_joins, to: :all
719
+ end
720
+ class Relation
721
+ MULTI_VALUE_METHODS = MULTI_VALUE_METHODS + [:left_outer_joins] unless MULTI_VALUE_METHODS.include?(:left_outer_joins)
722
+ end
723
+ module QueryMethods
724
+ attr_writer :left_outer_joins_values
725
+ def left_outer_joins_values
726
+ @left_outer_joins_values ||= []
727
+ end
728
+
729
+ def left_outer_joins(*args)
730
+ check_if_method_has_arguments!(:left_outer_joins, args)
731
+
732
+ args.compact!
733
+ args.flatten!
734
+
735
+ spawn.left_outer_joins!(*args)
736
+ end
737
+
738
+ def left_outer_joins!(*args) # :nodoc:
739
+ self.left_outer_joins_values += args
740
+ self
741
+ end
742
+
743
+ def build_left_outer_joins(manager, outer_joins)
744
+ buckets = outer_joins.group_by do |join|
745
+ case join
746
+ when Hash, Symbol, Array
747
+ :association_join
748
+ else
749
+ raise ArgumentError, 'only Hash, Symbol and Array are allowed'
750
+ end
751
+ end
752
+
753
+ build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
754
+ end
755
+ end
756
+ end
757
+ # (End of left_outer_joins support)
636
758
  end
637
759
  end
638
760
 
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.36
4
+ version: 1.0.39
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-06-26 00:00:00.000000000 Z
11
+ date: 2022-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
19
+ version: '4.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7.1'
22
+ version: '7.2'
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: '3.0'
29
+ version: '4.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7.1'
32
+ version: '7.2'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: appraisal
35
35
  requirement: !ruby/object:Gem::Requirement