brick 1.0.66 → 1.0.69

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7e8235e9e499424e41a8329f9056b4ab801fd7502889dfdafc527522f061ad3
4
- data.tar.gz: 898b3f172cb9eb6594b382087394857d7ff471a833069bfe7e060f404bfd2d4c
3
+ metadata.gz: 7399b8731b349e5c2a053956c5e6aa9998eb5a2010b5a0e7c081e87f9cac843e
4
+ data.tar.gz: bc3f65bb32230c05c63f7ef585a825de315ce2979d03b8db6efc6df0d0a5c143
5
5
  SHA512:
6
- metadata.gz: 0d0b88ac19a60e25ee48074e5ee67037c41d77b80a54ea22ad1813d22d4e3d233d253ed92a39e317f3faa86aac290ee51e0bed7ab178c583ca1d06b075bfaac1
7
- data.tar.gz: a0d8f7683236868789c9262a08a8c615786afdd6ad93b1f330807d5acad5962ea2e2ea645a236e37926b42bfd09db00ec9d00fae15de90da8fe589bfbe493b65
6
+ metadata.gz: b8681ca78d035e6c727fcb6b60d17a5658841bb28e8a4f3dd7405563d5c7cb3e9739984cfe09ce741fd70d5334b949b786e929a1ce4232cf77568621c2813c9d
7
+ data.tar.gz: 39a9586ea23107b66ab3d461e93eed2defc459231b26d4b25961a7e2e4df9b04167ff620ac570ad07040681e19ad6b313969e822d6fdd8b492b5f4c1fded4c1c
@@ -266,18 +266,27 @@ module ActiveRecord
266
266
  quoted_table_name = table_name.split('.').map { |x| "\"#{x}\"" }.join('.')
267
267
  order_by_txt = [] if is_do_txt
268
268
  ordering = [ordering] if ordering && !ordering.is_a?(Array)
269
- order_by = ordering&.map do |ord_part| # %%% If a term is also used as an eqi-condition in the WHERE clause, it can be omitted from ORDER BY
269
+ order_by = ordering&.each_with_object([]) do |ord_part, s| # %%% If a term is also used as an eqi-condition in the WHERE clause, it can be omitted from ORDER BY
270
270
  case ord_part
271
271
  when String
272
272
  ord_expr = ord_part.gsub('^^^', quoted_table_name)
273
273
  order_by_txt&.<<("Arel.sql(#{ord_expr})")
274
- Arel.sql(ord_expr)
274
+ s << Arel.sql(ord_expr)
275
275
  else # Expecting only Symbol
276
- ord_part = "_br_#{ord_part}_ct" if _br_hm_counts.key?(ord_part)
277
- # Retain any reference to a bt_descrip as being a symbol
278
- # Was: "#{quoted_table_name}.\"#{ord_part}\""
279
- order_by_txt&.<<(_br_bt_descrip.key?(ord_part) ? ord_part : ord_part.inspect)
280
- ord_part
276
+ if _br_hm_counts.key?(ord_part)
277
+ ord_part = "\"b_r_#{ord_part}_ct\""
278
+ elsif !_br_bt_descrip.key?(ord_part) && !column_names.include?(ord_part.to_s)
279
+ # Disallow ordering by a bogus column
280
+ # %%% Note this bogus entry so that Javascript can remove any bogus _brick_order
281
+ # parameter from the querystring, pushing it into the browser history.
282
+ ord_part = nil
283
+ end
284
+ if ord_part
285
+ # Retain any reference to a bt_descrip as being a symbol
286
+ # Was: "#{quoted_table_name}.\"#{ord_part}\""
287
+ order_by_txt&.<<(_br_bt_descrip.key?(ord_part) ? ord_part : ord_part.inspect)
288
+ s << ord_part
289
+ end
281
290
  end
282
291
  end
283
292
  [order_by, order_by_txt]
@@ -373,6 +382,7 @@ module ActiveRecord
373
382
  end
374
383
 
375
384
  def brick_select(params, selects = nil, order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
385
+ is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
376
386
  is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
377
387
  is_distinct = nil
378
388
  wheres = {}
@@ -401,10 +411,12 @@ module ActiveRecord
401
411
  col_alias = " AS _#{col.name}" if (col_name = col.name) == 'class'
402
412
  selects << if is_mysql
403
413
  "`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
404
- else
414
+ elsif is_postgres
405
415
  # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
406
416
  cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col.name)&.first&.start_with?('xml')
407
417
  "\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
418
+ else # Sqlite or Oracle
419
+ "#{tbl_no_schema}.#{col_name}#{col_alias}"
408
420
  end
409
421
  end
410
422
  end
@@ -430,13 +442,15 @@ module ActiveRecord
430
442
  # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
431
443
  is_xml = is_distinct && Brick.relations[sel_col.first.table_name]&.[](:cols)&.[](sel_col.last)&.first&.start_with?('xml')
432
444
  # If it's not unique then also include the belongs_to association name before the column name
433
- if used_col_aliases.key?(col_alias = "_brfk_#{v.first}__#{sel_col.last}")
434
- col_alias = "_brfk_#{v.first}__#{v1[idx][-2..-1].map(&:to_s).join('__')}"
445
+ if used_col_aliases.key?(col_alias = "br_fk_#{v.first}__#{sel_col.last}")
446
+ col_alias = "br_fk_#{v.first}__#{v1[idx][-2..-1].map(&:to_s).join('__')}"
435
447
  end
436
448
  selects << if is_mysql
437
449
  "`#{field_tbl_name}`.`#{sel_col.last}` AS `#{col_alias}`"
438
- else
450
+ elsif is_postgres
439
451
  "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{col_alias}\""
452
+ else
453
+ "#{field_tbl_name}.#{sel_col.last} AS \"#{col_alias}\""
440
454
  end
441
455
  used_col_aliases[col_alias] = nil
442
456
  v1[idx] << col_alias
@@ -447,9 +461,11 @@ module ActiveRecord
447
461
  ((id_col = k1.primary_key).is_a?(Array) ? id_col : [id_col]).each do |id_part|
448
462
  id_for_tables[v.first] << if id_part
449
463
  selects << if is_mysql
450
- "#{"`#{tbl_name}`.`#{id_part}`"} AS `#{(id_alias = "_brfk_#{v.first}__#{id_part}")}`"
464
+ "#{"`#{tbl_name}`.`#{id_part}`"} AS `#{(id_alias = "br_fk_#{v.first}__#{id_part}")}`"
465
+ elsif is_postgres
466
+ "#{"\"#{tbl_name}\".\"#{id_part}\""} AS \"#{(id_alias = "br_fk_#{v.first}__#{id_part}")}\""
451
467
  else
452
- "#{"\"#{tbl_name}\".\"#{id_part}\""} AS \"#{(id_alias = "_brfk_#{v.first}__#{id_part}")}\""
468
+ "#{"#{tbl_name}.#{id_part}"} AS \"#{(id_alias = "br_fk_#{v.first}__#{id_part}")}\""
453
469
  end
454
470
  id_alias
455
471
  end
@@ -479,9 +495,22 @@ module ActiveRecord
479
495
  end
480
496
  next unless count_column # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
481
497
 
482
- tbl_alias = is_mysql ? "`_br_#{hm.name}`" : "\"_br_#{hm.name}\""
498
+ tbl_alias = if is_mysql
499
+ "`b_r_#{hm.name}`"
500
+ elsif is_postgres
501
+ "\"b_r_#{hm.name}\""
502
+ else
503
+ "b_r_#{hm.name}"
504
+ end
483
505
  pri_tbl = hm.active_record
484
506
  pri_tbl_name = is_mysql ? "`#{pri_tbl.table_name}`" : "\"#{pri_tbl.table_name.gsub('.', '"."')}\""
507
+ pri_tbl_name = if is_mysql
508
+ "`#{pri_tbl.table_name}`"
509
+ elsif is_postgres
510
+ "\"#{pri_tbl.table_name.gsub('.', '"."')}\""
511
+ else
512
+ pri_tbl.table_name
513
+ end
485
514
  on_clause = []
486
515
  if fk_col.is_a?(Array) # Composite key?
487
516
  fk_col.each_with_index { |fk_col_part, idx| on_clause << "#{tbl_alias}.#{fk_col_part} = #{pri_tbl_name}.#{pri_tbl.primary_key[idx]}" }
@@ -494,22 +523,29 @@ module ActiveRecord
494
523
  selects << poly_type
495
524
  on_clause << "#{tbl_alias}.#{poly_type} = '#{name}'"
496
525
  end
497
- hm_table_name = is_mysql ? "`#{associative&.table_name || hm.klass.table_name}`" : "\"#{(associative&.table_name || hm.klass.table_name).gsub('.', '"."')}\""
526
+ hm_table_name = if is_mysql
527
+ "`#{associative&.table_name || hm.klass.table_name}`"
528
+ elsif is_postgres
529
+ "\"#{(associative&.table_name || hm.klass.table_name).gsub('.', '"."')}\""
530
+ else
531
+ associative&.table_name || hm.klass.table_name
532
+ end
533
+ group_bys = ::Brick.is_oracle ? selects : (1..selects.length).to_a
498
534
  join_clause = "LEFT OUTER
499
535
  JOIN (SELECT #{selects.join(', ')}, COUNT(#{'DISTINCT ' if hm.options[:through]}#{count_column
500
- }) AS _ct_ FROM #{hm_table_name} GROUP BY #{(1..selects.length).to_a.join(', ')}) AS #{tbl_alias}"
536
+ }) AS c_t_ FROM #{hm_table_name} GROUP BY #{group_bys.join(', ')}) #{tbl_alias}"
501
537
  joins!("#{join_clause} ON #{on_clause.join(' AND ')}")
502
538
  end
503
539
  where!(wheres) unless wheres.empty?
504
540
  # Must parse the order_by and see if there are any symbols which refer to BT associations
505
- # as they must be expanded to find the corresponding _br_model__column naming for each.
541
+ # as they must be expanded to find the corresponding b_r_model__column naming for each.
506
542
  if order_by.present?
507
543
  final_order_by = *order_by.each_with_object([]) do |v, s|
508
544
  if v.is_a?(Symbol)
509
545
  # Add the ordered series of columns derived from the BT based on its DSL
510
546
  if (bt_cols = klass._br_bt_descrip[v])
511
547
  bt_cols.values.each do |v1|
512
- v1.each { |v2| s << v2.last if v2.length > 1 }
548
+ v1.each { |v2| s << "\"#{v2.last}\"" if v2.length > 1 }
513
549
  end
514
550
  else
515
551
  s << v
@@ -657,9 +693,12 @@ Module.class_exec do
657
693
  full_class_name = +''
658
694
  full_class_name << "::#{self.name}" unless self == Object
659
695
  full_class_name << "::#{plural_class_name.underscore.singularize.camelize}"
660
- if (plural_class_name == 'BrickSwagger' ||
661
- ((::Brick.config.add_status || ::Brick.config.add_orphans) && plural_class_name == 'BrickGem') ||
662
- model = self.const_get(full_class_name))
696
+ if plural_class_name == 'BrickSwagger' ||
697
+ (
698
+ (::Brick.config.add_status || ::Brick.config.add_orphans) &&
699
+ plural_class_name == 'BrickGem'
700
+ ) ||
701
+ model = self.const_get(full_class_name)
663
702
  # if it's a controller and no match or a model doesn't really use the same table name, eager load all models and try to find a model class of the right name.
664
703
  Object.send(:build_controller, self, class_name, plural_class_name, model, relations)
665
704
  end
@@ -1017,6 +1056,7 @@ class Object
1017
1056
  table_name = ActiveSupport::Inflector.underscore(plural_class_name)
1018
1057
  singular_table_name = ActiveSupport::Inflector.singularize(table_name)
1019
1058
  pk = model&._brick_primary_key(relations.fetch(table_name, nil))
1059
+ is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1020
1060
  is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
1021
1061
 
1022
1062
  namespace_name = "#{namespace.name}::" if namespace
@@ -1033,7 +1073,7 @@ class Object
1033
1073
  self.define_method :orphans do
1034
1074
  instance_variable_set(:@orphans, ::Brick.find_orphans(::Brick.set_db_schema(params)))
1035
1075
  end
1036
- return [new_controller_class, code + ' # BrickGem controller']
1076
+ return [new_controller_class, code + "end # BrickGem controller\n"]
1037
1077
  when 'BrickSwagger'
1038
1078
  is_swagger = true # if request.format == :json)
1039
1079
  end
@@ -1122,7 +1162,13 @@ class Object
1122
1162
  # %%% Add custom HM count columns
1123
1163
  # %%% What happens when the PK is composite?
1124
1164
  counts = model._br_hm_counts.each_with_object([]) do |v, s|
1125
- s << (is_mysql ? "`_br_#{v.first}`._ct_ AS \"_br_#{v.first}_ct\"" : "\"_br_#{v.first}\"._ct_ AS \"_br_#{v.first}_ct\"")
1165
+ s << if is_mysql
1166
+ "`b_r_#{v.first}`.c_t_ AS \"b_r_#{v.first}_ct\""
1167
+ elsif is_postgres
1168
+ "\"b_r_#{v.first}\".c_t_ AS \"b_r_#{v.first}_ct\""
1169
+ else
1170
+ "b_r_#{v.first}.c_t_ AS \"b_r_#{v.first}_ct\""
1171
+ end
1126
1172
  end
1127
1173
  instance_variable_set("@#{table_name}".to_sym, ar_relation.dup._select!(*selects, *counts))
1128
1174
  if namespace && (idx = lookup_context.prefixes.index(table_name))
@@ -1193,6 +1239,8 @@ class Object
1193
1239
  else
1194
1240
  instance_variable_set("@#{singular_table_name}".to_sym,
1195
1241
  model.send(:create, send(params_name_sym)))
1242
+ index
1243
+ render :index
1196
1244
  end
1197
1245
  end
1198
1246
 
@@ -1352,15 +1400,18 @@ module ActiveRecord::ConnectionHandling
1352
1400
  end
1353
1401
  when 'Mysql2'
1354
1402
  ::Brick.default_schema = schema = ActiveRecord::Base.connection.current_database
1403
+ when 'OracleEnhanced'
1404
+ # ActiveRecord::Base.connection.current_database will be something like "XEPDB1"
1405
+ ::Brick.default_schema = schema = ActiveRecord::Base.connection.raw_connection.username
1406
+ ::Brick.db_schemas = {}
1407
+ execute_oracle("SELECT username FROM sys.all_users WHERE ORACLE_MAINTAINED != 'Y'").each { |s| ::Brick.db_schemas[s.first] = nil }
1355
1408
  when 'SQLite'
1356
- # %%% Retrieve internal ActiveRecord table names like this:
1357
- # ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
1358
1409
  sql = "SELECT m.name AS relation_name, UPPER(m.type) AS table_type,
1359
1410
  p.name AS column_name, p.type AS data_type,
1360
1411
  CASE p.pk WHEN 1 THEN 'PRIMARY KEY' END AS const
1361
1412
  FROM sqlite_master AS m
1362
1413
  INNER JOIN pragma_table_info(m.name) AS p
1363
- WHERE m.name NOT IN (?, ?)
1414
+ WHERE m.name NOT IN ('sqlite_sequence', ?, ?)
1364
1415
  ORDER BY m.name, p.cid"
1365
1416
  else
1366
1417
  puts "Unfamiliar with connection adapter #{ActiveRecord::Base.connection.adapter_name}"
@@ -1412,9 +1463,31 @@ module ActiveRecord::ConnectionHandling
1412
1463
  cols[col_name] = [r['data_type'], r['max_length'], measures&.include?(col_name), r['is_nullable'] == 'NO']
1413
1464
  # puts "KEY! #{r['relation_name']}.#{col_name} #{r['key']} #{r['const']}" if r['key']
1414
1465
  end
1415
- else # MySQL2 acts a little differently, bringing back an array for each row
1416
- ActiveRecord::Base.retrieve_schema_and_tables(sql).each do |r|
1417
- relation = relations[(relation_name = r[1])] # here relation represents a table or view from the database
1466
+ else # MySQL2 and OracleEnhanced act a little differently, bringing back an array for each row
1467
+ schema_and_tables = if ActiveRecord::Base.connection.adapter_name == 'OracleEnhanced'
1468
+ sql =
1469
+ "SELECT c.owner AS schema, c.table_name AS relation_name, 'BASE_TABLE' AS table_type,
1470
+ LOWER(c.column_name) AS column_name, c.data_type,
1471
+ COALESCE(c.data_length, c.data_precision) AS max_length,
1472
+ CASE ac.constraint_type WHEN 'P' THEN 'PRIMARY KEY' END AS const,
1473
+ ac.constraint_name AS \"key\",
1474
+ CASE c.nullable WHEN 'Y' THEN 'YES' ELSE 'NO' END AS is_nullable
1475
+ FROM all_tab_cols c
1476
+ LEFT OUTER JOIN all_cons_columns acc ON acc.owner = c.owner AND acc.table_name = c.table_name AND acc.column_name = c.column_name
1477
+ LEFT OUTER JOIN all_constraints ac ON ac.owner = acc.owner AND ac.table_name = acc.table_name AND ac.constraint_name = acc.constraint_name AND constraint_type = 'P'
1478
+ WHERE c.owner IN (#{::Brick.db_schemas.keys.map { |s| "'#{s}'" }.join(', ')})
1479
+ ORDER BY 1, 2, c.internal_column_id, acc.position"
1480
+ execute_oracle(sql, *ar_tables)
1481
+ else
1482
+ ActiveRecord::Base.retrieve_schema_and_tables(sql)
1483
+ end
1484
+ schema_and_tables.each do |r|
1485
+ next if r[1].index('$') # Oracle can have goofy table names with $
1486
+
1487
+ if (relation_name = r[1]) =~ /^[A-Z_]+$/
1488
+ relation_name.downcase!
1489
+ end
1490
+ relation = relations[relation_name] # here relation represents a table or view from the database
1418
1491
  relation[:isView] = true if r[2] == 'VIEW' # table_type
1419
1492
  col_name = r[3]
1420
1493
  key = case r[6] # constraint type
@@ -1471,32 +1544,53 @@ module ActiveRecord::ConnectionHandling
1471
1544
  AND kcu2.ORDINAL_POSITION = kcu1.ORDINAL_POSITION#{"
1472
1545
  WHERE kcu1.CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }"
1473
1546
  # AND kcu2.TABLE_NAME = ?;", Apartment::Tenant.current, table_name
1547
+ fk_references = ActiveRecord::Base.execute_sql(sql)
1474
1548
  when 'SQLite'
1475
1549
  sql = "SELECT m.name, fkl.\"from\", fkl.\"table\", m.name || '_' || fkl.\"from\" AS constraint_name
1476
1550
  FROM sqlite_master m
1477
1551
  INNER JOIN pragma_foreign_key_list(m.name) fkl ON m.type = 'table'
1478
1552
  ORDER BY m.name, fkl.seq"
1553
+ fk_references = ActiveRecord::Base.execute_sql(sql)
1554
+ when 'OracleEnhanced'
1555
+ schemas = ::Brick.db_schemas.keys.map { |s| "'#{s}'" }.join(', ')
1556
+ sql =
1557
+ "SELECT -- fk
1558
+ ac.owner AS constraint_schema, acc_fk.table_name, LOWER(acc_fk.column_name),
1559
+ -- referenced pk
1560
+ ac.r_owner AS primary_schema, acc_pk.table_name AS primary_table, acc_fk.constraint_name AS constraint_schema_fk
1561
+ -- , LOWER(acc_pk.column_name)
1562
+ FROM all_cons_columns acc_fk
1563
+ INNER JOIN all_constraints ac ON acc_fk.owner = ac.owner
1564
+ AND acc_fk.constraint_name = ac.constraint_name
1565
+ INNER JOIN all_cons_columns acc_pk ON ac.r_owner = acc_pk.owner
1566
+ AND ac.r_constraint_name = acc_pk.constraint_name
1567
+ WHERE ac.constraint_type = 'R'
1568
+ AND ac.owner IN (#{schemas})
1569
+ AND ac.r_owner IN (#{schemas})"
1570
+ fk_references = ActiveRecord::Base.execute_oracle(sql)
1479
1571
  else
1572
+ binding.pry
1480
1573
  end
1481
- if sql
1482
- # ::Brick.default_schema ||= schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1483
- ActiveRecord::Base.execute_sql(sql).each do |fk|
1484
- fk = fk.values unless fk.is_a?(Array)
1485
- # Multitenancy makes things a little more general overall, except for non-tenanted tables
1486
- if apartment_excluded&.include?(fk[1].singularize.camelize)
1487
- fk[0] = Apartment.default_schema
1488
- elsif is_postgres && (fk[0] == 'public' || (is_multitenant && fk[0] == schema)) ||
1489
- !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0])
1490
- fk[0] = nil
1491
- end
1492
- if apartment_excluded&.include?(fk[4].singularize.camelize)
1493
- fk[3] = Apartment.default_schema
1494
- elsif is_postgres && (fk[3] == 'public' || (is_multitenant && fk[3] == schema)) ||
1495
- !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[3])
1496
- fk[3] = nil
1497
- end
1498
- ::Brick._add_bt_and_hm(fk, relations)
1574
+ ::Brick.is_oracle = true if ActiveRecord::Base.connection.adapter_name == 'OracleEnhanced'
1575
+ # ::Brick.default_schema ||= schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1576
+ fk_references&.each do |fk|
1577
+ fk = fk.values unless fk.is_a?(Array)
1578
+ # Multitenancy makes things a little more general overall, except for non-tenanted tables
1579
+ if apartment_excluded&.include?(fk[1].singularize.camelize)
1580
+ fk[0] = Apartment.default_schema
1581
+ elsif is_postgres && (fk[0] == 'public' || (is_multitenant && fk[0] == schema)) ||
1582
+ !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0])
1583
+ fk[0] = nil
1584
+ end
1585
+ if apartment_excluded&.include?(fk[4].singularize.camelize)
1586
+ fk[3] = Apartment.default_schema
1587
+ elsif is_postgres && (fk[3] == 'public' || (is_multitenant && fk[3] == schema)) ||
1588
+ !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[3])
1589
+ fk[3] = nil
1499
1590
  end
1591
+ fk[1].downcase! if ::Brick.is_oracle && fk[1] =~ /^[A-Z_]+$/
1592
+ fk[4].downcase! if ::Brick.is_oracle && fk[4] =~ /^[A-Z_]+$/
1593
+ ::Brick._add_bt_and_hm(fk, relations)
1500
1594
  end
1501
1595
  end
1502
1596
 
@@ -1557,13 +1651,27 @@ module ActiveRecord::ConnectionHandling
1557
1651
  -- AND t.table_type IN ('VIEW') -- 'BASE TABLE', 'FOREIGN TABLE'
1558
1652
  AND t.table_name NOT IN ('pg_stat_statements', ?, ?)
1559
1653
  ORDER BY 1, t.table_type DESC, 2, c.ordinal_position"
1654
+ ActiveRecord::Base.execute_sql(sql, *ar_tables)
1655
+ end
1656
+
1657
+ def ar_tables
1560
1658
  ar_smtn = if ActiveRecord::Base.respond_to?(:schema_migrations_table_name)
1561
1659
  ActiveRecord::Base.schema_migrations_table_name
1562
1660
  else
1563
1661
  'schema_migrations'
1564
1662
  end
1565
1663
  ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1566
- ActiveRecord::Base.execute_sql(sql, ar_smtn, ar_imtn)
1664
+ [ar_smtn, ar_imtn]
1665
+ end
1666
+
1667
+ def execute_oracle(*sql_args)
1668
+ cursor = ActiveRecord::Base.execute_sql(*sql_args)
1669
+ result = []
1670
+ while row = cursor.fetch()
1671
+ result << row
1672
+ end
1673
+ cursor.close
1674
+ result
1567
1675
  end
1568
1676
  end
1569
1677
 
@@ -96,16 +96,15 @@ module Brick
96
96
 
97
97
  alias :_brick_find_template :find_template
98
98
  def find_template(*args, **options)
99
- unless (model_name = (
100
- @_brick_model ||
101
- (ActionView.version < ::Gem::Version.new('5.0') && args[1].is_a?(Array) ? set_brick_model(args) : nil)
102
- )&.name) ||
99
+ unless (model_name = @_brick_model&.name) ||
103
100
  (is_status = ::Brick.config.add_status && args[0..1] == ['status', ['brick_gem']]) ||
104
- (is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']])
101
+ (is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']]) ||
102
+ # Used to also have: ActionView.version < ::Gem::Version.new('5.0') &&
103
+ (model_name = (args[1].is_a?(Array) ? set_brick_model(args) : nil)&.name)
105
104
  return _brick_find_template(*args, **options)
106
105
  end
107
106
 
108
- unless is_status || is_orphans
107
+ if @_brick_model
109
108
  pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(model_name, nil))
110
109
  obj_name = model_name.split('::').last.underscore
111
110
  path_obj_name = model_name.underscore.tr('/', '_')
@@ -146,7 +145,7 @@ module Brick
146
145
  'nil'
147
146
  else
148
147
  # Postgres column names are limited to 63 characters
149
- "#{obj_name}.#{"_br_#{assoc_name}_ct"[0..62]} || 0"
148
+ "#{obj_name}.#{"b_r_#{assoc_name}_ct"[0..62]} || 0"
150
149
  end
151
150
  ", #{set_ct}, #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)}"
152
151
  end
@@ -156,7 +155,7 @@ module Brick
156
155
  end
157
156
  hm_entry << ']'
158
157
  hms_columns << hm_entry
159
- when 'show', 'update'
158
+ when 'show', 'new', 'update'
160
159
  hm_stuff << if hm_fk_name
161
160
  "<%= link_to '#{assoc_name}', #{hm_assoc.klass.name.underscore.tr('/', '_').pluralize}_path({ #{path_keys(hm_assoc, hm_fk_name, "@#{obj_name}", pk)} }) %>\n"
162
161
  else # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
@@ -179,6 +178,7 @@ module Brick
179
178
  end.keys.sort.each_with_object(+'') do |v, s|
180
179
  s << "<option value=\"#{v.underscore.gsub('.', '/').pluralize}\">#{v}</option>"
181
180
  end.html_safe
181
+ table_options << '<option value="brick_status">(Status)</option>'.html_safe if ::Brick.config.add_status
182
182
  table_options << '<option value="brick_orphans">(Orphans)</option>'.html_safe if is_orphans
183
183
  css = +"<style>
184
184
  h1, h3 {
@@ -275,7 +275,7 @@ tr th, tr td {
275
275
  color: #80B8D2;
276
276
  }
277
277
 
278
- table.shadow tbody tr {
278
+ table.shadow > tbody > tr {
279
279
  border-bottom: thin solid #dddddd;
280
280
  }
281
281
 
@@ -283,7 +283,7 @@ table tbody tr:nth-of-type(even) {
283
283
  background-color: #f3f3f3;
284
284
  }
285
285
 
286
- table.shadow tbody tr:last-of-type {
286
+ table.shadow > tbody > tr:last-of-type {
287
287
  border-bottom: 2px solid #009879;
288
288
  }
289
289
 
@@ -300,14 +300,6 @@ a.big-arrow {
300
300
  font-size: 2.5em;
301
301
  text-decoration: none;
302
302
  }
303
- .wide-input {
304
- display: block;
305
- overflow: hidden;
306
- }
307
- .wide-input input[type=text] {
308
- display: inline-block;
309
- width: 90%;
310
- }
311
303
  .dimmed {
312
304
  background-color: #C0C0C0;
313
305
  text-align: center;
@@ -324,9 +316,6 @@ svg.revert {
324
316
  display: none;
325
317
  margin-left: 0.25em;
326
318
  }
327
- .wide-input > svg.revert {
328
- float: right;
329
- }
330
319
  input+svg.revert {
331
320
  top: 0.5em;
332
321
  }
@@ -379,9 +368,10 @@ def display_value(col_type, val)
379
368
  '?'
380
369
  end
381
370
  end
382
- end %>"
371
+ end
372
+ callbacks = {} %>"
383
373
 
384
- if ['index', 'show', 'update'].include?(args.first)
374
+ if ['index', 'show', 'new', 'update'].include?(args.first)
385
375
  poly_cols = []
386
376
  css << "<% bts = { #{
387
377
  bt_items = bts.each_with_object([]) do |v, s|
@@ -537,17 +527,18 @@ if (headerTop) {
537
527
  }
538
528
  </script>"
539
529
 
540
- erd_markup = "<div id=\"mermaidErd\" class=\"mermaid\">
530
+ erd_markup = if @_brick_model
531
+ "<div id=\"mermaidErd\" class=\"mermaid\">
541
532
  erDiagram
542
533
  <% model_short_name = #{@_brick_model.name.split('::').last.inspect}
543
- callbacks = {}
544
534
  @_brick_bt_descrip&.each do |bt|
545
535
  bt_class = bt[1].first.first
546
536
  callbacks[bt_name = bt_class.name.split('::').last] = bt_class
547
537
  is_has_one = #{@_brick_model.name}.reflect_on_association(bt.first).inverse_of&.macro == :has_one ||
548
538
  ::Brick.config.has_ones&.fetch('#{@_brick_model.name}', nil)&.key?(bt.first.to_s)
549
539
  %> <%= \"#\{model_short_name} #\{is_has_one ? '||' : '}o'}--|| #\{bt_name} : \\\"#\{
550
- bt.first unless bt.first.to_s == bt[1].first.first.name.underscore.singularize.tr('/', '_')
540
+ bt_underscored = bt[1].first.first.name.underscore.singularize
541
+ bt.first unless bt.first.to_s == bt_underscored.split('/').last # Was: bt_underscored.tr('/', '_')
551
542
  }\\\"\".html_safe %>
552
543
  <% end
553
544
  last_through = nil
@@ -557,14 +548,15 @@ erDiagram
557
548
 
558
549
  callbacks[hm_name = hm_class.name.split('::').last] = hm_class
559
550
  if (through = hm.last.options[:through]&.to_s) # has_many :through (HMT)
560
- callbacks[through.singularize.camelize] = (through_assoc = hm.last.source_reflection).active_record
551
+ through_name = (through_assoc = hm.last.source_reflection).active_record.name.split('::').last
552
+ callbacks[through_name] = through_assoc.active_record
561
553
  if last_through == through # Same HM, so no need to build it again, and for clarity just put in a blank line
562
554
  %><%= \"\n\"
563
555
  %><% else
564
- %> <%= \"#\{model_short_name} ||--o{ #\{through_assoc.active_record.name}\".html_safe %> : \"\"
556
+ %> <%= \"#\{model_short_name} ||--o{ #\{through_name}\".html_safe %> : \"\"
565
557
  <% last_through = through
566
558
  end
567
- %> <%= \"#\{through_assoc.active_record.name} }o--|| #\{hm_name}\".html_safe %> : \"\"
559
+ %> <%= \"#\{through_name} }o--|| #\{hm_name}\".html_safe %> : \"\"
568
560
  <%= \"#\{model_short_name} }o..o{ #\{hm_name} : \\\"#\{hm.first}\\\"\".html_safe %><%
569
561
  else # has_many
570
562
  %> <%= \"#\{model_short_name} ||--o{ #\{hm_name} : \\\"#\{
@@ -572,21 +564,25 @@ erDiagram
572
564
  }\\\"\".html_safe %><%
573
565
  end %>
574
566
  <% end
567
+ def dt_lookup(dt)
568
+ { 'integer' => 'int', }[dt] || dt.tr(' ', '_')
569
+ end
575
570
  callbacks.merge({model_short_name => #{@_brick_model.name}}).each do |cb_k, cb_class|
576
571
  cb_relation = ::Brick.relations[cb_class.table_name]
577
572
  pkeys = cb_relation[:pkey]&.first&.last
578
573
  fkeys = cb_relation[:fks]&.values&.each_with_object([]) { |fk, s| s << fk[:fk] if fk.fetch(:is_bt, nil) }
574
+ cols = cb_relation[:cols]
579
575
  %> <%= cb_k %> {<%
580
576
  pkeys&.each do |pk| %>
581
- <%= \"int #\{pk} \\\"PK#\{' fk' if fkeys&.include?(pk)}\\\"\".html_safe %><%
577
+ <%= \"#\{dt_lookup(cols[pk].first)} #\{pk} \\\"PK#\{' fk' if fkeys&.include?(pk)}\\\"\".html_safe %><%
582
578
  end %><%
583
579
  fkeys&.each do |fk|
584
580
  if fk.is_a?(Array)
585
581
  fk.each do |fk_part| %>
586
- <%= \"int #\{fk_part} \\\"&nbsp;&nbsp;&nbsp;&nbsp;fk\\\"\".html_safe unless pkeys&.include?(fk_part) %><%
582
+ <%= \"#\{dt_lookup(cols[fk_part].first)} #\{fk_part} \\\"&nbsp;&nbsp;&nbsp;&nbsp;fk\\\"\".html_safe unless pkeys&.include?(fk_part) %><%
587
583
  end
588
584
  else %>
589
- <%= \"int #\{fk} \\\"&nbsp;&nbsp;&nbsp;&nbsp;fk\\\"\".html_safe unless pkeys&.include?(fk) %><%
585
+ <%= \"#\{dt_lookup(cols[fk].first)} #\{fk} \\\"&nbsp;&nbsp;&nbsp;&nbsp;fk\\\"\".html_safe unless pkeys&.include?(fk) %><%
590
586
  end
591
587
  end %>
592
588
  }
@@ -595,6 +591,7 @@ erDiagram
595
591
  %>
596
592
  </div>
597
593
  "
594
+ end
598
595
  inline = case args.first
599
596
  when 'index'
600
597
  obj_pk = if pk&.is_a?(Array) # Composite primary key?
@@ -690,7 +687,7 @@ erDiagram
690
687
  </script>
691
688
  <script async defer src=\"https://apis.google.com/js/api.js\" onload=\"gapiLoaded()\"></script>
692
689
  "
693
- end
690
+ end # DutyFree data export and import
694
691
  # %%% Instead of our current "for Janet Leverling (Employee)" kind of link we previously had this code that did a "where x = 123" thing:
695
692
  # (where <%= @_brick_params.each_with_object([]) { |v, s| s << \"#\{v.first\} = #\{v.last.inspect\}\" }.join(', ') %>)
696
693
  +"#{css}
@@ -829,6 +826,7 @@ erDiagram
829
826
  #{script}"
830
827
 
831
828
  when 'status'
829
+ if is_status
832
830
  # Status page - list of all resources and 5 things they do or don't have present, and what is turned on and off
833
831
  # Must load all models, and then find what table names are represented
834
832
  # Easily could be multiple files involved (STI for instance)
@@ -852,7 +850,7 @@ erDiagram
852
850
  @resources.each do |r|
853
851
  %>
854
852
  <tr>
855
- <td><%= link_to(r[0], \"/#\{r[0].tr('.', '/')}\") %></td>
853
+ <td><%= link_to(r[0], \"/#\{r[0].underscore.tr('.', '/')}\") %></td>
856
854
  <td<%= if r[1]
857
855
  ' class=\"orphan\"' unless ::Brick.relations.key?(r[1])
858
856
  else
@@ -873,6 +871,7 @@ erDiagram
873
871
  <% end %>
874
872
  </tbody></table>
875
873
  #{script}"
874
+ end
876
875
 
877
876
  when 'orphans'
878
877
  if is_orphans
@@ -890,7 +889,7 @@ erDiagram
890
889
  #{script}"
891
890
  end
892
891
 
893
- when 'show', 'update'
892
+ when 'show', 'new', 'update'
894
893
  +"#{css}
895
894
 
896
895
  <svg id=\"revertTemplate\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"
@@ -958,38 +957,41 @@ end
958
957
  <% end %>
959
958
  </th>
960
959
  <td>
960
+ <table><tr><td>
961
961
  <% dt_pickers = { datetime: 'datetimepicker', timestamp: 'datetimepicker', time: 'timepicker', date: 'datepicker' }
962
+ html_options = {}
963
+ html_options[:class] = 'dimmed' unless val
964
+ is_revert = true
962
965
  if bt
963
- html_options = { prompt: \"Select #\{bt_name\}\" }
964
- html_options[:class] = 'dimmed' unless val %>
966
+ html_options[:prompt] = \"Select #\{bt_name\}\" %>
965
967
  <%= f.select k.to_sym, bt[3], { value: val || '^^^brick_NULL^^^' }, html_options %>
966
968
  <%= if (bt_obj = bt_class&.find_by(bt_pair[1] => val))
967
969
  link_to('⇛', send(\"#\{bt_class.base_class.name.underscore.tr('/', '_')\}_path\".to_sym, bt_obj.send(bt_class.primary_key.to_sym)), { class: 'show-arrow' })
968
970
  elsif val
969
971
  \"<span class=\\\"orphan\\\">Orphaned ID: #\{val}</span>\".html_safe
970
- end %><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
972
+ end %>
971
973
  <% else
972
- html_options = {}
973
- html_options[:class] = 'dimmed' unless val
974
- case (col_type = col.type || col.sql_type)
974
+ case (col_type = col.type || col.sql_type)
975
975
  when :string, :text %>
976
- <% if is_bcrypt?(val) # || .readonly? %>
976
+ <% if is_bcrypt?(val) # || .readonly?
977
+ is_revert = false %>
977
978
  <%= hide_bcrypt(val, 1000) %>
978
979
  <% else %>
979
- <div class=\"wide-input\"><%= f.text_field(k.to_sym, html_options) %><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg></div>
980
+ <%= f.text_field(k.to_sym, html_options) %>
980
981
  <% end %>
981
982
  <% when :boolean %>
982
- <%= f.check_box k.to_sym %><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
983
+ <%= f.check_box k.to_sym %>
983
984
  <% when :integer, :decimal, :float %>
984
985
  <%= if col_type == :integer
985
986
  f.text_field k.to_sym, { pattern: '\\d*', class: 'check-validity' }
986
987
  else
987
988
  f.number_field k.to_sym
988
- end %><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
989
+ end %>
989
990
  <% when *dt_pickers.keys
990
991
  is_includes_dates = true %>
991
- <%= f.text_field k.to_sym, { class: dt_pickers[col_type] } %><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
992
- <% when :uuid %>
992
+ <%= f.text_field k.to_sym, { class: dt_pickers[col_type] } %>
993
+ <% when :uuid
994
+ is_revert = false %>
993
995
  <%=
994
996
  # Postgres naturally uses the +uuid_generate_v4()+ function from the uuid-ossp extension
995
997
  # If it's not yet enabled then: create extension \"uuid-ossp\";
@@ -1000,11 +1002,18 @@ end
1000
1002
  # In Postgres labels of data stored in a hierarchical tree-like structure
1001
1003
  # If it's not yet enabled then: create extension ltree;
1002
1004
  val %>
1003
- <% when :binary, :primary_key %>
1005
+ <% when :binary, :primary_key
1006
+ is_revert = false %>
1004
1007
  <% else %>
1005
- <%= display_value(col_type, val) %>
1008
+ <%= display_value(col_type, val)
1009
+ is_revert = false %>
1010
+ <% end
1011
+ end
1012
+ if is_revert
1013
+ %></td>
1014
+ <td><svg class=\"revert\" width=\"1.5em\" viewBox=\"0 0 512 512\"><use xlink:href=\"#revertPath\" /></svg>
1006
1015
  <% end %>
1007
- <% end %>
1016
+ </td></tr></table>
1008
1017
  </td>
1009
1018
  </tr>
1010
1019
  <% end
@@ -1066,7 +1075,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
1066
1075
  var mermaidErd = document.getElementById(\"mermaidErd\");
1067
1076
  var mermaidCode;
1068
1077
  var cbs = {<%= callbacks.map { |k, v| \"#\{k}: \\\"#\{v.name.underscore.pluralize}\\\"\" }.join(', ').html_safe %>};
1069
- imgErd.addEventListener(\"click\", showErd);
1078
+ if (imgErd) imgErd.addEventListener(\"click\", showErd);
1070
1079
  function showErd() {
1071
1080
  imgErd.style.display = \"none\";
1072
1081
  mermaidErd.style.display = \"inline-block\";
@@ -1087,7 +1096,9 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
1087
1096
  gErd.setAttribute(\"class\", \"relatedModel\");
1088
1097
  gErd.addEventListener(\"click\",
1089
1098
  function (evt) {
1090
- location.href = changeout(changeout(location.href, -1, cbs[this.id]), \"_brick_erd\", \"1\");
1099
+ location.href = changeout(changeout(
1100
+ changeout(location.href, '_brick_order', null), // Remove any ordering
1101
+ -1, cbs[this.id]), \"_brick_erd\", \"1\");
1091
1102
  }
1092
1103
  );
1093
1104
  }
@@ -1127,9 +1138,12 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
1127
1138
  var origVal = getInpVal(),
1128
1139
  prevVal = origVal;
1129
1140
  var revert;
1130
- if ((revert = ((inp.tagName === \"SELECT\" && inp.nextElementSibling.nextElementSibling) ||
1131
- inp.nextElementSibling ||
1132
- inp.parentElement.nextElementSibling)) && revert.tagName.toLowerCase() === \"svg\")
1141
+ if (inp.getAttribute(\"type\") == \"hidden\" || inp.getAttribute(\"type\") == \"submit\") return;
1142
+
1143
+ var svgTd = null;
1144
+ if ((revert = ((inp.tagName === \"SELECT\" && (svgTd = inp.parentElement.nextElementSibling) && svgTd.firstElementChild) ||
1145
+ ((svgTd = inp.parentElement.nextElementSibling) && svgTd.firstElementChild))
1146
+ ) && revert.tagName.toLowerCase() === \"svg\")
1133
1147
  revert.addEventListener(\"click\", function (e) {
1134
1148
  if (inp.type === \"checkbox\")
1135
1149
  inp.checked = origVal;
@@ -1160,7 +1174,7 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
1160
1174
  prevVal = getInpVal();
1161
1175
  }
1162
1176
  // Show or hide the revert button
1163
- if (revert) revert.style.display = getInpVal() === origVal ? \"none\" : \"inline-block\";
1177
+ if (revert) revert.style.display = getInpVal() === origVal ? \"none\" : \"block\";
1164
1178
  });
1165
1179
  function getInpVal() {
1166
1180
  return inp.type === \"checkbox\" ? inp.checked : inp.value;
@@ -1180,6 +1194,13 @@ document.querySelectorAll(\"input, select\").forEach(function (inp) {
1180
1194
  # In order to defer auto-creation of any routes that already exist, calculate Brick routes only after having loaded all others
1181
1195
  prepend ::Brick::RouteSet
1182
1196
  end
1197
+ # Do the root route before the Rails Welcome one would otherwise take precedence
1198
+ unless (route = ::Brick.config.default_route_fallback).blank? ||
1199
+ ::Rails.application.routes.named_routes.send(:routes)[:root]
1200
+ ::Rails.application.routes.append do
1201
+ send(:root, "#{route}#{'#index' unless route.index('#')}")
1202
+ end
1203
+ end
1183
1204
  end
1184
1205
 
1185
1206
  # Just in case it hadn't been done previously when we tried to load the brick initialiser,
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 66
8
+ TINY = 69
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -123,7 +123,7 @@ module Brick
123
123
  end
124
124
 
125
125
  class << self
126
- attr_accessor :default_schema, :db_schemas
126
+ attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle
127
127
 
128
128
  def set_db_schema(params)
129
129
  schema = params['_brick_schema'] || 'public'
@@ -461,11 +461,11 @@ In config/initializers/brick.rb appropriate entries would look something like:
461
461
 
462
462
  module RouteSet
463
463
  def finalize!
464
+ return super if ::Brick.routes_done
465
+
466
+ ::Brick.routes_done = true
464
467
  existing_controllers = routes.each_with_object({}) { |r, s| c = r.defaults[:controller]; s[c] = nil if c }
465
468
  ::Rails.application.routes.append do
466
- unless ::Brick.config.default_route_fallback.blank? || ::Rails.application.routes.named_routes.send(:routes)[:root]
467
- send(:root, "#{::Brick.config.default_route_fallback}#index")
468
- end
469
469
  # %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
470
470
  # If auto-controllers and auto-models are both enabled then this makes sense:
471
471
  ::Brick.relations.each do |rel_name, v|
@@ -279,8 +279,8 @@ module Brick
279
279
  # # route to go to the :index action for what would be a controller for that table. You can specify any controller
280
280
  # # name and action you wish in order to override this and have that be the default route when none other has been
281
281
  # # specified in routes.rb or elsewhere. (Or just use an empty string in order to disable this behaviour.)
282
- # Brick.default_route_fallback = 'customers' # This defaults to \"customers/index\"
283
- # Brick.default_route_fallback = 'orders/outstanding' # Example of a non-RESTful route
282
+ # Brick.default_route_fallback = 'customers' # This defaults to \"customers#index\"
283
+ # Brick.default_route_fallback = 'orders#outstanding' # Example of a non-RESTful route
284
284
  # Brick.default_route_fallback = '' # Omits setting a default route in the absence of any other
285
285
  ")
286
286
  end
@@ -22,7 +22,16 @@ module Brick
22
22
  'time without time zone' => 'time',
23
23
  'time with time zone' => 'time',
24
24
  'double precision' => 'float',
25
- 'smallint' => 'integer' } # %%% Need to put in "limit: 2"
25
+ 'smallint' => 'integer', # %%% Need to put in "limit: 2"
26
+ # Sqlite data types
27
+ 'TEXT' => 'text',
28
+ '' => 'string',
29
+ 'INTEGER' => 'integer',
30
+ 'REAL' => 'float',
31
+ 'BLOB' => 'binary',
32
+ 'TIMESTAMP' => 'timestamp',
33
+ 'DATETIME' => 'timestamp'
34
+ }
26
35
  # (Still need to find what "inet" and "json" data types map to.)
27
36
 
28
37
  desc 'Auto-generates migration files for an existing database.'
@@ -38,7 +47,8 @@ module Brick
38
47
  return
39
48
  end
40
49
 
41
- key_type = (ActiveRecord.version < ::Gem::Version.new('5.1') ? 'integer' : 'bigint')
50
+ is_sqlite = ActiveRecord::Base.connection.adapter_name == 'SQLite'
51
+ key_type = ((is_sqlite || ActiveRecord.version < ::Gem::Version.new('5.1')) ? 'integer' : 'bigint')
42
52
  is_4x_rails = ActiveRecord.version < ::Gem::Version.new('5.0')
43
53
  ar_version = "[#{ActiveRecord.version.segments[0..1].join('.')}]" unless is_4x_rails
44
54
  is_insert_versions = true
@@ -142,21 +152,20 @@ module Brick
142
152
  # if this one has come in as bigint or integer.
143
153
  pk_is_also_fk = fkey_cols.any? { |assoc| pkey_cols&.first == assoc[:fk] } ? pkey_cols&.first : nil
144
154
  # Support missing primary key (by adding: ,id: false)
145
- id_option = if pk_is_also_fk || (pkey_col_first = relation[:cols][pkey_cols&.first]&.first) != key_type
146
- if pk_is_also_fk || !pkey_cols&.present?
147
- ', id: false'
155
+ id_option = if pk_is_also_fk || !pkey_cols&.present?
156
+ ', id: false'
157
+ elsif ((pkey_col_first = relation[:cols][pkey_cols&.first]&.first) &&
158
+ (pkey_col_first = SQL_TYPES[pkey_col_first] || pkey_col_first) != key_type)
159
+ case pkey_col_first
160
+ when 'integer'
161
+ ', id: :serial'
162
+ when 'bigint'
163
+ ', id: :bigserial'
148
164
  else
149
- case pkey_col_first
150
- when 'integer'
151
- ', id: :serial'
152
- when 'bigint'
153
- ', id: :bigserial'
154
- else
155
- ", id: :#{SQL_TYPES[pkey_col_first] || pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
156
- end +
157
- (pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '') +
158
- (!is_4x_rails && (comment = relation&.fetch(:description, nil))&.present? ? ", comment: #{comment.inspect}" : '')
159
- end
165
+ ", id: :#{pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
166
+ end +
167
+ (pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '') +
168
+ (!is_4x_rails && (comment = relation&.fetch(:description, nil))&.present? ? ", comment: #{comment.inspect}" : '')
160
169
  end
161
170
  # Find the ActiveRecord class in order to see if the columns have comments
162
171
  unless is_4x_rails
@@ -208,7 +217,7 @@ module Brick
208
217
  mig << " t.references :#{fk[:assoc_name]}#{suffix}, foreign_key: { to_table: #{to_table} }\n"
209
218
  end
210
219
  else
211
- next if !id_option&.end_with?('id: false') && pkey_cols.include?(col)
220
+ next if !id_option&.end_with?('id: false') && pkey_cols&.include?(col)
212
221
 
213
222
  # See if there are generic timestamps
214
223
  if sql_type == 'timestamp' && ['created_at','updated_at'].include?(col)
@@ -244,7 +253,7 @@ module Brick
244
253
  mig << " #{'# ' if is_commented}add_foreign_key #{tbl_code}, #{add_fk[0]}, column: :#{add_fk[1]}, primary_key: :#{pk}\n"
245
254
  end
246
255
  mig << " end\n"
247
- versions_to_create << migration_file_write(mig_path, "create_#{tbl_parts.join('_')}", current_mig_time += 1.minute, ar_version, mig)
256
+ versions_to_create << migration_file_write(mig_path, "create_#{tbl_parts.map(&:underscore).join('_')}", current_mig_time += 1.minute, ar_version, mig)
248
257
  end
249
258
  done.concat(fringe)
250
259
  chosen -= done
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.66
4
+ version: 1.0.69
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-08-29 00:00:00.000000000 Z
11
+ date: 2022-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord