brick 1.0.107 → 1.0.109
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/brick/compatibility.rb +31 -4
- data/lib/brick/config.rb +44 -0
- data/lib/brick/extensions.rb +92 -29
- data/lib/brick/version_number.rb +1 -1
- data/lib/brick.rb +100 -71
- data/lib/generators/brick/install_generator.rb +1 -1
- 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: 1621b6af75759b90c788ce080db85608731c2bfc026c82d7bcea011a89c2162e
|
4
|
+
data.tar.gz: a4242388d2fa29a12229c620d91b5d572e9e2f7688783beb6963817cf3fac340
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa089c1bc9663e764b783c639ca9ca24c18a5cbbc788281e11620b33277e87282b6e1a0195d12686b72f53a5ae4a5bcb9e8343e9ef9bb4d97f53fb69ad4619fe
|
7
|
+
data.tar.gz: 784eed99a879191dff95b5dfd061f8025d52d3e30eb16b7a754b425c2f4ad58e03e8631949d807f130dc86e55cb3a5e08d215a3f1729b4465c58dc3cecffb96d
|
data/lib/brick/compatibility.rb
CHANGED
@@ -42,9 +42,36 @@ end
|
|
42
42
|
# file by having the line "require 'brick/compatibility'" to be the last line in that
|
43
43
|
# file.
|
44
44
|
require 'bigdecimal'
|
45
|
-
if
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
if ActiveRecord.version < ::Gem::Version.new('5.0')
|
46
|
+
if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.6')
|
47
|
+
def BigDecimal.new(*args, **kwargs)
|
48
|
+
BigDecimal(*args, **kwargs)
|
49
|
+
end
|
50
|
+
|
51
|
+
if ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('3.1')
|
52
|
+
# @@schemes fix for global_id gem < 1.0
|
53
|
+
URI.class_variable_set(:@@schemes, {}) unless URI.class_variables.include?(:@@schemes)
|
54
|
+
if Gem::Specification.all_names.find { |g| g.start_with?('puma-') }
|
55
|
+
require 'rack/handler/puma'
|
56
|
+
module Rack::Handler::Puma
|
57
|
+
class << self
|
58
|
+
alias _brick_run run
|
59
|
+
def run(app, *args, **options)
|
60
|
+
options.merge!(args.pop) if args.last.is_a?(Hash)
|
61
|
+
_brick_run(app, **options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
require 'json'
|
68
|
+
if JSON::Parser.method(:initialize).parameters.length < 2 && JSON.method(:parse).arity == -2
|
69
|
+
JSON.class_exec do
|
70
|
+
def self.parse(source, opts = {})
|
71
|
+
::JSON::Parser.new(source, **opts).parse
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
49
76
|
end
|
50
77
|
end
|
data/lib/brick/config.rb
CHANGED
@@ -110,6 +110,50 @@ module Brick
|
|
110
110
|
@mutex.synchronize { @api_filter = proc }
|
111
111
|
end
|
112
112
|
|
113
|
+
# # Proc gets called with up to 4 arguments: object_name, api_version, columns, data
|
114
|
+
# # Expected to return an array, either just of symbols defining column names, or an array with two sub-arrays, first of column detail and second of data
|
115
|
+
# def api_column_filter
|
116
|
+
# @mutex.synchronize { @api_column_filter }
|
117
|
+
# end
|
118
|
+
|
119
|
+
# def api_column_filter=(proc)
|
120
|
+
# @mutex.synchronize { @api_column_filter = proc }
|
121
|
+
# end
|
122
|
+
|
123
|
+
# Allows you to rename and exclude columns either specific to a given API version, or generally for a database object name
|
124
|
+
def api_column_renaming
|
125
|
+
@mutex.synchronize { @api_column_renaming }
|
126
|
+
end
|
127
|
+
|
128
|
+
def api_column_renaming=(renames)
|
129
|
+
@mutex.synchronize { @api_column_renaming = renames }
|
130
|
+
end
|
131
|
+
|
132
|
+
# All the view prefix things
|
133
|
+
def api_view_prefix
|
134
|
+
@mutex.synchronize { @api_view_prefix }
|
135
|
+
end
|
136
|
+
|
137
|
+
def api_view_prefix=(view_prefix)
|
138
|
+
@mutex.synchronize { @api_view_prefix = view_prefix }
|
139
|
+
end
|
140
|
+
|
141
|
+
def api_remove_view_prefix
|
142
|
+
@mutex.synchronize { @api_remove_view_prefix || @api_view_prefix }
|
143
|
+
end
|
144
|
+
|
145
|
+
def api_remove_view_prefix=(view_prefix)
|
146
|
+
@mutex.synchronize { @api_remove_view_prefix = view_prefix }
|
147
|
+
end
|
148
|
+
|
149
|
+
def api_add_view_prefix
|
150
|
+
@mutex.synchronize { @api_add_view_prefix || @api_view_prefix }
|
151
|
+
end
|
152
|
+
|
153
|
+
def api_add_view_prefix=(view_prefix)
|
154
|
+
@mutex.synchronize { @api_add_view_prefix = view_prefix }
|
155
|
+
end
|
156
|
+
|
113
157
|
# Additional table associations to use (Think of these as virtual foreign keys perhaps)
|
114
158
|
def additional_references
|
115
159
|
@mutex.synchronize { @additional_references }
|
data/lib/brick/extensions.rb
CHANGED
@@ -44,16 +44,20 @@
|
|
44
44
|
|
45
45
|
module ActiveRecord
|
46
46
|
class Base
|
47
|
-
|
48
|
-
|
49
|
-
end
|
47
|
+
class << self
|
48
|
+
attr_reader :_brick_relation
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
def is_brick?
|
51
|
+
instance_variables.include?(:@_brick_built) && instance_variable_get(:@_brick_built)
|
52
|
+
end
|
53
|
+
|
54
|
+
def _assoc_names
|
55
|
+
@_assoc_names ||= {}
|
56
|
+
end
|
54
57
|
|
55
|
-
|
56
|
-
|
58
|
+
def is_view?
|
59
|
+
false
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
63
|
def self._brick_primary_key(relation = nil)
|
@@ -417,7 +421,10 @@ module ActiveRecord
|
|
417
421
|
is_distinct = nil
|
418
422
|
wheres = {}
|
419
423
|
params.each do |k, v|
|
420
|
-
next if ['_brick_schema', '_brick_order',
|
424
|
+
next if ['_brick_schema', '_brick_order',
|
425
|
+
'_brick_erd', '_brick_exclude', '_brick_unexclude',
|
426
|
+
'_brick_page', '_brick_page_size', '_brick_offset', '_brick_limit',
|
427
|
+
'_brick_is_api', 'controller', 'action'].include?(k)
|
421
428
|
|
422
429
|
if (where_col = (ks = k.split('.')).last)[-1] == '!'
|
423
430
|
where_col = where_col[0..-2]
|
@@ -444,7 +451,10 @@ module ActiveRecord
|
|
444
451
|
# %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
|
445
452
|
# ActiveRecord::StatementInvalid (TinyTds::Error: DBPROCESS is dead or not enabled)
|
446
453
|
# Relevant info here: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/402
|
454
|
+
is_api = params['_brick_is_api']
|
447
455
|
columns.each do |col|
|
456
|
+
next if (col.type.nil? || col.type == :binary) && is_api
|
457
|
+
|
448
458
|
col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
|
449
459
|
selects << if is_mysql
|
450
460
|
"`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
|
@@ -787,21 +797,21 @@ JOIN (SELECT #{hm_selects.map { |s| "#{'br_t0.' if from_clause}#{s}" }.join(', '
|
|
787
797
|
end
|
788
798
|
self.order_values |= final_order_by # Same as: order!(*final_order_by)
|
789
799
|
end
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
800
|
+
# By default just 1000 rows
|
801
|
+
row_limit = params['_brick_limit'] || params['_brick_page_size'] || 1000
|
802
|
+
offset = if (page = params['_brick_page']&.to_i)
|
803
|
+
page = 1 if page < 1
|
804
|
+
(page - 1) * row_limit.to_i
|
805
|
+
else
|
806
|
+
params['_brick_offset']
|
807
|
+
end
|
798
808
|
if offset.is_a?(Numeric) || offset&.present?
|
799
809
|
offset = offset.to_i
|
800
810
|
self.offset_value = offset unless offset == 0
|
801
|
-
@_brick_page_num = (offset /
|
811
|
+
@_brick_page_num = (offset / row_limit.to_i) + 1 if row_limit&.!= 0 && (offset % row_limit.to_i) == 0
|
802
812
|
end
|
803
|
-
#
|
804
|
-
self.limit_value =
|
813
|
+
# Setting limit_value= is the same as doing: limit!(1000) but this way is compatible with AR <= 4.2
|
814
|
+
self.limit_value = row_limit.to_i unless row_limit.is_a?(String) && row_limit.empty?
|
805
815
|
wheres unless wheres.empty? # Return the specific parameters that we did use
|
806
816
|
end
|
807
817
|
|
@@ -1261,6 +1271,7 @@ class Object
|
|
1261
1271
|
# Having this separate -- will this now work out better?
|
1262
1272
|
built_model.class_exec do
|
1263
1273
|
@_brick_built = true
|
1274
|
+
@_brick_relation = relation
|
1264
1275
|
hmts&.each do |hmt_fk, hms|
|
1265
1276
|
hmt_fk = hmt_fk.tr('.', '_')
|
1266
1277
|
hms.each do |hm|
|
@@ -1533,9 +1544,13 @@ class Object
|
|
1533
1544
|
end
|
1534
1545
|
if (current_api_root || is_openapi) &&
|
1535
1546
|
!params&.key?('_brick_schema') &&
|
1536
|
-
(referrer_params = request.env['HTTP_REFERER']&.split('?')&.last&.split('&')&.
|
1547
|
+
(referrer_params = request.env['HTTP_REFERER']&.split('?')&.last&.split('&')&.each_with_object({}) do |x, s|
|
1548
|
+
if (kv = x.split('=')).length > 1
|
1549
|
+
s[kv.first] = kv[1..-1].join('=')
|
1550
|
+
end
|
1551
|
+
end).present?
|
1537
1552
|
if params
|
1538
|
-
referrer_params.each { |k, v| params.send(:parameters)[k] = v }
|
1553
|
+
referrer_params.each { |k, v| (params.respond_to?(:parameters) ? send(:parameters) : params)[k] = v }
|
1539
1554
|
else
|
1540
1555
|
api_params = referrer_params&.to_h
|
1541
1556
|
end
|
@@ -1570,13 +1585,22 @@ class Object
|
|
1570
1585
|
(api_ver_paths || { relation.first => all_actions }).each do |api_ver_path, actions|
|
1571
1586
|
relation_name = (api_ver_path || relation.first).tr('.', '/')
|
1572
1587
|
table_description = relation.last[:description]
|
1588
|
+
|
1589
|
+
# Column renaming / exclusions
|
1590
|
+
renamed_columns = if (column_renaming = ::Brick.find_col_renaming(api_ver_path, relation.first))
|
1591
|
+
column_renaming.each_with_object({}) do |rename, s|
|
1592
|
+
s[rename.last] = relation.last[:cols][rename.first] if rename.last
|
1593
|
+
end
|
1594
|
+
else
|
1595
|
+
relation.last[:cols]
|
1596
|
+
end
|
1573
1597
|
{ :index => [:get, 'list'], :create => [:post, 'create a'] }.each do |k, v|
|
1574
1598
|
unless actions&.exclude?(k)
|
1575
1599
|
this_resource = (s["#{current_api_root}#{relation_name}"] ||= {})
|
1576
1600
|
this_resource[v.first] = {
|
1577
1601
|
'summary': "#{v[1]} #{relation.first}",
|
1578
1602
|
'description': table_description,
|
1579
|
-
'parameters':
|
1603
|
+
'parameters': renamed_columns.map do |k2, v2|
|
1580
1604
|
param = { in: 'query', 'name': k2, 'schema': { 'type': v2.first } }
|
1581
1605
|
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k2, nil))
|
1582
1606
|
param['description'] = col_descrip
|
@@ -1596,7 +1620,7 @@ class Object
|
|
1596
1620
|
this_resource[v.first] = {
|
1597
1621
|
'summary': "#{v[1]} a #{relation.first.singularize}",
|
1598
1622
|
'description': table_description,
|
1599
|
-
'parameters':
|
1623
|
+
'parameters': renamed_columns.reject { |k1, _v1| Brick.config.metadata_columns.include?(k1) }.map do |k2, v2|
|
1600
1624
|
param = { 'name': k2, 'schema': { 'type': v2.first } }
|
1601
1625
|
if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k2, nil))
|
1602
1626
|
param['description'] = col_descrip
|
@@ -1637,13 +1661,46 @@ class Object
|
|
1637
1661
|
order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
|
1638
1662
|
|
1639
1663
|
ar_relation = ActiveRecord.version < Gem::Version.new('4') ? model.preload : model.all
|
1664
|
+
params['_brick_is_api'] = true if (is_api = request.format == :js || current_api_root)
|
1640
1665
|
@_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
|
1641
1666
|
translations = {},
|
1642
1667
|
join_array = ::Brick::JoinArray.new)
|
1643
1668
|
|
1644
|
-
if
|
1669
|
+
if is_api # Asking for JSON?
|
1670
|
+
# Apply column renaming
|
1645
1671
|
data = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects) : ar_relation.select(selects)
|
1646
|
-
|
1672
|
+
if data.present? &&
|
1673
|
+
(column_renaming = ::Brick.find_col_renaming(current_api_root, model&._brick_relation)&.select { |cr| cr.last })
|
1674
|
+
data.map!({}) do |row, s|
|
1675
|
+
column_renaming.each_with_object({}) do |rename, s|
|
1676
|
+
s[rename.last] = row[rename.first] if rename.last
|
1677
|
+
end
|
1678
|
+
end
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
# # %%% This currently only gives a window to check security and raise an exception if someone isn't
|
1682
|
+
# # authenticated / authorised. Still need to figure out column filtering and transformations.
|
1683
|
+
# proc_result = if (column_filter = ::Brick.config.api_column_filter).is_a?(Proc)
|
1684
|
+
# object_columns = (relation = model&._brick_relation)[:cols]
|
1685
|
+
# begin
|
1686
|
+
# num_args = column_filter.arity.negative? ? 5 : column_filter.arity
|
1687
|
+
# # object_name, api_version, columns, data
|
1688
|
+
# api_ver_path = request.path[0..-relation[:resource].length]
|
1689
|
+
# # Call the api_column_filter in the context of this auto-built controller
|
1690
|
+
# instance_exec(*[relation[:resource], relation, api_ver_path, object_columns, data][0...num_args], &column_filter)
|
1691
|
+
# rescue StandardError => e
|
1692
|
+
# puts "::Brick.api_column_filter Proc error: #{e.message}"
|
1693
|
+
# end
|
1694
|
+
# end
|
1695
|
+
# columns = if (proc_result) # Proc returns up to 2 things: columns, data
|
1696
|
+
# # If it's all valid column name strings then we're just rearranging the column sequence
|
1697
|
+
# col_names = proc_result.all? { |pr| object_columns.key?(pr) } ? proc_result : proc_result.first.keys
|
1698
|
+
# col_names.each_with_object({}) { |cn, s| s[cn] = relation.last[:cols][cn] }
|
1699
|
+
# else
|
1700
|
+
# relation.last[:cols]
|
1701
|
+
# end
|
1702
|
+
|
1703
|
+
render inline: { data: data }.to_json, content_type: ['*/*', 'text/html'].include?(request.format) ? 'application/json' : request.format
|
1647
1704
|
return
|
1648
1705
|
end
|
1649
1706
|
|
@@ -1940,7 +1997,6 @@ end.class_exec do
|
|
1940
1997
|
|
1941
1998
|
# return if ActiveRecord::Base.connection.current_database == 'postgres'
|
1942
1999
|
|
1943
|
-
initializer_loaded = false
|
1944
2000
|
orig_schema = nil
|
1945
2001
|
if (relations = ::Brick.relations).empty?
|
1946
2002
|
# Very first thing, load inflections since we'll be using .pluralize and .singularize on table and model names
|
@@ -1949,7 +2005,7 @@ end.class_exec do
|
|
1949
2005
|
end
|
1950
2006
|
# Now the Brick initializer since there may be important schema things configured
|
1951
2007
|
if File.exist?(brick_initializer = ::Rails.root.join('config/initializers/brick.rb'))
|
1952
|
-
initializer_loaded = load brick_initializer
|
2008
|
+
::Brick.initializer_loaded = load brick_initializer
|
1953
2009
|
end
|
1954
2010
|
# Load the initializer for the Apartment gem a little early so that if .excluded_models and
|
1955
2011
|
# .default_schema are specified then we can work with non-tenanted models more appropriately
|
@@ -2222,7 +2278,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
|
|
2222
2278
|
end
|
2223
2279
|
v[:class_name] = (schema_names + [singular]).map(&:camelize).join('::')
|
2224
2280
|
end
|
2225
|
-
::Brick.load_additional_references if initializer_loaded
|
2281
|
+
::Brick.load_additional_references if ::Brick.initializer_loaded
|
2226
2282
|
|
2227
2283
|
if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
|
2228
2284
|
puts "Now switching back to \"#{orig_schema}\" schema."
|
@@ -2603,6 +2659,13 @@ module Brick
|
|
2603
2659
|
end
|
2604
2660
|
end
|
2605
2661
|
|
2662
|
+
def find_col_renaming(api_ver_path, relation_name)
|
2663
|
+
::Brick.config.api_column_renaming&.fetch(
|
2664
|
+
api_ver_path,
|
2665
|
+
::Brick.config.api_column_renaming&.fetch(relation_name, nil)
|
2666
|
+
)
|
2667
|
+
end
|
2668
|
+
|
2606
2669
|
def _class_pk(dotted_name, multitenant)
|
2607
2670
|
Object.const_get((multitenant ? [dotted_name.split('.').last] : dotted_name.split('.')).map { |nm| "::#{nm.singularize.camelize}" }.join).primary_key
|
2608
2671
|
end
|
data/lib/brick/version_number.rb
CHANGED
data/lib/brick.rb
CHANGED
@@ -135,7 +135,7 @@ module Brick
|
|
135
135
|
@existing_stis ||= Brick.config.sti_namespace_prefixes.each_with_object({}) { |snp, s| s[snp.first[2..-1]] = snp.last unless snp.first.end_with?('::') }
|
136
136
|
end
|
137
137
|
|
138
|
-
attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle, :is_eager_loading, :auto_models
|
138
|
+
attr_accessor :default_schema, :db_schemas, :routes_done, :is_oracle, :is_eager_loading, :auto_models, :initializer_loaded
|
139
139
|
|
140
140
|
def set_db_schema(params = nil)
|
141
141
|
# If Apartment::Tenant.current is not still the default (usually 'public') then an elevator has brought us into
|
@@ -682,45 +682,86 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
682
682
|
if (schema_name = v.fetch(:schema, nil))
|
683
683
|
schema_prefix = "#{schema_name}."
|
684
684
|
end
|
685
|
+
|
686
|
+
# Track routes being built
|
687
|
+
if (class_name = v.fetch(:class_name, nil))
|
688
|
+
if v.key?(:isView)
|
689
|
+
view_class_length = class_name.length if class_name.length > view_class_length
|
690
|
+
views
|
691
|
+
else
|
692
|
+
table_class_length = class_name.length if class_name.length > table_class_length
|
693
|
+
tables
|
694
|
+
end << [class_name, "#{schema_prefix&.tr('.', '/')}#{v[:resource]}"]
|
695
|
+
end
|
696
|
+
|
685
697
|
options = {}
|
686
698
|
options[:only] = [:index, :show] if v.key?(:isView)
|
687
|
-
|
699
|
+
|
700
|
+
# First do the normal routes
|
701
|
+
if path_prefix
|
702
|
+
# Was: send(:scope, path: path_prefix) do
|
703
|
+
send(:namespace, path_prefix) do
|
704
|
+
brick_routes_create.call(schema_name, v[:resource], options)
|
705
|
+
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
706
|
+
brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
|
707
|
+
end
|
708
|
+
end
|
709
|
+
else
|
710
|
+
brick_routes_create.call(schema_name, v[:resource], options)
|
711
|
+
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
712
|
+
brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
# Now the API routes if necessary
|
688
717
|
full_resource = nil
|
689
718
|
::Brick.api_roots&.each do |api_root|
|
690
719
|
api_done_views = (versioned_views[api_root] ||= {})
|
691
720
|
found = nil
|
721
|
+
test_ver_num = nil
|
692
722
|
view_relation = nil
|
693
723
|
# If it's a view then see if there's a versioned one available by searching for resource names
|
694
724
|
# versioned with the closest number (equal to or less than) compared with our API version number.
|
695
|
-
if v.key?(:isView)
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
725
|
+
if v.key?(:isView)
|
726
|
+
if (ver = object_name.match(/^v([\d_]*)/)&.captures&.first) && ver[-1] == '_'
|
727
|
+
core_object_name = object_name[ver.length + 1..-1]
|
728
|
+
next if api_done_views.key?(unversioned = "#{schema_prefix}v_#{core_object_name}")
|
729
|
+
|
730
|
+
# Expect that the last item in the path generally holds versioning information
|
731
|
+
api_ver = api_root.split('/')[-1]&.gsub('_', '.')
|
732
|
+
vn_idx = api_ver.rindex(/[^\d._]/) # Position of the first numeric digit at the end of the version number
|
733
|
+
# Was: .to_d
|
734
|
+
test_ver_num = api_ver_num = api_ver[vn_idx + 1..-1].gsub('_', '.').to_i # Attempt to turn something like "v3" into the decimal value 3
|
735
|
+
# puts [api_ver, vn_idx, api_ver_num, unversioned].inspect
|
736
|
+
|
737
|
+
next if ver.to_i > api_ver_num # Don't surface any newer views in an older API
|
738
|
+
|
739
|
+
test_ver_num -= 1 until test_ver_num.zero? ||
|
740
|
+
(view_relation = ::Brick.relations.fetch(
|
741
|
+
found = "#{schema_prefix}v#{test_ver_num}_#{core_object_name}", nil
|
742
|
+
))
|
743
|
+
api_done_views[unversioned] = nil # Mark that for this API version this view is done
|
744
|
+
|
745
|
+
# puts "Found #{found}" if view_relation
|
746
|
+
# If we haven't found "v3_view_name" or "v2_view_name" or so forth, at the last
|
747
|
+
# fall back to simply looking for "v_view_name", and then finally "view_name".
|
748
|
+
no_v_prefix_name = "#{schema_prefix}#{core_object_name}"
|
749
|
+
standard_prefix = 'v_'
|
750
|
+
else
|
751
|
+
core_object_name = object_name
|
752
|
+
end
|
753
|
+
if (rvp = ::Brick.config.api_remove_view_prefix) && core_object_name.start_with?(rvp)
|
754
|
+
core_object_name.slice!(0, rvp.length)
|
755
|
+
end
|
756
|
+
no_prefix_name = "#{schema_prefix}#{core_object_name}"
|
757
|
+
unversioned = "#{schema_prefix}#{standard_prefix}#{::Brick.config.api_add_view_prefix}#{core_object_name}"
|
718
758
|
else
|
719
759
|
unversioned = k
|
720
760
|
end
|
721
761
|
|
722
762
|
view_relation ||= ::Brick.relations.fetch(found = unversioned, nil) ||
|
723
|
-
(no_v_prefix_name && ::Brick.relations.fetch(found = no_v_prefix_name, nil))
|
763
|
+
(no_v_prefix_name && ::Brick.relations.fetch(found = no_v_prefix_name, nil)) ||
|
764
|
+
(no_prefix_name && ::Brick.relations.fetch(found = no_prefix_name, nil))
|
724
765
|
if view_relation
|
725
766
|
actions = view_relation.key?(:isView) ? [:index, :show] : ::Brick::ALL_API_ACTIONS # By default all actions are allowed
|
726
767
|
# Call proc that limits which endpoints get surfaced based on version, table or view name, method (get list / get one / post / patch / delete)
|
@@ -730,7 +771,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
730
771
|
proc_result = if (filter = ::Brick.config.api_filter).is_a?(Proc)
|
731
772
|
begin
|
732
773
|
num_args = filter.arity.negative? ? 6 : filter.arity
|
733
|
-
filter.call(*[unversioned, k, actions, api_ver_num, found, test_ver_num][0...num_args])
|
774
|
+
filter.call(*[unversioned, k, view_relation, actions, api_ver_num, found, test_ver_num][0...num_args])
|
734
775
|
rescue StandardError => e
|
735
776
|
puts "::Brick.api_filter Proc error: #{e.message}"
|
736
777
|
end
|
@@ -799,33 +840,6 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
799
840
|
end
|
800
841
|
end
|
801
842
|
end
|
802
|
-
|
803
|
-
# Track routes being built
|
804
|
-
if (class_name = v.fetch(:class_name, nil))
|
805
|
-
if v.key?(:isView)
|
806
|
-
view_class_length = class_name.length if class_name.length > view_class_length
|
807
|
-
views
|
808
|
-
else
|
809
|
-
table_class_length = class_name.length if class_name.length > table_class_length
|
810
|
-
tables
|
811
|
-
end << [class_name, "#{schema_prefix&.tr('.', '/')}#{v[:resource]}"]
|
812
|
-
end
|
813
|
-
|
814
|
-
# Now the normal routes
|
815
|
-
if path_prefix
|
816
|
-
# Was: send(:scope, path: path_prefix) do
|
817
|
-
send(:namespace, path_prefix) do
|
818
|
-
brick_routes_create.call(schema_name, v[:resource], options)
|
819
|
-
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
820
|
-
brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
|
821
|
-
end
|
822
|
-
end
|
823
|
-
else
|
824
|
-
brick_routes_create.call(schema_name, v[:resource], options)
|
825
|
-
sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
|
826
|
-
brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
|
827
|
-
end
|
828
|
-
end
|
829
843
|
end
|
830
844
|
|
831
845
|
if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
|
@@ -845,7 +859,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
|
|
845
859
|
if Object.const_defined?('Rswag::Ui')
|
846
860
|
rswag_path = ::Rails.application.routes.routes.find { |r| r.app.app == Rswag::Ui::Engine }&.instance_variable_get(:@path_formatter)&.instance_variable_get(:@parts)&.join
|
847
861
|
first_endpoint_parts = nil
|
848
|
-
(doc_endpoints = Rswag::Ui.config.config_object[:urls]
|
862
|
+
(doc_endpoints = Rswag::Ui.config.config_object[:urls])&.each do |doc_endpoint|
|
849
863
|
puts "Mounting OpenApi 3.0 documentation endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
|
850
864
|
send(:get, doc_endpoint[:url], { to: 'brick_openapi#index' })
|
851
865
|
endpoint_parts = doc_endpoint[:url]&.split('/')
|
@@ -1180,8 +1194,13 @@ ActiveSupport.on_load(:active_record) do
|
|
1180
1194
|
arsc.class_exec do
|
1181
1195
|
def self.create(connection, callable = nil, &block)
|
1182
1196
|
relation = (callable || block).call ::ActiveRecord::StatementCache::Params.new
|
1183
|
-
bind_map = ::ActiveRecord::StatementCache::BindMap.new
|
1184
|
-
|
1197
|
+
bind_map = ::ActiveRecord::StatementCache::BindMap.new(
|
1198
|
+
# AR <= 4.2 uses relation.bind_values
|
1199
|
+
relation.respond_to?(:bound_attributes) ? relation.bound_attributes : relation.bind_values
|
1200
|
+
)
|
1201
|
+
options = [self, relation.arel]
|
1202
|
+
options.shift if connection.method(:cacheable_query).arity == 1 # Rails <= 5.0
|
1203
|
+
query_builder = connection.cacheable_query(*options)
|
1185
1204
|
new query_builder, bind_map
|
1186
1205
|
end
|
1187
1206
|
end
|
@@ -1225,7 +1244,8 @@ ActiveSupport.on_load(:active_record) do
|
|
1225
1244
|
end
|
1226
1245
|
end
|
1227
1246
|
|
1228
|
-
if
|
1247
|
+
if ActiveRecord.version < ::Gem::Version.new('6.1') &&
|
1248
|
+
Psych.method(:load).parameters.any? { |param| param.first == :key && param.last == :aliases }
|
1229
1249
|
Psych.class_exec do
|
1230
1250
|
class << self
|
1231
1251
|
alias _original_load load
|
@@ -1267,7 +1287,9 @@ ActiveSupport.on_load(:active_record) do
|
|
1267
1287
|
def initialize(base, associations, joins, eager_loading: true)
|
1268
1288
|
araat = ::ActiveRecord::Associations::AliasTracker
|
1269
1289
|
if araat.respond_to?(:create_with_joins) # Rails 5.0 and 5.1
|
1270
|
-
|
1290
|
+
cwj_options = [base.connection, base.table_name, joins]
|
1291
|
+
cwj_options << base.type_caster if araat.method(:create_with_joins).arity > 3 # Rails <= 5.1
|
1292
|
+
@alias_tracker = araat.create_with_joins(*cwj_options)
|
1271
1293
|
@eager_loading = eager_loading # (Unused in Rails 5.0)
|
1272
1294
|
else # Rails 4.2
|
1273
1295
|
@alias_tracker = araat.create(base.connection, joins)
|
@@ -1636,21 +1658,24 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
|
|
1636
1658
|
end
|
1637
1659
|
|
1638
1660
|
require 'active_model'
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1661
|
+
begin
|
1662
|
+
require 'active_model/type'
|
1663
|
+
require 'active_model/type/value'
|
1664
|
+
class ActiveModel::Type::Value
|
1665
|
+
def initialize(*args, precision: nil, limit: nil, scale: nil)
|
1666
|
+
@precision = precision
|
1667
|
+
@scale = scale
|
1668
|
+
@limit = limit
|
1669
|
+
end
|
1646
1670
|
end
|
1671
|
+
rescue LoadError => e # AR <= 4.2 doesn't have ActiveModel::Type
|
1647
1672
|
end
|
1648
1673
|
|
1649
1674
|
if Object.const_defined?('I18n')
|
1650
1675
|
module I18n::Base
|
1651
1676
|
alias _brick_translate translate
|
1652
1677
|
def translate(key = nil, *args, throw: false, raise: false, locale: nil, **options)
|
1653
|
-
options.merge!(args.pop) if args.
|
1678
|
+
options.merge!(args.pop) if args.last.is_a?(Hash)
|
1654
1679
|
_brick_translate(key = nil, throw: false, raise: false, locale: nil, **options)
|
1655
1680
|
end
|
1656
1681
|
end
|
@@ -1661,8 +1686,12 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
|
|
1661
1686
|
|
1662
1687
|
# Creates the authenticity token for the current request.
|
1663
1688
|
def form_authenticity_token(*args, form_options: {}) # :doc:
|
1664
|
-
|
1665
|
-
|
1689
|
+
if method(:masked_authenticity_token).arity == 1
|
1690
|
+
masked_authenticity_token(session) # AR <= 4.2 doesn't use form_options
|
1691
|
+
else
|
1692
|
+
form_options.merge!(args.pop) if args.last.is_a?(Hash)
|
1693
|
+
masked_authenticity_token(session, form_options: form_options)
|
1694
|
+
end
|
1666
1695
|
end
|
1667
1696
|
end
|
1668
1697
|
|
@@ -1672,7 +1701,7 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
|
|
1672
1701
|
encrypted = if method(:_encrypt).arity == 1
|
1673
1702
|
_encrypt(value) # Rails <= 5.1
|
1674
1703
|
else
|
1675
|
-
if args.
|
1704
|
+
if args.last.is_a?(Hash)
|
1676
1705
|
expires_at ||= args.last[:expires_at]
|
1677
1706
|
expires_in ||= args.last[:expires_in]
|
1678
1707
|
purpose ||= args.last[:purpose]
|
@@ -1685,7 +1714,7 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
|
|
1685
1714
|
if const_defined?('Messages')
|
1686
1715
|
class Messages::Metadata
|
1687
1716
|
def self.wrap(message, *args, expires_at: nil, expires_in: nil, purpose: nil)
|
1688
|
-
if args.
|
1717
|
+
if args.last.is_a?(Hash)
|
1689
1718
|
expires_at ||= args.last[:expires_at]
|
1690
1719
|
expires_in ||= args.last[:expires_in]
|
1691
1720
|
purpose ||= args.last[:purpose]
|
@@ -139,7 +139,7 @@ module Brick
|
|
139
139
|
# Settings for the Brick gem
|
140
140
|
# (By default this auto-creates models, controllers, views, and routes on-the-fly.)
|
141
141
|
|
142
|
-
if ActiveRecord::Base.respond_to?(:brick_select)
|
142
|
+
if ActiveRecord::Base.respond_to?(:brick_select) && !::Brick.initializer_loaded
|
143
143
|
# Mode -- generally :on or :off, or only in :development. Also available is :diag_env which enables only
|
144
144
|
# when the environment variable BRICK is set.
|
145
145
|
Brick.mode = :development
|
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.109
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorin Thwaits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|