brick 1.0.98 → 1.0.99

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: d4285ef6fb81d75bd90ceffc7d66c7fa096f04fb998da590f291f28fc9dfb45d
4
- data.tar.gz: 2d031b156fd9c82d19af9b7818387eaecdd8cfadf939cbcf3b3b479474a77b54
3
+ metadata.gz: 431e2aee4c3c199095d8475eeedcc46bd95e86a47c51623e3cea7fbbde59edcd
4
+ data.tar.gz: 32144a9a9ab6ec60ef297f27ae73e35cc891e5f9462b9beae4e7a0534ab77135
5
5
  SHA512:
6
- metadata.gz: 5967ede119f86cd92f88abb0f43bd2049eda4272c14ae7fa1c3f9ecc54c813c4c227be2d99aaa501363e42ef34a3eb5d0a0924ac4e540ab668e40a9a9d28311e
7
- data.tar.gz: ab01005e485b9335c67ba48bb01a13db78fed3ce31293122fae8fbf1317b3bc0c3197adb087ec4b125e2ff7153e52fb55d8b7fc675b1e7759233cf8d42769ac7
6
+ metadata.gz: f471bc993d97e92deae3c03e6cac9db0e350e72bd070afe5bcde1d0ca18d650b546db0d018a101009e429e9870a7e2c5e566f980c9e5b1319bc18873271c5550
7
+ data.tar.gz: 95f128f0f2a29cf0d1af1b5001eae27885b7e11ce23194e4a4da0141a0bfc059edd1917036f4addf1ee2aa4b69f763962e821ca31f9473048a6934dbecd8518e
@@ -398,15 +398,27 @@ module ActiveRecord
398
398
  # Links from ActiveRecord association pathing names over to real table correlation names
399
399
  # that get chosen when the AREL AST tree is walked.
400
400
  def brick_links
401
- @brick_links ||= {}
401
+ @brick_links ||= { '' => table_name }
402
402
  end
403
403
 
404
404
  def brick_select(params, selects = [], order_by = nil, translations = {}, join_array = ::Brick::JoinArray.new)
405
405
  is_add_bts = is_add_hms = true
406
406
 
407
- # Build out cust_cols, bt_descrip and hm_counts now so that they are available on the
408
- # model early in case the user wants to do an ORDER BY based on any of that.
409
- model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
407
+ if selects.empty?
408
+ # Build out cust_cols, bt_descrip and hm_counts now so that they are available on the
409
+ # model early in case the user wants to do an ORDER BY based on any of that.
410
+ model._brick_calculate_bts_hms(translations, join_array) if is_add_bts || is_add_hms
411
+ else
412
+ is_api = true
413
+ # If there are any provided selects, treat them as API columns and build them as cust_cols since they
414
+ # can be built using DSL.
415
+ # false = not polymorphic, and true = yes -- please emit_dsl
416
+ selects.each do |api_col|
417
+ pieces, my_dsl = brick_parse_dsl(join_array, [], translations, false, "[#{api_col}]", true)
418
+ _br_cust_cols[api_col.tr('.', '_')] = [pieces, my_dsl]
419
+ end
420
+ selects.clear # Now these have become custom columns
421
+ end
410
422
 
411
423
  is_postgres = ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
412
424
  is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2'
@@ -414,7 +426,7 @@ module ActiveRecord
414
426
  is_distinct = nil
415
427
  wheres = {}
416
428
  params.each do |k, v|
417
- next if ['_brick_schema', '_brick_order', 'controller', 'action'].include?(k)
429
+ next if ['_brick_schema', '_brick_order', '_brick_api', 'controller', 'action'].include?(k)
418
430
 
419
431
  if (where_col = (ks = k.split('.')).last)[-1] == '!'
420
432
  where_col = where_col[0..-2]
@@ -436,11 +448,14 @@ module ActiveRecord
436
448
 
437
449
  # %%% Skip the metadata columns
438
450
  if selects.empty? # Default to all columns
451
+ id_parts = (id_col = klass.primary_key).is_a?(Array) ? id_col : [id_col]
439
452
  tbl_no_schema = table.name.split('.').last
440
453
  # %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
441
454
  # ActiveRecord::StatementInvalid (TinyTds::Error: DBPROCESS is dead or not enabled)
442
455
  # Relevant info here: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/402
443
456
  columns.each do |col|
457
+ next if is_api && id_parts.exclude?(col.name) # Only keep the ID columns if this is an API request
458
+
444
459
  col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
445
460
  selects << if is_mysql
446
461
  "`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
@@ -490,22 +505,28 @@ module ActiveRecord
490
505
  # binding.pry
491
506
  next
492
507
  end
493
-
494
508
  key_klass = nil
495
509
  key_tbl_name = nil
496
510
  dest_pk = nil
497
511
  key_alias = nil
498
512
  cc.first.each do |cc_part|
499
- dest_klass = cc_part[0..-2].inject(klass) { |kl, cc_part_term| kl.reflect_on_association(cc_part_term).klass }
513
+ dest_klass = cc_part[0..-2].inject(klass) do |kl, cc_part_term|
514
+ # %%% Clear column info properly so we can do multiple subsequent requests
515
+ # binding.pry unless kl.reflect_on_association(cc_part_term)
516
+ kl.reflect_on_association(cc_part_term)&.klass || klass
517
+ end
500
518
  tbl_name = rel_dupe.brick_links[cc_part[0..-2].map(&:to_s).join('.')]
501
519
  # Deal with the conflict if there are two parts in the custom column named the same,
502
520
  # "category.name" and "product.name" for instance will end up with aliases of "name"
503
521
  # and "product__name".
504
- cc_part_idx = cc_part.length - 1
505
- while cc_part_idx > 0 &&
506
- (col_alias = "br_cc_#{k}__#{cc_part[cc_part_idx..-1].map(&:to_s).join('__')}") &&
507
- used_col_aliases.key?(col_alias)
508
- cc_part_idx -= 1
522
+ if (cc_part_idx = cc_part.length - 1).zero?
523
+ col_alias = "br_cc_#{k}__#{table_name.tr('.', '_')}"
524
+ else
525
+ while cc_part_idx > 0 &&
526
+ (col_alias = "br_cc_#{k}__#{cc_part[cc_part_idx..-1].map(&:to_s).join('__').tr('.', '_')}") &&
527
+ used_col_aliases.key?(col_alias)
528
+ cc_part_idx -= 1
529
+ end
509
530
  end
510
531
  used_col_aliases[col_alias] = nil
511
532
  # Set up custom column links by preparing key_klass and key_alias
@@ -1372,7 +1393,7 @@ class Object
1372
1393
  when Symbol
1373
1394
  order_tbl[order_default] || order_default
1374
1395
  else
1375
- pk.map(&:to_sym) # If it's not a custom ORDER BY, just use the key
1396
+ pk.map { |part| "#{table_name}.#{part}"}.join(', ') # If it's not a custom ORDER BY, just use the key
1376
1397
  end
1377
1398
  end
1378
1399
 
@@ -1568,7 +1589,15 @@ class Object
1568
1589
  order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
1569
1590
 
1570
1591
  ar_relation = ActiveRecord.version < Gem::Version.new('4') ? model.preload : model.all
1571
- @_brick_params = ar_relation.brick_select(params, (selects = []), order_by,
1592
+
1593
+ if (cc = params['_brick_api']&.split(','))
1594
+ is_api = true
1595
+ selects = cc
1596
+ counts = [] # No need for any extra HM count columns
1597
+ model._br_cust_cols.clear
1598
+ end
1599
+
1600
+ @_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
1572
1601
  translations = {},
1573
1602
  join_array = ::Brick::JoinArray.new)
1574
1603
  # %%% Add custom HM count columns
@@ -1582,6 +1611,7 @@ class Object
1582
1611
  "b_r_#{v.first}.c_t_ AS \"b_r_#{v.first}_ct\""
1583
1612
  end
1584
1613
  end
1614
+
1585
1615
  ar_select = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects, *counts) : ar_relation.select(selects + counts)
1586
1616
  instance_variable_set("@#{table_name.pluralize}".to_sym, ar_select)
1587
1617
  if namespace && (idx = lookup_context.prefixes.index(table_name))
@@ -424,6 +424,14 @@ h1, h3 {
424
424
  cursor: pointer;
425
425
  }
426
426
 
427
+ #apiToggle {
428
+ border: 2px solid purple;
429
+ }
430
+
431
+ #apiToggle, .apiColName {
432
+ cursor: pointer;
433
+ }
434
+
427
435
  #dropper {
428
436
  background-color: #eee;
429
437
  }
@@ -1004,6 +1012,9 @@ erDiagram
1004
1012
  <p style=\"color: green\"><%= notice %></p>#{"
1005
1013
  #{schema_options}" if schema_options}
1006
1014
  <select id=\"tbl\">#{table_options}</select>
1015
+
1016
+ <%= pick_api(#{model_name}).html_safe %>
1017
+
1007
1018
  <table id=\"resourceName\"><tr>
1008
1019
  <td><h1>#{model_name}</h1></td>
1009
1020
  <td id=\"imgErd\" title=\"Show ERD\"></td>
@@ -1077,8 +1088,13 @@ erDiagram
1077
1088
  end
1078
1089
 
1079
1090
  # Write out the mega-grid
1080
- brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
1081
- cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}}) %>
1091
+ if params['_brick_api'] # API response?
1092
+ brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, [], @_brick_excl,
1093
+ cols, poly_cols, {}, [], {})
1094
+ else
1095
+ brick_grid(@#{table_name}, @_brick_bt_descrip, @_brick_sequence, @_brick_incl, @_brick_excl,
1096
+ cols, poly_cols, bts, #{hms_keys.inspect}, {#{hms_columns.join(', ')}})
1097
+ end %>
1082
1098
 
1083
1099
  #{"<hr><%= link_to \"New #{obj_name}\", new_#{path_obj_name}_path %>" unless @_brick_model.is_view?}
1084
1100
  #{script}
@@ -11,7 +11,7 @@ module Brick::Rails::FormTags
11
11
  out << "<th x-order=\"#{pk.join(',')}\"></th>"
12
12
  end
13
13
 
14
- col_keys = relation.columns.each_with_object([]) do |col, s|
14
+ col_keys ||= relation.columns.each_with_object([]) do |col, s|
15
15
  col_name = col.name
16
16
  next if inclusions&.exclude?(col_name) ||
17
17
  (pk.include?(col_name) && [:integer, :uuid].include?(col.type) && !bts.key?(col_name)) ||
@@ -122,7 +122,7 @@ module Brick::Rails::FormTags
122
122
  if (link_id = obj.send(cust_col.last[1]) if cust_col.last)
123
123
  out << link_to(cust_txt, send("#{cust_col.last.first._brick_index(:singular)}_path", link_id))
124
124
  else
125
- out << cust_txt
125
+ out << (cust_txt || '')
126
126
  end
127
127
  else # Bad column name!
128
128
  out << '?'
@@ -137,6 +137,51 @@ module Brick::Rails::FormTags
137
137
  out.html_safe
138
138
  end # brick_grid
139
139
 
140
+ # Recursively render UL and LI to choose columns to include
141
+ def pick_api(model, is_last = nil, visited = [])
142
+ out = +''
143
+ if visited.empty?
144
+ out << '<span id="apiToggle">API buffet</span><div id="apiBuffet" style="display: none;">'
145
+ out << '<textarea id="apiCode" cols="100"></textarea>'
146
+ out << '<input type="button" id="apiRender" value="Render">'
147
+ end
148
+ out << "\n#{indent = ' ' * visited.length}<ul>"
149
+ model.column_names.each { |col_name| out << "\n#{indent} <li class=\"apiColName\" x-nm=\"#{visited.map { |v| "#{v.last}." }.join}#{col_name}\">#{col_name}</li>" }
150
+ unless is_last || visited.length == 2
151
+ model.reflect_on_all_associations.each_with_object({}) do |v, s|
152
+ next if v.macro == :has_many || v.polymorphic?
153
+
154
+ out << "\n#{indent} <li><b>#{v.name}</b>#{pick_api(v.klass, visited.map(&:first).include?(v.klass),
155
+ visited.dup << [v.klass, v.name]
156
+ )}"
157
+ out << "\n#{indent} </li>"
158
+ s[v.name] = nil
159
+ end
160
+ end
161
+ out << "\n#{indent}</ul>"
162
+ if visited.empty?
163
+ out << '</div><script>[... document.getElementsByClassName("apiColName")].forEach(function (li) {li.addEventListener("click", apiColClick);});'
164
+ out << "
165
+ var colList = [];
166
+ var apiBuffet = document.getElementById(\"apiBuffet\");
167
+ var apiCode = document.getElementById(\"apiCode\");
168
+ function apiColClick(evt) {
169
+ apiCode.innerHTML += this.getAttribute(\"x-nm\") + \",\\n\";
170
+ }
171
+ document.getElementById(\"apiToggle\").addEventListener(\"click\", function () {
172
+ apiBuffet.style.display = (apiBuffet.style.display === \"block\" ? \"none\" : \"block\");
173
+ });
174
+ // Cheap and cheerful way to render a list of columns just for the demo
175
+ document.getElementById(\"apiRender\").addEventListener(\"click\", function () {
176
+ var changecolList = apiCode.innerHTML.substring(0, apiCode.innerHTML.length - 2);
177
+ location.href = changeout(location.href, \"_brick_api\", changecolList);
178
+ });
179
+ </script>
180
+ "
181
+ end
182
+ out
183
+ end
184
+
140
185
  def link_to_brick(*args, **kwargs)
141
186
  return unless ::Brick.config.mode == :on
142
187
 
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 98
8
+ TINY = 99
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
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.98
4
+ version: 1.0.99
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-12-04 00:00:00.000000000 Z
11
+ date: 2022-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord