brick 1.0.59 → 1.0.60

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db41c2288f8bba8f3cb9c5d2d87bacd4806d1f2401ca9709f85de1886b0db377
4
- data.tar.gz: 42b0a7b285a3328ce922daa442e15bf994a382ad0bfc5ed8fe4370ae6b779fbb
3
+ metadata.gz: 741384ed503092151ed20f360abd8819fdf3b25fc4042e5aa953dae928acab6d
4
+ data.tar.gz: 11e88b4b7bdc51b9237e095fdaae1297741e1c315737e18d7194c3c84e937797
5
5
  SHA512:
6
- metadata.gz: b8baacad02f8ba5c0d9bfe11182d8297c817ba46bef250e172f55a0ff949591abcadda790aecc2614515468a4da468415a8a0e62fd2a60232177dcd3cd63ca03
7
- data.tar.gz: e84d2573ec0f95b01dfebf681cec409ec66a1e6052abbb59ebd3130728cad71015c51087f484c55e8e30f3b9a3736d3d9262b7d8cdebf23e5ab702035c0dcbfa
6
+ metadata.gz: daa2950ea3ff1354c642949797a4ed7e7ed5c14cfcba4e5560572e997e4df43b537ecb12e84dc2d710b3e067870a91c69519ee41735ea7e9ada0d110ae2bd906
7
+ data.tar.gz: 3e74b2d21d72d84ea7286a7b8959b0abb293c50844b5e3ba4fce73cc4f8b5dd68fa7a50dc9753901f0b82b6a3196ab3fd282c4e709d0ae82af37e5a4e68488a9
@@ -373,6 +373,7 @@ module ActiveRecord
373
373
  end
374
374
 
375
375
  def brick_select(params, selects = nil, order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
376
+ is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
376
377
  is_distinct = nil
377
378
  wheres = {}
378
379
  params.each do |k, v|
@@ -397,12 +398,14 @@ module ActiveRecord
397
398
  if selects&.empty? # Default to all columns
398
399
  tbl_no_schema = table.name.split('.').last
399
400
  columns.each do |col|
400
- if (col_name = col.name) == 'class'
401
- col_alias = ' AS _class'
402
- end
403
- # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
404
- cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col.name)&.first&.start_with?('xml')
405
- selects << "\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
401
+ col_alias = ' AS _class' if (col_name = col.name) == 'class'
402
+ selects << if is_mysql
403
+ "`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
404
+ else
405
+ # Postgres can not use DISTINCT with any columns that are XML, so for any of those just convert to text
406
+ cast_as_text = '::text' if is_distinct && Brick.relations[klass.table_name]&.[](:cols)&.[](col.name)&.first&.start_with?('xml')
407
+ "\"#{tbl_no_schema}\".\"#{col_name}\"#{cast_as_text}#{col_alias}"
408
+ end
406
409
  end
407
410
  end
408
411
 
@@ -430,7 +433,11 @@ module ActiveRecord
430
433
  if used_col_aliases.key?(col_alias = "_brfk_#{v.first}__#{sel_col.last}")
431
434
  col_alias = "_brfk_#{v.first}__#{v1[idx][-2..-1].map(&:to_s).join('__')}"
432
435
  end
433
- selects << "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{col_alias}\""
436
+ selects << if is_mysql
437
+ "`#{field_tbl_name}`.`#{sel_col.last}` AS `#{col_alias}`"
438
+ else
439
+ "\"#{field_tbl_name}\".\"#{sel_col.last}\"#{'::text' if is_xml} AS \"#{col_alias}\""
440
+ end
434
441
  used_col_aliases[col_alias] = nil
435
442
  v1[idx] << col_alias
436
443
  end
@@ -439,7 +446,11 @@ module ActiveRecord
439
446
  # Accommodate composite primary key by allowing id_col to come in as an array
440
447
  ((id_col = k1.primary_key).is_a?(Array) ? id_col : [id_col]).each do |id_part|
441
448
  id_for_tables[v.first] << if id_part
442
- selects << "#{"\"#{tbl_name}\".\"#{id_part}\""} AS \"#{(id_alias = "_brfk_#{v.first}__#{id_part}")}\""
449
+ selects << if is_mysql
450
+ "#{"`#{tbl_name}`.`#{id_part}`"} AS `#{(id_alias = "_brfk_#{v.first}__#{id_part}")}`"
451
+ else
452
+ "#{"\"#{tbl_name}\".\"#{id_part}\""} AS \"#{(id_alias = "_brfk_#{v.first}__#{id_part}")}\""
453
+ end
443
454
  id_alias
444
455
  end
445
456
  end
@@ -990,6 +1001,17 @@ class Object
990
1001
  self.send(macro, assoc_name, **options)
991
1002
  end
992
1003
 
1004
+ def default_ordering(table_name, pk)
1005
+ case (order_tbl = ::Brick.config.order[table_name]) && (order_default = order_tbl[:_brick_default])
1006
+ when Array
1007
+ order_default.map { |od_part| order_tbl[od_part] || od_part }
1008
+ when Symbol
1009
+ order_tbl[order_default] || order_default
1010
+ else
1011
+ pk.map(&:to_sym) # If it's not a custom ORDER BY, just use the key
1012
+ end
1013
+ end
1014
+
993
1015
  def build_controller(namespace, class_name, plural_class_name, model, relations)
994
1016
  table_name = ActiveSupport::Inflector.underscore(plural_class_name)
995
1017
  singular_table_name = ActiveSupport::Inflector.singularize(table_name)
@@ -1077,27 +1099,9 @@ class Object
1077
1099
  # Normal (non-swagger) request
1078
1100
 
1079
1101
  # %%% Allow params to define which columns to use for order_by
1080
- ordering = if (order_tbl = ::Brick.config.order[table_name])
1081
- case (order_default = order_tbl[:_brick_default])
1082
- when Array
1083
- order_default.map { |od_part| order_tbl[od_part] || od_part }
1084
- when Symbol
1085
- order_tbl[order_default] || order_default
1086
- else
1087
- pk
1088
- end
1089
- else
1090
- pk # If it's not a custom ORDER BY, just use the key
1091
- end
1092
- order_by, order_by_txt = model._brick_calculate_ordering(ordering)
1093
- if (order_params = params['_brick_order']&.split(',')&.map(&:to_sym)) # Overriding the default by providing a querystring param?
1094
- order_by, _ = model._brick_calculate_ordering(order_params, true) # Don't do the txt part
1095
- end
1096
-
1097
- code << " def index\n"
1098
- code << " @#{table_name} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
1099
- code << " @#{table_name}.brick_select(params)\n"
1100
- code << " end\n"
1102
+ # Overriding the default by providing a querystring param?
1103
+ ordering = params['_brick_order']&.split(',')&.map(&:to_sym) || Object.send(:default_ordering, table_name, pk)
1104
+ order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
1101
1105
 
1102
1106
  ::Brick.set_db_schema(params)
1103
1107
  if request.format == :csv # Asking for a template?
@@ -1130,6 +1134,12 @@ class Object
1130
1134
  @_brick_join_array = join_array
1131
1135
  end
1132
1136
 
1137
+ _, order_by_txt = model._brick_calculate_ordering(default_ordering(table_name, pk))
1138
+ code << " def index\n"
1139
+ code << " @#{table_name} = #{model.name}#{pk&.present? ? ".order(#{order_by_txt.join(', ')})" : '.all'}\n"
1140
+ code << " @#{table_name}.brick_select(params)\n"
1141
+ code << " end\n"
1142
+
1133
1143
  is_pk_string = nil
1134
1144
  if (pk_col = model&.primary_key)
1135
1145
  code << " def show\n"
@@ -1316,7 +1326,7 @@ module ActiveRecord::ConnectionHandling
1316
1326
  load apartment_initializer
1317
1327
  apartment_excluded = Apartment.excluded_models
1318
1328
  end
1319
- # Only for Postgres? (Doesn't work in sqlite3)
1329
+ # Only for Postgres (Doesn't work in sqlite3 or MySQL)
1320
1330
  # puts ActiveRecord::Base.execute_sql("SELECT current_setting('SEARCH_PATH')").to_a.inspect
1321
1331
 
1322
1332
  is_postgres = nil
@@ -1351,7 +1361,7 @@ module ActiveRecord::ConnectionHandling
1351
1361
  puts "Unfamiliar with connection adapter #{ActiveRecord::Base.connection.adapter_name}"
1352
1362
  end
1353
1363
 
1354
- ::Brick.db_schemas ||= []
1364
+ ::Brick.db_schemas ||= {}
1355
1365
 
1356
1366
  if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1357
1367
  if (possible_schema = ::Brick.config.schema_behavior&.[](:multitenant)&.[](:schema_to_analyse))
@@ -1367,41 +1377,11 @@ module ActiveRecord::ConnectionHandling
1367
1377
  # %%% Retrieve internal ActiveRecord table names like this:
1368
1378
  # ActiveRecord::Base.internal_metadata_table_name, ActiveRecord::Base.schema_migrations_table_name
1369
1379
  # For if it's not SQLite -- so this is the Postgres and MySQL version
1370
- sql ||= "SELECT t.table_schema AS schema, t.table_name AS relation_name, t.table_type,#{"
1371
- pg_catalog.obj_description((t.table_schema || '.' || t.table_name)::regclass, 'pg_class') AS table_description," if is_postgres}
1372
- c.column_name, c.data_type,
1373
- COALESCE(c.character_maximum_length, c.numeric_precision) AS max_length,
1374
- tc.constraint_type AS const, kcu.constraint_name AS \"key\",
1375
- c.is_nullable
1376
- FROM INFORMATION_SCHEMA.tables AS t
1377
- LEFT OUTER JOIN INFORMATION_SCHEMA.columns AS c ON t.table_schema = c.table_schema
1378
- AND t.table_name = c.table_name
1379
- LEFT OUTER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu ON
1380
- -- ON kcu.CONSTRAINT_CATALOG = t.table_catalog AND
1381
- kcu.CONSTRAINT_SCHEMA = c.table_schema
1382
- AND kcu.TABLE_NAME = c.table_name
1383
- AND kcu.position_in_unique_constraint IS NULL
1384
- AND kcu.ordinal_position = c.ordinal_position
1385
- LEFT OUTER JOIN INFORMATION_SCHEMA.table_constraints AS tc
1386
- ON kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
1387
- AND kcu.TABLE_NAME = tc.TABLE_NAME
1388
- AND kcu.CONSTRAINT_NAME = tc.constraint_name
1389
- WHERE t.table_schema NOT IN ('information_schema', 'pg_catalog')#{"
1390
- AND t.table_schema = COALESCE(current_setting('SEARCH_PATH'), 'public')" if schema }
1391
- -- AND t.table_type IN ('VIEW') -- 'BASE TABLE', 'FOREIGN TABLE'
1392
- AND t.table_name NOT IN ('pg_stat_statements', ?, ?)
1393
- ORDER BY 1, t.table_type DESC, c.ordinal_position"
1394
1380
  measures = []
1395
1381
  case ActiveRecord::Base.connection.adapter_name
1396
1382
  when 'PostgreSQL', 'SQLite' # These bring back a hash for each row because the query uses column aliases
1397
1383
  # schema ||= 'public' if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
1398
- ar_smtn = if ActiveRecord::Base.respond_to?(:schema_migrations_table_name)
1399
- ActiveRecord::Base.schema_migrations_table_name
1400
- else
1401
- 'schema_migrations'
1402
- end
1403
- ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1404
- ActiveRecord::Base.execute_sql(sql, ar_smtn, ar_imtn).each do |r|
1384
+ ActiveRecord::Base.retrieve_schema_and_tables(sql, is_postgres, schema).each do |r|
1405
1385
  # If Apartment gem lists the table as being associated with a non-tenanted model then use whatever it thinks
1406
1386
  # is the default schema, usually 'public'.
1407
1387
  schema_name = if ::Brick.config.schema_behavior[:multitenant]
@@ -1428,23 +1408,23 @@ module ActiveRecord::ConnectionHandling
1428
1408
  # puts "KEY! #{r['relation_name']}.#{col_name} #{r['key']} #{r['const']}" if r['key']
1429
1409
  end
1430
1410
  else # MySQL2 acts a little differently, bringing back an array for each row
1431
- ActiveRecord::Base.execute_sql(sql).each do |r|
1432
- relation = relations[(relation_name = r[0])] # here relation represents a table or view from the database
1433
- relation[:isView] = true if r[1] == 'VIEW' # table_type
1434
- col_name = r[2]
1435
- key = case r[5] # constraint type
1411
+ ActiveRecord::Base.retrieve_schema_and_tables(sql).each do |r|
1412
+ relation = relations[(relation_name = r[1])] # here relation represents a table or view from the database
1413
+ relation[:isView] = true if r[2] == 'VIEW' # table_type
1414
+ col_name = r[3]
1415
+ key = case r[6] # constraint type
1436
1416
  when 'PRIMARY KEY'
1437
1417
  # key
1438
- relation[:pkey][r[6] || relation_name] ||= []
1418
+ relation[:pkey][r[7] || relation_name] ||= []
1439
1419
  when 'UNIQUE'
1440
- relation[:ukeys][r[6] || "#{relation_name}.#{col_name}"] ||= []
1420
+ relation[:ukeys][r[7] || "#{relation_name}.#{col_name}"] ||= []
1441
1421
  # key = (relation[:ukeys] = Hash.new { |h, k| h[k] = [] }) if key.is_a?(Array)
1442
1422
  # key[r['key']]
1443
1423
  end
1444
1424
  key << col_name if key
1445
1425
  cols = relation[:cols] # relation.fetch(:cols) { relation[:cols] = [] }
1446
1426
  # 'data_type', 'max_length'
1447
- cols[col_name] = [r[3], r[4], measures&.include?(col_name)]
1427
+ cols[col_name] = [r[4], r[5], measures&.include?(col_name)]
1448
1428
  # puts "KEY! #{r['relation_name']}.#{col_name} #{r['key']} #{r['const']}" if r['key']
1449
1429
  end
1450
1430
  end
@@ -1482,7 +1462,7 @@ module ActiveRecord::ConnectionHandling
1482
1462
  AND kcu2.CONSTRAINT_SCHEMA = rc.UNIQUE_CONSTRAINT_SCHEMA
1483
1463
  AND kcu2.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME
1484
1464
  AND kcu2.ORDINAL_POSITION = kcu1.ORDINAL_POSITION#{"
1485
- WHERE kcu1.CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if schema }"
1465
+ WHERE kcu1.CONSTRAINT_SCHEMA = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }"
1486
1466
  # AND kcu2.TABLE_NAME = ?;", Apartment::Tenant.current, table_name
1487
1467
  when 'SQLite'
1488
1468
  sql = "SELECT m.name, fkl.\"from\", fkl.\"table\", m.name || '_' || fkl.\"from\" AS constraint_name
@@ -1498,12 +1478,14 @@ module ActiveRecord::ConnectionHandling
1498
1478
  # Multitenancy makes things a little more general overall, except for non-tenanted tables
1499
1479
  if apartment_excluded&.include?(fk[1].singularize.camelize)
1500
1480
  fk[0] = Apartment.default_schema
1501
- elsif fk[0] == 'public' || (is_multitenant && fk[0] == schema)
1481
+ elsif is_postgres && (fk[0] == 'public' || (is_multitenant && fk[0] == schema)) ||
1482
+ !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[0])
1502
1483
  fk[0] = nil
1503
1484
  end
1504
1485
  if apartment_excluded&.include?(fk[4].singularize.camelize)
1505
1486
  fk[3] = Apartment.default_schema
1506
- elsif fk[3] == 'public' || (is_multitenant && fk[3] == schema)
1487
+ elsif is_postgres && (fk[3] == 'public' || (is_multitenant && fk[3] == schema)) ||
1488
+ !is_postgres && ['mysql', 'performance_schema', 'sys'].exclude?(fk[3])
1507
1489
  fk[3] = nil
1508
1490
  end
1509
1491
  ::Brick._add_bt_and_hm(fk, relations)
@@ -1537,6 +1519,41 @@ module ActiveRecord::ConnectionHandling
1537
1519
 
1538
1520
  ::Brick.load_additional_references if initializer_loaded
1539
1521
  end
1522
+
1523
+ def retrieve_schema_and_tables(sql = nil, is_postgres = nil, schema = nil)
1524
+ sql ||= "SELECT t.table_schema AS \"schema\", t.table_name AS relation_name, t.table_type,#{"
1525
+ pg_catalog.obj_description((t.table_schema || '.' || t.table_name)::regclass, 'pg_class') AS table_description," if is_postgres}
1526
+ c.column_name, c.data_type,
1527
+ COALESCE(c.character_maximum_length, c.numeric_precision) AS max_length,
1528
+ tc.constraint_type AS const, kcu.constraint_name AS \"key\",
1529
+ c.is_nullable
1530
+ FROM INFORMATION_SCHEMA.tables AS t
1531
+ LEFT OUTER JOIN INFORMATION_SCHEMA.columns AS c ON t.table_schema = c.table_schema
1532
+ AND t.table_name = c.table_name
1533
+ LEFT OUTER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu ON
1534
+ -- ON kcu.CONSTRAINT_CATALOG = t.table_catalog AND
1535
+ kcu.CONSTRAINT_SCHEMA = c.table_schema
1536
+ AND kcu.TABLE_NAME = c.table_name
1537
+ AND kcu.position_in_unique_constraint IS NULL
1538
+ AND kcu.ordinal_position = c.ordinal_position
1539
+ LEFT OUTER JOIN INFORMATION_SCHEMA.table_constraints AS tc
1540
+ ON kcu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
1541
+ AND kcu.TABLE_NAME = tc.TABLE_NAME
1542
+ AND kcu.CONSTRAINT_NAME = tc.constraint_name
1543
+ WHERE t.table_schema NOT IN ('information_schema', #{
1544
+ is_postgres ? "'pg_catalog'" : "'mysql', 'performance_schema', 'sys'"})#{"
1545
+ AND t.table_schema = COALESCE(current_setting('SEARCH_PATH'), 'public')" if is_postgres && schema }
1546
+ -- AND t.table_type IN ('VIEW') -- 'BASE TABLE', 'FOREIGN TABLE'
1547
+ AND t.table_name NOT IN ('pg_stat_statements', ?, ?)
1548
+ ORDER BY 1, t.table_type DESC, 2, c.ordinal_position"
1549
+ ar_smtn = if ActiveRecord::Base.respond_to?(:schema_migrations_table_name)
1550
+ ActiveRecord::Base.schema_migrations_table_name
1551
+ else
1552
+ 'schema_migrations'
1553
+ end
1554
+ ar_imtn = ActiveRecord.version >= ::Gem::Version.new('5.0') ? ActiveRecord::Base.internal_metadata_table_name : ''
1555
+ ActiveRecord::Base.execute_sql(sql, ar_smtn, ar_imtn)
1556
+ end
1540
1557
  end
1541
1558
 
1542
1559
  # ==========================================
@@ -150,7 +150,6 @@ module Brick
150
150
  ", nil, #{path_keys(hm_assoc, hm_fk_name, obj_name, pk)}"
151
151
  end
152
152
  hm_entry << ']'
153
- puts hm_entry
154
153
  hms_columns << hm_entry
155
154
  when 'show', 'update'
156
155
  hm_stuff << if hm_fk_name
@@ -615,8 +614,9 @@ if (headerTop) {
615
614
  });
616
615
  });
617
616
  </script>
618
- <% end %>
619
- <table id=\"headerTop\">
617
+ <% end
618
+
619
+ %><table id=\"headerTop\">
620
620
  <table id=\"#{table_name}\">
621
621
  <thead><tr>#{"<th x-order=\"#{pk.join(',')}\"></th>" if pk.present?}<%=
622
622
  # Consider getting the name from the association -- hm.first.name -- if a more \"friendly\" alias should be used for a screwy table name
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 59
8
+ TINY = 60
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
@@ -32,6 +32,7 @@ module Brick
32
32
  end
33
33
  models = ::Brick.relations.keys.map do |tbl|
34
34
  tbl_parts = tbl.split('.')
35
+ tbl_parts.shift if [::Brick.default_schema, 'public'].include?(tbl_parts.first)
35
36
  tbl_parts[-1] = tbl_parts[-1].singularize
36
37
  tbl_parts.join('/').camelize
37
38
  end - existing_models.map(&:name)
@@ -54,7 +55,7 @@ module Brick
54
55
  chosen = gets_list(list: models, chosen: models.dup)
55
56
  relations = ::Brick.relations
56
57
  chosen.each do |model_name|
57
- # If we're in a schema then make sure the module file exists
58
+ # %%% If we're in a schema then make sure the module file exists
58
59
  base_module = if (model_parts = model_name.split('::')).length > 1
59
60
  "::#{model_parts.first}".constantize
60
61
  else
@@ -68,7 +69,7 @@ module Brick
68
69
  dir << "/#{path_part}"
69
70
  Dir.mkdir(dir) unless Dir.exists?(dir)
70
71
  end
71
- File.open("#{dir}/#{path.last}.rb", 'w') { |f| f.write code }
72
+ File.open("#{dir}/#{path.last}.rb", 'w') { |f| f.write code } unless code.blank?
72
73
  end
73
74
  puts "\n*** Created #{chosen.length} model files under app/models ***"
74
75
  end
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.59
4
+ version: 1.0.60
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-14 00:00:00.000000000 Z
11
+ date: 2022-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord