brick 1.0.190 → 1.0.192
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/config.rb +8 -0
- data/lib/brick/extensions.rb +175 -48
- data/lib/brick/frameworks/rails/engine.rb +34 -14
- data/lib/brick/frameworks/rails/form_builder.rb +2 -1
- data/lib/brick/frameworks/rails/form_tags.rb +13 -4
- data/lib/brick/frameworks/rails.rb +6 -0
- data/lib/brick/route_mapper.rb +348 -0
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +10 -335
- data/lib/generators/brick/controllers_generator.rb +91 -0
- data/lib/generators/brick/migration_builder.rb +224 -160
- data/lib/generators/brick/migrations_generator.rb +1 -0
- data/lib/generators/brick/models_generator.rb +2 -2
- data/lib/generators/brick/salesforce_migrations_generator.rb +101 -0
- data/lib/generators/brick/salesforce_schema.rb +105 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 148c8f46702d06322322c04487a1045e6d7a3927611394a84ffe138be78adb5e
|
4
|
+
data.tar.gz: 716bfaae50dc99809bc3aee4eecf5ff1c44325bca54271db225a765cdd97fb56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d97d94ed8d951718b34d1fc0d3ee8d023b3765bafc759fd41161155c927014ddec54a67e371363bbb17b18a614f4be16862d9cb51be313438050a3ce6e3356a2
|
7
|
+
data.tar.gz: efbd8b062eccd5d5441aa8e9fe6162bce076e188761f5c7877f9ca454899fc13873fa6cdf4db21cd2154e24c824487f56a085f41402432bd99486e17213e7f00
|
data/lib/brick/config.rb
CHANGED
@@ -399,6 +399,14 @@ module Brick
|
|
399
399
|
@mutex.synchronize { @not_nullables = columns }
|
400
400
|
end
|
401
401
|
|
402
|
+
def omit_empty_tables_in_dropdown
|
403
|
+
@mutex.synchronize { @omit_empty_tables_in_dropdown }
|
404
|
+
end
|
405
|
+
|
406
|
+
def omit_empty_tables_in_dropdown=(field_set)
|
407
|
+
@mutex.synchronize { @omit_empty_tables_in_dropdown = field_set }
|
408
|
+
end
|
409
|
+
|
402
410
|
def always_load_fields
|
403
411
|
@mutex.synchronize { @always_load_fields || {} }
|
404
412
|
end
|
data/lib/brick/extensions.rb
CHANGED
@@ -82,8 +82,10 @@ module ActiveRecord
|
|
82
82
|
|
83
83
|
def json_column?(col)
|
84
84
|
col.type == :json || ::Brick.config.json_columns[table_name]&.include?(col.name) ||
|
85
|
-
(
|
86
|
-
|
85
|
+
(
|
86
|
+
respond_to?(:attribute_types) && (attr_types = attribute_types[col.name]).respond_to?(:coder) &&
|
87
|
+
(attr_types.coder.is_a?(Class) ? attr_types.coder : attr_types.coder&.class)&.name&.end_with?('JSON')
|
88
|
+
)
|
87
89
|
end
|
88
90
|
|
89
91
|
def brick_foreign_type(assoc)
|
@@ -284,7 +286,10 @@ module ActiveRecord
|
|
284
286
|
end
|
285
287
|
this_obj&.to_s || ''
|
286
288
|
end
|
287
|
-
|
289
|
+
begin
|
290
|
+
is_brackets_have_content = true unless datum.blank?
|
291
|
+
rescue
|
292
|
+
end
|
288
293
|
output << (datum || '')
|
289
294
|
bracket_name = nil
|
290
295
|
else
|
@@ -329,27 +334,10 @@ module ActiveRecord
|
|
329
334
|
end
|
330
335
|
|
331
336
|
# Providing a relation object allows auto-modules built from table name prefixes to work
|
332
|
-
def self._brick_index(mode = nil, separator =
|
337
|
+
def self._brick_index(mode = nil, separator = nil, relation = nil)
|
333
338
|
return if abstract_class?
|
334
339
|
|
335
|
-
|
336
|
-
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
|
337
|
-
if (aps = relation&.fetch(:auto_prefixed_schema, nil)) && tbl_parts.last.start_with?(aps)
|
338
|
-
last_part = tbl_parts.last[aps.length..-1]
|
339
|
-
aps = aps[0..-2] if aps[-1] == '_'
|
340
|
-
tbl_parts[-1] = aps
|
341
|
-
tbl_parts << last_part
|
342
|
-
end
|
343
|
-
path_prefix = []
|
344
|
-
if ::Brick.config.path_prefix
|
345
|
-
tbl_parts.unshift(::Brick.config.path_prefix)
|
346
|
-
path_prefix << ::Brick.config.path_prefix
|
347
|
-
end
|
348
|
-
index = tbl_parts.map(&:underscore).join(separator)
|
349
|
-
# Rails applies an _index suffix to that route when the resource name isn't something plural
|
350
|
-
index << '_index' if mode != :singular && separator == '_' &&
|
351
|
-
index == (path_prefix + [name&.underscore&.tr('/', '_') || '_']).join(separator)
|
352
|
-
index
|
340
|
+
::Brick._brick_index(table_name, mode, separator, relation)
|
353
341
|
end
|
354
342
|
|
355
343
|
def self.brick_import_template
|
@@ -686,7 +674,7 @@ module ActiveRecord
|
|
686
674
|
(cust_col_override || klass._br_cust_cols).each do |k, cc|
|
687
675
|
if rel_dupe.respond_to?(k) # Name already taken?
|
688
676
|
# %%% Use ensure_unique here in this kind of fashion:
|
689
|
-
# cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", bts, hms)
|
677
|
+
# cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", nil, bts, hms)
|
690
678
|
# binding.pry
|
691
679
|
next
|
692
680
|
end
|
@@ -806,6 +794,7 @@ module ActiveRecord
|
|
806
794
|
|
807
795
|
# Add derived table JOIN for the has_many counts
|
808
796
|
nix = []
|
797
|
+
previous = []
|
809
798
|
klass._br_hm_counts.each do |k, hm|
|
810
799
|
count_column = if hm.options[:through]
|
811
800
|
# Build the chain of JOINs going to the final destination HMT table
|
@@ -832,7 +821,7 @@ module ActiveRecord
|
|
832
821
|
through_sources.push(this_hm = src_ref.active_record.reflect_on_association(thr))
|
833
822
|
end
|
834
823
|
through_sources.push(src_ref) unless src_ref.belongs_to?
|
835
|
-
from_clause = +"#{through_sources.first.table_name} br_t0"
|
824
|
+
from_clause = +"#{_br_quoted_name(through_sources.first.table_name)} br_t0"
|
836
825
|
fk_col = through_sources.shift.foreign_key
|
837
826
|
|
838
827
|
idx = 0
|
@@ -900,7 +889,7 @@ module ActiveRecord
|
|
900
889
|
next
|
901
890
|
end
|
902
891
|
|
903
|
-
tbl_alias = "b_r_#{hm.name}"
|
892
|
+
tbl_alias = unique63("b_r_#{hm.name}", previous)
|
904
893
|
on_clause = []
|
905
894
|
hm_selects = if fk_col.is_a?(Array) # Composite key?
|
906
895
|
fk_col.each_with_index { |fk_col_part, idx| on_clause << "#{tbl_alias}.#{fk_col_part} = #{pri_tbl.table_name}.#{pri_key[idx]}" }
|
@@ -1105,6 +1094,19 @@ Might want to add this in your brick.rb:
|
|
1105
1094
|
def shift_or_first(ary)
|
1106
1095
|
ary.length > 1 ? ary.shift : ary.first
|
1107
1096
|
end
|
1097
|
+
|
1098
|
+
def unique63(name, previous)
|
1099
|
+
name = name[0..62] if name.length > 63
|
1100
|
+
unique_num = 1
|
1101
|
+
loop do
|
1102
|
+
break unless previous.include?(name)
|
1103
|
+
|
1104
|
+
unique_suffix = "_#{unique_num += 1}"
|
1105
|
+
name = "#{name[0..name.length - unique_suffix.length - 1]}#{unique_suffix}"
|
1106
|
+
end
|
1107
|
+
previous << name
|
1108
|
+
name
|
1109
|
+
end
|
1108
1110
|
end
|
1109
1111
|
|
1110
1112
|
module Inheritance
|
@@ -1360,7 +1362,7 @@ end
|
|
1360
1362
|
end
|
1361
1363
|
rescue NameError # If the const_get for the model has failed...
|
1362
1364
|
skip_controller = true
|
1363
|
-
# ... then just fall through and allow it to fail when trying to
|
1365
|
+
# ... then just fall through and allow it to fail when trying to load the ____Controller class normally.
|
1364
1366
|
end
|
1365
1367
|
end
|
1366
1368
|
unless skip_controller
|
@@ -1715,7 +1717,8 @@ class Object
|
|
1715
1717
|
# options[:class_name] = hm.first[:inverse_table].singularize.camelize
|
1716
1718
|
# options[:foreign_key] = hm.first[:fk].to_sym
|
1717
1719
|
far_assoc = relations[hm.first[:inverse_table]][:fks].find { |_k, v| v[:assoc_name] == hm[1] }
|
1718
|
-
|
1720
|
+
# Was: ::Brick.namify(far_assoc.last[:inverse_table], :underscore).camelize
|
1721
|
+
options[:class_name] = relations[far_assoc.last[:inverse_table]][:class_name]
|
1719
1722
|
options[:foreign_key] = far_assoc.last[:fk].to_sym
|
1720
1723
|
end
|
1721
1724
|
options[:source] ||= hm[1].to_sym unless hmt_name.singularize == hm[1]
|
@@ -1744,7 +1747,7 @@ class Object
|
|
1744
1747
|
options[:optional] = true if assoc.key?(:optional)
|
1745
1748
|
if assoc.key?(:polymorphic) ||
|
1746
1749
|
# If a polymorphic association is missing but could be established then go ahead and put it into place.
|
1747
|
-
relations
|
1750
|
+
relations.fetch(assoc[:inverse_table], nil)&.fetch(:class_name, nil)&.constantize&.reflect_on_all_associations&.find { |inv_assoc| !inv_assoc.belongs_to? && inv_assoc.options[:as].to_s == assoc[:assoc_name] }
|
1748
1751
|
assoc[:polymorphic] ||= true
|
1749
1752
|
options[:polymorphic] = true
|
1750
1753
|
else
|
@@ -1802,9 +1805,9 @@ class Object
|
|
1802
1805
|
::Brick.config.schema_behavior[:multitenant] && singular_table_parts.first == 'public'
|
1803
1806
|
singular_table_parts.shift
|
1804
1807
|
end
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
+
if need_class_name
|
1809
|
+
options[:class_name] = "::#{assoc[:primary_class]&.name || ::Brick.relations[inverse_table][:class_name]}"
|
1810
|
+
end
|
1808
1811
|
if need_fk # Funky foreign key?
|
1809
1812
|
options_fk_key = :foreign_key
|
1810
1813
|
if assoc[:fk].is_a?(Array)
|
@@ -2559,6 +2562,8 @@ class Object
|
|
2559
2562
|
assoc_name = assoc_parts.join('.')
|
2560
2563
|
else
|
2561
2564
|
class_name_parts = ::Brick.namify(hm_assoc[:inverse_table], :underscore).split('.')
|
2565
|
+
last_idx = class_name_parts.length - 1
|
2566
|
+
class_name_parts[last_idx] = class_name_parts[last_idx].singularize
|
2562
2567
|
real_name = class_name_parts.map(&:camelize).join('::')
|
2563
2568
|
needs_class = (real_name != hm_assoc[:inverse_table].camelize)
|
2564
2569
|
end
|
@@ -2645,6 +2650,10 @@ end.class_exec do
|
|
2645
2650
|
orig_schema = nil
|
2646
2651
|
if (relations = ::Brick.relations).keys == [:db_name]
|
2647
2652
|
::Brick.remove_instance_variable(:@_additional_references_loaded) if ::Brick.instance_variable_defined?(:@_additional_references_loaded)
|
2653
|
+
|
2654
|
+
# --------------------------------------------
|
2655
|
+
# 1. Load three initializers early
|
2656
|
+
# (inflectsions.rb, brick.rb, apartment.rb)
|
2648
2657
|
# Very first thing, load inflections since we'll be using .pluralize and .singularize on table and model names
|
2649
2658
|
if File.exist?(inflections = ::Rails.root&.join('config/initializers/inflections.rb') || '')
|
2650
2659
|
load inflections
|
@@ -2695,6 +2704,8 @@ end.class_exec do
|
|
2695
2704
|
# Only for Postgres (Doesn't work in sqlite3 or MySQL)
|
2696
2705
|
# puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
|
2697
2706
|
|
2707
|
+
# ---------------------------
|
2708
|
+
# 2. Figure out schema things
|
2698
2709
|
is_postgres = nil
|
2699
2710
|
is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer'
|
2700
2711
|
case ActiveRecord::Base.connection.adapter_name
|
@@ -2767,6 +2778,8 @@ end.class_exec do
|
|
2767
2778
|
|
2768
2779
|
::Brick.db_schemas ||= {}
|
2769
2780
|
|
2781
|
+
# ---------------------
|
2782
|
+
# 3. Tables and columns
|
2770
2783
|
# %%% Retrieve internal ActiveRecord table names like this:
|
2771
2784
|
# ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
|
2772
2785
|
# For if it's not SQLite -- so this is the Postgres and MySQL version
|
@@ -2896,20 +2909,34 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2896
2909
|
# end
|
2897
2910
|
# end
|
2898
2911
|
# schema = ::Brick.default_schema # Reset back for this next round of fun
|
2912
|
+
|
2913
|
+
# ---------------------------------------------
|
2914
|
+
# 4. Foreign key info
|
2915
|
+
# (done in two parts which get JOINed together in Ruby code)
|
2899
2916
|
kcus = nil
|
2917
|
+
entry_type = nil
|
2900
2918
|
case ActiveRecord::Base.connection.adapter_name
|
2901
2919
|
when 'PostgreSQL', 'Mysql2', 'Trilogy', 'SQLServer'
|
2902
|
-
#
|
2920
|
+
# Part 1 -- all KCUs
|
2903
2921
|
sql = "SELECT CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, ORDINAL_POSITION,
|
2904
2922
|
TABLE_NAME, COLUMN_NAME
|
2905
2923
|
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE#{"
|
2906
|
-
WHERE CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }"
|
2924
|
+
WHERE CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }#{"
|
2925
|
+
WHERE CONSTRAINT_SCHEMA = '#{ActiveRecord::Base.connection.current_database&.tr("'", "''")}'" if is_mysql
|
2926
|
+
}"
|
2907
2927
|
kcus = ActiveRecord::Base.execute_sql(sql).each_with_object({}) do |v, s|
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2928
|
+
if (entry_type ||= v.is_a?(Array) ? :array : :hash) == :hash
|
2929
|
+
key = "#{v['constraint_name']}.#{v['constraint_schema']}.#{v['constraint_catalog']}.#{v['ordinal_position']}"
|
2930
|
+
key << ".#{v['table_name']}.#{v['column_name']}" unless is_postgres || is_mssql
|
2931
|
+
s[key] = [v['constraint_schema'], v['table_name']]
|
2932
|
+
else # Array
|
2933
|
+
key = "#{v[2]}.#{v[1]}.#{v[0]}.#{v[3]}"
|
2934
|
+
key << ".#{v[4]}.#{v[5]}" unless is_postgres || is_mssql
|
2935
|
+
s[key] = [v[1], v[4]]
|
2936
|
+
end
|
2911
2937
|
end
|
2912
2938
|
|
2939
|
+
# Part 2 -- fk_references
|
2913
2940
|
sql = "SELECT kcu.CONSTRAINT_SCHEMA, kcu.TABLE_NAME, kcu.COLUMN_NAME,
|
2914
2941
|
#{# These will get filled in with real values (effectively doing the JOIN in Ruby)
|
2915
2942
|
is_postgres || is_mssql ? 'NULL as primary_schema, NULL as primary_table' :
|
@@ -2921,7 +2948,8 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2921
2948
|
ON kcu.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG
|
2922
2949
|
AND kcu.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
|
2923
2950
|
AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME#{"
|
2924
|
-
WHERE kcu.CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema
|
2951
|
+
WHERE kcu.CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema}#{"
|
2952
|
+
WHERE kcu.CONSTRAINT_SCHEMA = '#{ActiveRecord::Base.connection.current_database&.tr("'", "''")}'" if is_mysql}"
|
2925
2953
|
fk_references = ActiveRecord::Base.execute_sql(sql)
|
2926
2954
|
when 'SQLite'
|
2927
2955
|
sql = "SELECT NULL AS constraint_schema, m.name, fkl.\"from\", NULL AS primary_schema, fkl.\"table\", m.name || '_' || fkl.\"from\" AS constraint_name
|
@@ -2949,11 +2977,13 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2949
2977
|
end
|
2950
2978
|
::Brick.is_oracle = true if ActiveRecord::Base.connection.adapter_name == 'OracleEnhanced'
|
2951
2979
|
# ::Brick.default_schema ||= schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
2952
|
-
::Brick.default_schema ||= 'public' if
|
2980
|
+
::Brick.default_schema ||= 'public' if is_postgres
|
2953
2981
|
fk_references&.each do |fk|
|
2954
2982
|
fk = fk.values unless fk.is_a?(Array)
|
2955
|
-
# Virtually JOIN
|
2956
|
-
|
2983
|
+
# Virtually JOIN KCUs to fk_references in order to fill in the primary schema and primary table
|
2984
|
+
kcu_key = "#{fk[6]}.#{fk[7]}.#{fk[8]}.#{fk[9]}"
|
2985
|
+
kcu_key << ".#{fk[3]}.#{fk[4]}" unless is_postgres || is_mssql
|
2986
|
+
if (kcu = kcus&.fetch(kcu_key, nil))
|
2957
2987
|
fk[3] = kcu[0]
|
2958
2988
|
fk[4] = kcu[1]
|
2959
2989
|
end
|
@@ -3000,18 +3030,86 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
3000
3030
|
&.find { |k1, _v1| singular.start_with?(k1) && singular.length > k1.length }
|
3001
3031
|
).present?
|
3002
3032
|
v[:auto_prefixed_schema] = tnp.first
|
3003
|
-
v[:resource] = rel_name.last[
|
3004
|
-
[tnp.last, singular[
|
3033
|
+
# v[:resource] = rel_name.last[tnp.first.length..-1]
|
3034
|
+
[tnp.last, singular[tnp.first.length..-1]]
|
3005
3035
|
else
|
3006
|
-
v[:resource] = rel_name.last
|
3036
|
+
# v[:resource] = rel_name.last
|
3007
3037
|
[singular]
|
3008
3038
|
end
|
3009
|
-
|
3039
|
+
proposed_name_parts = (schema_names + name_parts).map { |p| ::Brick.namify(p, :underscore).camelize }
|
3040
|
+
# Find out if the proposed name leads to a module or class that already exists and is not an AR class
|
3041
|
+
colliding_thing = nil
|
3042
|
+
loop do
|
3043
|
+
klass = Object
|
3044
|
+
proposed_name_parts.each do |part|
|
3045
|
+
if klass.const_defined?(part)
|
3046
|
+
klass = klass.const_get(part)
|
3047
|
+
else
|
3048
|
+
klass = nil
|
3049
|
+
break
|
3050
|
+
end
|
3051
|
+
end
|
3052
|
+
break if !klass || (klass < ActiveRecord::Base) # Break if all good -- no conflicts
|
3053
|
+
|
3054
|
+
# Find a unique name since there's already something that's non-AR with that same name
|
3055
|
+
last_idx = proposed_name_parts.length - 1
|
3056
|
+
proposed_name_parts[last_idx] = ::Brick.ensure_unique(proposed_name_parts[last_idx], 'X')
|
3057
|
+
colliding_thing ||= klass
|
3058
|
+
end
|
3059
|
+
v[:class_name] = proposed_name_parts.join('::')
|
3060
|
+
# Was: v[:resource] = v[:class_name].underscore.tr('/', '.').pluralize
|
3061
|
+
v[:resource] = proposed_name_parts.last.underscore.pluralize
|
3062
|
+
if colliding_thing
|
3063
|
+
message_start = if colliding_thing.is_a?(Module) && Object.const_defined?(:Rails) &&
|
3064
|
+
colliding_thing.constants.find { |c| colliding_thing.const_get(c) < Rails::Application }
|
3065
|
+
"The module for the Rails application itself, \"#{colliding_thing.name}\","
|
3066
|
+
else
|
3067
|
+
"Non-AR #{colliding_thing.class.name.downcase} \"#{colliding_thing.name}\""
|
3068
|
+
end
|
3069
|
+
puts "WARNING: #{message_start} already exists.\n Will set up to auto-create model #{v[:class_name]} for table #{k}."
|
3070
|
+
end
|
3010
3071
|
# Track anything that's out-of-the-ordinary
|
3011
3072
|
table_name_lookup[v[:class_name]] = k unless v[:class_name].underscore.pluralize == k
|
3012
3073
|
end
|
3013
3074
|
::Brick.load_additional_references if ::Brick.initializer_loaded
|
3014
3075
|
|
3076
|
+
if is_postgres
|
3077
|
+
params = []
|
3078
|
+
ActiveRecord::Base.execute_sql("-- inherited and partitioned tables counts
|
3079
|
+
SELECT n.nspname, parent.relname,
|
3080
|
+
((SUM(child.reltuples::float) / greatest(SUM(child.relpages), 1))) *
|
3081
|
+
(SUM(pg_relation_size(child.oid))::float / (current_setting('block_size')::float))::integer AS rowcount
|
3082
|
+
FROM pg_inherits
|
3083
|
+
INNER JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
|
3084
|
+
INNER JOIN pg_class child ON pg_inherits.inhrelid = child.oid
|
3085
|
+
INNER JOIN pg_catalog.pg_namespace n ON n.oid = parent.relnamespace#{
|
3086
|
+
if schema
|
3087
|
+
params = params << schema
|
3088
|
+
"
|
3089
|
+
WHERE n.nspname = COALESCE(?, 'public')"
|
3090
|
+
end}
|
3091
|
+
GROUP BY n.nspname, parent.relname, child.reltuples, child.relpages, child.oid
|
3092
|
+
|
3093
|
+
UNION ALL
|
3094
|
+
|
3095
|
+
-- table count
|
3096
|
+
SELECT n.nspname, pg_class.relname,
|
3097
|
+
(pg_class.reltuples::float / greatest(pg_class.relpages, 1)) *
|
3098
|
+
(pg_relation_size(pg_class.oid)::float / (current_setting('block_size')::float))::integer AS rowcount
|
3099
|
+
FROM pg_class
|
3100
|
+
INNER JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace#{
|
3101
|
+
if schema
|
3102
|
+
params = params << schema
|
3103
|
+
"
|
3104
|
+
WHERE n.nspname = COALESCE(?, 'public')"
|
3105
|
+
end}
|
3106
|
+
GROUP BY n.nspname, pg_class.relname, pg_class.reltuples, pg_class.relpages, pg_class.oid", params).each do |tblcount|
|
3107
|
+
# %%% What is the default schema here?
|
3108
|
+
prefix = "#{tblcount['nspname']}." unless tblcount['nspname'] == (schema || 'public')
|
3109
|
+
relations.fetch("#{prefix}#{tblcount['relname']}", nil)&.[]=(:rowcount, tblcount['rowcount'].to_i.round)
|
3110
|
+
end
|
3111
|
+
end
|
3112
|
+
|
3015
3113
|
if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
|
3016
3114
|
puts "Now switching back to \"#{orig_schema}\" schema."
|
3017
3115
|
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", orig_schema)
|
@@ -3151,7 +3249,7 @@ module Brick
|
|
3151
3249
|
# For any appended references (those that come from config), arrive upon a definitely unique constraint name
|
3152
3250
|
pri_tbl = is_class ? fk[4][:class].underscore : pri_tbl
|
3153
3251
|
pri_tbl = "#{bt_assoc_name}_#{pri_tbl}" if pri_tbl&.singularize != bt_assoc_name
|
3154
|
-
cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", bts, hms)
|
3252
|
+
cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", nil, bts, hms)
|
3155
3253
|
missing = []
|
3156
3254
|
missing << fk[1] unless relations.key?(fk[1])
|
3157
3255
|
missing << primary_table unless is_class || relations.key?(primary_table)
|
@@ -3285,15 +3383,17 @@ module Brick
|
|
3285
3383
|
end
|
3286
3384
|
end
|
3287
3385
|
|
3288
|
-
def ensure_unique(name, *sources)
|
3386
|
+
def ensure_unique(name, delimiter, *sources)
|
3289
3387
|
base = name
|
3290
|
-
|
3388
|
+
delimiter ||= '_'
|
3389
|
+
# By default ends up building this regex: /_(\d+)$/
|
3390
|
+
if (added_num = name.slice!(Regexp.new("#{delimiter}(\d+)$")))
|
3291
3391
|
added_num = added_num[1..-1].to_i
|
3292
3392
|
else
|
3293
3393
|
added_num = 1
|
3294
3394
|
end
|
3295
3395
|
while (
|
3296
|
-
name = "#{base}
|
3396
|
+
name = "#{base}#{delimiter}#{added_num += 1}"
|
3297
3397
|
sources.each_with_object(nil) do |v, s|
|
3298
3398
|
s || case v
|
3299
3399
|
when Hash
|
@@ -3371,6 +3471,33 @@ module Brick
|
|
3371
3471
|
end
|
3372
3472
|
end
|
3373
3473
|
|
3474
|
+
def _brick_index(tbl_name, mode = nil, separator = nil, relation = nil)
|
3475
|
+
separator ||= '_'
|
3476
|
+
res_name = (tbl_name_parts = tbl_name.split('.'))[0..-2].first
|
3477
|
+
res_name << '.' if res_name
|
3478
|
+
(res_name ||= +'') << (relation || ::Brick.relations.fetch(tbl_name, nil))&.fetch(:resource, nil) || tbl_name_parts.last
|
3479
|
+
|
3480
|
+
res_parts = ((mode == :singular) ? res_name.singularize : res_name).split('.')
|
3481
|
+
res_parts.shift if ::Brick.apartment_multitenant && res_parts.length > 1 && res_parts.first == ::Brick.apartment_default_tenant
|
3482
|
+
if (aps = relation&.fetch(:auto_prefixed_schema, nil)) && res_parts.last.start_with?(aps)
|
3483
|
+
last_part = res_parts.last[aps.length..-1]
|
3484
|
+
aps = aps[0..-2] if aps[-1] == '_'
|
3485
|
+
res_parts[-1] = aps
|
3486
|
+
res_parts << last_part
|
3487
|
+
end
|
3488
|
+
path_prefix = []
|
3489
|
+
if ::Brick.config.path_prefix
|
3490
|
+
res_parts.unshift(::Brick.config.path_prefix)
|
3491
|
+
path_prefix << ::Brick.config.path_prefix
|
3492
|
+
end
|
3493
|
+
index = res_parts.map(&:underscore).join(separator)
|
3494
|
+
index = index.tr('_', 'x') if separator == 'x'
|
3495
|
+
# Rails applies an _index suffix to that route when the resource name isn't something plural
|
3496
|
+
index << '_index' if mode != :singular && separator == '_' &&
|
3497
|
+
index == (path_prefix + [name&.underscore&.tr('/', '_') || '_']).join(separator)
|
3498
|
+
index
|
3499
|
+
end
|
3500
|
+
|
3374
3501
|
def find_col_renaming(api_ver_path, relation_name)
|
3375
3502
|
::Brick.config.api_column_renaming&.fetch(
|
3376
3503
|
api_ver_path,
|
@@ -345,7 +345,8 @@ function linkSchemas() {
|
|
345
345
|
end
|
346
346
|
::Brick.relations.each do |k, v|
|
347
347
|
unless k.is_a?(Symbol) || existing.key?(class_name = v[:class_name]) || Brick.config.exclude_tables.include?(k) ||
|
348
|
-
class_name.blank? || class_name.include?('::')
|
348
|
+
class_name.blank? || class_name.include?('::') ||
|
349
|
+
['ActiveAdminComment', 'MotorAlert', 'MotorAlertLock', 'MotorApiConfig', 'MotorAudit', 'MotorConfig', 'MotorDashboard', 'MotorForm', 'MotorNote', 'MotorNoteTag', 'MotorNoteTagTag', 'MotorNotification', 'MotorQuery', 'MotorReminder', 'MotorResource', 'MotorTag', 'MotorTaggableTag'].include?(class_name)
|
349
350
|
Object.const_get("#{class_name}Resource")
|
350
351
|
end
|
351
352
|
end
|
@@ -774,9 +775,18 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
774
775
|
end
|
775
776
|
# %%% If we are not auto-creating controllers (or routes) then omit by default, and if enabled anyway, such as in a development
|
776
777
|
# environment or whatever, then get either the controllers or routes list instead
|
777
|
-
|
778
|
-
|
779
|
-
|
778
|
+
table_rels = if ::Brick.config.omit_empty_tables_in_dropdown
|
779
|
+
::Brick.relations.reject { |k, v| k.is_a?(Symbol) || v[:rowcount] == 0 }
|
780
|
+
else
|
781
|
+
::Brick.relations
|
782
|
+
end
|
783
|
+
table_options = table_rels.sort do |a, b|
|
784
|
+
a[0] = '' if a[0].is_a?(Symbol)
|
785
|
+
b[0] = '' if b[0].is_a?(Symbol)
|
786
|
+
a.first <=> b.first
|
787
|
+
end.each_with_object(+'') do |rel, s|
|
788
|
+
next if rel.first.blank? || rel.last[:cols].empty? ||
|
789
|
+
::Brick.config.exclude_tables.include?(rel.first)
|
780
790
|
|
781
791
|
tbl_parts = rel.first.split('.')
|
782
792
|
if (aps = rel.last.fetch(:auto_prefixed_schema, nil))
|
@@ -784,16 +794,16 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
784
794
|
aps = aps[0..-2] if aps[-1] == '_'
|
785
795
|
tbl_parts[-2] = aps
|
786
796
|
end
|
787
|
-
if tbl_parts.first == apartment_default_schema
|
788
|
-
tbl_parts.shift
|
789
|
-
end
|
797
|
+
tbl_parts.shift if tbl_parts.first == apartment_default_schema
|
790
798
|
# %%% When table_name_prefixes are use then during rendering empty non-TNP
|
791
799
|
# entries get added at some point when an attempt is made to find the table.
|
792
800
|
# Will have to hunt that down at some point.
|
793
|
-
|
794
|
-
|
795
|
-
|
801
|
+
if (rowcount = rel.last.fetch(:rowcount, nil))
|
802
|
+
rowcount = rowcount > 0 ? " (#{rowcount})" : nil
|
803
|
+
end
|
804
|
+
s << "<option value=\"#{::Brick._brick_index(rel.first, nil, '/')}\">#{rel.first}#{rowcount}</option>"
|
796
805
|
end.html_safe
|
806
|
+
prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
|
797
807
|
table_options << "<option value=\"#{prefix}brick_status\">(Status)</option>".html_safe if ::Brick.config.add_status
|
798
808
|
table_options << "<option value=\"#{prefix}brick_orphans\">(Orphans)</option>".html_safe if is_orphans
|
799
809
|
table_options << "<option value=\"#{prefix}brick_crosstab\">(Crosstab)</option>".html_safe if is_crosstab
|
@@ -1476,7 +1486,7 @@ end
|
|
1476
1486
|
%>
|
1477
1487
|
<tr>
|
1478
1488
|
<td><%= begin
|
1479
|
-
kls = Object.const_get(::Brick.relations.fetch(r[0], nil)&.fetch(:class_name, nil))
|
1489
|
+
kls = Object.const_get((rel = ::Brick.relations.fetch(r[0], nil))&.fetch(:class_name, nil))
|
1480
1490
|
rescue
|
1481
1491
|
end
|
1482
1492
|
if kls.is_a?(Class) && (path_helper = respond_to?(bi_path = \"#\{kls._brick_index}_path\".to_sym) ? bi_path : nil)
|
@@ -1489,7 +1499,10 @@ end
|
|
1489
1499
|
else
|
1490
1500
|
' class=\"dimmed\"'
|
1491
1501
|
end&.html_safe %>><%= # Table
|
1492
|
-
|
1502
|
+
if (rowcount = rel&.fetch(:rowcount, nil))
|
1503
|
+
rowcount = (rowcount > 0 ? \" (#\{rowcount})\" : nil)
|
1504
|
+
end
|
1505
|
+
\"#\{r[1]}#\{rowcount}\" %></td>
|
1493
1506
|
<td<%= lines = r[2]&.map { |line| \"#\{line.first}:#\{line.last}\" }
|
1494
1507
|
' class=\"dimmed\"'.html_safe unless r[2] %>><%= # Migration
|
1495
1508
|
lines&.join('<br>')&.html_safe %></td>
|
@@ -1571,7 +1584,13 @@ end %>#{"
|
|
1571
1584
|
#{schema_options}" if schema_options}
|
1572
1585
|
<select id=\"tbl\">#{table_options}</select>
|
1573
1586
|
<table id=\"resourceName\"><td><h1><%= page_title %></h1></td>
|
1574
|
-
<%
|
1587
|
+
<% rel = Brick.relations[#{model_name}.table_name]
|
1588
|
+
if (in_app = rel.fetch(:existing, nil)&.fetch(:show, nil))
|
1589
|
+
in_app = send(\"#\{in_app}_path\", #{pk.is_a?(String) ? "obj.#{pk}" : '[' + pk.map { |pk_part| "obj.#{pk_part}" }.join(', ') + ']' }) if in_app.is_a?(Symbol) %>
|
1590
|
+
<td><%= link_to(::Brick::Rails::IN_APP.html_safe, in_app) %></td>
|
1591
|
+
<% end
|
1592
|
+
|
1593
|
+
if Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) %>
|
1575
1594
|
<td><%= link_to_brick(
|
1576
1595
|
::Brick::Rails::AVO_SVG.html_safe,
|
1577
1596
|
{ show_proc: Proc.new do |obj, relation|
|
@@ -1596,7 +1615,7 @@ end %>#{"
|
|
1596
1615
|
end %>
|
1597
1616
|
</table>
|
1598
1617
|
<%
|
1599
|
-
if (description =
|
1618
|
+
if (description = rel&.fetch(:description, nil)) %>
|
1600
1619
|
<span class=\"__brick\"><%= description %></span><br><%
|
1601
1620
|
end
|
1602
1621
|
%><%= link_to \"(See all #\{model_name.pluralize})\", see_all_path, { class: '__brick' } %>
|
@@ -1927,6 +1946,7 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
|
|
1927
1946
|
end
|
1928
1947
|
|
1929
1948
|
if ::Brick.enable_routes?
|
1949
|
+
require 'brick/route_mapper'
|
1930
1950
|
ActionDispatch::Routing::RouteSet.class_exec do
|
1931
1951
|
# In order to defer auto-creation of any routes that already exist, calculate Brick routes only after having loaded all others
|
1932
1952
|
prepend ::Brick::RouteSet
|
@@ -148,7 +148,8 @@ module Brick::Rails::FormBuilder
|
|
148
148
|
'(hidden)'
|
149
149
|
else
|
150
150
|
if val.is_a?(String)
|
151
|
-
val = val.dup.force_encoding('UTF-8').
|
151
|
+
return ::Brick::Rails.display_binary(val) unless (val_utf8 = val.dup.force_encoding('UTF-8')).valid_encoding?
|
152
|
+
val = val_utf8.strip
|
152
153
|
return CGI.escapeHTML(val) if is_xml
|
153
154
|
|
154
155
|
if val.length > max_len
|
@@ -2,7 +2,7 @@ module Brick::Rails::FormTags
|
|
2
2
|
# Our super speedy grid
|
3
3
|
def brick_grid(relation = nil, sequence = nil, inclusions = nil, exclusions = nil,
|
4
4
|
cols = {}, bt_descrip: nil, poly_cols: nil, bts: {}, hms_keys: [], hms_cols: {},
|
5
|
-
show_header: nil, show_row_count: nil, show_erd_button: nil, show_new_button: nil, show_avo_button: nil, show_aa_button: nil)
|
5
|
+
show_header: nil, show_row_count: nil, show_erd_button: nil, show_in_app_button: nil, show_new_button: nil, show_avo_button: nil, show_aa_button: nil)
|
6
6
|
# When a relation is not provided, first see if one exists which matches the controller name
|
7
7
|
unless (relation ||= instance_variable_get("@#{controller_name}".to_sym))
|
8
8
|
# Failing that, dig through the instance variables with hopes to find something that is an ActiveRecord::Relation
|
@@ -33,6 +33,7 @@ module Brick::Rails::FormTags
|
|
33
33
|
out = +"<div id=\"headerTopContainer\"><table id=\"headerTop\"></table>
|
34
34
|
"
|
35
35
|
klass = relation.klass
|
36
|
+
rel = ::Brick.relations&.fetch(relation.table_name, nil)
|
36
37
|
unless show_header == false
|
37
38
|
out << " <div id=\"headerTopAddNew\">
|
38
39
|
<div id=\"headerButtonBox\">
|
@@ -43,6 +44,11 @@ module Brick::Rails::FormTags
|
|
43
44
|
end
|
44
45
|
unless show_erd_button == false
|
45
46
|
out << " <div id=\"imgErd\" title=\"Show ERD\"></div>
|
47
|
+
"
|
48
|
+
end
|
49
|
+
if rel && show_in_app_button != false && (in_app = rel.fetch(:existing, nil)&.fetch(:index, nil))
|
50
|
+
in_app = send("#{in_app}_path") if in_app.is_a?(Symbol)
|
51
|
+
out << " <td title=\"Show in app\">#{link_to(::Brick::Rails::IN_APP.html_safe, in_app)}</td>
|
46
52
|
"
|
47
53
|
end
|
48
54
|
if show_avo_button != false && Object.const_defined?('Avo') && ::Avo.respond_to?(:railtie_namespace) && klass.name.exclude?('::')
|
@@ -151,7 +157,7 @@ module Brick::Rails::FormTags
|
|
151
157
|
# ActiveRecord::StatementTimeout in Warehouse::ColdRoomTemperatures_Archive#index
|
152
158
|
# TinyTds::Error: Adaptive Server connection timed out
|
153
159
|
# (After restarting the server it worked fine again.)
|
154
|
-
|
160
|
+
row_count = 0
|
155
161
|
relation.each do |obj|
|
156
162
|
out << "<tr>\n"
|
157
163
|
out << "<td class=\"col-sticky\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym,
|
@@ -252,13 +258,16 @@ module Brick::Rails::FormTags
|
|
252
258
|
out << '</td>'
|
253
259
|
end
|
254
260
|
out << '</tr>'
|
255
|
-
|
261
|
+
row_count += 1
|
262
|
+
end
|
263
|
+
if rel && (total_row_count = rel.fetch(:rowcount, nil))
|
264
|
+
total_row_count = total_row_count > row_count ? " (out of #{total_row_count})" : nil
|
256
265
|
end
|
257
266
|
out << " </tbody>
|
258
267
|
</table>
|
259
268
|
<script>
|
260
269
|
var rowCount = document.getElementById(\"rowCount\");
|
261
|
-
if (rowCount) rowCount.innerHTML = \"#{pluralize(
|
270
|
+
if (rowCount) rowCount.innerHTML = \"#{pluralize(row_count, "row")}#{total_row_count} \";
|
262
271
|
</script>
|
263
272
|
"
|
264
273
|
|