brick 1.0.107 → 1.0.109
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/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
|