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 +4 -4
- data/lib/brick/extensions.rb +123 -55
- data/lib/brick/rails/engine.rb +41 -19
- data/lib/brick/reflect_tables.rb +54 -22
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +5 -1
- data/lib/generators/brick/airtable_api_caller.rb +171 -0
- data/lib/generators/brick/airtable_migrations_generator.rb +24 -0
- data/lib/generators/brick/airtable_seeds_generator.rb +19 -0
- data/lib/generators/brick/install_generator.rb +18 -6
- data/lib/generators/brick/{migration_builder.rb → migrations_builder.rb} +7 -3
- data/lib/generators/brick/migrations_generator.rb +4 -4
- data/lib/generators/brick/salesforce_migrations_generator.rb +3 -3
- data/lib/generators/brick/salesforce_schema.rb +1 -1
- data/lib/generators/brick/seeds_builder.rb +329 -0
- data/lib/generators/brick/seeds_generator.rb +2 -242
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5230864d4450f23406da3efcab54e2c337ae9029c2b9fea3d1b8df1bb34583dd
|
4
|
+
data.tar.gz: b16f195b58d0df45611f8a2251e005ae6cc841970fb1c6eea17119af678d62a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55e9c658e0c258be349866a82f7c5a62234779aa27e7a5e04517979dbccdf9475948fecb2de8f78604daf773094e9a19f8a3c32b9d64ef5c8948cbd3fa4dffe2
|
7
|
+
data.tar.gz: a00b991cd2d4125e10baada1d070440d4b25a99994e462e543acafdcdcf4cf5a4703e7b0fc60dd2e6989e933828a9eb0355610f6901b9b2ca9d5a047a61260a3
|
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,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
|
-
|
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
|
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
|
data/lib/brick/rails/engine.rb
CHANGED
@@ -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
|
-
(
|
675
|
-
|
676
|
-
|
677
|
-
|
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',
|
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\"
|
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) {
|
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
|
-
<
|
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>
|
1235
|
+
<th>Score</th>
|
1220
1236
|
</tr></thead>
|
1221
1237
|
<tbody>
|
1222
|
-
<%
|
1238
|
+
<% @results&.each do |r| %>
|
1223
1239
|
<tr>
|
1224
|
-
<td><%=
|
1225
|
-
|
1226
|
-
|
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
|
-
<%
|
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
|
-
|
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) {
|
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}\""
|
@@ -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,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)
|
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
|