brick 1.0.228 → 1.0.229

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: ada376a5ef8d35110b7228a583cdcb18e5246fcfa52b975aff872c9a2ac7e37d
4
- data.tar.gz: 7621c881fcacca08f8b9543371fbcb190c0513e5d8c8b6bc2c767a51a48ef43e
3
+ metadata.gz: a5484fa8f1c3c64e6d10340f54ca460668cfa176373b0d2322fe1ede86cfad8c
4
+ data.tar.gz: bda7b20486fb89f0b5775975957ea7f3b0de3b51a635e42e4a21dbec3b71478f
5
5
  SHA512:
6
- metadata.gz: 8ccbeae9b7cf7874653de1666af8a708e77126248eadec4cd80d1766f33063f93a7b198aabdb02895e9a8456d89b63f36a15d6348a70a9b9ead928b7a29c1567
7
- data.tar.gz: 7fc00087943b2b7fdab18783793057772f59a1e98896239a8cc4c4d91f7aa41201265931393201a399c3b3261186a7e56deb4d8703cb46676eafd5a10ab3fa22
6
+ metadata.gz: c6f01661b3423287dc4ce703790e04d292f902a14dc23e1e3b68a4891c9347adeb2083594717af1e0ca93404a6e7748e2f393885d4d37944b595757ee5a4b6b8
7
+ data.tar.gz: 6967a37c53be78011f1b0e7b5eb69ecf1a7779b1c0c312e2288a6ab701fdb1ab2724345957d178970df06ee26481bd1470e8fb5ede8d14e06d6ac0a4a6418248
@@ -979,7 +979,8 @@ module ActiveRecord
979
979
  next
980
980
  end
981
981
 
982
- tbl_alias = unique63("b_r_#{hm.name}", previous)
982
+ tbl_alias = "b_r_#{hm.name}"
983
+ tbl_alias = unique63(tbl_alias, previous) if is_postgres
983
984
  on_clause = []
984
985
  hm_selects = if !pri_key.is_a?(Array) # Probable standard key?
985
986
  if fk_col.is_a?(Array) # Foreign is composite but not Primary? OK, or choose the first part of the foreign key if nothing else
@@ -1031,19 +1032,28 @@ JOIN (SELECT #{hm_selects.map { |s| _br_quoted_name("#{'br_t0.' if from_clause}#
1031
1032
  unless wheres.empty?
1032
1033
  # Rewrite the wheres to reference table and correlation names built out by AREL
1033
1034
  where_nots = {}
1035
+ where_comparisons = []
1034
1036
  wheres2 = wheres.each_with_object({}) do |v, s|
1035
1037
  is_not = if v.first[-1] == '!'
1036
1038
  v[0] = v[0][0..-2] # Take off ending ! from column name
1037
1039
  end
1038
- if (v_parts = v.first.split('.')).length == 1
1039
- (is_not ? where_nots : s)[v.first] = v.last
1040
+ tbl_and_col_name = if (v_parts = v.first.split('.')).length == 1
1041
+ []
1042
+ else
1043
+ [brick_links[v_parts[0..-2].join('.')].split('.').last]
1044
+ end
1045
+ tbl_and_col_name << v_parts.last
1046
+ if ['>', '<'].include?(first_char = v.last.first[0]) # Greater than or less than?
1047
+ col_name = v.last.first[1..-1]
1048
+ col_name = "'#{col_name}'" unless [:integer, :boolean, :decimal, :float].include?(klass.columns_hash[v.first].type)
1049
+ where_comparisons << "#{tbl_and_col_name.join('.')} #{first_char} #{col_name}"
1040
1050
  else
1041
- tbl_name = brick_links[v_parts[0..-2].join('.')].split('.').last
1042
- (is_not ? where_nots : s)["#{tbl_name}.#{v_parts.last}"] = v.last
1051
+ (is_not ? where_nots : s)[tbl_and_col_name.join('.')] = v.last
1043
1052
  end
1044
1053
  end
1045
1054
  if respond_to?(:where!)
1046
1055
  where!(wheres2) if wheres2.present?
1056
+ where_comparisons.each { |wc| where!(wc) }
1047
1057
  if where_nots.present?
1048
1058
  self.where_clause += WhereClause.new(predicate_builder.build_from_hash(where_nots)).invert
1049
1059
  end
@@ -1106,8 +1116,7 @@ JOIN (SELECT #{hm_selects.map { |s| _br_quoted_name("#{'br_t0.' if from_clause}#
1106
1116
 
1107
1117
  # Build out an AR relation that queries for a list of objects, and include all the appropriate JOINs to later apply DSL using #brick_descrip
1108
1118
  def brick_list
1109
- pks = klass.primary_key.is_a?(String) ? [klass.primary_key] : klass.primary_key
1110
- selects = pks.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
1119
+ selects = klass._pk_as_array.each_with_object([]) { |pk, s| s << pk unless s.include?(pk) }
1111
1120
  # Get foreign keys for anything marked to be auto-preloaded, or a self-referencing JOIN
1112
1121
  klass_cols = klass.column_names
1113
1122
  reflect_on_all_associations.each do |a|
@@ -1740,51 +1749,56 @@ class Object
1740
1749
  built_model = Class.new(base_model) do |new_model_class|
1741
1750
  (schema_module || Object).const_set(chosen_name, new_model_class) unless is_generator
1742
1751
  @_brick_relation = relation
1743
- # Enable Elasticsearch for this one?
1744
- access = ::Brick.elasticsearch_models&.is_a?(Hash) ? ::Brick.elasticsearch_models[name] : ::Brick.elasticsearch_models
1745
- @_brick_es_crud ||= case access
1746
- when String
1747
- access
1748
- when :all, :full
1749
- 'icrud' # Auto-create index, and full CRUD
1750
- else
1751
- ''
1752
- end
1753
- unless @_brick_es_crud.blank?
1752
+ # Enable Elasticsearch based on the table name?
1753
+ if (@_brick_es_crud = ::Brick.elasticsearch_models&.fetch(table_name, nil))
1754
1754
  include ::Elasticsearch::Model
1755
- code << " include Elasticsearch::Model\n"
1756
1755
  if @_brick_es_crud.index('i') # Enable auto-creation of indexes on import?
1757
1756
  class << self
1758
1757
  alias _original_import import
1759
1758
  def import(options={}, &block)
1760
- self.__elasticsearch__.create_index! unless self.__elasticsearch__.index_exists?
1759
+ unless self.__elasticsearch__.index_exists?
1760
+ self.__elasticsearch__.create_index!
1761
+ ::Brick.elasticsearch_existings << self.table_name
1762
+ end
1761
1763
  _original_import(options={}, &block)
1762
1764
  end
1763
1765
  end
1764
1766
  end
1765
- if @_brick_es_crud.index('c') || @_brick_es_crud.index('u') || @_brick_es_crud.index('d')
1767
+ if ::Elasticsearch::Model.const_defined?('Callbacks') &&
1768
+ @_brick_es_crud.index('c') || @_brick_es_crud.index('u') || @_brick_es_crud.index('d')
1766
1769
  include ::Elasticsearch::Model::Callbacks
1767
- code << " include Elasticsearch::Model::Callbacks\n"
1770
+ is_include_es_callbacks = true
1771
+ end
1772
+ # Create mappings for all text columns
1773
+ mappings do
1774
+ has_mappings = nil
1775
+ new_model_class.columns.select { |col| [:string, :text].include?(col.type) }.each do |string_col|
1776
+ unless has_mappings
1777
+ code << " include Elasticsearch::Model\n"
1778
+ code << " include Elasticsearch::Model::Callbacks\n" if is_include_es_callbacks
1779
+ code << " mappings do\n"
1780
+ has_mappings = true
1781
+ end
1782
+ code << " indexes :#{string_col.name}, type: #{string_col.type.to_s.inspect}\n"
1783
+ indexes string_col.name.to_sym, type: string_col.type.to_s
1784
+ end
1785
+ code << " end\n" if has_mappings
1768
1786
  end
1769
1787
  if @_brick_es_crud.index('r')
1770
- # Customer.__elasticsearch__.search('taco').to_a
1788
+ class << self
1789
+ # Search and hydrate records using only Elasticsearch data
1790
+ define_method :search do |q|
1791
+ self.__elasticsearch__.search(q).raw_response.body['hits']['hits'].map do |hit|
1792
+ obj = self.new(hit['_source'])
1793
+ obj.instance_variable_set(:@new_record, false) # Don't want to accidentally save a new one
1794
+ obj
1795
+ end
1796
+ rescue Elastic::Transport::Transport::Errors::NotFound => e
1797
+ self.create_index! if @_brick_es_crud.index('i')
1798
+ []
1799
+ end
1800
+ end
1771
1801
  end
1772
- # # Need some mappings for text columns
1773
- # mappings do
1774
- # indexes :company_name, type: 'text'
1775
- # indexes :country, type: 'text'
1776
- # end
1777
- # def self.search(q)
1778
- # s = self.__elasticsearch__.search(q)
1779
- # binding.pry
1780
- # s.to_a
1781
- # # class Elasticsearch::Model::Response::Response
1782
- # # def to_a
1783
- # # end
1784
- # # rescue Elastic::Transport::Transport::Errors::NotFound => e
1785
- # # self.create_index!
1786
- # # self.__elasticsearch__.search(q)
1787
- # end
1788
1802
  end
1789
1803
  if inheritable_name
1790
1804
  new_model_class.define_singleton_method :inherited do |subclass|
@@ -2272,6 +2286,39 @@ class Object
2272
2286
  render json: { data: result } # [ver, result]
2273
2287
  end
2274
2288
 
2289
+ self.define_method :search do
2290
+ # TODO: Make sure at least one index is actually present which allows for reading before attempting
2291
+ if (q = params['qry'] || params['_brick_es']) # Elasticsearch query?
2292
+ @indexes = ::Brick.elasticsearch_existings
2293
+ hits = Elasticsearch::Model.client.search({index: @indexes.join(','), q: q, size: 100})
2294
+ model_infos = {}
2295
+ # Number of indexes used: hits.body['_shards']['total']
2296
+ @count = hits.body['hits']['total']['value']
2297
+ @results = hits.body['hits']['hits'].map do |x|
2298
+ klass = ::Brick.relations[x['_index']][:class_name].constantize
2299
+ model_info = model_infos[klass] ||= [
2300
+ klass.primary_key,
2301
+ klass.brick_parse_dsl(join_array = ::Brick::JoinArray.new, [], translations = {}, false, nil, true)
2302
+ ]
2303
+ obj = klass.new(x['_source'])
2304
+ [
2305
+ klass.name,
2306
+ obj.send(model_info.first),
2307
+ obj.brick_descrip(
2308
+ model_info.last&.first&.map { |col2| obj.send(col2.last) },
2309
+ obj.send(klass.primary_key)
2310
+ ),
2311
+ send("#{klass._brick_index(:singular)}_path".to_sym, obj),
2312
+ x['_score']
2313
+ ]
2314
+ end
2315
+ respond_to do |format|
2316
+ format.js { render json: { result: @results } }
2317
+ format.any {}
2318
+ end
2319
+ end
2320
+ end
2321
+
2275
2322
  return [new_controller_class, code + "end # BrickGem controller\n"]
2276
2323
  when 'BrickOpenapi'
2277
2324
  is_openapi = true
@@ -2584,7 +2631,26 @@ class Object
2584
2631
  render json: { result: ::Brick.unexclude_column(table_name, col) }
2585
2632
  elsif is_json && (q = params['_brick_es']) # Elasticsearch
2586
2633
  # Make sure that the index is actually present and we allow reading before attempting
2587
- es_result = model.__elasticsearch__.search(q).to_a if (es_perms = model.instance_variable_get(:@_brick_es_crud)).index('r')
2634
+ if (es_perms = model.instance_variable_get(:@_brick_es_crud) ||
2635
+ # If a perms instance variable is missing for this model, get the perms ...
2636
+ (set = true && ::Brick.elasticsearch_models&.fetch(model.table_name, nil))
2637
+ ) && (
2638
+ # ... then set it on the model
2639
+ (set && model.instance_variable_set(:@_brick_es_crud, es_perms)) || es_perms
2640
+ )&.index('r')
2641
+ es_result = begin
2642
+ model.__elasticsearch__.search(q)
2643
+ rescue Elastic::Transport::Transport::Errors::NotFound => e
2644
+ if @_brick_es_crud.index('i')
2645
+ self.__elasticsearch__.create_index!
2646
+ # model.import
2647
+ ::Brick.elasticsearch_existings << self.table_name
2648
+ model.__elasticsearch__.search(q)
2649
+ else
2650
+ []
2651
+ end
2652
+ end
2653
+ end
2588
2654
  render json: { result: es_result }
2589
2655
  else
2590
2656
  real_model = model.real_model(params)
@@ -671,7 +671,9 @@ window.addEventListener(\"popstate\", linkSchemas);
671
671
  def find_template(*args, **options)
672
672
  find_template_err = nil
673
673
  unless (model_name = @_brick_model&.name) ||
674
- (is_search = ::Brick.config.add_search && args[0..1] == ['search', ['brick_gem']]) ||
674
+ (is_search = ::Brick.config.add_search && args[0..1] == ['search', ['brick_gem']] &&
675
+ ::Brick.elasticsearch_existings&.length&.positive?
676
+ ) ||
675
677
  (is_status = ::Brick.config.add_status && args[0..1] == ['status', ['brick_gem']]) ||
676
678
  (is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']]) ||
677
679
  (is_crosstab = args[0..1] == ['crosstab', ['brick_gem']])
@@ -792,7 +794,7 @@ window.addEventListener(\"popstate\", linkSchemas);
792
794
  b[0] = '' if b[0].is_a?(Symbol)
793
795
  a.first <=> b.first
794
796
  end.each_with_object(+'') do |rel, s|
795
- next if rel.first.blank? || rel.last[:cols].empty? ||
797
+ next if rel.first.is_a?(Symbol) || rel.first.blank? || rel.last[:cols].empty? ||
796
798
  ::Brick.config.exclude_tables.include?(rel.first)
797
799
 
798
800
  # %%% When table_name_prefixes are use then during rendering empty non-TNP
@@ -805,7 +807,7 @@ window.addEventListener(\"popstate\", linkSchemas);
805
807
  end.html_safe
806
808
  # Options for special Brick pages
807
809
  prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
808
- [['Search', ::Brick.config.add_search],
810
+ [['Search', is_search],
809
811
  ['Status', ::Brick.config.add_status],
810
812
  ['Orphans', is_orphans],
811
813
  ['Crosstab', is_crosstab]].each do |table_option, show_it|
@@ -1084,13 +1086,14 @@ end
1084
1086
  <% end
1085
1087
  # SEARCH BOX
1086
1088
  if @_brick_es&.index('r') # Must have at least Elasticsearch Read access %>
1087
- <input type=\"text\" id=\"esSearch\"><a href=\"\">S</a>
1089
+ <input type=\"text\" id=\"esSearch\" class=\"dimmed\">
1088
1090
  <script>
1089
- var esSearch = document.getElementById(\"esSearch\")
1091
+ var esSearch = document.getElementById(\"esSearch\");
1092
+ var usedTerms = {};
1090
1093
  var isEsFiltered = false;
1091
1094
  esSearch.addEventListener(\"input\", function () {
1092
1095
  var gridTrs;
1093
- if (this.value.length > 2) { # At least 3 letters in the search term
1096
+ if (this.value.length > 2 && usedTerms[this.value] !== null) { // At least 3 letters in the search term
1094
1097
  var es = doFetch(\"POST\", {_brick_es: this.value},
1095
1098
  function (p) {p.text().then(function (response) {
1096
1099
  var result = JSON.parse(response).result;
@@ -1111,13 +1114,16 @@ end
1111
1114
  if (!isHit) row.style.display = \"none\";
1112
1115
  }
1113
1116
  isEsFiltered = true;
1117
+ esSearch.className = \"\";
1114
1118
  } else {
1115
1119
  if (isEsFiltered) { // Show all rows and gray the search box
1120
+ usedTerms[this.value] = null; // No results for this term
1116
1121
  gridTrs = [... grid.querySelectorAll(\"tr\")];
1117
1122
  for (var i = 1; i < gridTrs.length; ++i) {
1118
1123
  gridTrs[i].style.display = \"table-row\";
1119
1124
  }
1120
1125
  }
1126
+ esSearch.className = \"dimmed\";
1121
1127
  }
1122
1128
  });}
1123
1129
  );
@@ -1127,6 +1133,7 @@ end
1127
1133
  for (var i = 1; i < gridTrs.length; ++i) {
1128
1134
  gridTrs[i].style.display = \"table-row\";
1129
1135
  }
1136
+ esSearch.className = \"dimmed\";
1130
1137
  }
1131
1138
  }
1132
1139
  });
@@ -1211,21 +1218,28 @@ end
1211
1218
  +"#{css}
1212
1219
  <p class=\"flashNotice\"><%= notice if request.respond_to?(:flash) %></p>#{"
1213
1220
  #{schema_options}" if schema_options}
1214
- <select id=\"tbl\">#{table_options}</select>
1215
- <h1>Search</h1>
1221
+ <select id=\"tbl\">#{table_options}</select><br><br>
1222
+ <form method=\"get\">
1223
+ <input type=\"text\" name=\"qry\"><input type=\"submit\", value=\"Search\">
1224
+ </form>
1225
+ <% if @results.present? %>
1226
+ <div id=\"rowCount\"><b><%= @count %> results from: </b><%= @indexes.sort.join(', ') %></div>
1227
+ <% end %>
1216
1228
  <table id=\"resourceName\" class=\"shadow\"><thead><tr>
1217
1229
  <th>Resource</th>
1218
1230
  <th>Description</th>
1219
- <th>ID</th>
1231
+ <th>Score</th>
1220
1232
  </tr></thead>
1221
1233
  <tbody>
1222
- <% # @results.each do |r| %>
1234
+ <% @results&.each do |r| %>
1223
1235
  <tr>
1224
- <td><%= %></td>
1225
- <td<%= %></td>
1226
- <td<%= %></td>
1236
+ <td><%= link_to (r[3]) do %><%= r[0] %><br>
1237
+ <%= r[1] %><% end %>
1238
+ </td>
1239
+ <td><%= r[2] %></td>
1240
+ <td><%= '%.3f' % r[4] %></td>
1227
1241
  </tr>
1228
- <% # end %>
1242
+ <% end %>
1229
1243
  </tbody></table>
1230
1244
  #{script}"
1231
1245
  end
@@ -1645,9 +1659,13 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
1645
1659
  # %%% Create a smart javascript routine which can do this client-side %>
1646
1660
  [... document.getElementsByTagName(\"TH\")].forEach(function (th) {
1647
1661
  th.addEventListener(\"click\", function (e) {
1648
- var xOrder;
1649
- if (xOrder = this.getAttribute(\"x-order\"))
1662
+ var xOrder,
1663
+ currentOrder;
1664
+ if (xOrder = this.getAttribute(\"x-order\")) {
1665
+ if ((currentOrder = changeout(location.href, \"_brick_order\")) === xOrder)
1666
+ xOrder = \"-\" + xOrder;
1650
1667
  location.href = changeout(location.href, \"_brick_order\", xOrder);
1668
+ }
1651
1669
  });
1652
1670
  });
1653
1671
  document.querySelectorAll(\"input, select\").forEach(function (inp) {
@@ -28,7 +28,8 @@ module Brick
28
28
  def method_missing(name, *args, &block)
29
29
  _original_method_missing(name, *args, &block)
30
30
  rescue Elastic::Transport::Transport::Errors::NotFound => e
31
- if (missing_index = args.last&.fetch(:defined_params, nil)&.fetch(:index, nil))
31
+ if (missing_index = args.last&.fetch(:defined_params, nil)&.fetch(:index, nil)) &&
32
+ ::Brick.elasticsearch_models&.fetch(missing_index, nil)&.include?('i')
32
33
  self.indices.create({ index: missing_index,
33
34
  body: { settings: {}, mappings: { properties: {} } } })
34
35
  puts "Auto-creating missing index \"#{missing_index}\""
@@ -39,7 +40,7 @@ module Brick
39
40
  end
40
41
  end
41
42
  end
42
- if ::Elasticsearch.const_defined?('Model')
43
+ if ::Elasticsearch.const_defined?('Model') && ::Brick.elasticsearch_models
43
44
  # By setting the environment variable ELASTICSEARCH_URL then you can specify an Elasticsearch/Opensearch host
44
45
  host = (client = ::Elasticsearch::Model.client).transport.hosts.first
45
46
  es_uri = URI.parse("#{host[:protocol]}://#{host[:host]}:#{host[:port]}")
@@ -47,34 +48,19 @@ module Brick
47
48
  begin
48
49
  cluster_info = client.info.body
49
50
  if (es_ver = cluster_info['version'])
50
- ::Brick.elasticsearch_models = :all
51
51
  puts "Found Elasticsearch gem and #{'local ' unless es_uri}#{es_ver['distribution'].titleize} #{es_ver['number']} installation#{" at #{es_uri}" if es_uri}."
52
- puts "Enable Elasticsearch support by either setting \"::Brick.elasticsearch_models = :all\" or by picking specific models by name."
53
-
54
- # # Auto-create when trying to import and there is a missing index
55
- # ::Elasticsearch::Model::Importing.class_exec do
56
- # end
52
+ if ::Brick.elasticsearch_models.empty?
53
+ puts "Enable Elasticsearch support by either setting \"::Brick.elasticsearch_models = :all\" or by picking specific models by name."
54
+ end
55
+ else
56
+ ::Brick.elasticsearch_models = nil
57
57
  end
58
58
  rescue StandardError => e # Errno::ECONNREFUSED
59
+ ::Brick.elasticsearch_models = nil
59
60
  puts "Found Elasticsearch gem, but could not connect to #{'local ' unless es_uri}Elasticsearch/Opensearch server#{" at #{es_uri}" if es_uri}."
60
61
  end
61
- # require 'net/http'
62
- # begin
63
- # es_uri = ENV['ELASTICSEARCH_URL']
64
- # binding.pry
65
- # cluster_info = JSON.parse(Net::HTTP.get(URI.parse(es_uri || 'http://localhost:9200')))
66
- # if (es_ver = cluster_info['version'])
67
- # ::Brick.elasticsearch_models = :all
68
- # puts "Found Elasticsearch gem and #{'local ' unless es_uri}#{es_ver['distribution'].titleize} #{es_ver['number']} installation#{" at #{es_uri}" if es_uri}."
69
- # puts "Enable Elasticsearch support by either setting \"::Brick.elasticsearch_models = :all\" or by picking specific models by name."
70
- # end
71
- # rescue StandardError => e
72
- # end
73
62
  end
74
63
  end
75
- # client = Elasticsearch::Client.new(host: 'https://my-elasticsearch-host.example')
76
- # client.ping
77
- # client.search(q: 'test')
78
64
 
79
65
  # Overwrite SQLite's #begin_db_transaction so it opens in IMMEDIATE mode instead of
80
66
  # the default DEFERRED mode.
@@ -527,6 +513,38 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
527
513
  end
528
514
  end
529
515
 
516
+ if ems = ::Brick.elasticsearch_models # ['comments']
517
+ access = case ems
518
+ when Hash, String # Hash is a list of resource names and ES permissions such as 'r' or 'icr'
519
+ ems
520
+ when :all
521
+ 'crud' # All CRUD
522
+ when :full
523
+ 'icrud' # Also able to auto-create indexes
524
+ else
525
+ ''
526
+ end
527
+ # Rewriting this to have all valid indexes and their perms
528
+ ::Brick.elasticsearch_models = unless access.blank?
529
+ # Find all existing indexes
530
+ client = Elastic::Transport::Client.new
531
+ ::Brick.elasticsearch_existings = client.perform_request('GET', '_aliases').body.each_with_object([]) do |entry, s|
532
+ s << entry.first if relations.include?(entry.first)
533
+ entry.last.fetch('aliases', nil)&.each { |k, _v| s << k if relations.include?(k) }
534
+ end
535
+ # Add this either if...
536
+ if access.is_a?(String) # ...they have permissions over absolutely anything,
537
+ relations.each_with_object({}) { |rel, s| s[rel.first] = access unless rel.first.is_a?(Symbol) }
538
+ else # or there are specific permissions for each resource, so find the matching indexes
539
+ client = Elastic::Transport::Client.new
540
+ ::Brick.elasticsearch_existings.each_with_object({}) do |index, s|
541
+ perms = access.is_a?(String) ? access : access[index] || '' # Look up permissions from above
542
+ s[index] = perms unless perms.blank?
543
+ end
544
+ end
545
+ end
546
+ end
547
+
530
548
  if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
531
549
  puts "Now switching back to \"#{orig_schema}\" schema."
532
550
  ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?", orig_schema)
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 228
8
+ TINY = 229
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
@@ -111,7 +111,7 @@ module Brick
111
111
  :established_drf,
112
112
  :is_oracle, :is_eager_loading, :auto_models, :initializer_loaded,
113
113
  :table_name_lookup,
114
- :elasticsearch_models,
114
+ :elasticsearch_models, :elasticsearch_existings,
115
115
  :routes_done
116
116
  ::Brick.auto_models = []
117
117
 
@@ -292,6 +292,10 @@ to instead be this:
292
292
  s.first[bt_key] = [a.name, a.klass]
293
293
  end
294
294
  else # This gets all forms of has_many and has_one
295
+ if a.scope&.arity&.> 0
296
+ puts "Skipping HM column \"#{a.name}\" because it has a scope which requires #{a.scope.arity} #{'argument'.pluralize(a.scope.arity)}"
297
+ next
298
+ end
295
299
  if through # has_many :through or has_one :through
296
300
  is_invalid_source = nil
297
301
  begin
@@ -346,7 +346,18 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
346
346
  # Brick.model_descrips = { 'User' => '[profile.firstname] [profile.lastname]' }
347
347
 
348
348
  # # FULL TEXT SEARCH
349
+ # # You can enable Elasticsearch support by adding the elasticsearch-model and elasticsearch-rails gems, and either
350
+ # # having a copy of Opensearch or Elasticsearch locally installed on the same machine listening on port 9200, or by
351
+ # # setting the ELASTICSEARCH_URL environment variable to point to the URI of a search machine.
352
+ # # With that configured, you can pick specific table names and permissions for search and update by putting them in
353
+ # # a hash like this:
354
+ # Brick.elasticsearch_models = { 'notes' => 'crud', 'issues' => 'cru', 'orders' => 'r' }
355
+ # # or to blanketly enable all models to have auto-updating CRUD behaviour when there are ActiveRecord changes, use:
349
356
  # Brick.elasticsearch_models = :all
357
+ # # As well there is another permission available -- the 'i' permission -- which will auto-create an index if it
358
+ # # is missing. If you set 'icrud' for a model it will auto-create an index, or to always do this for all models
359
+ # # then you can specify \"full control\" like this:
360
+ # Brick.elasticsearch_models = :full
350
361
 
351
362
  # # ERD SETTINGS
352
363
 
@@ -377,18 +388,19 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
377
388
 
378
389
  # # Polymorphic associations are set up by providing a model name and polymorphic association name#{poly}
379
390
 
380
- # # For multi-tenant databases that use a separate schema for each tenant, a single representative database schema
381
- # # can be analysed to determine the range of polymorphic classes that can be used for each association. Hopefully
382
- # # the schema chosen is one loaded with existing data that is representative of all possible polymorphic
383
- # # associations.
391
+ # # MULTITENANCY VIA THE ROS-APARTMENT GEM
392
+
393
+ # # If you are using the ros-apartment gem along with Postgres then you can have automatic detection of polymorphic
394
+ # # type names (model class names listed in a column such as imageable_type) by choosing a schema that is loaded up
395
+ # # with data that represents the full range of the various polymorphic has_many classes that should be associated.
384
396
  # Brick.schema_behavior = :namespaced
385
397
  #{Brick.config.schema_behavior.present? ? " Brick.schema_behavior = { multitenant: { schema_to_analyse: #{
386
398
  Brick.config.schema_behavior[:multitenant]&.fetch(:schema_to_analyse, nil).inspect}" :
387
399
  " # Brick.schema_behavior = { multitenant: { schema_to_analyse: 'engineering'"
388
400
  } } }
389
401
  #{"
390
- # # Note that if you have a real polymorphic model configured then it is better to set the list of classes up in the
391
- # # model file itself with a line like:
402
+ # # Note that for each polymorphic model configured then it is better to set the list of classes up in the model
403
+ # # file itself with a line like:
392
404
  # delegated_type :commentable, type: ['Post', 'Comment']" if ActiveRecord::Base.respond_to?(:delegated_type)}
393
405
 
394
406
  # # DEFAULT ROOT ROUTE
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.228
4
+ version: 1.0.229
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-19 00:00:00.000000000 Z
11
+ date: 2025-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord