brick 1.0.71 → 1.0.72
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 +79 -52
- data/lib/brick/frameworks/rails/engine.rb +4 -4
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +59 -1
- data/lib/generators/brick/migrations_generator.rb +42 -11
- 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: 06c3efed47ee7086f01a4f59c177f362343f376b1d6534f86e61ee38001b0d7b
|
|
4
|
+
data.tar.gz: 8b521c56eb5afc09b06aec0adf0085136cb9e94d2c1a93355a8a2fc79da0316b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1566ddaa89e45496b752b64ec218456e05dca50cc81a722d5a88e4d4bbe19b28ca981eeb253688f44e55a8ef9949d195bdc5a61f5ba7980b2507c315277b4d4d
|
|
7
|
+
data.tar.gz: 7643f78bf92721c89bdb0065f112592cba26023ea7745ba34551ce39d9378cd286f50b3ea1491c813e10f6d93521ef16c54fa70edc5dbcd4d70cb5ad6a859ad3
|
data/lib/brick/extensions.rb
CHANGED
|
@@ -68,13 +68,14 @@ module ActiveRecord
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def self._brick_primary_key(relation = nil)
|
|
71
|
-
return
|
|
71
|
+
return @_brick_primary_key if instance_variable_defined?(:@_brick_primary_key)
|
|
72
72
|
|
|
73
73
|
pk = begin
|
|
74
74
|
primary_key.is_a?(String) ? [primary_key] : primary_key || []
|
|
75
75
|
rescue
|
|
76
76
|
[]
|
|
77
77
|
end
|
|
78
|
+
pk.map! { |pk_part| pk_part =~ /^[A-Z0-9_]+$/ ? pk_part.downcase : pk_part } unless connection.adapter_name == 'MySQL2'
|
|
78
79
|
# Just return [] if we're missing any part of the primary key. (PK is usually just "id")
|
|
79
80
|
if relation && pk.present?
|
|
80
81
|
@_brick_primary_key ||= pk.any? { |pk_part| !relation[:cols].key?(pk_part) } ? [] : pk
|
|
@@ -146,11 +147,8 @@ module ActiveRecord
|
|
|
146
147
|
dsl2 << ch
|
|
147
148
|
end
|
|
148
149
|
end
|
|
149
|
-
# Rewrite the DSL
|
|
150
|
-
unless emit_dsl
|
|
151
|
-
# puts "Compare:\n #{dsl}\n #{dsl2}"
|
|
152
|
-
::Brick.config.model_descrips[name] = dsl2
|
|
153
|
-
end
|
|
150
|
+
# Rewrite the DSL in case it's now different from having to expand it
|
|
151
|
+
::Brick.config.model_descrips[name] = dsl2 unless emit_dsl
|
|
154
152
|
else # With no DSL available, still put this prefix into the JoinArray so we can get primary key (ID) info from this table
|
|
155
153
|
x = prefix.each_with_object(build_array) { |v, s| s[v.to_sym] }
|
|
156
154
|
x[prefix.last] = nil unless prefix.empty? # Using []= will "hydrate" any missing part(s) in our whole series
|
|
@@ -323,7 +321,7 @@ module ActiveRecord
|
|
|
323
321
|
end
|
|
324
322
|
|
|
325
323
|
class Relation
|
|
326
|
-
attr_reader :_brick_chains
|
|
324
|
+
attr_reader :_brick_chains, :_arel_applied_aliases
|
|
327
325
|
|
|
328
326
|
# CLASS STUFF
|
|
329
327
|
def _recurse_arel(piece, prefix = '')
|
|
@@ -361,7 +359,7 @@ module ActiveRecord
|
|
|
361
359
|
# parent = piece.left == on.left.relation ? on.right.relation : on.left.relation
|
|
362
360
|
# binding.pry if piece.left.is_a?(Arel::Nodes::TableAlias)
|
|
363
361
|
if table.is_a?(Arel::Nodes::TableAlias)
|
|
364
|
-
alias_name = table.right
|
|
362
|
+
@_arel_applied_aliases << (alias_name = table.right)
|
|
365
363
|
table = table.left
|
|
366
364
|
end
|
|
367
365
|
(_brick_chains[table._arel_table_type] ||= []) << (alias_name || table.table_alias || table.name)
|
|
@@ -387,6 +385,7 @@ module ActiveRecord
|
|
|
387
385
|
|
|
388
386
|
# INSTANCE STUFF
|
|
389
387
|
def _arel_alias_names
|
|
388
|
+
@_arel_applied_aliases = []
|
|
390
389
|
# %%% If with Rails 3.1 and older you get "NoMethodError: undefined method `eq' for nil:NilClass"
|
|
391
390
|
# when trying to call relation.arel, then somewhere along the line while navigating a has_many
|
|
392
391
|
# relationship it can't find the proper foreign key.
|
|
@@ -429,22 +428,7 @@ module ActiveRecord
|
|
|
429
428
|
if selects&.empty? # Default to all columns
|
|
430
429
|
tbl_no_schema = table.name.split('.').last
|
|
431
430
|
columns.each do |col|
|
|
432
|
-
if (col_name = col.name) == 'class'
|
|
433
|
-
col_alias = " AS #{col.name}_"
|
|
434
|
-
else
|
|
435
|
-
alias_name = nil
|
|
436
|
-
idx = 0
|
|
437
|
-
col_name.each_char do |c|
|
|
438
|
-
unless (c >= 'a' && c <= 'z') ||
|
|
439
|
-
c == '_' ||
|
|
440
|
-
(c >= 'A' && c <= 'Z') ||
|
|
441
|
-
(c >= '0' && c <= '9')
|
|
442
|
-
(alias_name ||= col_name.dup)[idx] = 'x'
|
|
443
|
-
end
|
|
444
|
-
++idx
|
|
445
|
-
end
|
|
446
|
-
col_alias = " AS #{alias_name}" if alias_name
|
|
447
|
-
end
|
|
431
|
+
col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
|
|
448
432
|
selects << if is_mysql
|
|
449
433
|
"`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
|
|
450
434
|
elsif is_postgres || is_mssql
|
|
@@ -452,8 +436,8 @@ module ActiveRecord
|
|
|
452
436
|
cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col_name)&.first&.start_with?('xml')
|
|
453
437
|
"\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
|
|
454
438
|
elsif col.type # Could be Sqlite or Oracle
|
|
455
|
-
if col_alias
|
|
456
|
-
"#{tbl_no_schema}
|
|
439
|
+
if col_alias || !(/^[a-z0-9_]+$/ =~ col_name)
|
|
440
|
+
"#{tbl_no_schema}.\"#{col_name}\"#{col_alias}"
|
|
457
441
|
else
|
|
458
442
|
"#{tbl_no_schema}.#{col_name}"
|
|
459
443
|
end
|
|
@@ -478,9 +462,14 @@ module ActiveRecord
|
|
|
478
462
|
next if chains[k1].nil?
|
|
479
463
|
|
|
480
464
|
tbl_name = (field_tbl_names[v.first][k1] ||= shift_or_first(chains[k1])).split('.').last
|
|
465
|
+
# If it's Oracle, quote any AREL aliases that had been applied
|
|
466
|
+
tbl_name = "\"#{tbl_name}\"" if ::Brick.is_oracle && rel_dupe._arel_applied_aliases.include?(tbl_name)
|
|
481
467
|
field_tbl_name = nil
|
|
482
468
|
v1.map { |x| [translations[x[0..-2].map(&:to_s).join('.')], x.last] }.each_with_index do |sel_col, idx|
|
|
469
|
+
# binding.pry if chains[sel_col.first].nil?
|
|
483
470
|
field_tbl_name = (field_tbl_names[v.first][sel_col.first] ||= shift_or_first(chains[sel_col.first])).split('.').last
|
|
471
|
+
# If it's Oracle, quote any AREL aliases that had been applied
|
|
472
|
+
field_tbl_name = "\"#{field_tbl_name}\"" if ::Brick.is_oracle && rel_dupe._arel_applied_aliases.include?(field_tbl_name)
|
|
484
473
|
|
|
485
474
|
# Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
|
|
486
475
|
is_xml = is_distinct && Brick.relations[sel_col.first.table_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
|
|
@@ -751,9 +740,11 @@ Module.class_exec do
|
|
|
751
740
|
base_module == Object && # %%% This works for Person::Person -- but also limits us to not being able to allow more than one level of namespacing
|
|
752
741
|
(schema_name = [(singular_table_name = class_name.underscore),
|
|
753
742
|
(table_name = singular_table_name.pluralize),
|
|
754
|
-
class_name,
|
|
743
|
+
::Brick.is_oracle ? class_name.upcase : class_name,
|
|
755
744
|
(plural_class_name = class_name.pluralize)].find { |s| Brick.db_schemas.include?(s) }&.camelize ||
|
|
756
745
|
(::Brick.config.sti_namespace_prefixes&.key?("::#{class_name}::") && class_name))
|
|
746
|
+
return self.const_get(schema_name) if self.const_defined?(schema_name)
|
|
747
|
+
|
|
757
748
|
# Build out a module for the schema if it's namespaced
|
|
758
749
|
# schema_name = schema_name.camelize
|
|
759
750
|
base_module.const_set(schema_name.to_sym, (built_module = Module.new))
|
|
@@ -1386,8 +1377,13 @@ class Object
|
|
|
1386
1377
|
[new_alt_name, true]
|
|
1387
1378
|
else
|
|
1388
1379
|
assoc_name = ::Brick.namify(hm_assoc[:inverse_table]).pluralize
|
|
1380
|
+
if (needs_class = assoc_name.include?('.')) # If there is a schema name present, use a downcased version for the :has_many
|
|
1381
|
+
assoc_parts = assoc_name.split('.')
|
|
1382
|
+
assoc_parts[0].downcase! if assoc_parts[0] =~ /^[A-Z0-9_]+$/
|
|
1383
|
+
assoc_name = assoc_parts.join('.')
|
|
1384
|
+
end
|
|
1389
1385
|
# hm_assoc[:assoc_name] = assoc_name
|
|
1390
|
-
[assoc_name,
|
|
1386
|
+
[assoc_name, needs_class]
|
|
1391
1387
|
end
|
|
1392
1388
|
end
|
|
1393
1389
|
end
|
|
@@ -1443,7 +1439,8 @@ module ActiveRecord::ConnectionHandling
|
|
|
1443
1439
|
row['table_schema']
|
|
1444
1440
|
end
|
|
1445
1441
|
# Remove any system schemas
|
|
1446
|
-
s[row] = nil unless ['information_schema', 'pg_catalog'
|
|
1442
|
+
s[row] = nil unless ['information_schema', 'pg_catalog',
|
|
1443
|
+
'INFORMATION_SCHEMA', 'sys'].include?(row)
|
|
1447
1444
|
end
|
|
1448
1445
|
if (is_multitenant = (multitenancy = ::Brick.config.schema_behavior[:multitenant]) &&
|
|
1449
1446
|
(sta = multitenancy[:schema_to_analyse]) != 'public') &&
|
|
@@ -1487,6 +1484,7 @@ module ActiveRecord::ConnectionHandling
|
|
|
1487
1484
|
# ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
|
|
1488
1485
|
# For if it's not SQLite -- so this is the Postgres and MySQL version
|
|
1489
1486
|
measures = []
|
|
1487
|
+
::Brick.is_oracle = true if ActiveRecord::Base.connection.adapter_name == 'OracleEnhanced'
|
|
1490
1488
|
case ActiveRecord::Base.connection.adapter_name
|
|
1491
1489
|
when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
|
|
1492
1490
|
# schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
|
@@ -1538,15 +1536,21 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
1538
1536
|
else
|
|
1539
1537
|
ActiveRecord::Base.retrieve_schema_and_tables(sql)
|
|
1540
1538
|
end
|
|
1539
|
+
|
|
1541
1540
|
schema_and_tables.each do |r|
|
|
1542
1541
|
next if r[1].index('$') # Oracle can have goofy table names with $
|
|
1543
1542
|
|
|
1544
|
-
if (relation_name = r[1]) =~ /^[A-
|
|
1543
|
+
if (relation_name = r[1]) =~ /^[A-Z0-9_]+$/
|
|
1545
1544
|
relation_name.downcase!
|
|
1546
1545
|
end
|
|
1546
|
+
# Expect the default schema for SQL Server to be 'dbo'.
|
|
1547
|
+
if (::Brick.is_oracle && r[0] != schema) || (is_mssql && r[0] != 'dbo')
|
|
1548
|
+
relation_name = "#{r[0]}.#{relation_name}"
|
|
1549
|
+
end
|
|
1550
|
+
|
|
1547
1551
|
relation = relations[relation_name] # here relation represents a table or view from the database
|
|
1548
1552
|
relation[:isView] = true if r[2] == 'VIEW' # table_type
|
|
1549
|
-
col_name = r[3]
|
|
1553
|
+
col_name = ::Brick.is_oracle ? connection.send(:oracle_downcase, r[3]) : r[3]
|
|
1550
1554
|
key = case r[6] # constraint type
|
|
1551
1555
|
when 'PRIMARY KEY'
|
|
1552
1556
|
# key
|
|
@@ -1558,8 +1562,8 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
1558
1562
|
end
|
|
1559
1563
|
key << col_name if key
|
|
1560
1564
|
cols = relation[:cols] # relation.fetch(:cols) { relation[:cols] = [] }
|
|
1561
|
-
# 'data_type', 'max_length'
|
|
1562
|
-
cols[col_name] = [r[4], r[5], measures&.include?(col_name)]
|
|
1565
|
+
# 'data_type', 'max_length', measure, 'is_nullable'
|
|
1566
|
+
cols[col_name] = [r[4], r[5], measures&.include?(col_name), r[8] == 'NO']
|
|
1563
1567
|
# puts "KEY! #{r['relation_name']}.#{col_name} #{r['key']} #{r['const']}" if r['key']
|
|
1564
1568
|
end
|
|
1565
1569
|
end
|
|
@@ -1612,10 +1616,10 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
1612
1616
|
schemas = ::Brick.db_schemas.keys.map { |s| "'#{s}'" }.join(', ')
|
|
1613
1617
|
sql =
|
|
1614
1618
|
"SELECT -- fk
|
|
1615
|
-
ac.owner AS constraint_schema, acc_fk.table_name,
|
|
1619
|
+
ac.owner AS constraint_schema, acc_fk.table_name, acc_fk.column_name,
|
|
1616
1620
|
-- referenced pk
|
|
1617
1621
|
ac.r_owner AS primary_schema, acc_pk.table_name AS primary_table, acc_fk.constraint_name AS constraint_schema_fk
|
|
1618
|
-
-- ,
|
|
1622
|
+
-- , acc_pk.column_name
|
|
1619
1623
|
FROM all_cons_columns acc_fk
|
|
1620
1624
|
INNER JOIN all_constraints ac ON acc_fk.owner = ac.owner
|
|
1621
1625
|
AND acc_fk.constraint_name = ac.constraint_name
|
|
@@ -1633,49 +1637,71 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
1633
1637
|
# Multitenancy makes things a little more general overall, except for non-tenanted tables
|
|
1634
1638
|
if apartment_excluded&.include?(::Brick.namify(fk[1]).singularize.camelize)
|
|
1635
1639
|
fk[0] = Apartment.default_schema
|
|
1636
|
-
elsif is_postgres && (fk[0] == 'public' || (is_multitenant && fk[0] == schema)) ||
|
|
1637
|
-
|
|
1640
|
+
elsif (is_postgres && (fk[0] == 'public' || (is_multitenant && fk[0] == schema))) ||
|
|
1641
|
+
(::Brick.is_oracle && fk[0] == schema) ||
|
|
1642
|
+
(is_mssql && fk[0] == 'dbo') ||
|
|
1643
|
+
(!is_postgres && !::Brick.is_oracle && !is_mssql && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0]))
|
|
1638
1644
|
fk[0] = nil
|
|
1639
1645
|
end
|
|
1640
1646
|
if apartment_excluded&.include?(fk[4].singularize.camelize)
|
|
1641
1647
|
fk[3] = Apartment.default_schema
|
|
1642
|
-
elsif is_postgres && (fk[3] == 'public' || (is_multitenant && fk[3] == schema)) ||
|
|
1643
|
-
|
|
1648
|
+
elsif (is_postgres && (fk[3] == 'public' || (is_multitenant && fk[3] == schema))) ||
|
|
1649
|
+
(::Brick.is_oracle && fk[3] == schema) ||
|
|
1650
|
+
(is_mssql && fk[3] == 'dbo') ||
|
|
1651
|
+
(!is_postgres && !::Brick.is_oracle && !is_mssql && ['mysql', 'performance_schema', 'sys'].exclude?(fk[3]))
|
|
1644
1652
|
fk[3] = nil
|
|
1645
1653
|
end
|
|
1646
|
-
|
|
1647
|
-
|
|
1654
|
+
if ::Brick.is_oracle
|
|
1655
|
+
fk[1].downcase! if fk[1] =~ /^[A-Z0-9_]+$/
|
|
1656
|
+
fk[4].downcase! if fk[4] =~ /^[A-Z0-9_]+$/
|
|
1657
|
+
fk[2] = connection.send(:oracle_downcase, fk[2])
|
|
1658
|
+
end
|
|
1648
1659
|
::Brick._add_bt_and_hm(fk, relations)
|
|
1649
1660
|
end
|
|
1650
1661
|
end
|
|
1651
1662
|
|
|
1652
1663
|
tables = []
|
|
1653
1664
|
views = []
|
|
1665
|
+
table_class_length = 0
|
|
1666
|
+
view_class_length = 0
|
|
1654
1667
|
relations.each do |k, v|
|
|
1655
1668
|
name_parts = k.split('.')
|
|
1656
1669
|
idx = 1
|
|
1657
1670
|
name_parts = name_parts.map do |x|
|
|
1658
|
-
(
|
|
1671
|
+
(idx += 1) < name_parts.length ? x : x.singularize
|
|
1659
1672
|
end
|
|
1673
|
+
name_parts.shift if apartment && name_parts.length > 1 && name_parts.first == Apartment.default_schema
|
|
1674
|
+
class_name = name_parts.map(&:camelize).join('::')
|
|
1660
1675
|
if v.key?(:isView)
|
|
1676
|
+
view_class_length = class_name.length if class_name.length > view_class_length
|
|
1661
1677
|
views
|
|
1662
1678
|
else
|
|
1663
|
-
|
|
1679
|
+
table_class_length = class_name.length if class_name.length > table_class_length
|
|
1664
1680
|
tables
|
|
1665
|
-
end << name_parts
|
|
1681
|
+
end << [class_name, name_parts]
|
|
1666
1682
|
end
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1683
|
+
puts "\n" if tables.present? || views.present?
|
|
1684
|
+
if tables.present?
|
|
1685
|
+
puts "Classes that can be built from tables:"
|
|
1686
|
+
display_classes(tables, table_class_length)
|
|
1670
1687
|
end
|
|
1671
|
-
|
|
1672
|
-
puts "
|
|
1673
|
-
views
|
|
1688
|
+
if views.present?
|
|
1689
|
+
puts "Classes that can be built from views:"
|
|
1690
|
+
display_classes(views, view_class_length)
|
|
1674
1691
|
end
|
|
1675
1692
|
|
|
1676
1693
|
::Brick.load_additional_references if initializer_loaded
|
|
1677
1694
|
end
|
|
1678
1695
|
|
|
1696
|
+
def display_classes(rels, max_length)
|
|
1697
|
+
rels.sort.each do |rel|
|
|
1698
|
+
rel_link = rel.last.dup.map(&:underscore)
|
|
1699
|
+
rel_link[-1] = rel_link[-1].pluralize
|
|
1700
|
+
puts "#{rel.first}#{' ' * (max_length - rel.first.length)} /#{rel_link.join('/')}"
|
|
1701
|
+
end
|
|
1702
|
+
puts "\n"
|
|
1703
|
+
end
|
|
1704
|
+
|
|
1679
1705
|
def retrieve_schema_and_tables(sql = nil, is_postgres = nil, is_mssql = nil, schema = nil)
|
|
1680
1706
|
is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if is_mssql.nil?
|
|
1681
1707
|
sql ||= "SELECT t.table_schema AS \"schema\", t.table_name AS relation_name, t.table_type,#{"
|
|
@@ -1705,7 +1731,8 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
|
1705
1731
|
-- AND kcu.position_in_unique_constraint IS NULL" unless is_mssql}
|
|
1706
1732
|
AND kcu.ordinal_position = c.ordinal_position
|
|
1707
1733
|
WHERE t.table_schema #{is_postgres || is_mssql ?
|
|
1708
|
-
"NOT IN ('information_schema', 'pg_catalog'
|
|
1734
|
+
"NOT IN ('information_schema', 'pg_catalog',
|
|
1735
|
+
'INFORMATION_SCHEMA', 'sys')"
|
|
1709
1736
|
:
|
|
1710
1737
|
"= '#{ActiveRecord::Base.connection.current_database.tr("'", "''")}'"}#{"
|
|
1711
1738
|
AND t.table_schema = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }
|
|
@@ -1750,7 +1777,7 @@ module Brick
|
|
|
1750
1777
|
|
|
1751
1778
|
class << self
|
|
1752
1779
|
def _add_bt_and_hm(fk, relations, is_polymorphic = false, is_optional = false)
|
|
1753
|
-
bt_assoc_name = ::Brick.namify(fk[2])
|
|
1780
|
+
bt_assoc_name = ::Brick.namify(fk[2], true)
|
|
1754
1781
|
unless is_polymorphic
|
|
1755
1782
|
bt_assoc_name = if bt_assoc_name.underscore.end_with?('_id')
|
|
1756
1783
|
bt_assoc_name[-3] == '_' ? bt_assoc_name[0..-4] : bt_assoc_name[0..-3]
|
|
@@ -87,9 +87,9 @@ module Brick
|
|
|
87
87
|
|
|
88
88
|
def path_keys(hm_assoc, fk_name, obj_name, pk)
|
|
89
89
|
keys = if fk_name.is_a?(Array) && pk.is_a?(Array) # Composite keys?
|
|
90
|
-
fk_name.zip(pk.map { |
|
|
90
|
+
fk_name.zip(pk.map { |fk_part| "#{obj_name}.#{fk_part}" })
|
|
91
91
|
else
|
|
92
|
-
pk = pk.
|
|
92
|
+
pk = pk.map { |pk_part| "#{obj_name}.#{pk_part}" }
|
|
93
93
|
[[fk_name, pk.length == 1 ? pk.first : pk.inspect]]
|
|
94
94
|
end
|
|
95
95
|
keys << [hm_assoc.inverse_of.foreign_type, hm_assoc.active_record.name] if hm_assoc.options.key?(:as)
|
|
@@ -106,8 +106,8 @@ module Brick
|
|
|
106
106
|
return _brick_find_template(*args, **options)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(
|
|
109
|
+
if @_brick_model
|
|
110
|
+
pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(@_brick_model&.table_name, nil))
|
|
111
111
|
obj_name = model_name.split('::').last.underscore
|
|
112
112
|
path_obj_name = model_name.underscore.tr('/', '_')
|
|
113
113
|
table_name = obj_name.pluralize
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
|
@@ -152,7 +152,8 @@ module Brick
|
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
# Convert spaces to underscores if the second character and onwards is mixed case
|
|
155
|
-
def namify(name)
|
|
155
|
+
def namify(name, attempt_downcase = false)
|
|
156
|
+
name.downcase! if attempt_downcase && name =~ /^[A-Z0-9_]+$/
|
|
156
157
|
if name.include?(' ')
|
|
157
158
|
# All uppers or all lowers?
|
|
158
159
|
if name[1..-1] =~ /^[A-Z0-9_]+$/ || name[1..-1] =~ /^[a-z0-9_]+$/
|
|
@@ -726,6 +727,63 @@ ActiveSupport.on_load(:active_record) do
|
|
|
726
727
|
end
|
|
727
728
|
end
|
|
728
729
|
end
|
|
730
|
+
|
|
731
|
+
# Migration stuff
|
|
732
|
+
module ConnectionAdapters
|
|
733
|
+
# Override the downcasing implementation from the OracleEnhanced gem as it has bad regex
|
|
734
|
+
if const_defined?(:OracleEnhanced)
|
|
735
|
+
module OracleEnhanced::Quoting
|
|
736
|
+
private
|
|
737
|
+
|
|
738
|
+
def oracle_downcase(column_name)
|
|
739
|
+
return nil if column_name.nil?
|
|
740
|
+
|
|
741
|
+
/^[A-Za-z0-9_]+$/ =~ column_name ? column_name.downcase : column_name
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
end
|
|
745
|
+
if const_defined?(:SQLServerAdapter)
|
|
746
|
+
class SQLServer::TableDefinition
|
|
747
|
+
alias _brick_new_column_definition new_column_definition
|
|
748
|
+
def new_column_definition(name, type, **options)
|
|
749
|
+
case type
|
|
750
|
+
when :serial
|
|
751
|
+
type = :integer
|
|
752
|
+
options[:is_identity] = true
|
|
753
|
+
when :bigserial
|
|
754
|
+
type = :bigint
|
|
755
|
+
options[:is_identity] = true
|
|
756
|
+
end
|
|
757
|
+
_brick_new_column_definition(name, type, **options)
|
|
758
|
+
end
|
|
759
|
+
def serial(*args)
|
|
760
|
+
options = args.extract_options!
|
|
761
|
+
options[:is_identity] = true
|
|
762
|
+
args.each { |name| column(name, 'integer', options) }
|
|
763
|
+
end
|
|
764
|
+
def bigserial(*args)
|
|
765
|
+
options = args.extract_options!
|
|
766
|
+
options[:is_identity] = true
|
|
767
|
+
args.each { |name| column(name, 'bigint', options) }
|
|
768
|
+
end
|
|
769
|
+
# Seems that geography gets used a fair bit in MSSQL
|
|
770
|
+
def geography(*args)
|
|
771
|
+
options = args.extract_options!
|
|
772
|
+
# options[:precision] ||= 8
|
|
773
|
+
# options[:scale] ||= 2
|
|
774
|
+
args.each { |name| column(name, 'geography', options) }
|
|
775
|
+
end
|
|
776
|
+
end
|
|
777
|
+
class SQLServerAdapter
|
|
778
|
+
unless respond_to?(:schema_exists?)
|
|
779
|
+
def schema_exists?(schema)
|
|
780
|
+
schema_sql = 'SELECT 1 FROM sys.schemas WHERE name = ?'
|
|
781
|
+
ActiveRecord::Base.execute_sql(schema_sql, schema).present?
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
end
|
|
729
787
|
end
|
|
730
788
|
# rubocop:enable Lint/ConstantDefinitionInBlock
|
|
731
789
|
|
|
@@ -23,6 +23,21 @@ module Brick
|
|
|
23
23
|
'time with time zone' => 'time',
|
|
24
24
|
'double precision' => 'float',
|
|
25
25
|
'smallint' => 'integer', # %%% Need to put in "limit: 2"
|
|
26
|
+
# # Oracle data types
|
|
27
|
+
'VARCHAR2' => 'string',
|
|
28
|
+
'CHAR' => 'string',
|
|
29
|
+
['NUMBER', 22] => 'integer',
|
|
30
|
+
/^INTERVAL / => 'string', # Time interval stuff like INTERVAL YEAR(2) TO MONTH, INTERVAL '999' DAY(3), etc
|
|
31
|
+
'XMLTYPE' => 'xml',
|
|
32
|
+
'RAW' => 'binary',
|
|
33
|
+
'SDO_GEOMETRY' => 'geometry',
|
|
34
|
+
# MSSQL data types
|
|
35
|
+
'int' => 'integer',
|
|
36
|
+
'nvarchar' => 'string',
|
|
37
|
+
'nchar' => 'string',
|
|
38
|
+
'datetime2' => 'timestamp',
|
|
39
|
+
'bit' => 'boolean',
|
|
40
|
+
'varbinary' => 'binary',
|
|
26
41
|
# Sqlite data types
|
|
27
42
|
'TEXT' => 'text',
|
|
28
43
|
'' => 'string',
|
|
@@ -122,7 +137,7 @@ module Brick
|
|
|
122
137
|
fringe.each do |tbl|
|
|
123
138
|
next unless (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
|
|
124
139
|
|
|
125
|
-
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [
|
|
140
|
+
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ApplicationRecord.primary_key].flatten.sort)
|
|
126
141
|
# In case things aren't as standard
|
|
127
142
|
if pkey_cols.empty?
|
|
128
143
|
pkey_cols = if rpk.empty? && relation[:cols][arpk.first]&.first == key_type
|
|
@@ -141,7 +156,7 @@ module Brick
|
|
|
141
156
|
end
|
|
142
157
|
unless schema.blank? || built_schemas.key?(schema)
|
|
143
158
|
mig = +" def change\n create_schema(:#{schema}) unless schema_exists?(:#{schema})\n end\n"
|
|
144
|
-
migration_file_write(mig_path, "create_db_schema_#{schema}", current_mig_time += 1.minute, ar_version, mig)
|
|
159
|
+
migration_file_write(mig_path, "create_db_schema_#{schema.underscore}", current_mig_time += 1.minute, ar_version, mig)
|
|
145
160
|
built_schemas[schema] = nil
|
|
146
161
|
end
|
|
147
162
|
|
|
@@ -151,11 +166,16 @@ module Brick
|
|
|
151
166
|
# a column definition which includes :primary_key -- %%% also using a data type of bigserial or serial
|
|
152
167
|
# if this one has come in as bigint or integer.
|
|
153
168
|
pk_is_also_fk = fkey_cols.any? { |assoc| pkey_cols&.first == assoc[:fk] } ? pkey_cols&.first : nil
|
|
154
|
-
# Support missing primary key (by adding: ,id: false)
|
|
169
|
+
# Support missing primary key (by adding: , id: false)
|
|
155
170
|
id_option = if pk_is_also_fk || !pkey_cols&.present?
|
|
171
|
+
needs_serial_col = true
|
|
156
172
|
', id: false'
|
|
157
|
-
elsif ((pkey_col_first = relation[:cols][pkey_cols&.first]&.first) &&
|
|
158
|
-
(pkey_col_first = SQL_TYPES[pkey_col_first] ||
|
|
173
|
+
elsif ((pkey_col_first = (col_def = relation[:cols][pkey_cols&.first])&.first) &&
|
|
174
|
+
(pkey_col_first = SQL_TYPES[pkey_col_first] || SQL_TYPES[col_def&.[](0..1)] ||
|
|
175
|
+
SQL_TYPES.find { |r| r.first.is_a?(Regexp) && pkey_col_first =~ r.first }&.last ||
|
|
176
|
+
pkey_col_first
|
|
177
|
+
) != key_type
|
|
178
|
+
)
|
|
159
179
|
case pkey_col_first
|
|
160
180
|
when 'integer'
|
|
161
181
|
', id: :serial'
|
|
@@ -164,9 +184,14 @@ module Brick
|
|
|
164
184
|
else
|
|
165
185
|
", id: :#{pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
|
|
166
186
|
end +
|
|
167
|
-
(pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
|
|
168
|
-
(!is_4x_rails && (comment = relation&.fetch(:description, nil))&.present? ? ", comment: #{comment.inspect}" : '')
|
|
187
|
+
(pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
|
|
169
188
|
end
|
|
189
|
+
if !id_option && pkey_cols.sort != arpk
|
|
190
|
+
id_option = ", primary_key: :#{pkey_cols.first}"
|
|
191
|
+
end
|
|
192
|
+
if !is_4x_rails && (comment = relation&.fetch(:description, nil))&.present?
|
|
193
|
+
(id_option ||= +'') << ", comment: #{comment.inspect}"
|
|
194
|
+
end
|
|
170
195
|
# Find the ActiveRecord class in order to see if the columns have comments
|
|
171
196
|
unless is_4x_rails
|
|
172
197
|
klass = begin
|
|
@@ -187,18 +212,24 @@ module Brick
|
|
|
187
212
|
possible_ts = [] # Track possible generic timestamps
|
|
188
213
|
add_fks = [] # Track foreign keys to add after table creation
|
|
189
214
|
relation[:cols].each do |col, col_type|
|
|
190
|
-
sql_type = SQL_TYPES[col_type.first] || col_type
|
|
191
|
-
|
|
215
|
+
sql_type = SQL_TYPES[col_type.first] || SQL_TYPES[col_type[0..1]] ||
|
|
216
|
+
SQL_TYPES.find { |r| r.first.is_a?(Regexp) && col_type.first =~ r.first }&.last ||
|
|
217
|
+
col_type.first
|
|
218
|
+
suffix = col_type[3] || pkey_cols&.include?(col) ? +', null: false' : +''
|
|
192
219
|
if !is_4x_rails && klass && (comment = klass.columns_hash.fetch(col, nil)&.comment)&.present?
|
|
193
220
|
suffix << ", comment: #{comment.inspect}"
|
|
194
221
|
end
|
|
195
222
|
# Determine if this column is used as part of a foreign key
|
|
196
|
-
if fk = fkey_cols.find { |assoc| col == assoc[:fk] }
|
|
223
|
+
if (fk = fkey_cols.find { |assoc| col == assoc[:fk] })
|
|
197
224
|
to_table = fk[:inverse_table].split('.')
|
|
198
225
|
to_table = to_table.length == 1 ? ":#{to_table.first}" : "'#{fk[:inverse_table]}'"
|
|
226
|
+
if needs_serial_col && pkey_cols&.include?(col) && (new_serial_type = {'integer' => 'serial', 'bigint' => 'bigserial'}[sql_type])
|
|
227
|
+
sql_type = new_serial_type
|
|
228
|
+
needs_serial_col = false
|
|
229
|
+
end
|
|
199
230
|
if fk[:fk] != "#{fk[:assoc_name].singularize}_id" # Need to do our own foreign_key tricks, not use references?
|
|
200
231
|
column = fk[:fk]
|
|
201
|
-
mig <<
|
|
232
|
+
mig << emit_column(sql_type, column, suffix)
|
|
202
233
|
add_fks << [to_table, column, ::Brick.relations[fk[:inverse_table]]]
|
|
203
234
|
else
|
|
204
235
|
suffix << ", type: :#{sql_type}" unless sql_type == key_type
|
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.72
|
|
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-09-
|
|
11
|
+
date: 2022-09-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|