brick 1.0.71 → 1.0.72
Sign up to get free protection for your applications and to get access to all the features.
- 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
|