brick 1.0.92 → 1.0.93
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 +78 -154
- data/lib/brick/frameworks/rails/engine.rb +61 -41
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +33 -81
- metadata +2 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8488acac0623c04f11e916c67303fd06d471154231c92613318cc7458fcfe23f
|
4
|
+
data.tar.gz: af566c853bb25e7497a6afbba539ad0d14ec23ad000c053e6dbdf757deefbaa0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0d8428b6f80bf3a79abb16265fb8625404f92caf30034da94186a5c5982a78543f29e0a49cc0dc515eb8b6d6da24ccdd53e8d089c90dce46ce214ce5bee4339
|
7
|
+
data.tar.gz: 562bd7522f0f45843a89464645e1cc153e455e1e5b4e3dec5f1b38a8bfaefd8bd359a2538aa274b90b50353285d2175f315b7e304e54e60516a5ce2ed3b2fc7e
|
data/lib/brick/extensions.rb
CHANGED
@@ -42,21 +42,6 @@
|
|
42
42
|
# Dynamically create model or controller classes when needed
|
43
43
|
# ==========================================================
|
44
44
|
|
45
|
-
# By default all models indicate that they are not views
|
46
|
-
module Arel
|
47
|
-
class Table
|
48
|
-
def _arel_table_type
|
49
|
-
# AR < 4.2 doesn't have type_caster at all, so rely on an instance variable getting set
|
50
|
-
# AR 4.2 - 5.1 have buggy type_caster entries for the root node
|
51
|
-
instance_variable_get(:@_arel_table_type) ||
|
52
|
-
# 5.2-7.0 does type_caster just fine, no bugs there, but the property with the type differs:
|
53
|
-
# 5.2 has "types" as public, 6.0 "types" as private, and >= 6.1 "klass" as private.
|
54
|
-
((tc = send(:type_caster)) && tc.instance_variable_get(:@types)) ||
|
55
|
-
tc.send(:klass)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
45
|
module ActiveRecord
|
61
46
|
class Base
|
62
47
|
def self.is_brick?
|
@@ -270,7 +255,7 @@ module ActiveRecord
|
|
270
255
|
|
271
256
|
def self._brick_index(mode = nil)
|
272
257
|
tbl_parts = ((mode == :singular) ? table_name.singularize : table_name).split('.')
|
273
|
-
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first ==
|
258
|
+
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
|
274
259
|
tbl_parts.unshift(::Brick.config.path_prefix) if ::Brick.config.path_prefix
|
275
260
|
index = tbl_parts.map(&:underscore).join('_')
|
276
261
|
# Rails applies an _index suffix to that route when the resource name is singular
|
@@ -407,86 +392,12 @@ module ActiveRecord
|
|
407
392
|
end
|
408
393
|
|
409
394
|
class Relation
|
410
|
-
|
411
|
-
|
412
|
-
# Links from ActiveRecord association pathing names over to real
|
413
|
-
# table correlation names built from AREL aliasing
|
395
|
+
# Links from ActiveRecord association pathing names over to real table correlation names
|
396
|
+
# that get chosen when the AREL AST tree is walked.
|
414
397
|
def brick_links
|
415
398
|
@brick_links ||= {}
|
416
399
|
end
|
417
400
|
|
418
|
-
# CLASS STUFF
|
419
|
-
def _recurse_arel(piece, prefix = '')
|
420
|
-
names = []
|
421
|
-
# Our JOINs mashup of nested arrays and hashes
|
422
|
-
# binding.pry if defined?(@arel)
|
423
|
-
case piece
|
424
|
-
when Array
|
425
|
-
names += piece.inject([]) { |s, v| s + _recurse_arel(v, prefix) }
|
426
|
-
when Hash
|
427
|
-
names += piece.inject([]) do |s, v|
|
428
|
-
new_prefix = "#{prefix}#{v.first}_"
|
429
|
-
s << [v.last.shift, new_prefix]
|
430
|
-
s + _recurse_arel(v.last, new_prefix)
|
431
|
-
end
|
432
|
-
|
433
|
-
# ActiveRecord AREL objects
|
434
|
-
when Arel::Nodes::Join # INNER or OUTER JOIN
|
435
|
-
# rubocop:disable Style/IdenticalConditionalBranches
|
436
|
-
if piece.right.is_a?(Arel::Table) # Came in from AR < 3.2?
|
437
|
-
# Arel 2.x and older is a little curious because these JOINs work "back to front".
|
438
|
-
# The left side here is either another earlier JOIN, or at the end of the whole tree, it is
|
439
|
-
# the first table.
|
440
|
-
names += _recurse_arel(piece.left)
|
441
|
-
# The right side here at the top is the very last table, and anywhere else down the tree it is
|
442
|
-
# the later "JOIN" table of this pair. (The table that comes after all the rest of the JOINs
|
443
|
-
# from the left side.)
|
444
|
-
names << [piece.right._arel_table_type, (piece.right.table_alias || piece.right.name)]
|
445
|
-
else # "Normal" setup, fed from a JoinSource which has an array of JOINs
|
446
|
-
# The left side is the "JOIN" table
|
447
|
-
names += _recurse_arel(table = piece.left)
|
448
|
-
# The expression on the right side is the "ON" clause
|
449
|
-
# on = piece.right.expr
|
450
|
-
# # Find the table which is not ourselves, and thus must be the "path" that led us here
|
451
|
-
# parent = piece.left == on.left.relation ? on.right.relation : on.left.relation
|
452
|
-
# binding.pry if piece.left.is_a?(Arel::Nodes::TableAlias)
|
453
|
-
if table.is_a?(Arel::Nodes::TableAlias)
|
454
|
-
@_arel_applied_aliases << (alias_name = table.right)
|
455
|
-
table = table.left
|
456
|
-
end
|
457
|
-
end
|
458
|
-
# rubocop:enable Style/IdenticalConditionalBranches
|
459
|
-
when Arel::Table # Table
|
460
|
-
names << [piece._arel_table_type, (piece.table_alias || piece.name)]
|
461
|
-
when Arel::Nodes::TableAlias # Alias
|
462
|
-
# Can get the real table name from: self._recurse_arel(piece.left)
|
463
|
-
names << [piece.left._arel_table_type, piece.right.to_s] # This is simply a string; the alias name itself
|
464
|
-
when Arel::Nodes::JoinSource # Leaving this until the end because AR < 3.2 doesn't know at all about JoinSource!
|
465
|
-
# The left side is the "FROM" table
|
466
|
-
names << (this_name = [piece.left._arel_table_type, (piece.left.table_alias || piece.left.name)])
|
467
|
-
# The right side is an array of all JOINs
|
468
|
-
piece.right.each { |join| names << _recurse_arel(join) }
|
469
|
-
end
|
470
|
-
names
|
471
|
-
end
|
472
|
-
|
473
|
-
# INSTANCE STUFF
|
474
|
-
def _arel_alias_names
|
475
|
-
@_arel_applied_aliases = []
|
476
|
-
# %%% If with Rails 3.1 and older you get "NoMethodError: undefined method `eq' for nil:NilClass"
|
477
|
-
# when trying to call relation.arel, then somewhere along the line while navigating a has_many
|
478
|
-
# relationship it can't find the proper foreign key.
|
479
|
-
core = arel.ast.cores.first
|
480
|
-
# Accommodate AR < 3.2
|
481
|
-
if core.froms.is_a?(Arel::Table)
|
482
|
-
# All recent versions of AR have #source which brings up an Arel::Nodes::JoinSource
|
483
|
-
_recurse_arel(core.source)
|
484
|
-
else
|
485
|
-
# With AR < 3.2, "froms" brings up the top node, an Arel::Nodes::InnerJoin
|
486
|
-
_recurse_arel(core.froms)
|
487
|
-
end
|
488
|
-
end
|
489
|
-
|
490
401
|
def brick_select(params, selects = [], order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
|
491
402
|
is_add_bts = is_add_hms = true
|
492
403
|
|
@@ -502,13 +413,16 @@ module ActiveRecord
|
|
502
413
|
params.each do |k, v|
|
503
414
|
next if ['_brick_schema', '_brick_order', 'controller', 'action'].include?(k)
|
504
415
|
|
505
|
-
|
416
|
+
if (where_col = (ks = k.split('.')).last)[-1] == '!'
|
417
|
+
where_col = where_col[0..-2]
|
418
|
+
end
|
419
|
+
case ks.length
|
506
420
|
when 1
|
507
|
-
next unless klass.column_names.any?(
|
421
|
+
next unless klass.column_names.any?(where_col) || klass._brick_get_fks.include?(where_col)
|
508
422
|
when 2
|
509
423
|
assoc_name = ks.first.to_sym
|
510
424
|
# Make sure it's a good association name and that the model has that column name
|
511
|
-
next unless klass.reflect_on_association(assoc_name)&.klass&.column_names&.any?(
|
425
|
+
next unless klass.reflect_on_association(assoc_name)&.klass&.column_names&.any?(where_col)
|
512
426
|
|
513
427
|
join_array[assoc_name] = nil # Store this relation name in our special collection for .joins()
|
514
428
|
is_distinct = true
|
@@ -546,8 +460,19 @@ module ActiveRecord
|
|
546
460
|
|
547
461
|
if join_array.present?
|
548
462
|
left_outer_joins!(join_array)
|
549
|
-
#
|
550
|
-
|
463
|
+
# Touching AREL AST walks the JoinDependency tree, and in that process uses our
|
464
|
+
# "brick_links" patch to find how every AR chain of association names relates to exact
|
465
|
+
# table correlation names chosen by AREL. We use a duplicate relation object for this
|
466
|
+
# because an important side-effect of referencing the AST is that the @arel instance
|
467
|
+
# variable gets set, and this is a signal to ActiveRecord that a relation has now
|
468
|
+
# become immutable. (We aren't quite ready for our "real deal" relation object to be
|
469
|
+
# set in stone ... still need to add .select(), and possibly .where() and .order()
|
470
|
+
# things ... also if there are any HM counts then an OUTER JOIN for each of them out
|
471
|
+
# to a derived table to do that counting. All of these things need to know proper
|
472
|
+
# table correlation names, which will now become available in brick_links on the
|
473
|
+
# rel_dupe object.)
|
474
|
+
(rel_dupe = dup).arel.ast
|
475
|
+
|
551
476
|
core_selects = selects.dup
|
552
477
|
id_for_tables = Hash.new { |h, k| h[k] = [] }
|
553
478
|
field_tbl_names = Hash.new { |h, k| h[k] = {} }
|
@@ -609,12 +534,12 @@ module ActiveRecord
|
|
609
534
|
next unless (tbl_name = rel_dupe.brick_links[v.first.to_s]&.split('.')&.last)
|
610
535
|
|
611
536
|
# If it's Oracle, quote any AREL aliases that had been applied
|
612
|
-
tbl_name = "\"#{tbl_name}\"" if ::Brick.is_oracle && rel_dupe.
|
537
|
+
tbl_name = "\"#{tbl_name}\"" if ::Brick.is_oracle && rel_dupe.brick_links.values.include?(tbl_name)
|
613
538
|
field_tbl_name = nil
|
614
539
|
v1.map { |x| [x[0..-2].map(&:to_s).join('.'), x.last] }.each_with_index do |sel_col, idx|
|
615
540
|
field_tbl_name = rel_dupe.brick_links[sel_col.first].split('.').last
|
616
541
|
# If it's Oracle, quote any AREL aliases that had been applied
|
617
|
-
field_tbl_name = "\"#{field_tbl_name}\"" if ::Brick.is_oracle && rel_dupe.
|
542
|
+
field_tbl_name = "\"#{field_tbl_name}\"" if ::Brick.is_oracle && rel_dupe.brick_links.values.include?(field_tbl_name)
|
618
543
|
|
619
544
|
# Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
|
620
545
|
is_xml = is_distinct && Brick.relations[field_tbl_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
|
@@ -786,16 +711,23 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
786
711
|
|
787
712
|
unless wheres.empty?
|
788
713
|
# Rewrite the wheres to reference table and correlation names built out by AREL
|
714
|
+
where_nots = {}
|
789
715
|
wheres2 = wheres.each_with_object({}) do |v, s|
|
716
|
+
is_not = if v.first[-1] == '!'
|
717
|
+
v[0] = v[0][0..-2] # Take off ending ! from column name
|
718
|
+
end
|
790
719
|
if (v_parts = v.first.split('.')).length == 1
|
791
|
-
s[v.first] = v.last
|
720
|
+
(is_not ? where_nots : s)[v.first] = v.last
|
792
721
|
else
|
793
722
|
tbl_name = rel_dupe.brick_links[v_parts.first].split('.').last
|
794
|
-
s["#{tbl_name}.#{v_parts.last}"] = v.last
|
723
|
+
(is_not ? where_nots : s)["#{tbl_name}.#{v_parts.last}"] = v.last
|
795
724
|
end
|
796
725
|
end
|
797
726
|
if respond_to?(:where!)
|
798
|
-
where!(wheres2)
|
727
|
+
where!(wheres2) if wheres2.present?
|
728
|
+
if where_nots.present?
|
729
|
+
self.where_clause += WhereClause.new(predicate_builder.build_from_hash(where_nots)).invert
|
730
|
+
end
|
799
731
|
else # AR < 4.0
|
800
732
|
self.where_values << build_where(wheres2)
|
801
733
|
end
|
@@ -1091,7 +1023,8 @@ Module.class_exec do
|
|
1091
1023
|
(table_name = singular_table_name.pluralize),
|
1092
1024
|
::Brick.is_oracle ? class_name.upcase : class_name,
|
1093
1025
|
(plural_class_name = class_name.pluralize)].find { |s| Brick.db_schemas&.include?(s) }&.camelize ||
|
1094
|
-
(::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name)
|
1026
|
+
(::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name) ||
|
1027
|
+
(::Brick.config.table_name_prefixes&.values.include?(class_name) && class_name))
|
1095
1028
|
return self.const_get(schema_name) if self.const_defined?(schema_name)
|
1096
1029
|
|
1097
1030
|
# Build out a module for the schema if it's namespaced
|
@@ -1142,6 +1075,7 @@ class Object
|
|
1142
1075
|
private
|
1143
1076
|
|
1144
1077
|
def build_model(relations, base_module, base_name, class_name, inheritable_name = nil)
|
1078
|
+
tnp = ::Brick.config.table_name_prefixes&.find { |p| p.last == base_module.name }&.first
|
1145
1079
|
if (base_model = ::Brick.config.sti_namespace_prefixes&.fetch("::#{base_module.name}::", nil)&.constantize) || # Are we part of an auto-STI namespace? ...
|
1146
1080
|
base_module != Object # ... or otherwise already in some namespace?
|
1147
1081
|
schema_name = [(singular_schema_name = base_name.underscore),
|
@@ -1163,11 +1097,11 @@ class Object
|
|
1163
1097
|
table_name = if (base_model = ::Brick.sti_models[model_name]&.fetch(:base, nil) || ::Brick.existing_stis[model_name]&.constantize)
|
1164
1098
|
base_model.table_name
|
1165
1099
|
else
|
1166
|
-
ActiveSupport::Inflector.pluralize(singular_table_name)
|
1100
|
+
"#{tnp}#{ActiveSupport::Inflector.pluralize(singular_table_name)}"
|
1167
1101
|
end
|
1168
1102
|
if ::Brick.apartment_multitenant &&
|
1169
1103
|
Apartment.excluded_models.include?(table_name.singularize.camelize)
|
1170
|
-
schema_name =
|
1104
|
+
schema_name = ::Brick.apartment_default_tenant
|
1171
1105
|
end
|
1172
1106
|
# Maybe, just maybe there's a database table that will satisfy this need
|
1173
1107
|
if (matching = [table_name, singular_table_name, plural_class_name, model_name, table_name.titleize].find { |m| relations.key?(schema_name ? "#{schema_name}.#{m}" : m) })
|
@@ -1178,7 +1112,7 @@ class Object
|
|
1178
1112
|
|
1179
1113
|
def build_model_worker(schema_name, inheritable_name, model_name, singular_table_name, table_name, relations, matching)
|
1180
1114
|
if ::Brick.apartment_multitenant &&
|
1181
|
-
schema_name ==
|
1115
|
+
schema_name == ::Brick.apartment_default_tenant
|
1182
1116
|
relation = relations["#{schema_name}.#{matching}"]
|
1183
1117
|
end
|
1184
1118
|
full_name = if relation || schema_name.blank?
|
@@ -1380,7 +1314,7 @@ class Object
|
|
1380
1314
|
# If it's multitenant with something like: public.____ ...
|
1381
1315
|
if (it_parts = inverse_table.split('.')).length > 1 &&
|
1382
1316
|
::Brick.apartment_multitenant &&
|
1383
|
-
it_parts.first ==
|
1317
|
+
it_parts.first == ::Brick.apartment_default_tenant
|
1384
1318
|
it_parts.shift # ... then ditch the generic schema name
|
1385
1319
|
end
|
1386
1320
|
inverse_assoc_name, _x = _brick_get_hm_assoc_name(relations[inverse_table], inverse, it_parts.join('_').singularize)
|
@@ -1477,7 +1411,7 @@ class Object
|
|
1477
1411
|
instance_variable_set(:@resources, ::Brick.get_status_of_resources)
|
1478
1412
|
end
|
1479
1413
|
self.define_method :orphans do
|
1480
|
-
instance_variable_set(:@orphans, ::Brick.find_orphans(::Brick.set_db_schema(params)))
|
1414
|
+
instance_variable_set(:@orphans, ::Brick.find_orphans(::Brick.set_db_schema(params).first))
|
1481
1415
|
end
|
1482
1416
|
return [new_controller_class, code + "end # BrickGem controller\n"]
|
1483
1417
|
when 'BrickOpenapi'
|
@@ -1495,7 +1429,7 @@ class Object
|
|
1495
1429
|
api_params = referrer_params&.to_h
|
1496
1430
|
end
|
1497
1431
|
end
|
1498
|
-
::Brick.set_db_schema(params || api_params)
|
1432
|
+
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params || api_params)
|
1499
1433
|
|
1500
1434
|
if is_openapi
|
1501
1435
|
json = { 'openapi': '3.0.1', 'info': { 'title': Rswag::Ui.config.config_object[:urls].last&.fetch(:name, 'API documentation'), 'version': ::Brick.config.api_version },
|
@@ -1597,7 +1531,6 @@ class Object
|
|
1597
1531
|
end
|
1598
1532
|
|
1599
1533
|
unless is_openapi
|
1600
|
-
::Brick.set_db_schema
|
1601
1534
|
_, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk)) if pk
|
1602
1535
|
code << " def index\n"
|
1603
1536
|
code << " @#{table_name.pluralize} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
|
@@ -1610,7 +1543,7 @@ class Object
|
|
1610
1543
|
code << " #{find_by_name = "find_#{singular_table_name}"}\n"
|
1611
1544
|
code << " end\n"
|
1612
1545
|
self.define_method :show do
|
1613
|
-
::Brick.set_db_schema(params)
|
1546
|
+
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
1614
1547
|
instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
|
1615
1548
|
end
|
1616
1549
|
end
|
@@ -1621,7 +1554,7 @@ class Object
|
|
1621
1554
|
code << " @#{singular_table_name} = #{model.name}.new\n"
|
1622
1555
|
code << " end\n"
|
1623
1556
|
self.define_method :new do
|
1624
|
-
::Brick.set_db_schema(params)
|
1557
|
+
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
1625
1558
|
instance_variable_set("@#{singular_table_name}".to_sym, model.new)
|
1626
1559
|
end
|
1627
1560
|
|
@@ -1660,7 +1593,7 @@ class Object
|
|
1660
1593
|
code << " #{find_by_name}\n"
|
1661
1594
|
code << " end\n"
|
1662
1595
|
self.define_method :edit do
|
1663
|
-
::Brick.set_db_schema(params)
|
1596
|
+
_schema, @_is_show_schema_list = ::Brick.set_db_schema(params)
|
1664
1597
|
instance_variable_set("@#{singular_table_name}".to_sym, find_obj)
|
1665
1598
|
end
|
1666
1599
|
|
@@ -1889,13 +1822,22 @@ end.class_exec do
|
|
1889
1822
|
s[row.first] = { dt: row.last } unless ['information_schema', 'pg_catalog', 'pg_toast', 'heroku_ext',
|
1890
1823
|
'INFORMATION_SCHEMA', 'sys'].include?(row.first)
|
1891
1824
|
end
|
1892
|
-
if (
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1825
|
+
if (possible_schemas = (multitenancy = ::Brick.config.schema_behavior&.[](:multitenant)) &&
|
1826
|
+
multitenancy&.[](:schema_to_analyse))
|
1827
|
+
possible_schemas = [possible_schemas] unless possible_schemas.is_a?(Array)
|
1828
|
+
if (possible_schema = possible_schemas.find { |ps| ::Brick.db_schemas.key?(ps) })
|
1829
|
+
::Brick.default_schema = ::Brick.apartment_default_tenant
|
1830
|
+
schema = possible_schema
|
1831
|
+
orig_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
1832
|
+
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema)
|
1833
|
+
elsif Rails.env == 'test' # When testing, just find the most recently-created schema
|
1834
|
+
::Brick.default_schema = schema = ::Brick.db_schemas.to_a.sort { |a, b| b.last[:dt] <=> a.last[:dt] }.first.first
|
1835
|
+
puts "While running tests, had noticed in the brick.rb initializer that the line \"::Brick.schema_behavior = ...\" refers to a schema called \"#{possible_schema}\" which does not exist. Reading table structure from the most recently-created schema, #{schema}."
|
1836
|
+
orig_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
1837
|
+
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema)
|
1838
|
+
else
|
1839
|
+
puts "*** In the brick.rb initializer the line \"::Brick.schema_behavior = ...\" refers to schema(s) called #{possible_schemas.map { |s| "\"#{s}\"" }.join(', ')}. No mentioned schema exists. ***"
|
1840
|
+
end
|
1899
1841
|
end
|
1900
1842
|
when 'Mysql2'
|
1901
1843
|
::Brick.default_schema = schema = ActiveRecord::Base.connection.current_database
|
@@ -1918,24 +1860,6 @@ end.class_exec do
|
|
1918
1860
|
|
1919
1861
|
::Brick.db_schemas ||= {}
|
1920
1862
|
|
1921
|
-
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
1922
|
-
if (possible_schemas = ::Brick.config.schema_behavior&.[](:multitenant)&.[](:schema_to_analyse))
|
1923
|
-
possible_schemas = [possible_schemas] unless possible_schemas.is_a?(Array)
|
1924
|
-
if (possible_schema = possible_schemas.find { |ps| ::Brick.db_schemas.key?(ps) })
|
1925
|
-
::Brick.default_schema = schema = possible_schema
|
1926
|
-
orig_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
1927
|
-
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema)
|
1928
|
-
elsif Rails.env == 'test' # When testing, just find the most recently-created schema
|
1929
|
-
::Brick.default_schema = schema = ::Brick.db_schemas.to_a.sort { |a, b| b.last[:dt] <=> a.last[:dt] }.first.first
|
1930
|
-
puts "While running tests, had noticed in the brick.rb initializer that the line \"::Brick.schema_behavior = ...\" refers to a schema called \"#{possible_schema}\" which does not exist. Reading table structure from the most recently-created schema, #{schema}."
|
1931
|
-
orig_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
1932
|
-
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", schema)
|
1933
|
-
else
|
1934
|
-
puts "*** In the brick.rb initializer the line \"::Brick.schema_behavior = ...\" refers to schema(s) called #{possible_schemas.map { |s| "\"#{s}\"" }.join(', ')}. No mentioned schema exists. ***"
|
1935
|
-
end
|
1936
|
-
end
|
1937
|
-
end
|
1938
|
-
|
1939
1863
|
# %%% Retrieve internal ActiveRecord table names like this:
|
1940
1864
|
# ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
|
1941
1865
|
# For if it's not SQLite -- so this is the Postgres and MySQL version
|
@@ -1948,7 +1872,7 @@ end.class_exec do
|
|
1948
1872
|
# If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
|
1949
1873
|
# is the default schema, usually 'public'.
|
1950
1874
|
schema_name = if ::Brick.config.schema_behavior[:multitenant]
|
1951
|
-
|
1875
|
+
::Brick.apartment_default_tenant if apartment_excluded&.include?(r['relation_name'].singularize.camelize)
|
1952
1876
|
elsif ![schema, 'public'].include?(r['schema'])
|
1953
1877
|
r['schema']
|
1954
1878
|
end
|
@@ -2099,16 +2023,16 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2099
2023
|
fk = fk.values unless fk.is_a?(Array)
|
2100
2024
|
# Multitenancy makes things a little more general overall, except for non-tenanted tables
|
2101
2025
|
if apartment_excluded&.include?(::Brick.namify(fk[1]).singularize.camelize)
|
2102
|
-
fk[0] =
|
2103
|
-
elsif (is_postgres && (fk[0] == 'public' || (
|
2026
|
+
fk[0] = ::Brick.apartment_default_tenant
|
2027
|
+
elsif (is_postgres && (fk[0] == 'public' || (multitenancy && fk[0] == schema))) ||
|
2104
2028
|
(::Brick.is_oracle && fk[0] == schema) ||
|
2105
2029
|
(is_mssql && fk[0] == 'dbo') ||
|
2106
2030
|
(!is_postgres && !::Brick.is_oracle && !is_mssql && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0]))
|
2107
2031
|
fk[0] = nil
|
2108
2032
|
end
|
2109
2033
|
if apartment_excluded&.include?(fk[4].singularize.camelize)
|
2110
|
-
fk[3] =
|
2111
|
-
elsif (is_postgres && (fk[3] == 'public' || (
|
2034
|
+
fk[3] = ::Brick.apartment_default_tenant
|
2035
|
+
elsif (is_postgres && (fk[3] == 'public' || (multitenancy && fk[3] == schema))) ||
|
2112
2036
|
(::Brick.is_oracle && fk[3] == schema) ||
|
2113
2037
|
(is_mssql && fk[3] == 'dbo') ||
|
2114
2038
|
(!is_postgres && !::Brick.is_oracle && !is_mssql && ['mysql', 'performance_schema', 'sys'].exclude?(fk[3]))
|
@@ -2126,7 +2050,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2126
2050
|
relations.each do |k, v|
|
2127
2051
|
rel_name = k.split('.').map { |rel_part| ::Brick.namify(rel_part, :underscore) }
|
2128
2052
|
schema_names = rel_name[0..-2]
|
2129
|
-
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first ==
|
2053
|
+
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first == ::Brick.apartment_default_tenant
|
2130
2054
|
v[:schema] = schema_names.join('.') unless schema_names.empty?
|
2131
2055
|
# %%% If more than one schema has the same table name, will need to add a schema name prefix to have uniqueness
|
2132
2056
|
v[:resource] = rel_name.last
|
@@ -2137,7 +2061,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2137
2061
|
end
|
2138
2062
|
::Brick.load_additional_references if initializer_loaded
|
2139
2063
|
|
2140
|
-
if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'heroku_ext']).first)
|
2064
|
+
if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
|
2141
2065
|
puts "Now switching back to \"#{orig_schema}\" schema."
|
2142
2066
|
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", orig_schema)
|
2143
2067
|
end
|
@@ -2175,7 +2099,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2175
2099
|
AND kcu.column_name = c.column_name#{"
|
2176
2100
|
-- AND kcu.position_in_unique_constraint IS NULL" unless is_mssql}
|
2177
2101
|
WHERE t.table_schema #{is_postgres || is_mssql ?
|
2178
|
-
"NOT IN ('information_schema', 'pg_catalog',
|
2102
|
+
"NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'heroku_ext',
|
2179
2103
|
'INFORMATION_SCHEMA', 'sys')"
|
2180
2104
|
:
|
2181
2105
|
"= '#{ActiveRecord::Base.connection.current_database.tr("'", "''")}'"}#{"
|
@@ -2274,7 +2198,7 @@ module Brick
|
|
2274
2198
|
for_tbl = fk[1]
|
2275
2199
|
fk_namified = ::Brick.namify(fk[1])
|
2276
2200
|
apartment = Object.const_defined?('Apartment') && Apartment
|
2277
|
-
fk[0] =
|
2201
|
+
fk[0] = ::Brick.apartment_default_tenant if apartment && apartment.excluded_models.include?(fk_namified.singularize.camelize)
|
2278
2202
|
fk[1] = "#{fk[0]}.#{fk[1]}" if fk[0] # && fk[0] != ::Brick.default_schema
|
2279
2203
|
bts = (relation = relations.fetch(fk[1], nil))&.fetch(:fks) { relation[:fks] = {} }
|
2280
2204
|
|
@@ -2290,7 +2214,7 @@ module Brick
|
|
2290
2214
|
# If Apartment gem lists the primary table as being associated with a non-tenanted model
|
2291
2215
|
# then use 'public' schema for the primary table
|
2292
2216
|
if apartment && apartment&.excluded_models.include?(fk[4].singularize.camelize)
|
2293
|
-
fk[3] =
|
2217
|
+
fk[3] = ::Brick.apartment_default_tenant
|
2294
2218
|
true
|
2295
2219
|
end
|
2296
2220
|
else
|
@@ -2365,7 +2289,7 @@ module Brick
|
|
2365
2289
|
end
|
2366
2290
|
assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
|
2367
2291
|
else
|
2368
|
-
inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && apartment && fk[0] ==
|
2292
|
+
inv_tbl = if ::Brick.config.schema_behavior[:multitenant] && apartment && fk[0] == ::Brick.apartment_default_tenant
|
2369
2293
|
for_tbl
|
2370
2294
|
else
|
2371
2295
|
fk[1]
|
@@ -2424,7 +2348,7 @@ module Brick
|
|
2424
2348
|
end
|
2425
2349
|
::Brick.relations.keys.map do |v|
|
2426
2350
|
tbl_parts = v.split('.')
|
2427
|
-
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first ==
|
2351
|
+
tbl_parts.shift if ::Brick.apartment_multitenant && tbl_parts.length > 1 && tbl_parts.first == ::Brick.apartment_default_tenant
|
2428
2352
|
res = tbl_parts.join('.')
|
2429
2353
|
[v, (model = models[res])&.last&.table_name, migrations&.fetch(res, nil), model&.first]
|
2430
2354
|
end
|
@@ -2454,14 +2378,14 @@ module Brick
|
|
2454
2378
|
|
2455
2379
|
# Locate orphaned records
|
2456
2380
|
def find_orphans(multi_schema)
|
2457
|
-
is_default_schema = multi_schema&.==(
|
2381
|
+
is_default_schema = multi_schema&.==(::Brick.apartment_default_tenant)
|
2458
2382
|
relations.each_with_object([]) do |v, s|
|
2459
2383
|
frn_tbl = v.first
|
2460
2384
|
next if (relation = v.last).key?(:isView) || config.exclude_tables.include?(frn_tbl) ||
|
2461
2385
|
!(for_pk = (relation[:pkey].values.first&.first))
|
2462
2386
|
|
2463
2387
|
is_default_frn_schema = !is_default_schema && multi_schema &&
|
2464
|
-
((frn_parts = frn_tbl.split('.')).length > 1 && frn_parts.first)&.==(
|
2388
|
+
((frn_parts = frn_tbl.split('.')).length > 1 && frn_parts.first)&.==(::Brick.apartment_default_tenant)
|
2465
2389
|
relation[:fks].select { |_k, assoc| assoc[:is_bt] }.each do |_k, bt|
|
2466
2390
|
begin
|
2467
2391
|
if bt.key?(:polymorphic)
|
@@ -2477,7 +2401,7 @@ module Brick
|
|
2477
2401
|
# Skip if database is multitenant, we're not focused on "public", and the foreign and primary tables
|
2478
2402
|
# are both in the "public" schema
|
2479
2403
|
next if is_default_frn_schema &&
|
2480
|
-
((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(
|
2404
|
+
((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(::Brick.apartment_default_tenant)
|
2481
2405
|
|
2482
2406
|
selects << "SELECT '#{pri_tbl}' AS pri_tbl, frn.#{fk_type_col} AS pri_type, frn.#{fk_id_col} AS pri_id, frn.#{for_pk} AS frn_id
|
2483
2407
|
FROM #{frn_tbl} AS frn
|
@@ -2496,7 +2420,7 @@ module Brick
|
|
2496
2420
|
# are both in the "public" schema
|
2497
2421
|
pri_tbl = bt.key?(:inverse_table) && bt[:inverse_table]
|
2498
2422
|
next if is_default_frn_schema &&
|
2499
|
-
((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(
|
2423
|
+
((pri_parts = pri_tbl&.split('.'))&.length > 1 && pri_parts.first)&.==(::Brick.apartment_default_tenant)
|
2500
2424
|
|
2501
2425
|
pri_pk = relations[pri_tbl].fetch(:pkey, nil)&.values&.first&.first ||
|
2502
2426
|
_class_pk(pri_tbl, multi_schema)
|
@@ -192,13 +192,13 @@ module Brick
|
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
195
|
-
apartment_default_schema = ::Brick.apartment_multitenant &&
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
195
|
+
apartment_default_schema = ::Brick.apartment_multitenant && ::Brick.apartment_default_tenant
|
196
|
+
if ::Brick.apartment_multitenant && ::Brick.db_schemas.length > 1
|
197
|
+
schema_options = +'<select id="schema"><% if @_is_show_schema_list %>'
|
198
|
+
::Brick.db_schemas.keys.each { |v| schema_options << "\n <option value=\"#{v}\">#{v}</option>" }
|
199
|
+
schema_options << "\n<% else %><option selected value=\"#{Apartment::Tenant.current}\">#{Apartment::Tenant.current}</option>\n"
|
200
|
+
schema_options << '<% end %></select>'
|
201
|
+
end
|
202
202
|
# %%% If we are not auto-creating controllers (or routes) then omit by default, and if enabled anyway, such as in a development
|
203
203
|
# environment or whatever, then get either the controllers or routes list instead
|
204
204
|
prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
|
@@ -466,6 +466,22 @@ var #{table_name}HtColumns;
|
|
466
466
|
// This PageTransitionEvent fires when the page first loads, as well as after any other history
|
467
467
|
// transition such as when using the browser's Back and Forward buttons.
|
468
468
|
window.addEventListener(\"pageshow\", function() {
|
469
|
+
if (tblSelect) { // Always present
|
470
|
+
var i = #{::Brick.config.path_prefix ? '0' : 'schemaSelect ? 1 : 0'},
|
471
|
+
changeoutList = changeout(location.href);
|
472
|
+
for (; i < changeoutList.length; ++i) {
|
473
|
+
tblSelect.value = changeoutList[i];
|
474
|
+
if (tblSelect.value !== \"\") break;
|
475
|
+
}
|
476
|
+
|
477
|
+
tblSelect.addEventListener(\"change\", function () {
|
478
|
+
var lhr = changeout(location.href, null, this.value);
|
479
|
+
if (brickSchema)
|
480
|
+
lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
|
481
|
+
location.href = lhr;
|
482
|
+
});
|
483
|
+
}
|
484
|
+
|
469
485
|
if (schemaSelect && schemaSelect.options.length > 1) { // First drop-down is only present if multitenant
|
470
486
|
brickSchema = changeout(location.href, \"_brick_schema\");
|
471
487
|
if (brickSchema) {
|
@@ -478,6 +494,7 @@ window.addEventListener(\"pageshow\", function() {
|
|
478
494
|
location.href = changeout(location.href, \"_brick_schema\", this.value, tblSelect.value);
|
479
495
|
});
|
480
496
|
}
|
497
|
+
|
481
498
|
[... document.getElementsByTagName(\"FORM\")].forEach(function (form) {
|
482
499
|
if (brickSchema)
|
483
500
|
form.action = changeout(form.action, \"_brick_schema\", brickSchema);
|
@@ -489,22 +506,6 @@ window.addEventListener(\"pageshow\", function() {
|
|
489
506
|
return true;
|
490
507
|
});
|
491
508
|
});
|
492
|
-
|
493
|
-
if (tblSelect) { // Always present
|
494
|
-
var i = #{::Brick.config.path_prefix ? '0' : 'schemaSelect ? 1 : 0'},
|
495
|
-
changeoutList = changeout(location.href);
|
496
|
-
for (; i < changeoutList.length; ++i) {
|
497
|
-
tblSelect.value = changeoutList[i];
|
498
|
-
if (tblSelect.value !== \"\") break;
|
499
|
-
}
|
500
|
-
|
501
|
-
tblSelect.addEventListener(\"change\", function () {
|
502
|
-
var lhr = changeout(location.href, null, this.value);
|
503
|
-
if (brickSchema)
|
504
|
-
lhr = changeout(lhr, \"_brick_schema\", schemaSelect.value);
|
505
|
-
location.href = lhr;
|
506
|
-
});
|
507
|
-
}
|
508
509
|
});
|
509
510
|
|
510
511
|
// Add \"Are you sure?\" behaviour to any data-confirm buttons out there
|
@@ -834,7 +835,7 @@ erDiagram
|
|
834
835
|
</head>
|
835
836
|
<body>
|
836
837
|
<p style=\"color: green\"><%= notice %></p>#{"
|
837
|
-
|
838
|
+
#{schema_options}" if schema_options}
|
838
839
|
<select id=\"tbl\">#{table_options}</select>
|
839
840
|
<table id=\"resourceName\"><tr>
|
840
841
|
<td><h1>#{model_name}</h1></td>
|
@@ -954,10 +955,12 @@ erDiagram
|
|
954
955
|
poly_id = #{obj_name}.send(\"#\{bt.first}_id\")
|
955
956
|
%><%= link_to(\"#\{bt_class} ##\{poly_id}\", send(\"#\{base_class_underscored}_path\".to_sym, poly_id)) if poly_id %><%
|
956
957
|
else
|
957
|
-
# binding.pry if @_brick_bt_descrip[bt.first][bt[1].first.first].nil?
|
958
958
|
bt_class = bt[1].first.first
|
959
959
|
descrips = @_brick_bt_descrip[bt.first][bt_class]
|
960
|
-
bt_id_col = if descrips.
|
960
|
+
bt_id_col = if descrips.nil?
|
961
|
+
puts \"Caught it in the act for #{obj_name} / #\{col_name}!\"
|
962
|
+
# binding.pry
|
963
|
+
elsif descrips.length == 1
|
961
964
|
[#{obj_name}.class.reflect_on_association(bt.first)&.foreign_key]
|
962
965
|
else
|
963
966
|
descrips.last
|
@@ -974,16 +977,16 @@ erDiagram
|
|
974
977
|
if hms_col.length == 1 %>
|
975
978
|
<%= hms_col.first %>
|
976
979
|
<% else
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
980
|
+
%><%= klass = (col = cols[col_name])[1]
|
981
|
+
if col[2] == 'HO'
|
982
|
+
descrips = @_brick_bt_descrip[col_name.to_sym][klass]
|
983
|
+
if (ho_id = (ho_id_col = descrips.last).map { |id_col| #{obj_name}.send(id_col.to_sym) })&.first
|
984
|
+
ho_txt = klass.brick_descrip(#{obj_name}, descrips[0..-2].map { |id| #{obj_name}.send(id.last[0..62]) }, ho_id_col)
|
985
|
+
link_to(ho_txt, send(\"#\{klass.base_class._brick_index(:singular)}_path\".to_sym, ho_id))
|
986
|
+
end
|
987
|
+
elsif hms_col[1]&.positive?
|
988
|
+
link_to \"#\{hms_col[1] || 'View'} #\{hms_col.first}\", send(\"#\{klass._brick_index}_path\".to_sym, hms_col[2])
|
989
|
+
end %>
|
987
990
|
<% end
|
988
991
|
elsif (col = cols[col_name])
|
989
992
|
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
@@ -1019,7 +1022,7 @@ erDiagram
|
|
1019
1022
|
# Easily could be multiple files involved (STI for instance)
|
1020
1023
|
+"#{css}
|
1021
1024
|
<p style=\"color: green\"><%= notice %></p>#{"
|
1022
|
-
|
1025
|
+
#{schema_options}" if schema_options}
|
1023
1026
|
<select id=\"tbl\">#{table_options}</select>
|
1024
1027
|
<h1>Status</h1>
|
1025
1028
|
<table id=\"status\" class=\"shadow\"><thead><tr>
|
@@ -1068,7 +1071,7 @@ erDiagram
|
|
1068
1071
|
if is_orphans
|
1069
1072
|
+"#{css}
|
1070
1073
|
<p style=\"color: green\"><%= notice %></p>#{"
|
1071
|
-
|
1074
|
+
#{schema_options}" if schema_options}
|
1072
1075
|
<select id=\"tbl\">#{table_options}</select>
|
1073
1076
|
<h1>Orphans<%= \" for #\{}\" if false %></h1>
|
1074
1077
|
<% @orphans.each do |o|
|
@@ -1099,7 +1102,7 @@ erDiagram
|
|
1099
1102
|
</svg>
|
1100
1103
|
|
1101
1104
|
<p style=\"color: green\"><%= notice %></p>#{"
|
1102
|
-
|
1105
|
+
#{schema_options}" if schema_options}
|
1103
1106
|
<select id=\"tbl\">#{table_options}</select>
|
1104
1107
|
<h1><%= page_title %></h1><%
|
1105
1108
|
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
@@ -1411,9 +1414,26 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
|
|
1411
1414
|
# As if it were an inline template (see #determine_template in actionview-5.2.6.2/lib/action_view/renderer/template_renderer.rb)
|
1412
1415
|
keys = options.has_key?(:locals) ? options[:locals].keys : []
|
1413
1416
|
handler = ActionView::Template.handler_for_extension(options[:type] || 'erb')
|
1414
|
-
ActionView::Template.new(inline, "auto-generated #{args.first} template", handler, locals: keys)
|
1417
|
+
ActionView::Template.new(inline, "auto-generated #{args.first} template", handler, locals: keys).tap do |t|
|
1418
|
+
t.instance_variable_set(:@is_brick, true)
|
1419
|
+
end
|
1415
1420
|
end
|
1416
|
-
end
|
1421
|
+
end # LookupContext
|
1422
|
+
|
1423
|
+
# For any auto-generated template, if multitenancy is active via some flavour of an Apartment gem, switch back to the default tenant.
|
1424
|
+
# (Underlying reason -- ros-apartment can hold on to a selected tenant between requests when there is no elevator middleware.)
|
1425
|
+
ActionView::TemplateRenderer.class_exec do
|
1426
|
+
private
|
1427
|
+
|
1428
|
+
alias _brick_render_template render_template
|
1429
|
+
def render_template(view, template, *args)
|
1430
|
+
result = _brick_render_template(view, template, *args)
|
1431
|
+
if template.instance_variable_get(:@is_brick)
|
1432
|
+
Apartment::Tenant.switch!(::Brick.apartment_default_tenant) if ::Brick.apartment_multitenant
|
1433
|
+
end
|
1434
|
+
result
|
1435
|
+
end
|
1436
|
+
end # TemplateRenderer
|
1417
1437
|
end
|
1418
1438
|
|
1419
1439
|
if ::Brick.enable_routes?
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -136,17 +136,19 @@ module Brick
|
|
136
136
|
attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle, :is_eager_loading, :auto_models
|
137
137
|
|
138
138
|
def set_db_schema(params = nil)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
139
|
+
# If Apartment::Tenant.current is not still the default (usually 'public') then an elevator has brought us into
|
140
|
+
# a different tenant. If so then don't allow schema navigation.
|
141
|
+
chosen = if (is_show_schema_list = (apartment_multitenant && Apartment::Tenant.current == ::Brick.default_schema)) &&
|
142
|
+
(schema = (params ? params['_brick_schema'] : ::Brick.default_schema)) &&
|
143
|
+
::Brick.db_schemas&.key?(schema)
|
144
|
+
Apartment::Tenant.switch!(schema)
|
145
|
+
schema
|
146
|
+
elsif ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
147
|
+
# Just return the current schema
|
148
|
+
current_schema = ActiveRecord::Base.execute_sql('SELECT current_schemas(true)').first['current_schemas'][1..-2].split(',')
|
149
|
+
(current_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first
|
150
|
+
end
|
151
|
+
[chosen == ::Brick.default_schema ? nil : chosen, is_show_schema_list]
|
150
152
|
end
|
151
153
|
|
152
154
|
# All tables and views (what Postgres calls "relations" including column and foreign key info)
|
@@ -162,6 +164,10 @@ module Brick
|
|
162
164
|
@apartment_multitenant
|
163
165
|
end
|
164
166
|
|
167
|
+
def apartment_default_tenant
|
168
|
+
Apartment.default_tenant || 'public'
|
169
|
+
end
|
170
|
+
|
165
171
|
# If multitenancy is enabled, a list of non-tenanted "global" models
|
166
172
|
def non_tenanted_models
|
167
173
|
@pending_models ||= {}
|
@@ -1086,21 +1092,9 @@ ActiveSupport.on_load(:active_record) do
|
|
1086
1092
|
end
|
1087
1093
|
end
|
1088
1094
|
|
1089
|
-
# First part of arel_table_type stuff:
|
1090
|
-
# ------------------------------------
|
1091
|
-
# (more found below)
|
1092
1095
|
# was: ActiveRecord.version >= ::Gem::Version.new('3.2') &&
|
1093
1096
|
if ActiveRecord.version < ::Gem::Version.new('5.0')
|
1094
|
-
# Used by Util#_arel_table_type
|
1095
1097
|
module ActiveRecord
|
1096
|
-
class Base
|
1097
|
-
def self.arel_table
|
1098
|
-
@arel_table ||= Arel::Table.new(table_name, arel_engine).tap do |x|
|
1099
|
-
x.instance_variable_set(:@_arel_table_type, self)
|
1100
|
-
end
|
1101
|
-
end
|
1102
|
-
end
|
1103
|
-
|
1104
1098
|
# Final pieces for left_outer_joins support, which was derived from this commit:
|
1105
1099
|
# https://github.com/rails/rails/commit/3f46ef1ddab87482b730a3f53987e04308783d8b
|
1106
1100
|
module Associations
|
@@ -1185,13 +1179,9 @@ if is_postgres && ActiveRecord.version < ::Gem::Version.new('5.0') # Was: && Ob
|
|
1185
1179
|
PGError = PG::Error
|
1186
1180
|
end
|
1187
1181
|
|
1188
|
-
# More arel_table_type stuff:
|
1189
|
-
# ---------------------------
|
1190
1182
|
if ActiveRecord.version < ::Gem::Version.new('5.2')
|
1191
1183
|
# Specifically for AR 3.1 and 3.2 to avoid: "undefined method `delegate' for ActiveRecord::Reflection::ThroughReflection:Class"
|
1192
1184
|
require 'active_support/core_ext/module/delegation' if ActiveRecord.version < ::Gem::Version.new('4.0')
|
1193
|
-
# Used by Util#_arel_table_type
|
1194
|
-
# rubocop:disable Style/CommentedKeyword
|
1195
1185
|
module ActiveRecord
|
1196
1186
|
module Reflection
|
1197
1187
|
# AR < 4.0 doesn't know about join_table and derive_join_table
|
@@ -1209,61 +1199,23 @@ if ActiveRecord.version < ::Gem::Version.new('5.2')
|
|
1209
1199
|
end
|
1210
1200
|
end
|
1211
1201
|
end
|
1212
|
-
|
1213
|
-
module Associations
|
1214
|
-
# Specific to AR 4.2 - 5.1:
|
1215
|
-
if self.const_defined?('JoinDependency') && JoinDependency.private_instance_methods.include?(:table_aliases_for)
|
1216
|
-
class JoinDependency
|
1217
|
-
private
|
1218
|
-
|
1219
|
-
if ActiveRecord.version < ::Gem::Version.new('5.1') # 4.2 or 5.0
|
1220
|
-
def table_aliases_for(parent, node)
|
1221
|
-
node.reflection.chain.map do |reflection|
|
1222
|
-
alias_tracker.aliased_table_for(
|
1223
|
-
reflection.table_name,
|
1224
|
-
table_alias_for(reflection, parent, reflection != node.reflection)
|
1225
|
-
).tap do |x|
|
1226
|
-
# %%% Specific only to Rails 4.2 (and maybe 4.1?)
|
1227
|
-
x = x.left if x.is_a?(Arel::Nodes::TableAlias)
|
1228
|
-
y = reflection.chain.find { |c| c.table_name == x.name }
|
1229
|
-
x.instance_variable_set(:@_arel_table_type, y.klass)
|
1230
|
-
end
|
1231
|
-
end
|
1232
|
-
end
|
1233
|
-
end
|
1234
|
-
end
|
1235
|
-
elsif Associations.const_defined?('JoinHelper') && JoinHelper.private_instance_methods.include?(:construct_tables)
|
1236
|
-
module JoinHelper
|
1237
|
-
private
|
1238
|
-
|
1239
|
-
# AR > 3.0 and < 4.2 (%%% maybe only < 4.1?) uses construct_tables like this:
|
1240
|
-
def construct_tables
|
1241
|
-
tables = []
|
1242
|
-
chain.each do |reflection|
|
1243
|
-
tables << alias_tracker.aliased_table_for(
|
1244
|
-
table_name_for(reflection),
|
1245
|
-
table_alias_for(reflection, reflection != self.reflection)
|
1246
|
-
).tap do |x|
|
1247
|
-
x = x.left if x.is_a?(Arel::Nodes::TableAlias)
|
1248
|
-
x.instance_variable_set(:@_arel_table_type, reflection.chain.find { |c| c.table_name == x.name }.klass)
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
next unless reflection.source_macro == :has_and_belongs_to_many
|
1252
|
-
|
1253
|
-
tables << alias_tracker.aliased_table_for(
|
1254
|
-
(reflection.source_reflection || reflection).join_table,
|
1255
|
-
table_alias_for(reflection, true)
|
1256
|
-
)
|
1257
|
-
end
|
1258
|
-
tables
|
1259
|
-
end
|
1260
|
-
end
|
1261
|
-
end
|
1262
|
-
end
|
1263
|
-
end # module ActiveRecord
|
1264
|
-
# rubocop:enable Style/CommentedKeyword
|
1202
|
+
end
|
1265
1203
|
end
|
1266
1204
|
|
1205
|
+
# The "brick_links" patch -- this finds how every AR chain of association names
|
1206
|
+
# relates back to an exact table correlation name chosen by AREL when the AST tree is
|
1207
|
+
# walked. For instance, from a Customer model there could be a join_tree such as
|
1208
|
+
# { orders: { line_items: :product} }, which would end up recording three entries, the
|
1209
|
+
# last of which for products would have a key of "orders.line_items.product" after
|
1210
|
+
# having gone through two HMs and one BT. AREL would have chosen a correlation name of
|
1211
|
+
# "products", being able to use the same name as the table name because it's the first
|
1212
|
+
# time that table is used in this query. But let's see what happens if each customer
|
1213
|
+
# also had a BT to a favourite product, referenced earlier in the join_tree like this:
|
1214
|
+
# [:favourite_product, orders: { line_items: :product}] -- then the second reference to
|
1215
|
+
# "products" would end up being called "products_line_items" in order to differentiate
|
1216
|
+
# it from the first reference, which would have already snagged the simpler name
|
1217
|
+
# "products". It's essential that The Brick can find accurate correlation names when
|
1218
|
+
# there are multiple JOINs to the same table.
|
1267
1219
|
module ActiveRecord
|
1268
1220
|
module QueryMethods
|
1269
1221
|
private
|
@@ -1290,7 +1242,7 @@ module ActiveRecord
|
|
1290
1242
|
end
|
1291
1243
|
end
|
1292
1244
|
|
1293
|
-
# require '
|
1245
|
+
# require 'active_record/associations/join_dependency'
|
1294
1246
|
module Associations
|
1295
1247
|
# For AR >= 4.2
|
1296
1248
|
if self.const_defined?('JoinDependency')
|
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.93
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -164,20 +164,6 @@ dependencies:
|
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: 1.42.0
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: mysql2
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0.5'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0.5'
|
181
167
|
- !ruby/object:Gem::Dependency
|
182
168
|
name: pg
|
183
169
|
requirement: !ruby/object:Gem::Requirement
|