brick 1.0.228 → 1.0.230

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: 5230864d4450f23406da3efcab54e2c337ae9029c2b9fea3d1b8df1bb34583dd
4
+ data.tar.gz: b16f195b58d0df45611f8a2251e005ae6cc841970fb1c6eea17119af678d62a8
5
5
  SHA512:
6
- metadata.gz: 8ccbeae9b7cf7874653de1666af8a708e77126248eadec4cd80d1766f33063f93a7b198aabdb02895e9a8456d89b63f36a15d6348a70a9b9ead928b7a29c1567
7
- data.tar.gz: 7fc00087943b2b7fdab18783793057772f59a1e98896239a8cc4c4d91f7aa41201265931393201a399c3b3261186a7e56deb4d8703cb46676eafd5a10ab3fa22
6
+ metadata.gz: 55e9c658e0c258be349866a82f7c5a62234779aa27e7a5e04517979dbccdf9475948fecb2de8f78604daf773094e9a19f8a3c32b9d64ef5c8948cbd3fa4dffe2
7
+ data.tar.gz: a00b991cd2d4125e10baada1d070440d4b25a99994e462e543acafdcdcf4cf5a4703e7b0fc60dd2e6989e933828a9eb0355610f6901b9b2ca9d5a047a61260a3
@@ -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,52 +1749,6 @@ 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?
1754
- include ::Elasticsearch::Model
1755
- code << " include Elasticsearch::Model\n"
1756
- if @_brick_es_crud.index('i') # Enable auto-creation of indexes on import?
1757
- class << self
1758
- alias _original_import import
1759
- def import(options={}, &block)
1760
- self.__elasticsearch__.create_index! unless self.__elasticsearch__.index_exists?
1761
- _original_import(options={}, &block)
1762
- end
1763
- end
1764
- end
1765
- if @_brick_es_crud.index('c') || @_brick_es_crud.index('u') || @_brick_es_crud.index('d')
1766
- include ::Elasticsearch::Model::Callbacks
1767
- code << " include Elasticsearch::Model::Callbacks\n"
1768
- end
1769
- if @_brick_es_crud.index('r')
1770
- # Customer.__elasticsearch__.search('taco').to_a
1771
- 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
- end
1789
1752
  if inheritable_name
1790
1753
  new_model_class.define_singleton_method :inherited do |subclass|
1791
1754
  super(subclass)
@@ -1858,6 +1821,59 @@ class Object
1858
1821
  end
1859
1822
  end
1860
1823
 
1824
+ # Enable Elasticsearch based on the table name?
1825
+ if (@_brick_es_crud = ::Brick.elasticsearch_models&.fetch(matching, nil))
1826
+ include ::Elasticsearch::Model
1827
+ if @_brick_es_crud.index('i') # Enable auto-creation of indexes on import?
1828
+ class << self
1829
+ alias _original_import import
1830
+ def import(options={}, &block)
1831
+ unless self.__elasticsearch__.index_exists?
1832
+ self.__elasticsearch__.create_index!
1833
+ ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
1834
+ end
1835
+ _original_import(options={}, &block)
1836
+ end
1837
+ end
1838
+ end
1839
+ if ::Elasticsearch::Model.const_defined?('Callbacks') &&
1840
+ @_brick_es_crud.index('c') || @_brick_es_crud.index('u') || @_brick_es_crud.index('d')
1841
+ include ::Elasticsearch::Model::Callbacks
1842
+ is_include_es_callbacks = true
1843
+ end
1844
+ # Create mappings for all text columns
1845
+ mappings do
1846
+ has_mappings = nil
1847
+ new_model_class.columns.select { |col| [:string, :text].include?(col.type) }.each do |string_col|
1848
+ unless has_mappings
1849
+ code << " include Elasticsearch::Model\n"
1850
+ code << " include Elasticsearch::Model::Callbacks\n" if is_include_es_callbacks
1851
+ code << " mappings do\n"
1852
+ has_mappings = true
1853
+ end
1854
+ code << " indexes :#{string_col.name}, type: 'text'\n"
1855
+ indexes string_col.name.to_sym, type: 'text'
1856
+ end
1857
+ code << " end\n" if has_mappings
1858
+ end
1859
+ if @_brick_es_crud.index('r')
1860
+ class << self
1861
+ # Search and hydrate records using only Elasticsearch data
1862
+ define_method :search do |q|
1863
+ self.__elasticsearch__.search(q).raw_response.body['hits']['hits'].map do |hit|
1864
+ obj = self.new(hit['_source'])
1865
+ obj.instance_variable_set(:@new_record, false) # Don't want to accidentally save a new one
1866
+ obj
1867
+ end
1868
+ rescue Elastic::Transport::Transport::Errors::NotFound => e
1869
+ self.__elasticsearch__.create_index! if @_brick_es_crud.index('i')
1870
+ ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
1871
+ []
1872
+ end
1873
+ end
1874
+ end
1875
+ end
1876
+
1861
1877
  unless is_sti
1862
1878
  fks = relation[:fks] || {}
1863
1879
  # Do the bulk of the has_many / belongs_to processing, and store details about HMT so they can be done at the very last
@@ -2272,6 +2288,39 @@ class Object
2272
2288
  render json: { data: result } # [ver, result]
2273
2289
  end
2274
2290
 
2291
+ self.define_method :search do
2292
+ # TODO: Make sure at least one index is actually present which allows for reading before attempting
2293
+ if (@qry = params['qry'] || params['_brick_es']) # Elasticsearch query?
2294
+ @indexes = ::Brick.elasticsearch_existings&.keys
2295
+ hits = Elasticsearch::Model.client.search({index: @indexes.join(','), q: @qry, size: 100})
2296
+ model_infos = {}
2297
+ # Number of indexes used: hits.body['_shards']['total']
2298
+ @count = hits.body['hits']['total']['value']
2299
+ @results = hits.body['hits']['hits'].map do |x|
2300
+ klass = ::Brick.relations[::Brick.elasticsearch_existings[x['_index']]][:class_name].constantize
2301
+ model_info = model_infos[klass] ||= [
2302
+ klass.primary_key,
2303
+ klass.brick_parse_dsl(join_array = ::Brick::JoinArray.new, [], translations = {}, false, nil, true)
2304
+ ]
2305
+ obj = klass.new(x['_source'])
2306
+ [
2307
+ klass.name,
2308
+ obj.send(model_info.first),
2309
+ obj.brick_descrip(
2310
+ model_info.last&.first&.map { |col2| obj.send(col2.last) },
2311
+ obj.send(klass.primary_key)
2312
+ ),
2313
+ send("#{klass._brick_index(:singular)}_path".to_sym, obj),
2314
+ x['_score']
2315
+ ]
2316
+ end
2317
+ respond_to do |format|
2318
+ format.js { render json: { result: @results } }
2319
+ format.any {}
2320
+ end
2321
+ end
2322
+ end
2323
+
2275
2324
  return [new_controller_class, code + "end # BrickGem controller\n"]
2276
2325
  when 'BrickOpenapi'
2277
2326
  is_openapi = true
@@ -2584,7 +2633,26 @@ class Object
2584
2633
  render json: { result: ::Brick.unexclude_column(table_name, col) }
2585
2634
  elsif is_json && (q = params['_brick_es']) # Elasticsearch
2586
2635
  # 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')
2636
+ if (es_perms = model.instance_variable_get(:@_brick_es_crud) ||
2637
+ # If a perms instance variable is missing for this model, get the perms ...
2638
+ (set = true && ::Brick.elasticsearch_models&.fetch(model.table_name, nil))
2639
+ ) && (
2640
+ # ... then set it on the model
2641
+ (set && model.instance_variable_set(:@_brick_es_crud, es_perms)) || es_perms
2642
+ )&.index('r')
2643
+ es_result = begin
2644
+ model.__elasticsearch__.search(q)
2645
+ rescue Elastic::Transport::Transport::Errors::NotFound => e
2646
+ if @_brick_es_crud.index('i')
2647
+ self.__elasticsearch__.create_index!
2648
+ # model.import
2649
+ ::Brick.elasticsearch_existings[self.table_name] = self.table_name.tr('.', '-').pluralize
2650
+ model.__elasticsearch__.search(q)
2651
+ else
2652
+ []
2653
+ end
2654
+ end
2655
+ end
2588
2656
  render json: { result: es_result }
2589
2657
  else
2590
2658
  real_model = model.real_model(params)
@@ -3254,7 +3322,7 @@ module Brick
3254
3322
  # Rails applies an _index suffix to that route when the resource name isn't something plural
3255
3323
  index << '_index' if mode != :singular && !not_path &&
3256
3324
  index == (
3257
- index2 + [relation[:class_name][(relation&.fetch(:auto_prefixed_class, nil)&.length&.+ 2) || 0..-1]&.underscore&.tr('/', '_') || '_']
3325
+ index2 + [relation[:class_name]&.[]((relation&.fetch(:auto_prefixed_class, nil)&.length&.+ 2) || 0..-1)&.underscore&.tr('/', '_') || '_']
3258
3326
  ).join(separator)
3259
3327
  end
3260
3328
  index
@@ -671,10 +671,16 @@ 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']]) ||
675
- (is_status = ::Brick.config.add_status && args[0..1] == ['status', ['brick_gem']]) ||
676
- (is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']]) ||
677
- (is_crosstab = args[0..1] == ['crosstab', ['brick_gem']])
674
+ (
675
+ args[1].first == 'brick_gem' &&
676
+ ((is_search = ::Brick.config.add_search && args[0] == 'search' &&
677
+ ::Brick.elasticsearch_existings&.length&.positive?
678
+ ) ||
679
+ (is_status = ::Brick.config.add_status && args[0] == 'status') ||
680
+ (is_orphans = ::Brick.config.add_orphans && args[0] == 'orphans') ||
681
+ (is_crosstab = args[0] == 'crosstab')
682
+ )
683
+ )
678
684
  begin
679
685
  if (possible_template = _brick_find_template(*args, **options))
680
686
  return possible_template
@@ -792,7 +798,7 @@ window.addEventListener(\"popstate\", linkSchemas);
792
798
  b[0] = '' if b[0].is_a?(Symbol)
793
799
  a.first <=> b.first
794
800
  end.each_with_object(+'') do |rel, s|
795
- next if rel.first.blank? || rel.last[:cols].empty? ||
801
+ next if rel.first.is_a?(Symbol) || rel.first.blank? || rel.last[:cols].empty? ||
796
802
  ::Brick.config.exclude_tables.include?(rel.first)
797
803
 
798
804
  # %%% When table_name_prefixes are use then during rendering empty non-TNP
@@ -805,7 +811,7 @@ window.addEventListener(\"popstate\", linkSchemas);
805
811
  end.html_safe
806
812
  # Options for special Brick pages
807
813
  prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
808
- [['Search', ::Brick.config.add_search],
814
+ [['Search', is_search],
809
815
  ['Status', ::Brick.config.add_status],
810
816
  ['Orphans', is_orphans],
811
817
  ['Crosstab', is_crosstab]].each do |table_option, show_it|
@@ -1084,13 +1090,14 @@ end
1084
1090
  <% end
1085
1091
  # SEARCH BOX
1086
1092
  if @_brick_es&.index('r') # Must have at least Elasticsearch Read access %>
1087
- <input type=\"text\" id=\"esSearch\"><a href=\"\">S</a>
1093
+ <input type=\"text\" id=\"esSearch\" class=\"dimmed\">
1088
1094
  <script>
1089
- var esSearch = document.getElementById(\"esSearch\")
1095
+ var esSearch = document.getElementById(\"esSearch\");
1096
+ var usedTerms = {};
1090
1097
  var isEsFiltered = false;
1091
1098
  esSearch.addEventListener(\"input\", function () {
1092
1099
  var gridTrs;
1093
- if (this.value.length > 2) { # At least 3 letters in the search term
1100
+ if (this.value.length > 2 && usedTerms[this.value] !== null) { // At least 3 letters in the search term
1094
1101
  var es = doFetch(\"POST\", {_brick_es: this.value},
1095
1102
  function (p) {p.text().then(function (response) {
1096
1103
  var result = JSON.parse(response).result;
@@ -1111,13 +1118,16 @@ end
1111
1118
  if (!isHit) row.style.display = \"none\";
1112
1119
  }
1113
1120
  isEsFiltered = true;
1121
+ esSearch.className = \"\";
1114
1122
  } else {
1115
1123
  if (isEsFiltered) { // Show all rows and gray the search box
1124
+ usedTerms[this.value] = null; // No results for this term
1116
1125
  gridTrs = [... grid.querySelectorAll(\"tr\")];
1117
1126
  for (var i = 1; i < gridTrs.length; ++i) {
1118
1127
  gridTrs[i].style.display = \"table-row\";
1119
1128
  }
1120
1129
  }
1130
+ esSearch.className = \"dimmed\";
1121
1131
  }
1122
1132
  });}
1123
1133
  );
@@ -1127,6 +1137,7 @@ end
1127
1137
  for (var i = 1; i < gridTrs.length; ++i) {
1128
1138
  gridTrs[i].style.display = \"table-row\";
1129
1139
  }
1140
+ esSearch.className = \"dimmed\";
1130
1141
  }
1131
1142
  }
1132
1143
  });
@@ -1211,21 +1222,28 @@ end
1211
1222
  +"#{css}
1212
1223
  <p class=\"flashNotice\"><%= notice if request.respond_to?(:flash) %></p>#{"
1213
1224
  #{schema_options}" if schema_options}
1214
- <select id=\"tbl\">#{table_options}</select>
1215
- <h1>Search</h1>
1225
+ <select id=\"tbl\">#{table_options}</select><br><br>
1226
+ <form method=\"get\">
1227
+ <input type=\"text\" name=\"qry\"<%= \" value=\\\"#\{@qry}\\\"\".html_safe unless @qry.blank? %>><input type=\"submit\", value=\"Search\">
1228
+ </form>
1229
+ <% if @results.present? %>
1230
+ <div id=\"rowCount\"><b><%= @count %> results from: </b><%= @indexes.sort.join(', ') %></div>
1231
+ <% end %>
1216
1232
  <table id=\"resourceName\" class=\"shadow\"><thead><tr>
1217
1233
  <th>Resource</th>
1218
1234
  <th>Description</th>
1219
- <th>ID</th>
1235
+ <th>Score</th>
1220
1236
  </tr></thead>
1221
1237
  <tbody>
1222
- <% # @results.each do |r| %>
1238
+ <% @results&.each do |r| %>
1223
1239
  <tr>
1224
- <td><%= %></td>
1225
- <td<%= %></td>
1226
- <td<%= %></td>
1240
+ <td><%= link_to (r[3]) do %><%= r[0] %><br>
1241
+ <%= r[1] %><% end %>
1242
+ </td>
1243
+ <td><%= r[2] %></td>
1244
+ <td><%= '%.3f' % r[4] %></td>
1227
1245
  </tr>
1228
- <% # end %>
1246
+ <% end %>
1229
1247
  </tbody></table>
1230
1248
  #{script}"
1231
1249
  end
@@ -1645,9 +1663,13 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
1645
1663
  # %%% Create a smart javascript routine which can do this client-side %>
1646
1664
  [... document.getElementsByTagName(\"TH\")].forEach(function (th) {
1647
1665
  th.addEventListener(\"click\", function (e) {
1648
- var xOrder;
1649
- if (xOrder = this.getAttribute(\"x-order\"))
1666
+ var xOrder,
1667
+ currentOrder;
1668
+ if (xOrder = this.getAttribute(\"x-order\")) {
1669
+ if ((currentOrder = changeout(location.href, \"_brick_order\")) === xOrder)
1670
+ xOrder = \"-\" + xOrder;
1650
1671
  location.href = changeout(location.href, \"_brick_order\", xOrder);
1672
+ }
1651
1673
  });
1652
1674
  });
1653
1675
  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}\""
@@ -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,52 @@ 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
+ rel_name = entry.first.tr('-', '.')
533
+ s[entry.first] = rel_name if relations.include?(entry.first)
534
+ s[entry.first] = rel_name.singularize if relations.include?(rel_name.singularize)
535
+ entry.last.fetch('aliases', nil)&.each do |k, _v|
536
+ rel_name = k.tr('-', '.')
537
+ s[k] = rel_name if relations.include?(rel_name)
538
+ s[k] = rel_name.singularize if relations.include?(rel_name.singularize)
539
+ end
540
+ end
541
+ # Add this either if...
542
+ if access.is_a?(String) # ...they have permissions over absolutely anything,
543
+ relations.each_with_object({}) do |rel, s|
544
+ next if rel.first.is_a?(Symbol)
545
+
546
+ perms = rel.last.fetch(:isView, nil) ? access.tr('cud', '') : access
547
+ s[rel.first] = perms
548
+ end
549
+ else # or there are specific permissions for each resource, so find the matching indexes
550
+ client = Elastic::Transport::Client.new
551
+ ::Brick.elasticsearch_existings.each_with_object({}) do |index, s|
552
+ this_access = access.is_a?(String) ? access : access[index.first] || '' # Look up permissions from above
553
+ next unless (rel = relations.fetch(index.first, nil))
554
+
555
+ perms = rel&.fetch(:isView, nil) ? this_access.tr('cud', '') : this_access
556
+ s[index.first] = perms unless perms.blank?
557
+ end
558
+ end
559
+ end
560
+ end
561
+
530
562
  if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
531
563
  puts "Now switching back to \"#{orig_schema}\" schema."
532
564
  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 = 230
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