brick 1.0.220 → 1.0.222
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/config.rb +13 -0
- data/lib/brick/extensions.rb +58 -8
- data/lib/brick/{frameworks/rails → rails}/engine.rb +101 -7
- data/lib/brick/{frameworks/rails → rails}/form_tags.rb +5 -4
- data/lib/brick/{frameworks/rails.rb → rails.rb} +2 -2
- data/lib/brick/reflect_tables.rb +67 -2
- data/lib/brick/route_mapper.rb +9 -4
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +5 -3
- data/lib/generators/brick/install_generator.rb +23 -4
- data/lib/generators/brick/migration_builder.rb +3 -2
- data/lib/generators/brick/seeds_generator.rb +66 -4
- metadata +11 -11
- /data/lib/brick/{frameworks/rails → rails}/controller.rb +0 -0
- /data/lib/brick/{frameworks/rails → rails}/crosstab.brk +0 -0
- /data/lib/brick/{frameworks/rails → rails}/form_builder.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3e0a0e804ed376999842c2f8f31ba5b2db0ca019bce0e94b6b85b5869256667
|
4
|
+
data.tar.gz: 27cea38b19cec28e95515256aafd2e4a7fb1a220d3147d1123edd2ac74aa45b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4de80d5d689bb00369190f4b02093f56320309e6de856ed1e69ca570996e73987d6c27bbe3cfd124fae9ec274a19411d3935900c16e1d81e19cd40542f3714da
|
7
|
+
data.tar.gz: 453ac262c8314586ec6b1f68051871288659d4efffdbc442880efdae06ab435637508f7667e7dea93d543bbe82b291523d36fc2bfd67f801852c5416db8acdf6
|
data/lib/brick/config.rb
CHANGED
@@ -482,6 +482,19 @@ module Brick
|
|
482
482
|
@mutex.synchronize { @ignore_migration_fks = relations }
|
483
483
|
end
|
484
484
|
|
485
|
+
def salesforce_mode
|
486
|
+
@mutex.synchronize { @salesforce_mode }
|
487
|
+
end
|
488
|
+
|
489
|
+
def salesforce_mode=(true_or_false)
|
490
|
+
@mutex.synchronize { @salesforce_mode = true_or_false }
|
491
|
+
end
|
492
|
+
|
493
|
+
# Add search page for general Elasticsearch / Opensearch querying
|
494
|
+
def add_search
|
495
|
+
true
|
496
|
+
end
|
497
|
+
|
485
498
|
# Add status page showing all resources and what files have been built out for them
|
486
499
|
def add_status
|
487
500
|
true
|
data/lib/brick/extensions.rb
CHANGED
@@ -192,7 +192,7 @@ module ActiveRecord
|
|
192
192
|
# If there's no DSL yet specified, just try to find the first usable column on this model
|
193
193
|
unless (dsl = ::Brick.config.model_descrips[name])
|
194
194
|
skip_columns = _brick_get_fks + (::Brick.config.metadata_columns || []) + [primary_key]
|
195
|
-
dsl = if (descrip_col = columns.find { |c| [:boolean, :binary, :xml].exclude?(c.type) && skip_columns.exclude?(c.name) })
|
195
|
+
dsl = if table_exists? && (descrip_col = columns.find { |c| [:boolean, :binary, :xml].exclude?(c.type) && skip_columns.exclude?(c.name) })
|
196
196
|
"[#{descrip_col.name}]"
|
197
197
|
else
|
198
198
|
"#{name} ##{_pk_as_array.map { |pk_part| "[#{pk_part}]" }.join(', ')}"
|
@@ -383,7 +383,7 @@ module ActiveRecord
|
|
383
383
|
|
384
384
|
# Providing a relation object allows auto-modules built from table name prefixes to work
|
385
385
|
def self._brick_index(mode = nil, separator = nil, relation = nil, not_path = nil)
|
386
|
-
return if abstract_class?
|
386
|
+
return if abstract_class? || !table_exists?
|
387
387
|
|
388
388
|
::Brick._brick_index(table_name, mode, separator, relation, not_path)
|
389
389
|
end
|
@@ -467,7 +467,7 @@ module ActiveRecord
|
|
467
467
|
end
|
468
468
|
skip_klass_hms = ::Brick.config.skip_index_hms[self.name] || {}
|
469
469
|
hms.each do |k, hm|
|
470
|
-
next if skip_klass_hms.key?(k)
|
470
|
+
next if skip_klass_hms.key?(k) || !hm.klass.table_exists?
|
471
471
|
|
472
472
|
if hm.macro == :has_one
|
473
473
|
# For our purposes a :has_one is similar enough to a :belongs_to that we can just join forces
|
@@ -744,7 +744,6 @@ module ActiveRecord
|
|
744
744
|
end
|
745
745
|
end
|
746
746
|
|
747
|
-
# core_selects = selects.dup
|
748
747
|
id_for_tables = Hash.new { |h, k| h[k] = [] }
|
749
748
|
field_tbl_names = Hash.new { |h, k| h[k] = {} }
|
750
749
|
used_col_aliases = {} # Used to make sure there is not a name clash
|
@@ -758,7 +757,6 @@ module ActiveRecord
|
|
758
757
|
if @_brick_rel_dup.respond_to?(k) # Name already taken?
|
759
758
|
# %%% Use ensure_unique here in this kind of fashion:
|
760
759
|
# cnstr_name = ensure_unique(+"(brick) #{for_tbl}_#{pri_tbl}", nil, bts, hms)
|
761
|
-
# binding.pry
|
762
760
|
next
|
763
761
|
end
|
764
762
|
|
@@ -1290,8 +1288,9 @@ Might want to add this in your brick.rb:
|
|
1290
1288
|
end
|
1291
1289
|
|
1292
1290
|
if Object.const_defined?('ActionView')
|
1293
|
-
require 'brick/
|
1294
|
-
require 'brick/
|
1291
|
+
require 'brick/rails'
|
1292
|
+
require 'brick/rails/form_tags'
|
1293
|
+
require 'brick/rails/form_builder'
|
1295
1294
|
module ::ActionView::Helpers
|
1296
1295
|
module FormTagHelper
|
1297
1296
|
include ::Brick::Rails::FormTags
|
@@ -1480,7 +1479,7 @@ end
|
|
1480
1479
|
begin
|
1481
1480
|
if plural_class_name == 'BrickOpenapi' ||
|
1482
1481
|
(
|
1483
|
-
(::Brick.config.add_status || ::Brick.config.add_orphans) &&
|
1482
|
+
(::Brick.config.add_search || ::Brick.config.add_status || ::Brick.config.add_orphans) &&
|
1484
1483
|
plural_class_name == 'BrickGem'
|
1485
1484
|
# Was: ) || (model = self.const_get(full_class_name))
|
1486
1485
|
) || (model = Object.const_get(full_class_name))
|
@@ -1741,6 +1740,52 @@ class Object
|
|
1741
1740
|
built_model = Class.new(base_model) do |new_model_class|
|
1742
1741
|
(schema_module || Object).const_set(chosen_name, new_model_class) unless is_generator
|
1743
1742
|
@_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
|
1744
1789
|
if inheritable_name
|
1745
1790
|
new_model_class.define_singleton_method :inherited do |subclass|
|
1746
1791
|
super(subclass)
|
@@ -2431,6 +2476,7 @@ class Object
|
|
2431
2476
|
s << excl_parts.last
|
2432
2477
|
end
|
2433
2478
|
end
|
2479
|
+
@_brick_es = real_model.instance_variable_get(:@_brick_es_crud)
|
2434
2480
|
@_brick_bt_descrip = real_model._br_bt_descrip
|
2435
2481
|
@_brick_hm_counts = real_model._br_hm_counts
|
2436
2482
|
@_brick_join_array = join_array
|
@@ -2530,6 +2576,10 @@ class Object
|
|
2530
2576
|
session[:_brick_exclude] = excls
|
2531
2577
|
end
|
2532
2578
|
render json: { result: ::Brick.unexclude_column(table_name, col) }
|
2579
|
+
elsif is_json && (q = params['_brick_es']) # Elasticsearch
|
2580
|
+
# Make sure that the index is actually present and we allow reading before attempting
|
2581
|
+
es_result = model.__elasticsearch__.search(q).to_a if (es_perms = model.instance_variable_get(:@_brick_es_crud)).index('r')
|
2582
|
+
render json: { result: es_result }
|
2533
2583
|
else
|
2534
2584
|
real_model = model.real_model(params)
|
2535
2585
|
singular_table_name = real_model.name.underscore.split('/').last
|
@@ -582,7 +582,10 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
582
582
|
alias :_brick_lookup_context :lookup_context
|
583
583
|
def lookup_context(*args)
|
584
584
|
ret = _brick_lookup_context(*args)
|
585
|
-
|
585
|
+
if self.class < AbstractController::Base
|
586
|
+
request if respond_to?(:request) # ActionMailer does not have +request+
|
587
|
+
@_lookup_context.instance_variable_set(:@_brick_req_params, params) if request && params.present?
|
588
|
+
end
|
586
589
|
ret
|
587
590
|
end
|
588
591
|
end
|
@@ -592,12 +595,14 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
592
595
|
# Used by Rails 5.0 and above
|
593
596
|
alias :_brick_template_exists? :template_exists?
|
594
597
|
def template_exists?(*args, **options)
|
598
|
+
(::Brick.config.add_search && args.first == 'search') ||
|
595
599
|
(::Brick.config.add_status && args.first == 'status') ||
|
596
600
|
(::Brick.config.add_orphans && args.first == 'orphans') ||
|
597
601
|
(args.first == 'crosstab') ||
|
598
602
|
_brick_template_exists?(*args, **options) ||
|
599
|
-
#
|
600
|
-
(
|
603
|
+
# By default do not auto-create a template when it's searching for an application.html.erb, which comes in like: ["edit", ["games", "application"]]
|
604
|
+
# (Although specifying a class name for controllers_inherit_from will override this.)
|
605
|
+
((args[1].length == 1 || ::Brick.config.controllers_inherit_from.present? || args[1][-1] != 'application') &&
|
601
606
|
set_brick_model(args, @_brick_req_params))
|
602
607
|
end
|
603
608
|
|
@@ -654,6 +659,7 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
654
659
|
def find_template(*args, **options)
|
655
660
|
find_template_err = nil
|
656
661
|
unless (model_name = @_brick_model&.name) ||
|
662
|
+
(is_search = ::Brick.config.add_search && args[0..1] == ['search', ['brick_gem']]) ||
|
657
663
|
(is_status = ::Brick.config.add_status && args[0..1] == ['status', ['brick_gem']]) ||
|
658
664
|
(is_orphans = ::Brick.config.add_orphans && args[0..1] == ['orphans', ['brick_gem']]) ||
|
659
665
|
(is_crosstab = args[0..1] == ['crosstab', ['brick_gem']])
|
@@ -775,10 +781,14 @@ window.addEventListener(\"popstate\", linkSchemas);
|
|
775
781
|
end
|
776
782
|
s << "<option value=\"#{::Brick._brick_index(rel.first, nil, '/', nil, true)}\">#{rel.first}#{rowcount}</option>"
|
777
783
|
end.html_safe
|
784
|
+
# Options for special Brick pages
|
778
785
|
prefix = "#{::Brick.config.path_prefix}/" if ::Brick.config.path_prefix
|
779
|
-
|
780
|
-
|
781
|
-
|
786
|
+
[['Search', ::Brick.config.add_search],
|
787
|
+
['Status', ::Brick.config.add_status],
|
788
|
+
['Orphans', is_orphans],
|
789
|
+
['Crosstab', is_crosstab]].each do |table_option, show_it|
|
790
|
+
table_options << "<option value=\"#{prefix}brick_#{table_option.downcase}\">(#{table_option})</option>".html_safe if show_it
|
791
|
+
end
|
782
792
|
css = +''
|
783
793
|
css << ::Brick::Rails::BRICK_CSS
|
784
794
|
css << "<script>
|
@@ -1048,6 +1058,64 @@ end
|
|
1048
1058
|
});
|
1049
1059
|
});
|
1050
1060
|
</script>
|
1061
|
+
<% end
|
1062
|
+
# SEARCH BOX
|
1063
|
+
if @_brick_es&.index('r') # Must have at least Elasticsearch Read access %>
|
1064
|
+
<input type=\"text\" id=\"esSearch\"><a href=\"\">S</a>
|
1065
|
+
<script>
|
1066
|
+
var esSearch = document.getElementById(\"esSearch\")
|
1067
|
+
var isEsFiltered = false;
|
1068
|
+
esSearch.addEventListener(\"input\", function () {
|
1069
|
+
var gridTrs;
|
1070
|
+
if (this.value.length > 2) { # At least 3 letters in the search term
|
1071
|
+
var es = doFetch(\"POST\", {_brick_es: this.value},
|
1072
|
+
function (p) {p.text().then(function (response) {
|
1073
|
+
var result = JSON.parse(response).result;
|
1074
|
+
if (result.length > 0) {
|
1075
|
+
// Show only rows that have matches
|
1076
|
+
gridTrs = [... grid.querySelectorAll(\"tr\")];
|
1077
|
+
for (var i = 1; i < gridTrs.length; ++i) {
|
1078
|
+
var row = gridTrs[i];
|
1079
|
+
// Check all results to see if this one is in the list
|
1080
|
+
var rid = row.getAttribute(\"x-id\");
|
1081
|
+
var isHit = false;
|
1082
|
+
for (var j = 0; j < result.length; ++j) {
|
1083
|
+
if (rid == result[j]._id) {
|
1084
|
+
isHit = true;
|
1085
|
+
break;
|
1086
|
+
}
|
1087
|
+
}
|
1088
|
+
if (!isHit) row.style.display = \"none\";
|
1089
|
+
}
|
1090
|
+
isEsFiltered = true;
|
1091
|
+
} else {
|
1092
|
+
if (isEsFiltered) { // Show all rows and gray the search box
|
1093
|
+
gridTrs = [... grid.querySelectorAll(\"tr\")];
|
1094
|
+
for (var i = 1; i < gridTrs.length; ++i) {
|
1095
|
+
gridTrs[i].style.display = \"table-row\";
|
1096
|
+
}
|
1097
|
+
}
|
1098
|
+
}
|
1099
|
+
});}
|
1100
|
+
);
|
1101
|
+
} else {
|
1102
|
+
if (isEsFiltered) { // Show all rows and gray the search box
|
1103
|
+
gridTrs = [... grid.querySelectorAll(\"tr\")];
|
1104
|
+
for (var i = 1; i < gridTrs.length; ++i) {
|
1105
|
+
gridTrs[i].style.display = \"table-row\";
|
1106
|
+
}
|
1107
|
+
}
|
1108
|
+
}
|
1109
|
+
});
|
1110
|
+
esSearch.addEventListener(\"keypress\", function (e) {
|
1111
|
+
if (e.keyCode == 13) {
|
1112
|
+
// debugger
|
1113
|
+
// Go to search results page
|
1114
|
+
// var es = doFetch(\"POST\", {_brick_es: this.value});
|
1115
|
+
// console.log(es);
|
1116
|
+
}
|
1117
|
+
});
|
1118
|
+
</script>
|
1051
1119
|
<% end %>
|
1052
1120
|
</div></div>
|
1053
1121
|
#{::Brick::Rails.erd_markup(@_brick_model, prefix) if @_brick_model}
|
@@ -1113,6 +1181,32 @@ end
|
|
1113
1181
|
</html>
|
1114
1182
|
"
|
1115
1183
|
|
1184
|
+
|
1185
|
+
when 'search'
|
1186
|
+
if is_search
|
1187
|
+
# Search page - query across all indexes that appear to be related to models
|
1188
|
+
+"#{css}
|
1189
|
+
<p class=\"flashNotice\"><%= notice if request.respond_to?(:flash) %></p>#{"
|
1190
|
+
#{schema_options}" if schema_options}
|
1191
|
+
<select id=\"tbl\">#{table_options}</select>
|
1192
|
+
<h1>Search</h1>
|
1193
|
+
<table id=\"resourceName\" class=\"shadow\"><thead><tr>
|
1194
|
+
<th>Resource</th>
|
1195
|
+
<th>Description</th>
|
1196
|
+
<th>ID</th>
|
1197
|
+
</tr></thead>
|
1198
|
+
<tbody>
|
1199
|
+
<% # @results.each do |r| %>
|
1200
|
+
<tr>
|
1201
|
+
<td><%= %></td>
|
1202
|
+
<td<%= %></td>
|
1203
|
+
<td<%= %></td>
|
1204
|
+
</tr>
|
1205
|
+
<% # end %>
|
1206
|
+
</tbody></table>
|
1207
|
+
#{script}"
|
1208
|
+
end
|
1209
|
+
|
1116
1210
|
when 'status'
|
1117
1211
|
if is_status
|
1118
1212
|
# Status page - list of all resources and 5 things they do or don't have present, and what is turned on and off
|
@@ -1197,7 +1291,7 @@ end
|
|
1197
1291
|
decipher.iv = "\xB4,\r2\x19\xF5\xFE/\aR\x1A\x8A\xCFV\v\x8C"
|
1198
1292
|
decipher.key = Digest::SHA256.hexdigest(::Brick.config.license).scan(/../).map { |x| x.hex }.pack('c*')
|
1199
1293
|
brick_path = Gem::Specification.find_by_name('brick').gem_dir
|
1200
|
-
decipher.update(File.binread("#{brick_path}/lib/brick/
|
1294
|
+
decipher.update(File.binread("#{brick_path}/lib/brick/rails/crosstab.brk"))[16..-1]
|
1201
1295
|
else
|
1202
1296
|
'Crosstab Charting not yet activated -- enter a valid license key in brick.rb'
|
1203
1297
|
end
|
@@ -69,7 +69,7 @@ module Brick::Rails::FormTags
|
|
69
69
|
options[col[1].inheritance_column] = col[1].name unless col[1] == col[1].base_class
|
70
70
|
x_order = " x-order=\"#{col_name}\"" if true
|
71
71
|
s << "#{x_order}>#{col[2]} "
|
72
|
-
s << (col.first ? col[3].to_s : "#{link_to(col[3], send("#{col[1]._brick_index}_path", options))}")
|
72
|
+
s << ((col.first || !col[1].table_exists?) ? col[3].to_s : "#{link_to(col[3], send("#{col[1]._brick_index}_path", options))}")
|
73
73
|
elsif cust_cols.key?(col_name) # Custom column
|
74
74
|
x_order = " x-order=\"#{col_name}\"" if true
|
75
75
|
s << "#{x_order}>#{col_name}"
|
@@ -99,9 +99,10 @@ module Brick::Rails::FormTags
|
|
99
99
|
# proxy = relation.instance_variable_get(:@proxy) || relation.instance_variable_set(:@proxy, {})
|
100
100
|
bi = relation.instance_variable_get(:@_brick_includes)
|
101
101
|
relation.each do |obj|
|
102
|
-
|
103
|
-
out << "<
|
104
|
-
|
102
|
+
rid = pk.map { |pk_part| obj.send(pk_part.to_sym) }
|
103
|
+
out << "<tr x-id=\"#{rid.join('/')}\">\n"
|
104
|
+
out << "<td class=\"col-sticky alternating-gray\">#{link_to('⇛', send("#{klass._brick_index(:singular)}_path".to_sym, rid),
|
105
|
+
{ class: 'big-arrow' })}</td>\n" if pk.present?
|
105
106
|
ac = obj.instance_variable_get(:@association_cache) || obj.instance_variable_set(:@association_cache, {})
|
106
107
|
# included =
|
107
108
|
bi&.each do |bi_key|
|
data/lib/brick/reflect_tables.rb
CHANGED
@@ -8,10 +8,75 @@ module Brick
|
|
8
8
|
|
9
9
|
# return if ActiveRecord::Base.connection.current_database == 'postgres'
|
10
10
|
|
11
|
+
# Utilise Elasticsearch indexes, if any
|
12
|
+
if Object.const_defined?('Elasticsearch')
|
13
|
+
if ::Elasticsearch.const_defined?('Client')
|
14
|
+
# Allow Elasticsearch gem > 7.10 to work with Opensearch
|
15
|
+
::Elasticsearch::Client.class_exec do
|
16
|
+
alias _original_initialize initialize
|
17
|
+
def initialize(arguments = {}, &block)
|
18
|
+
_original_initialize(arguments, &block)
|
19
|
+
@verified = true
|
20
|
+
@transport
|
21
|
+
end
|
22
|
+
|
23
|
+
# Auto-create when there is a missing index
|
24
|
+
alias _original_method_missing method_missing
|
25
|
+
def method_missing(name, *args, &block)
|
26
|
+
_original_method_missing(name, *args, &block)
|
27
|
+
rescue Elastic::Transport::Transport::Errors::NotFound => e
|
28
|
+
if (missing_index = args.last&.fetch(:defined_params, nil)&.fetch(:index, nil))
|
29
|
+
self.indices.create({ index: missing_index,
|
30
|
+
body: { settings: {}, mappings: { properties: {} } } })
|
31
|
+
puts "Auto-creating missing index \"#{missing_index}\""
|
32
|
+
_original_method_missing(name, *args, &block)
|
33
|
+
else
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
if ::Elasticsearch.const_defined?('Model')
|
40
|
+
# By setting the environment variable ELASTICSEARCH_URL then you can specify an Elasticsearch/Opensearch host
|
41
|
+
host = (client = ::Elasticsearch::Model.client).transport.hosts.first
|
42
|
+
es_uri = URI.parse("#{host[:protocol]}://#{host[:host]}:#{host[:port]}")
|
43
|
+
es_uri = nil if es_uri.to_s == 'http://localhost:9200'
|
44
|
+
begin
|
45
|
+
cluster_info = client.info.body
|
46
|
+
if (es_ver = cluster_info['version'])
|
47
|
+
::Brick.elasticsearch_models = :all
|
48
|
+
puts "Found Elasticsearch gem and #{'local ' unless es_uri}#{es_ver['distribution'].titleize} #{es_ver['number']} installation#{" at #{es_uri}" if es_uri}."
|
49
|
+
puts "Enable Elasticsearch support by either setting \"::Brick.elasticsearch_models = :all\" or by picking specific models by name."
|
50
|
+
|
51
|
+
# # Auto-create when trying to import and there is a missing index
|
52
|
+
# ::Elasticsearch::Model::Importing.class_exec do
|
53
|
+
# end
|
54
|
+
end
|
55
|
+
rescue StandardError => e # Errno::ECONNREFUSED
|
56
|
+
puts "Found Elasticsearch gem, but could not connect to #{'local ' unless es_uri}Elasticsearch/Opensearch server#{" at #{es_uri}" if es_uri}."
|
57
|
+
end
|
58
|
+
# require 'net/http'
|
59
|
+
# begin
|
60
|
+
# es_uri = ENV['ELASTICSEARCH_URL']
|
61
|
+
# binding.pry
|
62
|
+
# cluster_info = JSON.parse(Net::HTTP.get(URI.parse(es_uri || 'http://localhost:9200')))
|
63
|
+
# if (es_ver = cluster_info['version'])
|
64
|
+
# ::Brick.elasticsearch_models = :all
|
65
|
+
# puts "Found Elasticsearch gem and #{'local ' unless es_uri}#{es_ver['distribution'].titleize} #{es_ver['number']} installation#{" at #{es_uri}" if es_uri}."
|
66
|
+
# puts "Enable Elasticsearch support by either setting \"::Brick.elasticsearch_models = :all\" or by picking specific models by name."
|
67
|
+
# end
|
68
|
+
# rescue StandardError => e
|
69
|
+
# end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# client = Elasticsearch::Client.new(host: 'https://my-elasticsearch-host.example')
|
73
|
+
# client.ping
|
74
|
+
# client.search(q: 'test')
|
75
|
+
|
11
76
|
# Overwrite SQLite's #begin_db_transaction so it opens in IMMEDIATE mode instead of
|
12
77
|
# the default DEFERRED mode.
|
13
78
|
# https://discuss.rubyonrails.org/t/failed-write-transaction-upgrades-in-sqlite3/81480/2
|
14
|
-
if ActiveRecord::Base.connection.adapter_name == 'SQLite'
|
79
|
+
if ActiveRecord::Base.connection.adapter_name == 'SQLite' && ActiveRecord.version >= Gem::Version.new('5.1')
|
15
80
|
arca = ::ActiveRecord::ConnectionAdapters
|
16
81
|
db_statements = arca::SQLite3.const_defined?('DatabaseStatements') ? arca::SQLite3::DatabaseStatements : arca::SQLite3::SchemaStatements
|
17
82
|
# Rails 7.1 and later
|
@@ -410,7 +475,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
410
475
|
v[:resource] = proposed_name_parts.last.underscore
|
411
476
|
if colliding_thing
|
412
477
|
message_start = if colliding_thing.is_a?(Module) && Object.const_defined?(:Rails) &&
|
413
|
-
colliding_thing.constants.find { |c| colliding_thing.const_get(c) < ::Rails::Application }
|
478
|
+
colliding_thing.constants.find { |c| (ctc = colliding_thing.const_get(c)).is_a?(Class) && ctc < ::Rails::Application }
|
414
479
|
"The module for the Rails application itself, \"#{colliding_thing.name}\","
|
415
480
|
else
|
416
481
|
"Non-AR #{colliding_thing.class.name.downcase} \"#{colliding_thing.name}\""
|
data/lib/brick/route_mapper.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Brick
|
4
|
-
class << self
|
5
|
-
attr_accessor :routes_done
|
6
|
-
end
|
7
|
-
|
8
4
|
module RouteMapper
|
9
5
|
def add_brick_routes
|
10
6
|
routeset_to_use = ::Rails.application.routes
|
@@ -276,6 +272,15 @@ module Brick
|
|
276
272
|
end
|
277
273
|
|
278
274
|
if (named_routes = instance_variable_get(:@set).named_routes).respond_to?(:find)
|
275
|
+
# Generic Elasticsearch / Opensearch query page
|
276
|
+
if ::Brick.config.add_search && (search_as = "#{controller_prefix.tr('/', '_')}brick_search".to_sym)
|
277
|
+
(
|
278
|
+
!(search_route = instance_variable_get(:@set).named_routes.find { |route| route.first == search_as }&.last) ||
|
279
|
+
!search_route.ast.to_s.include?("/#{controller_prefix}brick_search/")
|
280
|
+
)
|
281
|
+
get("/#{controller_prefix}brick_search", to: 'brick_gem#search', as: search_as.to_s)
|
282
|
+
end
|
283
|
+
|
279
284
|
if ::Brick.config.add_status && (status_as = "#{controller_prefix.tr('/', '_')}brick_status".to_sym)
|
280
285
|
(
|
281
286
|
!(status_route = instance_variable_get(:@set).named_routes.find { |route| route.first == status_as }&.last) ||
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -92,7 +92,7 @@ require 'brick/config'
|
|
92
92
|
require 'brick/reflect_tables'
|
93
93
|
if Gem::Dependency.new('rails').matching_specs.present?
|
94
94
|
require 'rails'
|
95
|
-
require 'brick/
|
95
|
+
# require 'brick/rails'
|
96
96
|
end
|
97
97
|
module Brick
|
98
98
|
ALL_API_ACTIONS = [:index, :show, :create, :update, :destroy]
|
@@ -110,7 +110,9 @@ module Brick
|
|
110
110
|
attr_accessor :default_schema, :db_schemas, :test_schema,
|
111
111
|
:established_drf,
|
112
112
|
:is_oracle, :is_eager_loading, :auto_models, :initializer_loaded,
|
113
|
-
:table_name_lookup
|
113
|
+
:table_name_lookup,
|
114
|
+
:elasticsearch_models,
|
115
|
+
:routes_done
|
114
116
|
::Brick.auto_models = []
|
115
117
|
|
116
118
|
def get_possible_schemas
|
@@ -297,7 +299,7 @@ module Brick
|
|
297
299
|
end
|
298
300
|
else
|
299
301
|
this_fks = (this_fk = a.foreign_key).is_a?(Array) ? this_fk.uniq : [this_fk.to_s]
|
300
|
-
if !a.options.key?(:as) && (this_fks - a.klass.column_names).length.positive?
|
302
|
+
if !a.options.key?(:as) && a.klass.table_exists? && (this_fks - a.klass.column_names).length.positive?
|
301
303
|
options = ", #{a.options.map { |k, v| "#{k.inspect} => #{v.inspect}" }.join(', ')}" if a.options.present?
|
302
304
|
puts "WARNING: Model #{model.name} has this association:
|
303
305
|
has_many :#{a.name}#{options}
|
@@ -119,15 +119,18 @@ module Brick
|
|
119
119
|
end
|
120
120
|
resembles_fks = resembles_fks.values.flatten
|
121
121
|
|
122
|
+
# Brick additional references
|
123
|
+
# Used to have: ActiveRecord::Base.connection.current_database -- but this doesn't work with SQLite3Adapter
|
124
|
+
current_db = ActiveRecord::Base.connection&.instance_variable_get(:@config)&.fetch(:database, nil)
|
122
125
|
bar = case (possible_additional_references = possible_additional_references.values.flatten).length
|
123
126
|
when 0
|
124
127
|
+" # Brick.additional_references = [['orders', 'customer_id', 'customer'],
|
125
128
|
# ['customer', 'region_id', 'regions']]"
|
126
129
|
when 1
|
127
|
-
+" # # Here is a possible additional reference that has been auto-identified for the #{
|
130
|
+
+" # # Here is a possible additional reference that has been auto-identified for the #{current_db} database:
|
128
131
|
# Brick.additional_references = [#{possible_additional_references.first}]"
|
129
132
|
else
|
130
|
-
+" # # Here are possible additional references that have been auto-identified for the #{
|
133
|
+
+" # # Here are possible additional references that have been auto-identified for the #{current_db} database:
|
131
134
|
# Brick.additional_references = [
|
132
135
|
# #{possible_additional_references.join(",\n # ")}
|
133
136
|
# ]"
|
@@ -146,12 +149,12 @@ module Brick
|
|
146
149
|
# }"
|
147
150
|
when 1
|
148
151
|
".
|
149
|
-
# # Here is a possible polymorphic association that has been auto-identified for the #{
|
152
|
+
# # Here is a possible polymorphic association that has been auto-identified for the #{current_db} database:
|
150
153
|
# Brick.polymorphics = { #{possible_additional_references.first} }"
|
151
154
|
|
152
155
|
else
|
153
156
|
".
|
154
|
-
# # Here are possible polymorphic associations that have been auto-identified for the #{
|
157
|
+
# # Here are possible polymorphic associations that have been auto-identified for the #{current_db} database:
|
155
158
|
# Brick.polymorphics = {
|
156
159
|
# #{possible_polymorphics.join(",\n # ")}
|
157
160
|
# }"
|
@@ -342,6 +345,9 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
|
342
345
|
# # user, then you can use model_descrips like this, putting expressions with property references in square brackets:
|
343
346
|
# Brick.model_descrips = { 'User' => '[profile.firstname] [profile.lastname]' }
|
344
347
|
|
348
|
+
# # FULL TEXT SEARCH
|
349
|
+
# Brick.elasticsearch_models = :all
|
350
|
+
|
345
351
|
# # ERD SETTINGS
|
346
352
|
|
347
353
|
# # By default the Entity Relationship Diagram fragment which is available to be shown on the Grid page includes
|
@@ -392,6 +398,19 @@ if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
|
392
398
|
# Brick.default_route_fallback = 'customers'
|
393
399
|
# Brick.default_route_fallback = 'orders#outstanding' # Example of a non-RESTful route
|
394
400
|
# Brick.default_route_fallback = '' # Omits setting a default route in the absence of any other
|
401
|
+
|
402
|
+
# # GENERATORS
|
403
|
+
# # ==========
|
404
|
+
|
405
|
+
# # MIGRATIONS
|
406
|
+
|
407
|
+
# # Salesforce has table names which use multiple underscores in a row, more than two at a time. This can greatly
|
408
|
+
# # confuse some of the other underscore support put into place for Oracle table names which can have up to two
|
409
|
+
# # underscores at a time.
|
410
|
+
# #
|
411
|
+
# # Setting this +true+ turns on \"salesforce mode\" which means that auto-created migrations will convert
|
412
|
+
# # underscores in filenames and class names to the letter 'x' in order to keep the peace.
|
413
|
+
# Brick.config.salesforce_mode = true
|
395
414
|
end
|
396
415
|
")
|
397
416
|
end
|
@@ -109,6 +109,7 @@ module Brick
|
|
109
109
|
s[v_parts.first] = nil unless [::Brick.default_schema, 'public'].include?(v_parts.first)
|
110
110
|
end
|
111
111
|
end
|
112
|
+
separator = ::Brick.config.salesforce_mode ? 'x' : nil
|
112
113
|
# Start the timestamps back the same number of minutes from now as expected number of migrations to create
|
113
114
|
current_mig_time = [Time.now - (schemas.length + chosen.length).minutes]
|
114
115
|
done = []
|
@@ -146,7 +147,7 @@ module Brick
|
|
146
147
|
key_type, is_4x_rails, ar_version, do_fks_last, versions_to_create)
|
147
148
|
after_fks.concat(add_fks) if do_fks_last
|
148
149
|
current_mig_time[0] += 1.minute
|
149
|
-
versions_to_create << migration_file_write(mig_path, "create_#{::Brick._brick_index(tbl, nil,
|
150
|
+
versions_to_create << migration_file_write(mig_path, "create_#{::Brick._brick_index(tbl, nil, separator)}", current_mig_time, ar_version, mig)
|
150
151
|
end
|
151
152
|
done.concat(fringe)
|
152
153
|
chosen -= done
|
@@ -159,7 +160,7 @@ module Brick
|
|
159
160
|
key_type, is_4x_rails, ar_version, do_fks_last, versions_to_create)
|
160
161
|
after_fks.concat(add_fks)
|
161
162
|
current_mig_time[0] += 1.minute
|
162
|
-
versions_to_create << migration_file_write(mig_path, "create_#{::Brick._brick_index(tbl, :migration,
|
163
|
+
versions_to_create << migration_file_write(mig_path, "create_#{::Brick._brick_index(tbl, :migration, separator)}", current_mig_time, ar_version, mig)
|
163
164
|
end
|
164
165
|
done.concat(chosen)
|
165
166
|
chosen.clear
|
@@ -64,6 +64,8 @@ module Brick
|
|
64
64
|
stuck = {}
|
65
65
|
indexes = {} # Track index names to make sure things are unique
|
66
66
|
ar_base = Object.const_defined?(:ApplicationRecord) ? ApplicationRecord : Class.new(ActiveRecord::Base)
|
67
|
+
atrt_idx = 0 # ActionText::RichText unique index number
|
68
|
+
@has_atrts = nil # Any ActionText::RichText present?
|
67
69
|
# Start by making entries for fringe models (those with no foreign keys).
|
68
70
|
# Continue layer by layer, creating entries for models that reference ones already done, until
|
69
71
|
# no more entries can be created. (At that point hopefully all models are accounted for.)
|
@@ -88,6 +90,16 @@ module Brick
|
|
88
90
|
end
|
89
91
|
).present?
|
90
92
|
seeds << "\n"
|
93
|
+
# Search through the fringe to see if we should bump special dependent classes forward to the next fringe.
|
94
|
+
# (Currently only ActiveStorage::Attachment if there's also an ActiveStorage::VariantRecord in the same
|
95
|
+
# fringe, and always have ActionText::EncryptedRichText at the very end.)
|
96
|
+
fringe_classes = fringe.map { |f| f.klass.name }
|
97
|
+
unless (asa_idx = fringe_classes.index('ActiveStorage::Attachment')).nil?
|
98
|
+
fringe.slice!(asa_idx) if fringe_classes.include?('ActiveStorage::VariantRecord')
|
99
|
+
end
|
100
|
+
unless (atert_idx = fringe_classes.index('ActionText::EncryptedRichText')).nil?
|
101
|
+
fringe.slice!(atert_idx) if fringe_classes.length > 1
|
102
|
+
end
|
91
103
|
fringe.each do |seed_model|
|
92
104
|
tbl = seed_model.table_name
|
93
105
|
next unless ::Brick.config.exclude_tables.exclude?(tbl) &&
|
@@ -122,12 +134,14 @@ module Brick
|
|
122
134
|
klass.order(*pkey_cols).each do |obj|
|
123
135
|
unless has_rows
|
124
136
|
has_rows = true
|
125
|
-
seeds << " puts 'Seeding: #{
|
137
|
+
seeds << " puts 'Seeding: #{klass.name}'\n"
|
126
138
|
end
|
127
139
|
is_empty = false
|
128
140
|
pk_val = obj.send(pkey_cols.first)
|
141
|
+
var_name = "#{tbl.gsub('.', '__')}_#{brick_escape(pk_val)}"
|
129
142
|
fk_vals = []
|
130
143
|
data = []
|
144
|
+
updates = []
|
131
145
|
relation[:cols].each do |col, _col_type|
|
132
146
|
next if !(fk = fkeys.find { |assoc| col == assoc[:fk] }) &&
|
133
147
|
pkey_cols.include?(col)
|
@@ -142,11 +156,52 @@ module Brick
|
|
142
156
|
inv_tbl = fk[:inverse_table].gsub('.', '__')
|
143
157
|
fk_vals << "#{fk[:assoc_name]}: #{inv_tbl}_#{brick_escape(val)}" if val
|
144
158
|
else
|
145
|
-
val =
|
146
|
-
|
159
|
+
val = case val.class.name
|
160
|
+
when 'ActiveStorage::Filename'
|
161
|
+
val.to_s.inspect
|
162
|
+
when 'ActionText::RichText'
|
163
|
+
ensure_has_atrts(updates)
|
164
|
+
atrt_var = "atrt#{atrt_idx += 1}"
|
165
|
+
atrt_create = "(#{atrt_var} = #{val.class.name}.create(name: #{val.name.inspect}, body: #{val.to_trix_html.inspect
|
166
|
+
}, record_type: #{val.record_type.inspect}, record_id: #{var_name}.#{pkey_cols.first
|
167
|
+
}, created_at: DateTime.parse('#{val.created_at.inspect}'), updated_at: DateTime.parse('#{val.updated_at.inspect}')))"
|
168
|
+
updates << "#{var_name}.update(#{col}: #{atrt_create})\n"
|
169
|
+
# obj.send(col)&.embeds_blobs&.each do |blob|
|
170
|
+
updates << "atrt_ids[[#{val.id}, '#{val.class.name}']] = #{atrt_var}.id\n"
|
171
|
+
# end
|
172
|
+
next
|
173
|
+
else
|
174
|
+
val.inspect
|
175
|
+
end
|
176
|
+
data << "#{col}: #{val}" unless val == 'nil'
|
147
177
|
end
|
148
178
|
end
|
149
|
-
|
179
|
+
case klass.name
|
180
|
+
when 'ActiveStorage::VariantRecord'
|
181
|
+
ensure_has_atrts(updates)
|
182
|
+
updates << "atrt_ids[[#{obj.id}, '#{klass.name}']] = #{var_name}.id\n"
|
183
|
+
end
|
184
|
+
# Make sure that ActiveStorage::Attachment and ActionText::EncryptedRichText get
|
185
|
+
# wired up to the proper record_id
|
186
|
+
if klass.name == 'ActiveStorage::Attachment' || klass.name == 'ActionText::EncryptedRichText'
|
187
|
+
record_class = data.find { |d| d.start_with?('record_type: ') }[14..-2]
|
188
|
+
record_id = data.find { |d| d.start_with?('record_id: ') }[11..-1]
|
189
|
+
data.reject! { |d| d.start_with?('record_id: ') || d.start_with?('created_at: ') || d.start_with?('updated_at: ') }
|
190
|
+
data << "record_id: atrt_ids[[#{record_id}, '#{record_class}']]"
|
191
|
+
seeds << "#{var_name} = #{klass.name}.find_or_create_by(#{(fk_vals + data).join(', ')}) do |asa|
|
192
|
+
asa.created_at = DateTime.parse('#{obj.created_at.inspect}')#{"
|
193
|
+
asa.updated_at = DateTime.parse('#{obj.updated_at.inspect}')" if obj.respond_to?(:updated_at)}
|
194
|
+
end\n"
|
195
|
+
else
|
196
|
+
seeds << "#{var_name} = #{seed_model.klass.name}.create(#{(fk_vals + data).join(', ')})\n"
|
197
|
+
klass.attachment_reflections.each do |k, v|
|
198
|
+
if (attached = obj.send(k))
|
199
|
+
ensure_has_atrts(updates)
|
200
|
+
updates << "atrt_ids[[#{obj.id}, '#{klass.name}']] = #{var_name}.id\n"
|
201
|
+
end
|
202
|
+
end if klass.respond_to?(:attachment_reflections)
|
203
|
+
end
|
204
|
+
updates.each { |update| seeds << update } # Anything that needs patching up after-the-fact
|
150
205
|
end
|
151
206
|
seeds << " # (Skipping #{seed_model.klass.name} as it has no rows)\n" unless has_rows
|
152
207
|
File.open(seed_file_path, "w") { |f| f.write seeds }
|
@@ -190,5 +245,12 @@ module Brick
|
|
190
245
|
val
|
191
246
|
end
|
192
247
|
end
|
248
|
+
|
249
|
+
def ensure_has_atrts(array)
|
250
|
+
unless @has_atrts
|
251
|
+
array << "atrt_ids = {}\n"
|
252
|
+
@has_atrts = true
|
253
|
+
end
|
254
|
+
end
|
193
255
|
end
|
194
256
|
end
|
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.222
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -190,14 +190,14 @@ dependencies:
|
|
190
190
|
requirements:
|
191
191
|
- - "~>"
|
192
192
|
- !ruby/object:Gem::Version
|
193
|
-
version:
|
193
|
+
version: 2.3.0
|
194
194
|
type: :development
|
195
195
|
prerelease: false
|
196
196
|
version_requirements: !ruby/object:Gem::Requirement
|
197
197
|
requirements:
|
198
198
|
- - "~>"
|
199
199
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
200
|
+
version: 2.3.0
|
201
201
|
description: 'Auto-create models, views, controllers, and routes with this slick Rails
|
202
202
|
extension
|
203
203
|
|
@@ -212,14 +212,14 @@ files:
|
|
212
212
|
- lib/brick/config.rb
|
213
213
|
- lib/brick/extensions.rb
|
214
214
|
- lib/brick/frameworks/cucumber.rb
|
215
|
-
- lib/brick/frameworks/rails.rb
|
216
|
-
- lib/brick/frameworks/rails/controller.rb
|
217
|
-
- lib/brick/frameworks/rails/crosstab.brk
|
218
|
-
- lib/brick/frameworks/rails/engine.rb
|
219
|
-
- lib/brick/frameworks/rails/form_builder.rb
|
220
|
-
- lib/brick/frameworks/rails/form_tags.rb
|
221
215
|
- lib/brick/frameworks/rspec.rb
|
222
216
|
- lib/brick/join_array.rb
|
217
|
+
- lib/brick/rails.rb
|
218
|
+
- lib/brick/rails/controller.rb
|
219
|
+
- lib/brick/rails/crosstab.brk
|
220
|
+
- lib/brick/rails/engine.rb
|
221
|
+
- lib/brick/rails/form_builder.rb
|
222
|
+
- lib/brick/rails/form_tags.rb
|
223
223
|
- lib/brick/reflect_tables.rb
|
224
224
|
- lib/brick/route_mapper.rb
|
225
225
|
- lib/brick/serializers/json.rb
|
@@ -257,7 +257,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
257
|
- !ruby/object:Gem::Version
|
258
258
|
version: 1.3.6
|
259
259
|
requirements: []
|
260
|
-
rubygems_version: 3.
|
260
|
+
rubygems_version: 3.4.19
|
261
261
|
signing_key:
|
262
262
|
specification_version: 4
|
263
263
|
summary: Create a Rails app from data alone
|
File without changes
|
File without changes
|
File without changes
|