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 +4 -4
- data/lib/brick/extensions.rb +106 -40
- data/lib/brick/rails/engine.rb +34 -16
- data/lib/brick/reflect_tables.rb +41 -23
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +5 -1
- data/lib/generators/brick/install_generator.rb +18 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5484fa8f1c3c64e6d10340f54ca460668cfa176373b0d2322fe1ede86cfad8c
|
4
|
+
data.tar.gz: bda7b20486fb89f0b5775975957ea7f3b0de3b51a635e42e4a21dbec3b71478f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6f01661b3423287dc4ce703790e04d292f902a14dc23e1e3b68a4891c9347adeb2083594717af1e0ca93404a6e7748e2f393885d4d37944b595757ee5a4b6b8
|
7
|
+
data.tar.gz: 6967a37c53be78011f1b0e7b5eb69ecf1a7779b1c0c312e2288a6ab701fdb1ab2724345957d178970df06ee26481bd1470e8fb5ede8d14e06d6ac0a4a6418248
|
data/lib/brick/extensions.rb
CHANGED
@@ -979,7 +979,8 @@ module ActiveRecord
|
|
979
979
|
next
|
980
980
|
end
|
981
981
|
|
982
|
-
tbl_alias =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
1744
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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)
|
data/lib/brick/rails/engine.rb
CHANGED
@@ -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',
|
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\"
|
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) {
|
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
|
-
<
|
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>
|
1231
|
+
<th>Score</th>
|
1220
1232
|
</tr></thead>
|
1221
1233
|
<tbody>
|
1222
|
-
<%
|
1234
|
+
<% @results&.each do |r| %>
|
1223
1235
|
<tr>
|
1224
|
-
<td><%=
|
1225
|
-
|
1226
|
-
|
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
|
-
<%
|
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
|
-
|
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) {
|
data/lib/brick/reflect_tables.rb
CHANGED
@@ -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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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)
|
data/lib/brick/version_number.rb
CHANGED
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
|
-
# #
|
381
|
-
|
382
|
-
# #
|
383
|
-
# #
|
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
|
391
|
-
# #
|
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.
|
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-
|
11
|
+
date: 2025-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|