brick 1.0.129 → 1.0.131
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/extensions.rb +56 -33
- data/lib/brick/frameworks/rails/engine.rb +6 -3
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +24 -2
- 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: 6e9356edd43a6af6120f30bfbcd520383f3ae700e6ff04be11ebdd3493852ef4
|
4
|
+
data.tar.gz: a099075c53acc9bf29c718043cc619b5ab4f895366f9c7ddd14d53c8f7f432b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f9df598bad9ce128a88f4fe364d568be8c38eee57e595024866d39a255b42f513a26adc68d64d14cdecd4b5d13fb7424935f17df7dbb41c3bda2ae31057a4c7
|
7
|
+
data.tar.gz: 845e5747a916a338ee494426e4ef0ac6fd5c65c3579df0210c8a80468887fac12103407acfbaee3659b3b45763f98ef0bd109935d70920b932b4fd41cc15fdc5
|
data/lib/brick/extensions.rb
CHANGED
@@ -148,7 +148,8 @@ module ActiveRecord
|
|
148
148
|
translations[parts[0..-2].join('.')] = klass
|
149
149
|
end
|
150
150
|
if klass&.column_names.exclude?(parts.last) &&
|
151
|
-
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.
|
151
|
+
(klass = (orig_class = klass).reflect_on_association(possible_dsl = parts.last&.to_sym)&.klass)
|
152
|
+
parts.pop
|
152
153
|
if prefix.empty? # Custom columns start with an empty prefix
|
153
154
|
prefix << parts.shift until parts.empty?
|
154
155
|
end
|
@@ -162,6 +163,7 @@ module ActiveRecord
|
|
162
163
|
if emit_dsl
|
163
164
|
dsl3 << "[#{prefix[1..-1].map { |p| "#{p.to_s}." }.join if prefix.length > 1}#{bracket_name}]"
|
164
165
|
end
|
166
|
+
parts[-1] = column_names.first if parts[-1].nil? # No primary key to be found? Grab something to display!
|
165
167
|
members << parts
|
166
168
|
end
|
167
169
|
end
|
@@ -231,7 +233,8 @@ module ActiveRecord
|
|
231
233
|
if this_obj.is_a?(ActiveRecord::Base) && (obj_descrip = this_obj.class.brick_descrip(this_obj))
|
232
234
|
this_obj = obj_descrip
|
233
235
|
end
|
234
|
-
if
|
236
|
+
if Object.const_defined?('ActiveStorage') && this_obj.is_a?(::ActiveStorage::Filename) &&
|
237
|
+
this_obj.instance_variable_get(:@filename).nil?
|
235
238
|
this_obj.instance_variable_set(:@filename, '')
|
236
239
|
end
|
237
240
|
this_obj&.to_s || ''
|
@@ -667,6 +670,7 @@ module ActiveRecord
|
|
667
670
|
link_back = []
|
668
671
|
# Track polymorphic type field if necessary
|
669
672
|
if hm.source_reflection.options[:as]
|
673
|
+
# Might be able to simplify as: hm.source_reflection.type
|
670
674
|
poly_ft = [hm.source_reflection.inverse_of.foreign_type, hmt_assoc.source_reflection.class_name]
|
671
675
|
end
|
672
676
|
# link_back << hm.source_reflection.inverse_of.name
|
@@ -741,12 +745,21 @@ module ActiveRecord
|
|
741
745
|
end
|
742
746
|
else
|
743
747
|
fk_col = (inv = hm.inverse_of)&.foreign_key || hm.foreign_key
|
744
|
-
|
748
|
+
# %%% Might only need hm.type and not the first part :)
|
749
|
+
poly_type = inv&.foreign_type || hm.type if hm.options.key?(:as)
|
745
750
|
pk = hm.klass.primary_key
|
746
751
|
(pk.is_a?(Array) ? pk.first : pk) || '*'
|
747
752
|
end
|
748
753
|
next unless count_column # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
|
749
754
|
|
755
|
+
pri_tbl = hm.active_record
|
756
|
+
pri_key = hm.options[:primary_key] || pri_tbl.primary_key
|
757
|
+
unless hm.active_record.column_names.include?(pri_key)
|
758
|
+
# %%% When this gets hit then if an attempt is made to display the ERD, it might end up being blank
|
759
|
+
nix << k
|
760
|
+
next
|
761
|
+
end
|
762
|
+
|
750
763
|
tbl_alias = if is_mysql
|
751
764
|
"`b_r_#{hm.name}`"
|
752
765
|
elsif is_postgres
|
@@ -754,7 +767,6 @@ module ActiveRecord
|
|
754
767
|
else
|
755
768
|
"b_r_#{hm.name}"
|
756
769
|
end
|
757
|
-
pri_tbl = hm.active_record
|
758
770
|
pri_tbl_name = is_mysql ? "`#{pri_tbl.table_name}`" : "\"#{pri_tbl.table_name.gsub('.', '"."')}\""
|
759
771
|
pri_tbl_name = if is_mysql
|
760
772
|
"`#{pri_tbl.table_name}`"
|
@@ -765,10 +777,10 @@ module ActiveRecord
|
|
765
777
|
end
|
766
778
|
on_clause = []
|
767
779
|
hm_selects = if fk_col.is_a?(Array) # Composite key?
|
768
|
-
fk_col.each_with_index { |fk_col_part, idx| on_clause << "#{tbl_alias}.#{fk_col_part} = #{pri_tbl_name}.#{
|
780
|
+
fk_col.each_with_index { |fk_col_part, idx| on_clause << "#{tbl_alias}.#{fk_col_part} = #{pri_tbl_name}.#{pri_key[idx]}" }
|
769
781
|
fk_col.dup
|
770
782
|
else
|
771
|
-
on_clause << "#{tbl_alias}.#{fk_col} = #{pri_tbl_name}.#{
|
783
|
+
on_clause << "#{tbl_alias}.#{fk_col} = #{pri_tbl_name}.#{pri_key}"
|
772
784
|
[fk_col]
|
773
785
|
end
|
774
786
|
if poly_type
|
@@ -864,6 +876,12 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
864
876
|
def brick_list
|
865
877
|
pks = klass.primary_key.is_a?(String) ? [klass.primary_key] : klass.primary_key
|
866
878
|
selects = pks.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
|
879
|
+
# Get foreign keys for anything marked to be auto-preloaded, or a self-referencing JOIN
|
880
|
+
klass_cols = klass.column_names
|
881
|
+
reflect_on_all_associations.each do |a|
|
882
|
+
selects << a.foreign_key if a.belongs_to? && (preload_values.include?(a.name) ||
|
883
|
+
(!a.options[:polymorphic] && a.klass == klass && klass_cols.include?(a.foreign_key)))
|
884
|
+
end
|
867
885
|
# ActiveStorage compatibility
|
868
886
|
selects << 'service_name' if klass.name == 'ActiveStorage::Blob' && ActiveStorage::Blob.columns_hash.key?('service_name')
|
869
887
|
selects << 'blob_id' if klass.name == 'ActiveStorage::Attachment' && ActiveStorage::Attachment.columns_hash.key?('blob_id')
|
@@ -1003,16 +1021,17 @@ Module.class_exec do
|
|
1003
1021
|
is_controller = requested.end_with?('Controller')
|
1004
1022
|
# self.name is nil when a model name is requested in an .erb file
|
1005
1023
|
if self.name && ::Brick.config.path_prefix
|
1006
|
-
|
1024
|
+
split_self_name.shift if (split_self_name = self.name.split('::')).first.blank?
|
1007
1025
|
# Asking for the prefix module?
|
1026
|
+
camelize_prefix = ::Brick.config.path_prefix.camelize
|
1008
1027
|
if self == Object && requested == camelize_prefix
|
1009
1028
|
Object.const_set(args.first, (built_module = Module.new))
|
1010
1029
|
puts "module #{camelize_prefix}; end\n"
|
1011
1030
|
return built_module
|
1012
|
-
|
1013
|
-
|
1014
|
-
if split_self_name.first == camelize_prefix
|
1031
|
+
elsif module_parent == Object && self.name == camelize_prefix ||
|
1032
|
+
module_parent.name == camelize_prefix && module_parent.module_parent == Object
|
1015
1033
|
split_self_name.shift # Remove the identified path prefix from the split name
|
1034
|
+
is_brick_prefix = true
|
1016
1035
|
if is_controller
|
1017
1036
|
brick_root = split_self_name.empty? ? self : camelize_prefix.constantize
|
1018
1037
|
end
|
@@ -1045,26 +1064,30 @@ Module.class_exec do
|
|
1045
1064
|
self
|
1046
1065
|
end
|
1047
1066
|
# puts "#{self.name} - #{args.first}"
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1067
|
+
# Unless it's a Brick prefix looking for a TNP that should create a module ...
|
1068
|
+
unless (is_tnp_module = (is_brick_prefix && !is_controller && ::Brick.config.table_name_prefixes.values.include?(requested)))
|
1069
|
+
# ... first look around for an existing module or class.
|
1070
|
+
desired_classname = (self == Object || !name) ? requested : "#{name}::#{requested}"
|
1071
|
+
if ((is_defined = self.const_defined?(args.first)) && (possible = self.const_get(args.first)) &&
|
1072
|
+
# Reset `possible` if it's a controller request that's not a perfect match
|
1073
|
+
# Was: (possible = nil) but changed to #local_variable_set in order to suppress the "= should be ==" warning
|
1074
|
+
(possible&.name == desired_classname || (is_controller && binding.local_variable_set(:possible, nil)))) ||
|
1075
|
+
# Try to require the respective Ruby file
|
1076
|
+
((filename = ActiveSupport::Dependencies.search_for_file(desired_classname.underscore) ||
|
1077
|
+
(self != Object && ActiveSupport::Dependencies.search_for_file((desired_classname = requested).underscore))
|
1078
|
+
) && (require_dependency(filename) || true) &&
|
1079
|
+
((possible = self.const_get(args.first)) && possible.name == desired_classname)
|
1080
|
+
) ||
|
1081
|
+
# If any class has turned up so far (and we're not in the middle of eager loading)
|
1082
|
+
# then return what we've found.
|
1083
|
+
(is_defined && !::Brick.is_eager_loading) # Used to also have: && possible != self
|
1084
|
+
if ((!brick_root && (filename || possible.instance_of?(Class))) ||
|
1085
|
+
(possible.instance_of?(Module) && possible&.module_parent == self) ||
|
1086
|
+
(possible.instance_of?(Class) && possible == self)) && # Are we simply searching for ourselves?
|
1087
|
+
# Skip when what we found as `possible` is not related to the base class of an STI model
|
1088
|
+
(!sti_base || possible.is_a?(sti_base))
|
1089
|
+
return possible
|
1090
|
+
end
|
1068
1091
|
end
|
1069
1092
|
end
|
1070
1093
|
class_name = ::Brick.namify(requested)
|
@@ -1099,7 +1122,7 @@ Module.class_exec do
|
|
1099
1122
|
(plural_class_name = class_name.pluralize)].find { |s| Brick.db_schemas&.include?(s) }&.camelize ||
|
1100
1123
|
(::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name) ||
|
1101
1124
|
(::Brick.config.table_name_prefixes.values.include?(class_name) && class_name))
|
1102
|
-
return self.const_get(schema_name) if self.const_defined?(schema_name)
|
1125
|
+
return self.const_get(schema_name) if !is_tnp_module && self.const_defined?(schema_name)
|
1103
1126
|
|
1104
1127
|
# Build out a module for the schema if it's namespaced
|
1105
1128
|
# schema_name = schema_name.camelize
|
@@ -1869,7 +1892,7 @@ class Object
|
|
1869
1892
|
# Convert any Filename objects with nil into an empty string so that #encode can be called on them
|
1870
1893
|
new_obj.serializable_hash.each do |k, v|
|
1871
1894
|
new_obj.send("#{k}=", ActiveStorage::Filename.new('')) if v.is_a?(ActiveStorage::Filename) && !v.instance_variable_get(:@filename)
|
1872
|
-
end
|
1895
|
+
end if Object.const_defined?('ActiveStorage')
|
1873
1896
|
end
|
1874
1897
|
instance_variable_set("@#{singular_table_name}".to_sym, new_obj)
|
1875
1898
|
end
|
@@ -2441,7 +2464,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2441
2464
|
singular = rel_name.last
|
2442
2465
|
end
|
2443
2466
|
name_parts = if (tnp = ::Brick.config.table_name_prefixes
|
2444
|
-
|
2467
|
+
&.find { |k1, _v1| singular.start_with?(k1) && singular.length > k1.length }
|
2445
2468
|
).present?
|
2446
2469
|
v[:auto_prefixed_schema] = tnp.first
|
2447
2470
|
v[:resource] = rel_name.last[(tnp_length = tnp.first.length)..-1]
|
@@ -225,7 +225,7 @@ function linkSchemas() {
|
|
225
225
|
end
|
226
226
|
|
227
227
|
# When table names have specific prefixes, automatically place them in their own module with a table_name_prefix.
|
228
|
-
::Brick.table_name_prefixes
|
228
|
+
::Brick.config.table_name_prefixes ||= app.config.brick.fetch(:table_name_prefixes, {})
|
229
229
|
|
230
230
|
# Columns to treat as being metadata for purposes of identifying associative tables for has_many :through
|
231
231
|
::Brick.metadata_columns = app.config.brick.fetch(:metadata_columns, ['created_at', 'updated_at', 'deleted_at'])
|
@@ -625,6 +625,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
625
625
|
if (class_name = (resource_parts = resource_name.split('/')).last&.singularize)
|
626
626
|
resource_parts[-1] = class_name # Make sure the last part, defining the class name, is singular
|
627
627
|
begin
|
628
|
+
resource_parts.shift if resource_parts.first == ::Brick.config.path_prefix
|
628
629
|
if (model = Object.const_get(resource_parts.map(&:camelize).join('::')))&.is_a?(Class) && (
|
629
630
|
['index', 'show'].include?(find_args.first) || # Everything has index and show
|
630
631
|
# Only CUD stuff has create / update / destroy
|
@@ -652,7 +653,9 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
652
653
|
else
|
653
654
|
hm_assoc.active_record.name
|
654
655
|
end
|
655
|
-
|
656
|
+
# %%% Might only need hm_assoc.type and not the first part :)
|
657
|
+
type_col = hm_assoc.inverse_of&.foreign_type || hm_assoc.type
|
658
|
+
keys << [type_col, poly_type]
|
656
659
|
end
|
657
660
|
keys.to_h
|
658
661
|
end
|
@@ -1667,7 +1670,7 @@ end
|
|
1667
1670
|
<% if (assoc = @#{obj_name}.class.reflect_on_association(:#{hm_name})).macro == :has_one &&
|
1668
1671
|
assoc.options&.fetch(:through, nil).nil?
|
1669
1672
|
# In order to apply DSL properly, evaluate this HO the other way around as if it were as a BT
|
1670
|
-
collection = assoc.klass.where(assoc.foreign_key => @#{obj_name}.#{pk})
|
1673
|
+
collection = assoc.klass.where(assoc.foreign_key => #{pk.is_a?(String) ? "@#{obj_name}.#{pk}" : pk.map { |pk_part| "@#{obj_name}.#{pk_part}" }.inspect})
|
1671
1674
|
collection = collection.instance_exec(&assoc.scopes.first) if assoc.scopes.present?
|
1672
1675
|
if assoc.klass.name == 'ActiveStorage::Attachment'
|
1673
1676
|
br_descrip = begin
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -125,6 +125,7 @@ if Gem::Specification.all_names.any? { |g| g.start_with?('rails-') }
|
|
125
125
|
end
|
126
126
|
module Brick
|
127
127
|
ALL_API_ACTIONS = [:index, :show, :create, :update, :destroy]
|
128
|
+
CURRENCY_SYMBOLS = '$£¢₵€₠ƒ¥₿₩₪₹₫₴₱₲₳₸₺₼₽៛₡₢₣₤₥₦₧₨₭₮₯₰₶₷₻₾'
|
128
129
|
|
129
130
|
class << self
|
130
131
|
def sti_models
|
@@ -200,9 +201,20 @@ module Brick
|
|
200
201
|
end
|
201
202
|
|
202
203
|
def get_bts_and_hms(model)
|
204
|
+
model_cols = model.columns_hash
|
205
|
+
pk_type = if (mpk = model.primary_key).is_a?(Array)
|
206
|
+
# Composite keys should really use: model.primary_key.map { |pk_part| model_cols[pk_part].type }
|
207
|
+
model_cols[mpk.first].type
|
208
|
+
else
|
209
|
+
mpk && model_cols[mpk].type
|
210
|
+
end
|
203
211
|
bts, hms = model.reflect_on_all_associations.each_with_object([{}, {}]) do |a, s|
|
212
|
+
# %%% The time will come when we will support type checking of composite foreign keys!
|
213
|
+
# binding.pry if a.foreign_key.is_a?(Array)
|
204
214
|
next unless a.polymorphic? || (!a.belongs_to? && (through = a.options[:through])) ||
|
205
|
-
(a.klass && ::Brick.config.exclude_tables.exclude?(a.klass.table_name)
|
215
|
+
(a.klass && ::Brick.config.exclude_tables.exclude?(a.klass.table_name) &&
|
216
|
+
(!a.belongs_to? || model_cols[a.foreign_key]&.type == pk_type)
|
217
|
+
)
|
206
218
|
|
207
219
|
if a.belongs_to?
|
208
220
|
if a.polymorphic?
|
@@ -239,6 +251,15 @@ module Brick
|
|
239
251
|
puts "WARNING: HMT relationship :#{a.name} in model #{model.name} has invalid source :#{a.source_reflection_name}."
|
240
252
|
next
|
241
253
|
end
|
254
|
+
else
|
255
|
+
if !a.options.key?(:as) && a.klass.column_names.exclude?(a.foreign_key)
|
256
|
+
options = ", #{a.options.map { |k, v| "#{k.inspect} => #{v.inspect}" }.join(', ')}" if a.options.present?
|
257
|
+
puts "WARNING: Model #{model.name} has this association:
|
258
|
+
has_many :#{a.name}#{options}
|
259
|
+
which expects column #{a.foreign_key} to exist in table #{a.klass.table_name}. This column is missing."
|
260
|
+
next
|
261
|
+
|
262
|
+
end
|
242
263
|
end
|
243
264
|
s.last[a.name] = a
|
244
265
|
end
|
@@ -1661,7 +1682,8 @@ module ActiveRecord
|
|
1661
1682
|
relation.brick_links[link_path] = if child.table.is_a?(Arel::Nodes::TableAlias)
|
1662
1683
|
child.table.right
|
1663
1684
|
else
|
1664
|
-
result.first&.left&.table_alias || child.table_name
|
1685
|
+
# Was: result.first&.left&.table_alias || child.table_name
|
1686
|
+
child.table.table_alias || child.table_name
|
1665
1687
|
end
|
1666
1688
|
end
|
1667
1689
|
result
|
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.131
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|