brick 1.0.71 → 1.0.73
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 +25 -0
- data/lib/brick/extensions.rb +256 -144
- data/lib/brick/frameworks/rails/engine.rb +60 -29
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +95 -9
- data/lib/generators/brick/install_generator.rb +2 -0
- data/lib/generators/brick/migrations_generator.rb +42 -11
- metadata +2 -2
@@ -87,9 +87,9 @@ module Brick
|
|
87
87
|
|
88
88
|
def path_keys(hm_assoc, fk_name, obj_name, pk)
|
89
89
|
keys = if fk_name.is_a?(Array) && pk.is_a?(Array) # Composite keys?
|
90
|
-
fk_name.zip(pk.map { |
|
90
|
+
fk_name.zip(pk.map { |fk_part| "#{obj_name}.#{fk_part}" })
|
91
91
|
else
|
92
|
-
pk = pk.
|
92
|
+
pk = pk.map { |pk_part| "#{obj_name}.#{pk_part}" }
|
93
93
|
[[fk_name, pk.length == 1 ? pk.first : pk.inspect]]
|
94
94
|
end
|
95
95
|
keys << [hm_assoc.inverse_of.foreign_type, hm_assoc.active_record.name] if hm_assoc.options.key?(:as)
|
@@ -106,8 +106,8 @@ module Brick
|
|
106
106
|
return _brick_find_template(*args, **options)
|
107
107
|
end
|
108
108
|
|
109
|
-
|
110
|
-
pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(
|
109
|
+
if @_brick_model
|
110
|
+
pk = @_brick_model._brick_primary_key(::Brick.relations.fetch(@_brick_model&.table_name, nil))
|
111
111
|
obj_name = model_name.split('::').last.underscore
|
112
112
|
path_obj_name = model_name.underscore.tr('/', '_')
|
113
113
|
table_name = obj_name.pluralize
|
@@ -159,7 +159,7 @@ module Brick
|
|
159
159
|
hms_columns << hm_entry
|
160
160
|
when 'show', 'new', 'update'
|
161
161
|
hm_stuff << if hm_fk_name
|
162
|
-
"<%= link_to '#{assoc_name}', #{hm_assoc.klass.
|
162
|
+
"<%= link_to '#{assoc_name}', #{hm_assoc.klass._brick_index}_path({ #{path_keys(hm_assoc, hm_fk_name, "@#{obj_name}", pk)} }) %>\n"
|
163
163
|
else # %%% Would be able to remove this when multiple foreign keys to same destination becomes bulletproof
|
164
164
|
assoc_name
|
165
165
|
end
|
@@ -173,12 +173,13 @@ module Brick
|
|
173
173
|
# environment or whatever, then get either the controllers or routes list instead
|
174
174
|
apartment_default_schema = ::Brick.apartment_multitenant && Apartment.default_schema
|
175
175
|
table_options = (::Brick.relations.keys - ::Brick.config.exclude_tables).each_with_object({}) do |tbl, s|
|
176
|
+
binding.pry if tbl.is_a?(Symbol)
|
176
177
|
if (tbl_parts = tbl.split('.')).first == apartment_default_schema
|
177
178
|
tbl = tbl_parts.last
|
178
179
|
end
|
179
180
|
s[tbl] = nil
|
180
181
|
end.keys.sort.each_with_object(+'') do |v, s|
|
181
|
-
s << "<option value=\"#{v.underscore.gsub('.', '/')
|
182
|
+
s << "<option value=\"#{v.underscore.gsub('.', '/')}\">#{v}</option>"
|
182
183
|
end.html_safe
|
183
184
|
table_options << '<option value="brick_status">(Status)</option>'.html_safe if ::Brick.config.add_status
|
184
185
|
table_options << '<option value="brick_orphans">(Orphans)</option>'.html_safe if is_orphans
|
@@ -351,15 +352,39 @@ def hide_bcrypt(val, max_len = 200)
|
|
351
352
|
end
|
352
353
|
def display_value(col_type, val)
|
353
354
|
case col_type
|
354
|
-
when 'geometry'
|
355
|
+
when 'geometry', 'geography'
|
355
356
|
if Object.const_defined?('RGeo')
|
356
357
|
@is_mysql = ActiveRecord::Base.connection.adapter_name == 'Mysql2' if @is_mysql.nil?
|
357
|
-
if @
|
358
|
-
|
359
|
-
|
360
|
-
|
358
|
+
@is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
|
359
|
+
val_err = nil
|
360
|
+
if @is_mysql || @is_mssql
|
361
|
+
# MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
|
362
|
+
if (srid = val&.[](0..3)&.unpack('I'))
|
363
|
+
val = val.force_encoding('BINARY')[4..-1].bytes
|
364
|
+
|
365
|
+
# MSSQL spatial bitwise flags, often 0C for a point:
|
366
|
+
# xxxx xxx1 = HasZValues
|
367
|
+
# xxxx xx1x = HasMValues
|
368
|
+
# xxxx x1xx = IsValid
|
369
|
+
# xxxx 1xxx = IsSinglePoint
|
370
|
+
# xxx1 xxxx = IsSingleLineSegment
|
371
|
+
# xx1x xxxx = IsWholeGlobe
|
372
|
+
# Convert Microsoft's unique geography binary to standard WKB
|
373
|
+
# (MSSQL point usually has two doubles, lng / lat, and can also have Z)
|
374
|
+
if @is_mssql
|
375
|
+
if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
|
376
|
+
(val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
|
377
|
+
idx = 2
|
378
|
+
new_val = [0, 0, 0, 0, 1]
|
379
|
+
new_val.concat(val[idx - 8...idx].reverse) while (idx += 8) <= val.length
|
380
|
+
val = new_val
|
381
|
+
else
|
382
|
+
val_err = '(Microsoft internal SQL geography type)'
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
361
386
|
end
|
362
|
-
RGeo::WKRep::WKBParser.new.parse(val)
|
387
|
+
val_err || (val ? RGeo::WKRep::WKBParser.new.parse(val.pack('c*')) : nil)
|
363
388
|
else
|
364
389
|
'(Add RGeo gem to parse geometry detail)'
|
365
390
|
end
|
@@ -448,7 +473,7 @@ function changeout(href, param, value, trimAfter) {
|
|
448
473
|
var params = hrefParts.length > 1 ? hrefParts[1].split(\"&\") : [];
|
449
474
|
if (param === undefined || param === null || param === -1) {
|
450
475
|
hrefParts = hrefParts[0].split(\"://\");
|
451
|
-
var pathParts = hrefParts[hrefParts.length - 1].split(\"/\");
|
476
|
+
var pathParts = hrefParts[hrefParts.length - 1].split(\"/\").filter(function (pp) {return pp !== \"\";});
|
452
477
|
if (value === undefined)
|
453
478
|
// A couple possibilities if it's namespaced, starting with two parts in the path -- and then try just one
|
454
479
|
return [pathParts.slice(1, 3).join('/'), pathParts.slice(1, 2)[0]];
|
@@ -562,7 +587,7 @@ erDiagram
|
|
562
587
|
<%= \"#\{model_short_name} }o..o{ #\{hm_name} : \\\"#\{hm.first}\\\"\".html_safe %><%
|
563
588
|
else # has_many
|
564
589
|
%> <%= \"#\{model_short_name} ||--o{ #\{hm_name} : \\\"#\{
|
565
|
-
|
590
|
+
hm.first.to_s unless hm.first.to_s.downcase == hm_class.name.underscore.pluralize.tr('/', '_')
|
566
591
|
}\\\"\".html_safe %><%
|
567
592
|
end %>
|
568
593
|
<% end
|
@@ -604,7 +629,7 @@ erDiagram
|
|
604
629
|
end
|
605
630
|
if Object.const_defined?('DutyFree')
|
606
631
|
template_link = "
|
607
|
-
<%= link_to 'CSV', #{
|
632
|
+
<%= link_to 'CSV', #{@_brick_model._brick_index}_path(format: :csv) %> <a href=\"#\" id=\"sheetsLink\">Sheets</a>
|
608
633
|
<div id=\"dropper\" contenteditable=\"true\"></div>
|
609
634
|
<input type=\"button\" id=\"btnImport\" value=\"Import\">
|
610
635
|
|
@@ -667,7 +692,7 @@ erDiagram
|
|
667
692
|
console.log(\"x1\", sheetUrl);
|
668
693
|
|
669
694
|
// Get JSON data
|
670
|
-
fetch(changeout(<%= #{
|
695
|
+
fetch(changeout(<%= #{@_brick_model._brick_index}_path(format: :js).inspect.html_safe %>, \"_brick_schema\", brickSchema)).then(function (response) {
|
671
696
|
response.json().then(function (data) {
|
672
697
|
gapi.client.sheets.spreadsheets.values.append({
|
673
698
|
spreadsheetId: spreadsheetId,
|
@@ -698,7 +723,7 @@ erDiagram
|
|
698
723
|
<select id=\"schema\">#{schema_options}</select>" if ::Brick.config.schema_behavior[:multitenant] && ::Brick.db_schemas.length > 1}
|
699
724
|
<select id=\"tbl\">#{table_options}</select>
|
700
725
|
<table id=\"resourceName\"><tr>
|
701
|
-
<td><h1>#{
|
726
|
+
<td><h1>#{model_name}</h1></td>
|
702
727
|
<td id=\"imgErd\" title=\"Show ERD\"></td>
|
703
728
|
</tr></table>#{template_link}<%
|
704
729
|
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
@@ -712,10 +737,10 @@ erDiagram
|
|
712
737
|
origin = (key_parts = k.split('.')).length == 1 ? #{model_name} : #{model_name}.reflect_on_association(key_parts.first).klass
|
713
738
|
if (destination_fk = Brick.relations[origin.table_name][:fks].values.find { |fk| fk[:fk] == key_parts.last }) &&
|
714
739
|
(obj = (destination = origin.reflect_on_association(destination_fk[:assoc_name])&.klass)&.find(id)) %>
|
715
|
-
<h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination.
|
740
|
+
<h3>for <%= link_to \"#{"#\{obj.brick_descrip\} (#\{destination.name\})\""}, send(\"#\{destination._brick_index\}_path\".to_sym, id) %></h3><%
|
716
741
|
end
|
717
742
|
end %>
|
718
|
-
(<%= link_to 'See all #{
|
743
|
+
(<%= link_to 'See all #{model_name.split('::').last.pluralize}', #{@_brick_model._brick_index}_path %>)
|
719
744
|
<% end
|
720
745
|
# COLUMN EXCLUSIONS
|
721
746
|
if @_brick_excl&.present? %>
|
@@ -768,7 +793,7 @@ erDiagram
|
|
768
793
|
end
|
769
794
|
elsif col # HM column
|
770
795
|
s << \"<th#\{' x-order=\"' + col_name + '\"' if true}>#\{col[2]} \"
|
771
|
-
s << (col.first ? \"#\{col[3]}\" : \"#\{link_to(col[3], send(\"#\{col[1].
|
796
|
+
s << (col.first ? \"#\{col[3]}\" : \"#\{link_to(col[3], send(\"#\{col[1]._brick_index}_path\"))}\")
|
772
797
|
else # Bad column name!
|
773
798
|
s << \"<th title=\\\"<< Unknown column >>\\\">#\{col_name}\"
|
774
799
|
end
|
@@ -776,7 +801,11 @@ erDiagram
|
|
776
801
|
end.html_safe
|
777
802
|
%></tr></thead>
|
778
803
|
<tbody>
|
779
|
-
<%
|
804
|
+
<% # %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
|
805
|
+
# ActiveRecord::StatementTimeout in Warehouse::ColdRoomTemperatures_Archive#index
|
806
|
+
# TinyTds::Error: Adaptive Server connection timed out
|
807
|
+
# (After restarting the server it worked fine again.)
|
808
|
+
@#{table_name}.each do |#{obj_name}|
|
780
809
|
hms_cols = {#{hms_columns.join(', ')}} %>
|
781
810
|
<tr>#{"
|
782
811
|
<td><%= link_to '⇛', #{path_obj_name}_path(#{obj_pk}), { class: 'big-arrow' } %></td>" if obj_pk}
|
@@ -811,10 +840,11 @@ erDiagram
|
|
811
840
|
else
|
812
841
|
\"#\{hms_col[1] || 'View'\} #\{hms_col.first}\"
|
813
842
|
end %>
|
814
|
-
<%= link_to txt, send(\"#\{klass.
|
843
|
+
<%= link_to txt, send(\"#\{klass._brick_index}_path\".to_sym, hms_col[2]) unless hms_col[1]&.zero? %>
|
815
844
|
<% end
|
816
845
|
elsif (col = cols[col_name])
|
817
|
-
|
846
|
+
col_type = col&.sql_type == 'geography' ? col.sql_type : col&.type
|
847
|
+
%><%= display_value(col_type || col&.sql_type, val) %><%
|
818
848
|
else # Bad column name!
|
819
849
|
%>?<%
|
820
850
|
end
|
@@ -908,7 +938,7 @@ erDiagram
|
|
908
938
|
if (description = (relation = Brick.relations[#{model_name}.table_name])&.fetch(:description, nil)) %><%=
|
909
939
|
description %><br><%
|
910
940
|
end
|
911
|
-
%><%= link_to '(See all #{obj_name.pluralize})', #{
|
941
|
+
%><%= link_to '(See all #{obj_name.pluralize})', #{@_brick_model._brick_index}_path %>
|
912
942
|
#{erd_markup}
|
913
943
|
<% if obj %>
|
914
944
|
<br><br>
|
@@ -974,7 +1004,8 @@ end
|
|
974
1004
|
\"<span class=\\\"orphan\\\">Orphaned ID: #\{val}</span>\".html_safe
|
975
1005
|
end %>
|
976
1006
|
<% else
|
977
|
-
|
1007
|
+
col_type = col.sql_type == 'geography' ? col.sql_type : col.type
|
1008
|
+
case (col_type ||= col.sql_type)
|
978
1009
|
when :string, :text %>
|
979
1010
|
<% if is_bcrypt?(val) # || .readonly?
|
980
1011
|
is_revert = false %>
|
@@ -1008,8 +1039,8 @@ end
|
|
1008
1039
|
<% when :binary, :primary_key
|
1009
1040
|
is_revert = false %>
|
1010
1041
|
<% else %>
|
1011
|
-
<%=
|
1012
|
-
|
1042
|
+
<%= is_revert = false
|
1043
|
+
display_value(col_type, val) %>
|
1013
1044
|
<% end
|
1014
1045
|
end
|
1015
1046
|
if is_revert
|
@@ -1077,7 +1108,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1077
1108
|
var imgErd = document.getElementById(\"imgErd\");
|
1078
1109
|
var mermaidErd = document.getElementById(\"mermaidErd\");
|
1079
1110
|
var mermaidCode;
|
1080
|
-
var cbs = {<%= callbacks.map { |k, v| \"#\{k}: \\\"#\{v.
|
1111
|
+
var cbs = {<%= callbacks.map { |k, v| \"#\{k}: \\\"#\{send(\"#\{v._brick_index}_path\".to_sym)}\\\"\" }.join(', ').html_safe %>};
|
1081
1112
|
if (imgErd) imgErd.addEventListener(\"click\", showErd);
|
1082
1113
|
function showErd() {
|
1083
1114
|
imgErd.style.display = \"none\";
|
@@ -1101,7 +1132,7 @@ flatpickr(\".timepicker\", {enableTime: true, noCalendar: true});
|
|
1101
1132
|
function (evt) {
|
1102
1133
|
location.href = changeout(changeout(
|
1103
1134
|
changeout(location.href, '_brick_order', null), // Remove any ordering
|
1104
|
-
-1, cbs[this.id]), \"_brick_erd\", \"1\");
|
1135
|
+
-1, cbs[this.id].replace(/^[\/]+/, \"\")), \"_brick_erd\", \"1\");
|
1105
1136
|
}
|
1106
1137
|
);
|
1107
1138
|
}
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -125,8 +125,8 @@ module Brick
|
|
125
125
|
class << self
|
126
126
|
attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle
|
127
127
|
|
128
|
-
def set_db_schema(params)
|
129
|
-
schema = params['_brick_schema'] || 'public'
|
128
|
+
def set_db_schema(params = nil)
|
129
|
+
schema = (params ? params['_brick_schema'] : ::Brick.default_schema) || 'public'
|
130
130
|
if schema && ::Brick.db_schemas&.include?(schema)
|
131
131
|
ActiveRecord::Base.execute_sql("SET SEARCH_PATH = ?;", schema)
|
132
132
|
schema
|
@@ -152,16 +152,19 @@ module Brick
|
|
152
152
|
end
|
153
153
|
|
154
154
|
# Convert spaces to underscores if the second character and onwards is mixed case
|
155
|
-
def namify(name)
|
155
|
+
def namify(name, action = nil)
|
156
|
+
has_uppers = name =~ /[A-Z]+/
|
157
|
+
has_lowers = name =~ /[a-z]+/
|
158
|
+
name.downcase! if has_uppers && action == :downcase
|
156
159
|
if name.include?(' ')
|
157
160
|
# All uppers or all lowers?
|
158
|
-
if
|
161
|
+
if !has_uppers || !has_lowers
|
159
162
|
name.titleize.tr(' ', '_')
|
160
163
|
else # Mixed uppers and lowers -- just remove existing spaces
|
161
164
|
name.tr(' ', '')
|
162
165
|
end
|
163
166
|
else
|
164
|
-
name
|
167
|
+
action == :underscore ? name.underscore : name
|
165
168
|
end
|
166
169
|
end
|
167
170
|
|
@@ -265,6 +268,26 @@ module Brick
|
|
265
268
|
!!Brick.config.enable_routes
|
266
269
|
end
|
267
270
|
|
271
|
+
# @api public
|
272
|
+
def enable_api=(path)
|
273
|
+
Brick.config.enable_api = path
|
274
|
+
end
|
275
|
+
|
276
|
+
# @api public
|
277
|
+
def enable_api
|
278
|
+
Brick.config.enable_api
|
279
|
+
end
|
280
|
+
|
281
|
+
# @api public
|
282
|
+
def api_root=(path)
|
283
|
+
Brick.config.api_root = path
|
284
|
+
end
|
285
|
+
|
286
|
+
# @api public
|
287
|
+
def api_root
|
288
|
+
Brick.config.api_root
|
289
|
+
end
|
290
|
+
|
268
291
|
# @api public
|
269
292
|
def skip_database_views=(value)
|
270
293
|
Brick.config.skip_database_views = value
|
@@ -483,7 +506,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
483
506
|
# %%% TODO: If no auto-controllers then enumerate the controllers folder in order to build matching routes
|
484
507
|
# If auto-controllers and auto-models are both enabled then this makes sense:
|
485
508
|
::Brick.relations.each do |rel_name, v|
|
486
|
-
rel_name = rel_name.split('.').map { |
|
509
|
+
rel_name = rel_name.split('.').map { |rel_part| ::Brick.namify(rel_part, :underscore) }
|
487
510
|
schema_names = rel_name[0..-2]
|
488
511
|
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first == Apartment.default_schema
|
489
512
|
# %%% If more than one schema has the same table name, will need to add a schema name prefix to have uniqueness
|
@@ -493,10 +516,12 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
493
516
|
options[:only] = [:index, :show] if v.key?(:isView)
|
494
517
|
if schema_names.present? # && !Object.const_defined('Apartment')
|
495
518
|
send(:namespace, schema_names.first) do
|
496
|
-
send(:resources,
|
519
|
+
send(:resources, k.to_sym, **options)
|
497
520
|
end
|
521
|
+
send(:get, "/api/v1/#{schema_names.first}/#{k}", { to: "#{schema_names.first}/#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
|
498
522
|
else
|
499
|
-
send(:resources,
|
523
|
+
send(:resources, k.to_sym, **options)
|
524
|
+
send(:get, "/api/v1/#{k}", { to: "#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
|
500
525
|
end
|
501
526
|
end
|
502
527
|
if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
|
@@ -506,7 +531,11 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
506
531
|
get('/brick_orphans', to: 'brick_gem#orphans', as: 'brick_orphans')
|
507
532
|
end
|
508
533
|
end
|
509
|
-
|
534
|
+
if Object.const_defined?('Rswag::Ui') && doc_endpoint = Rswag::Ui.config.config_object[:urls].last
|
535
|
+
# Serves JSON swagger info from a path such as '/api-docs/v1/swagger.json'
|
536
|
+
puts "Mounting swagger info endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
|
537
|
+
send(:get, doc_endpoint[:url], { to: 'brick_swagger#index' })
|
538
|
+
end
|
510
539
|
end
|
511
540
|
super
|
512
541
|
end
|
@@ -726,6 +755,63 @@ ActiveSupport.on_load(:active_record) do
|
|
726
755
|
end
|
727
756
|
end
|
728
757
|
end
|
758
|
+
|
759
|
+
# Migration stuff
|
760
|
+
module ConnectionAdapters
|
761
|
+
# Override the downcasing implementation from the OracleEnhanced gem as it has bad regex
|
762
|
+
if const_defined?(:OracleEnhanced)
|
763
|
+
module OracleEnhanced::Quoting
|
764
|
+
private
|
765
|
+
|
766
|
+
def oracle_downcase(column_name)
|
767
|
+
return nil if column_name.nil?
|
768
|
+
|
769
|
+
/^[A-Za-z0-9_]+$/ =~ column_name ? column_name.downcase : column_name
|
770
|
+
end
|
771
|
+
end
|
772
|
+
end
|
773
|
+
if const_defined?(:SQLServerAdapter)
|
774
|
+
class SQLServer::TableDefinition
|
775
|
+
alias _brick_new_column_definition new_column_definition
|
776
|
+
def new_column_definition(name, type, **options)
|
777
|
+
case type
|
778
|
+
when :serial
|
779
|
+
type = :integer
|
780
|
+
options[:is_identity] = true
|
781
|
+
when :bigserial
|
782
|
+
type = :bigint
|
783
|
+
options[:is_identity] = true
|
784
|
+
end
|
785
|
+
_brick_new_column_definition(name, type, **options)
|
786
|
+
end
|
787
|
+
def serial(*args)
|
788
|
+
options = args.extract_options!
|
789
|
+
options[:is_identity] = true
|
790
|
+
args.each { |name| column(name, 'integer', options) }
|
791
|
+
end
|
792
|
+
def bigserial(*args)
|
793
|
+
options = args.extract_options!
|
794
|
+
options[:is_identity] = true
|
795
|
+
args.each { |name| column(name, 'bigint', options) }
|
796
|
+
end
|
797
|
+
# Seems that geography gets used a fair bit in MSSQL
|
798
|
+
def geography(*args)
|
799
|
+
options = args.extract_options!
|
800
|
+
# options[:precision] ||= 8
|
801
|
+
# options[:scale] ||= 2
|
802
|
+
args.each { |name| column(name, 'geography', options) }
|
803
|
+
end
|
804
|
+
end
|
805
|
+
class SQLServerAdapter
|
806
|
+
unless respond_to?(:schema_exists?)
|
807
|
+
def schema_exists?(schema)
|
808
|
+
schema_sql = 'SELECT 1 FROM sys.schemas WHERE name = ?'
|
809
|
+
ActiveRecord::Base.execute_sql(schema_sql, schema).present?
|
810
|
+
end
|
811
|
+
end
|
812
|
+
end
|
813
|
+
end
|
814
|
+
end
|
729
815
|
end
|
730
816
|
# rubocop:enable Lint/ConstantDefinitionInBlock
|
731
817
|
|
@@ -147,6 +147,8 @@ module Brick
|
|
147
147
|
# Brick.enable_controllers = true # Setting this to \"false\" will disable controllers in development
|
148
148
|
# Brick.enable_views = true # Setting this to \"false\" will disable views in development
|
149
149
|
|
150
|
+
# Brick.api_root = '/api/v1/' # Path from which to serve out API resources when the RSwag gem is present
|
151
|
+
|
150
152
|
# # By default models are auto-created for database views, and set to be read-only. This can be skipped.
|
151
153
|
# Brick.skip_database_views = true
|
152
154
|
|
@@ -23,6 +23,21 @@ module Brick
|
|
23
23
|
'time with time zone' => 'time',
|
24
24
|
'double precision' => 'float',
|
25
25
|
'smallint' => 'integer', # %%% Need to put in "limit: 2"
|
26
|
+
# # Oracle data types
|
27
|
+
'VARCHAR2' => 'string',
|
28
|
+
'CHAR' => 'string',
|
29
|
+
['NUMBER', 22] => 'integer',
|
30
|
+
/^INTERVAL / => 'string', # Time interval stuff like INTERVAL YEAR(2) TO MONTH, INTERVAL '999' DAY(3), etc
|
31
|
+
'XMLTYPE' => 'xml',
|
32
|
+
'RAW' => 'binary',
|
33
|
+
'SDO_GEOMETRY' => 'geometry',
|
34
|
+
# MSSQL data types
|
35
|
+
'int' => 'integer',
|
36
|
+
'nvarchar' => 'string',
|
37
|
+
'nchar' => 'string',
|
38
|
+
'datetime2' => 'timestamp',
|
39
|
+
'bit' => 'boolean',
|
40
|
+
'varbinary' => 'binary',
|
26
41
|
# Sqlite data types
|
27
42
|
'TEXT' => 'text',
|
28
43
|
'' => 'string',
|
@@ -122,7 +137,7 @@ module Brick
|
|
122
137
|
fringe.each do |tbl|
|
123
138
|
next unless (relation = ::Brick.relations.fetch(tbl, nil))&.fetch(:cols, nil)&.present?
|
124
139
|
|
125
|
-
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [
|
140
|
+
pkey_cols = (rpk = relation[:pkey].values.flatten) & (arpk = [ApplicationRecord.primary_key].flatten.sort)
|
126
141
|
# In case things aren't as standard
|
127
142
|
if pkey_cols.empty?
|
128
143
|
pkey_cols = if rpk.empty? && relation[:cols][arpk.first]&.first == key_type
|
@@ -141,7 +156,7 @@ module Brick
|
|
141
156
|
end
|
142
157
|
unless schema.blank? || built_schemas.key?(schema)
|
143
158
|
mig = +" def change\n create_schema(:#{schema}) unless schema_exists?(:#{schema})\n end\n"
|
144
|
-
migration_file_write(mig_path, "create_db_schema_#{schema}", current_mig_time += 1.minute, ar_version, mig)
|
159
|
+
migration_file_write(mig_path, "create_db_schema_#{schema.underscore}", current_mig_time += 1.minute, ar_version, mig)
|
145
160
|
built_schemas[schema] = nil
|
146
161
|
end
|
147
162
|
|
@@ -151,11 +166,16 @@ module Brick
|
|
151
166
|
# a column definition which includes :primary_key -- %%% also using a data type of bigserial or serial
|
152
167
|
# if this one has come in as bigint or integer.
|
153
168
|
pk_is_also_fk = fkey_cols.any? { |assoc| pkey_cols&.first == assoc[:fk] } ? pkey_cols&.first : nil
|
154
|
-
# Support missing primary key (by adding: ,id: false)
|
169
|
+
# Support missing primary key (by adding: , id: false)
|
155
170
|
id_option = if pk_is_also_fk || !pkey_cols&.present?
|
171
|
+
needs_serial_col = true
|
156
172
|
', id: false'
|
157
|
-
elsif ((pkey_col_first = relation[:cols][pkey_cols&.first]&.first) &&
|
158
|
-
(pkey_col_first = SQL_TYPES[pkey_col_first] ||
|
173
|
+
elsif ((pkey_col_first = (col_def = relation[:cols][pkey_cols&.first])&.first) &&
|
174
|
+
(pkey_col_first = SQL_TYPES[pkey_col_first] || SQL_TYPES[col_def&.[](0..1)] ||
|
175
|
+
SQL_TYPES.find { |r| r.first.is_a?(Regexp) && pkey_col_first =~ r.first }&.last ||
|
176
|
+
pkey_col_first
|
177
|
+
) != key_type
|
178
|
+
)
|
159
179
|
case pkey_col_first
|
160
180
|
when 'integer'
|
161
181
|
', id: :serial'
|
@@ -164,9 +184,14 @@ module Brick
|
|
164
184
|
else
|
165
185
|
", id: :#{pkey_col_first}" # Something like: id: :integer, primary_key: :businessentityid
|
166
186
|
end +
|
167
|
-
(pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
|
168
|
-
(!is_4x_rails && (comment = relation&.fetch(:description, nil))&.present? ? ", comment: #{comment.inspect}" : '')
|
187
|
+
(pkey_cols.first ? ", primary_key: :#{pkey_cols.first}" : '')
|
169
188
|
end
|
189
|
+
if !id_option && pkey_cols.sort != arpk
|
190
|
+
id_option = ", primary_key: :#{pkey_cols.first}"
|
191
|
+
end
|
192
|
+
if !is_4x_rails && (comment = relation&.fetch(:description, nil))&.present?
|
193
|
+
(id_option ||= +'') << ", comment: #{comment.inspect}"
|
194
|
+
end
|
170
195
|
# Find the ActiveRecord class in order to see if the columns have comments
|
171
196
|
unless is_4x_rails
|
172
197
|
klass = begin
|
@@ -187,18 +212,24 @@ module Brick
|
|
187
212
|
possible_ts = [] # Track possible generic timestamps
|
188
213
|
add_fks = [] # Track foreign keys to add after table creation
|
189
214
|
relation[:cols].each do |col, col_type|
|
190
|
-
sql_type = SQL_TYPES[col_type.first] || col_type
|
191
|
-
|
215
|
+
sql_type = SQL_TYPES[col_type.first] || SQL_TYPES[col_type[0..1]] ||
|
216
|
+
SQL_TYPES.find { |r| r.first.is_a?(Regexp) && col_type.first =~ r.first }&.last ||
|
217
|
+
col_type.first
|
218
|
+
suffix = col_type[3] || pkey_cols&.include?(col) ? +', null: false' : +''
|
192
219
|
if !is_4x_rails && klass && (comment = klass.columns_hash.fetch(col, nil)&.comment)&.present?
|
193
220
|
suffix << ", comment: #{comment.inspect}"
|
194
221
|
end
|
195
222
|
# Determine if this column is used as part of a foreign key
|
196
|
-
if fk = fkey_cols.find { |assoc| col == assoc[:fk] }
|
223
|
+
if (fk = fkey_cols.find { |assoc| col == assoc[:fk] })
|
197
224
|
to_table = fk[:inverse_table].split('.')
|
198
225
|
to_table = to_table.length == 1 ? ":#{to_table.first}" : "'#{fk[:inverse_table]}'"
|
226
|
+
if needs_serial_col && pkey_cols&.include?(col) && (new_serial_type = {'integer' => 'serial', 'bigint' => 'bigserial'}[sql_type])
|
227
|
+
sql_type = new_serial_type
|
228
|
+
needs_serial_col = false
|
229
|
+
end
|
199
230
|
if fk[:fk] != "#{fk[:assoc_name].singularize}_id" # Need to do our own foreign_key tricks, not use references?
|
200
231
|
column = fk[:fk]
|
201
|
-
mig <<
|
232
|
+
mig << emit_column(sql_type, column, suffix)
|
202
233
|
add_fks << [to_table, column, ::Brick.relations[fk[:inverse_table]]]
|
203
234
|
else
|
204
235
|
suffix << ", type: :#{sql_type}" unless sql_type == key_type
|
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.73
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|