brick 1.0.37 → 1.0.40
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 +10 -1
- data/lib/brick/extensions.rb +15 -6
- data/lib/brick/frameworks/rails/engine.rb +31 -19
- data/lib/brick/tasks/orphans.rake +57 -0
- data/lib/brick/util.rb +16 -9
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +138 -11
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf29d4af64b65c01ae68df45762b816403a1ebc0035e1221552f249ff3ba2ce9
|
4
|
+
data.tar.gz: 076cdb672d7c2137cc74421467d72491e9ea89751fab32015f427158fc367b45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce17038567ddd9d6d9d9dce6eb71fd50612d167b56351898ef9b3f9441d1a7ef3ee4ec3a57f3f24e613829e6c8a2f59517fc0d4e9266f11166b92821310b0c06
|
7
|
+
data.tar.gz: 6a7bb38b009853594a8bf1ab28489bbc92d6300fcd0f8497c7950e81c6a62a4c6da2bd65840f93bd7afea40153727cb93914529120ecf9b0dceca39b21fef880
|
data/lib/brick/compatibility.rb
CHANGED
@@ -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"
|
data/lib/brick/extensions.rb
CHANGED
@@ -70,7 +70,11 @@ module ActiveRecord
|
|
70
70
|
def self._brick_primary_key(relation = nil)
|
71
71
|
return instance_variable_get(:@_brick_primary_key) if instance_variable_defined?(:@_brick_primary_key)
|
72
72
|
|
73
|
-
pk =
|
73
|
+
pk = begin
|
74
|
+
primary_key.is_a?(String) ? [primary_key] : primary_key || []
|
75
|
+
rescue
|
76
|
+
[]
|
77
|
+
end
|
74
78
|
# Just return [] if we're missing any part of the primary key. (PK is usually just "id")
|
75
79
|
if relation && pk.present?
|
76
80
|
@_brick_primary_key ||= pk.any? { |pk_part| !relation[:cols].key?(pk_part) } ? [] : pk
|
@@ -204,7 +208,7 @@ module ActiveRecord
|
|
204
208
|
assoc_name = CGI.escapeHTML(assoc_name.to_s)
|
205
209
|
model_path = Rails.application.routes.url_helpers.send("#{model_underscore.tr('/', '_').pluralize}_path".to_sym)
|
206
210
|
av_class = Class.new.extend(ActionView::Helpers::UrlHelper)
|
207
|
-
av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('
|
211
|
+
av_class.extend(ActionView::Helpers::TagHelper) if ActionView.version < ::Gem::Version.new('7')
|
208
212
|
link = av_class.link_to(name, model_path)
|
209
213
|
model_underscore == assoc_name ? link : "#{assoc_name}-#{link}".html_safe
|
210
214
|
end
|
@@ -552,7 +556,7 @@ Module.class_exec do
|
|
552
556
|
# return my_const
|
553
557
|
end
|
554
558
|
|
555
|
-
relations = ::Brick.
|
559
|
+
relations = ::Brick.relations
|
556
560
|
# puts "ON OBJECT: #{args.inspect}" if self.module_parent == Object
|
557
561
|
result = if ::Brick.enable_controllers? && class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
|
558
562
|
# Otherwise now it's up to us to fill in the gaps
|
@@ -627,8 +631,8 @@ Module.class_exec do
|
|
627
631
|
# module_prefixes.unshift('') unless module_prefixes.first.blank?
|
628
632
|
# candidate_file = Rails.root.join('app/models' + module_prefixes.map(&:underscore).join('/') + '.rb')
|
629
633
|
self._brick_const_missing(*args)
|
630
|
-
elsif self != Object
|
631
|
-
|
634
|
+
# elsif self != Object
|
635
|
+
# module_parent.const_missing(*args)
|
632
636
|
else
|
633
637
|
puts "MISSING! #{self.name} #{args.inspect} #{table_name}"
|
634
638
|
self._brick_const_missing(*args)
|
@@ -1188,8 +1192,13 @@ module ActiveRecord::ConnectionHandling
|
|
1188
1192
|
case ActiveRecord::Base.connection.adapter_name
|
1189
1193
|
when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
|
1190
1194
|
# schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
1195
|
+
ar_smtn = if ActiveRecord::Base.respond_to?(:schema_migrations_table_name)
|
1196
|
+
ActiveRecord::Base.schema_migrations_table_name
|
1197
|
+
else
|
1198
|
+
'schema_migrations'
|
1199
|
+
end
|
1191
1200
|
ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
|
1192
|
-
ActiveRecord::Base.execute_sql(sql,
|
1201
|
+
ActiveRecord::Base.execute_sql(sql, ar_smtn, ar_imtn).each do |r|
|
1193
1202
|
# If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
|
1194
1203
|
# is the default schema, usually 'public'.
|
1195
1204
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
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
|
-
|
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('/', '_')
|
@@ -462,8 +469,8 @@ if (headerTop) {
|
|
462
469
|
<select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
|
463
470
|
<select id=\"tbl\">#{table_options}</select>
|
464
471
|
<h1>#{model_plural = model_name.pluralize}</h1>#{template_link}<%
|
465
|
-
if (relation = Brick.relations[#{model_name}.table_name])
|
466
|
-
|
472
|
+
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
473
|
+
description %><br><%
|
467
474
|
end
|
468
475
|
if @_brick_params&.present? %>
|
469
476
|
<% if @_brick_params.length == 1 # %%% Does not yet work with composite keys
|
@@ -488,7 +495,7 @@ if (headerTop) {
|
|
488
495
|
::Brick.config.metadata_columns.include?(col_name) || poly_cols.include?(col_name)
|
489
496
|
|
490
497
|
col_order << col_name
|
491
|
-
%><th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe
|
498
|
+
%><th<%= \" title = \\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>><%
|
492
499
|
if (bt = bts[col_name]) %>
|
493
500
|
BT <%
|
494
501
|
bt[1].each do |bt_pair| %><%=
|
@@ -522,6 +529,7 @@ if (headerTop) {
|
|
522
529
|
# 0..62 because Postgres column names are limited to 63 characters
|
523
530
|
#{obj_name}, (descrips = @_brick_bt_descrip[bt.first][bt_class])[0..-2].map { |z| #{obj_name}.send(z.last[0..62]) }, (bt_id_col = descrips.last)
|
524
531
|
)
|
532
|
+
bt_txt ||= \"<< Orphaned ID: #\{val} >>\" if val
|
525
533
|
bt_id = #{obj_name}.send(*bt_id_col) if bt_id_col&.present? %>
|
526
534
|
<%= bt_id ? link_to(bt_txt, send(\"#\{bt_class.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, bt_id)) : bt_txt %>
|
527
535
|
<%#= Previously was: bt_obj = bt[1].first.first.find_by(bt[2] => val); link_to(bt_obj.brick_descrip, send(\"#\{bt[1].first.first.name.underscore\}_path\".to_sym, bt_obj.send(bt[1].first.first.primary_key.to_sym))) if bt_obj %>
|
@@ -545,8 +553,8 @@ if (headerTop) {
|
|
545
553
|
<select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
|
546
554
|
<select id=\"tbl\">#{table_options}</select>
|
547
555
|
<h1>#{model_name}: <%= (obj = @#{obj_name})&.brick_descrip || controller_name %></h1><%
|
548
|
-
if (relation = Brick.relations[#{model_name}.table_name])
|
549
|
-
|
556
|
+
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
557
|
+
description %><br><%
|
550
558
|
end
|
551
559
|
%><%= link_to '(See all #{obj_name.pluralize})', #{path_obj_name.pluralize}_path %>
|
552
560
|
<% if obj %>
|
@@ -562,7 +570,7 @@ end
|
|
562
570
|
<tr>
|
563
571
|
<% next if (#{(pk || []).inspect}.include?(k) && !bts.key?(k)) ||
|
564
572
|
::Brick.config.metadata_columns.include?(k) %>
|
565
|
-
<th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe
|
573
|
+
<th class=\"show-field\"<%= \" title = \\\"#\{col.comment}\\\"\".html_safe if col.respond_to?(:comment) && !col.comment.blank? %>>
|
566
574
|
<% has_fields = true
|
567
575
|
if (bt = bts[k])
|
568
576
|
# Add a final member in this array with descriptive options to be used in <select> drop-downs
|
@@ -603,7 +611,11 @@ end
|
|
603
611
|
html_options = { prompt: \"Select #\{bt_name\}\" }
|
604
612
|
html_options[:class] = 'dimmed' unless val %>
|
605
613
|
<%= f.select k.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options %>
|
606
|
-
<%= bt_obj = bt_class&.find_by(bt_pair[1] => val)
|
614
|
+
<%= if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
|
615
|
+
link_to('⇛', send(\"#\{bt_class.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, bt_obj.send(bt_class.primary_key.to_sym)), { class: 'show-arrow' })
|
616
|
+
elsif val
|
617
|
+
\"Orphaned ID: #\{val}\"
|
618
|
+
end %>
|
607
619
|
<% else case #{model_name}.column_for_attribute(k).type
|
608
620
|
when :string, :text %>
|
609
621
|
<% if is_bcrypt?(val) # || .readonly? %>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if Object.const_defined?('::Rake::TaskManager')
|
4
|
+
namespace :brick do
|
5
|
+
desc 'Find any seemingly-orphaned records'
|
6
|
+
task orphans: :environment do
|
7
|
+
def class_pk(dotted_name, multitenant)
|
8
|
+
Object.const_get((multitenant ? [dotted_name.split('.').last] : dotted_name.split('.')).map { |nm| "::#{nm.singularize.camelize}" }.join).primary_key
|
9
|
+
end
|
10
|
+
|
11
|
+
schema_list = ((multi = ::Brick.config.schema_behavior[:multitenant]) && ::Brick.db_schemas.keys.sort) || []
|
12
|
+
if schema_list.length > 1
|
13
|
+
require 'fancy_gets'
|
14
|
+
include FancyGets
|
15
|
+
schema = gets_list(
|
16
|
+
list: schema_list,
|
17
|
+
chosen: multi[:schema_to_analyse]
|
18
|
+
)
|
19
|
+
elsif schema_list.length.positive?
|
20
|
+
schema = schema_list.first
|
21
|
+
end
|
22
|
+
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema) if schema
|
23
|
+
orphans = +''
|
24
|
+
::Brick.relations.each do |k, v|
|
25
|
+
next if v.key?(:isView) || ::Brick.config.exclude_tables.include?(k) ||
|
26
|
+
!(pri_pk = v[:pkey].values.first&.first) ||
|
27
|
+
!(pri_pk = class_pk(k, multi))
|
28
|
+
v[:fks].each do |k1, v1|
|
29
|
+
next if v1[:is_bt] ||
|
30
|
+
!(for_rel = ::Brick.relations.fetch(v1[:inverse_table], nil)) ||
|
31
|
+
v1[:inverse]&.key?(:polymorphic) ||
|
32
|
+
!(for_pk = for_rel.fetch(:pkey, nil)&.values&.first&.first) ||
|
33
|
+
!(for_pk = class_pk(v1[:inverse_table], multi))
|
34
|
+
begin
|
35
|
+
ActiveRecord::Base.execute_sql(
|
36
|
+
"SELECT DISTINCT frn.#{v1[:fk]} AS pri_id, frn.#{for_pk} AS fk_id
|
37
|
+
FROM #{v1[:inverse_table]} AS frn
|
38
|
+
LEFT OUTER JOIN #{k} AS pri ON pri.#{pri_pk} = frn.#{v1[:fk]}
|
39
|
+
WHERE frn.#{v1[:fk]} IS NOT NULL AND pri.#{pri_pk} IS NULL
|
40
|
+
ORDER BY 1, 2"
|
41
|
+
).each do |o|
|
42
|
+
orphans << "#{v1[:inverse_table]} #{o['fk_id']} refers to non-existant #{k} #{o['pri_id']}\n"
|
43
|
+
end
|
44
|
+
rescue StandardError => err
|
45
|
+
puts "Strange -- #{err.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
puts "For #{schema}:\n#{'=' * (schema.length + 5)}" if schema
|
50
|
+
if orphans.blank?
|
51
|
+
puts "No orphans!"
|
52
|
+
else
|
53
|
+
print orphans
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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 (
|
115
|
-
File.open(replacement_path, 'w') do |
|
116
|
-
|
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
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'brick/compatibility'
|
4
4
|
|
5
|
-
# Allow ActiveRecord 4.
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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,
|
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,
|
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,24 @@ 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
|
+
|
484
|
+
# Rake tasks
|
485
|
+
class Railtie < Rails::Railtie
|
486
|
+
Dir.glob("#{File.expand_path(__dir__)}/brick/tasks/**/*.rake").each { |task| load task }
|
487
|
+
end
|
488
|
+
|
418
489
|
# Major compatibility fixes for ActiveRecord < 4.2
|
419
490
|
# ================================================
|
420
491
|
ActiveSupport.on_load(:active_record) do
|
@@ -633,6 +704,62 @@ ActiveSupport.on_load(:active_record) do
|
|
633
704
|
end
|
634
705
|
end
|
635
706
|
end
|
707
|
+
|
708
|
+
if is_add_left_outer_join
|
709
|
+
# Final pieces for left_outer_joins support, which was derived from this commit:
|
710
|
+
# https://github.com/rails/rails/commit/3f46ef1ddab87482b730a3f53987e04308783d8b
|
711
|
+
module Associations
|
712
|
+
class JoinDependency
|
713
|
+
def make_left_outer_joins(parent, child)
|
714
|
+
tables = child.tables
|
715
|
+
join_type = Arel::Nodes::OuterJoin
|
716
|
+
info = make_constraints parent, child, tables, join_type
|
717
|
+
|
718
|
+
[info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
|
719
|
+
end
|
720
|
+
end
|
721
|
+
end
|
722
|
+
module Querying
|
723
|
+
delegate :left_outer_joins, to: :all
|
724
|
+
end
|
725
|
+
class Relation
|
726
|
+
MULTI_VALUE_METHODS = MULTI_VALUE_METHODS + [:left_outer_joins] unless MULTI_VALUE_METHODS.include?(:left_outer_joins)
|
727
|
+
end
|
728
|
+
module QueryMethods
|
729
|
+
attr_writer :left_outer_joins_values
|
730
|
+
def left_outer_joins_values
|
731
|
+
@left_outer_joins_values ||= []
|
732
|
+
end
|
733
|
+
|
734
|
+
def left_outer_joins(*args)
|
735
|
+
check_if_method_has_arguments!(:left_outer_joins, args)
|
736
|
+
|
737
|
+
args.compact!
|
738
|
+
args.flatten!
|
739
|
+
|
740
|
+
spawn.left_outer_joins!(*args)
|
741
|
+
end
|
742
|
+
|
743
|
+
def left_outer_joins!(*args) # :nodoc:
|
744
|
+
self.left_outer_joins_values += args
|
745
|
+
self
|
746
|
+
end
|
747
|
+
|
748
|
+
def build_left_outer_joins(manager, outer_joins)
|
749
|
+
buckets = outer_joins.group_by do |join|
|
750
|
+
case join
|
751
|
+
when Hash, Symbol, Array
|
752
|
+
:association_join
|
753
|
+
else
|
754
|
+
raise ArgumentError, 'only Hash, Symbol and Array are allowed'
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
build_join_query(manager, buckets, Arel::Nodes::OuterJoin)
|
759
|
+
end
|
760
|
+
end
|
761
|
+
end
|
762
|
+
# (End of left_outer_joins support)
|
636
763
|
end
|
637
764
|
end
|
638
765
|
|
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.40
|
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
|
+
date: 2022-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,20 +16,34 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '4.2'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '7.
|
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: '
|
29
|
+
version: '4.2'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '7.
|
32
|
+
version: '7.2'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: fancy_gets
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
33
47
|
- !ruby/object:Gem::Dependency
|
34
48
|
name: appraisal
|
35
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,6 +239,7 @@ files:
|
|
225
239
|
- lib/brick/join_array.rb
|
226
240
|
- lib/brick/serializers/json.rb
|
227
241
|
- lib/brick/serializers/yaml.rb
|
242
|
+
- lib/brick/tasks/orphans.rake
|
228
243
|
- lib/brick/util.rb
|
229
244
|
- lib/brick/version_number.rb
|
230
245
|
- lib/generators/brick/USAGE
|