brick 1.0.108 → 1.0.109

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e9a085e3f9ba811623d8ebc5d840018348d207b6b1ecab97c066894c44c6ab0
4
- data.tar.gz: 83f32dc71791730d7370f3375b3c19e6cc00e8062efe5b01bdb4cf5aa40b92b9
3
+ metadata.gz: 1621b6af75759b90c788ce080db85608731c2bfc026c82d7bcea011a89c2162e
4
+ data.tar.gz: a4242388d2fa29a12229c620d91b5d572e9e2f7688783beb6963817cf3fac340
5
5
  SHA512:
6
- metadata.gz: dda58c12995437cb95ce60224543d64ef2ed16b0792a083e0def39e7be4569ceaaad86098f6470daf45c358db1d10a1ff350195c0c61ccd3363cbcfae0c344c2
7
- data.tar.gz: 673a82fbbd268c4c8ba590c8eb980fe6e71a62caff710d32ff3b21b3c67927a22ec02380d5d8f8366a1dcadaece238aab3e737f92e879de9da5893dcde0251fa
6
+ metadata.gz: fa089c1bc9663e764b783c639ca9ca24c18a5cbbc788281e11620b33277e87282b6e1a0195d12686b72f53a5ae4a5bcb9e8343e9ef9bb4d97f53fb69ad4619fe
7
+ data.tar.gz: 784eed99a879191dff95b5dfd061f8025d52d3e30eb16b7a754b425c2f4ad58e03e8631949d807f130dc86e55cb3a5e08d215a3f1729b4465c58dc3cecffb96d
@@ -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 ::Gem::Version.new(RUBY_VERSION) >= ::Gem::Version.new('2.6') &&
46
- ActiveRecord.version < ::Gem::Version.new('5.0')
47
- def BigDecimal.new(*args, **kwargs)
48
- BigDecimal(*args, **kwargs)
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
@@ -421,7 +421,10 @@ module ActiveRecord
421
421
  is_distinct = nil
422
422
  wheres = {}
423
423
  params.each do |k, v|
424
- next if ['_brick_schema', '_brick_order', 'controller', 'action'].include?(k)
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)
425
428
 
426
429
  if (where_col = (ks = k.split('.')).last)[-1] == '!'
427
430
  where_col = where_col[0..-2]
@@ -448,7 +451,10 @@ module ActiveRecord
448
451
  # %%% Have once gotten this error with MSSQL referring to http://localhost:3000/warehouse/cold_room_temperatures__archive
449
452
  # ActiveRecord::StatementInvalid (TinyTds::Error: DBPROCESS is dead or not enabled)
450
453
  # Relevant info here: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/402
454
+ is_api = params['_brick_is_api']
451
455
  columns.each do |col|
456
+ next if (col.type.nil? || col.type == :binary) && is_api
457
+
452
458
  col_alias = " AS #{col.name}_" if (col_name = col.name) == 'class'
453
459
  selects << if is_mysql
454
460
  "`#{tbl_no_schema}`.`#{col_name}`#{col_alias}"
@@ -1538,9 +1544,13 @@ class Object
1538
1544
  end
1539
1545
  if (current_api_root || is_openapi) &&
1540
1546
  !params&.key?('_brick_schema') &&
1541
- (referrer_params = request.env['HTTP_REFERER']&.split('?')&.last&.split('&')&.map { |x| x.split('=') }).present?
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?
1542
1552
  if params
1543
- 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 }
1544
1554
  else
1545
1555
  api_params = referrer_params&.to_h
1546
1556
  end
@@ -1651,11 +1661,12 @@ class Object
1651
1661
  order_by, _ = model._brick_calculate_ordering(ordering, true) # Don't do the txt part
1652
1662
 
1653
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)
1654
1665
  @_brick_params = ar_relation.brick_select(params, (selects ||= []), order_by,
1655
1666
  translations = {},
1656
1667
  join_array = ::Brick::JoinArray.new)
1657
1668
 
1658
- if request.format == :js || current_api_root # Asking for JSON?
1669
+ if is_api # Asking for JSON?
1659
1670
  # Apply column renaming
1660
1671
  data = ar_relation.respond_to?(:_select!) ? ar_relation.dup._select!(*selects) : ar_relation.select(selects)
1661
1672
  if data.present? &&
@@ -1667,13 +1678,16 @@ class Object
1667
1678
  end
1668
1679
  end
1669
1680
 
1670
- # %%% Still need to figure out column filtering and transformations
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.
1671
1683
  # proc_result = if (column_filter = ::Brick.config.api_column_filter).is_a?(Proc)
1672
- # object_columns = relation.last[:cols]
1684
+ # object_columns = (relation = model&._brick_relation)[:cols]
1673
1685
  # begin
1674
1686
  # num_args = column_filter.arity.negative? ? 5 : column_filter.arity
1675
1687
  # # object_name, api_version, columns, data
1676
- # column_filter.call(*[relation.first, api_ver_path, object_columns, nil][0...num_args])
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)
1677
1691
  # rescue StandardError => e
1678
1692
  # puts "::Brick.api_column_filter Proc error: #{e.message}"
1679
1693
  # end
@@ -1685,7 +1699,6 @@ class Object
1685
1699
  # else
1686
1700
  # relation.last[:cols]
1687
1701
  # end
1688
- # binding.pry
1689
1702
 
1690
1703
  render inline: { data: data }.to_json, content_type: ['*/*', 'text/html'].include?(request.format) ? 'application/json' : request.format
1691
1704
  return
@@ -1984,7 +1997,6 @@ end.class_exec do
1984
1997
 
1985
1998
  # return if ActiveRecord::Base.connection.current_database == 'postgres'
1986
1999
 
1987
- initializer_loaded = false
1988
2000
  orig_schema = nil
1989
2001
  if (relations = ::Brick.relations).empty?
1990
2002
  # Very first thing, load inflections since we'll be using .pluralize and .singularize on table and model names
@@ -1993,7 +2005,7 @@ end.class_exec do
1993
2005
  end
1994
2006
  # Now the Brick initializer since there may be important schema things configured
1995
2007
  if File.exist?(brick_initializer = ::Rails.root.join('config/initializers/brick.rb'))
1996
- initializer_loaded = load brick_initializer
2008
+ ::Brick.initializer_loaded = load brick_initializer
1997
2009
  end
1998
2010
  # Load the initializer for the Apartment gem a little early so that if .excluded_models and
1999
2011
  # .default_schema are specified then we can work with non-tenanted models more appropriately
@@ -2266,7 +2278,7 @@ ORDER BY 1, 2, c.internal_column_id, acc.position"
2266
2278
  end
2267
2279
  v[:class_name] = (schema_names + [singular]).map(&:camelize).join('::')
2268
2280
  end
2269
- ::Brick.load_additional_references if initializer_loaded
2281
+ ::Brick.load_additional_references if ::Brick.initializer_loaded
2270
2282
 
2271
2283
  if orig_schema && (orig_schema = (orig_schema - ['pg_catalog', 'pg_toast', 'heroku_ext']).first)
2272
2284
  puts "Now switching back to \"#{orig_schema}\" schema."
@@ -2648,8 +2660,10 @@ module Brick
2648
2660
  end
2649
2661
 
2650
2662
  def find_col_renaming(api_ver_path, relation_name)
2651
- (column_renames = ::Brick.config.api_column_renaming&.fetch(api_ver_path, nil) ||
2652
- ::Brick.config.api_column_renaming)&.fetch(relation_name, nil)
2663
+ ::Brick.config.api_column_renaming&.fetch(
2664
+ api_ver_path,
2665
+ ::Brick.config.api_column_renaming&.fetch(relation_name, nil)
2666
+ )
2653
2667
  end
2654
2668
 
2655
2669
  def _class_pk(dotted_name, multitenant)
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 108
8
+ TINY = 109
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
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,9 +682,38 @@ 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
- # First do the API routes if necessary
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] ||= {})
@@ -742,7 +771,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
742
771
  proc_result = if (filter = ::Brick.config.api_filter).is_a?(Proc)
743
772
  begin
744
773
  num_args = filter.arity.negative? ? 6 : filter.arity
745
- 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])
746
775
  rescue StandardError => e
747
776
  puts "::Brick.api_filter Proc error: #{e.message}"
748
777
  end
@@ -811,33 +840,6 @@ In config/initializers/brick.rb appropriate entries would look something like:
811
840
  end
812
841
  end
813
842
  end
814
-
815
- # Track routes being built
816
- if (class_name = v.fetch(:class_name, nil))
817
- if v.key?(:isView)
818
- view_class_length = class_name.length if class_name.length > view_class_length
819
- views
820
- else
821
- table_class_length = class_name.length if class_name.length > table_class_length
822
- tables
823
- end << [class_name, "#{schema_prefix&.tr('.', '/')}#{v[:resource]}"]
824
- end
825
-
826
- # Now the normal routes
827
- if path_prefix
828
- # Was: send(:scope, path: path_prefix) do
829
- send(:namespace, path_prefix) do
830
- brick_routes_create.call(schema_name, v[:resource], options)
831
- sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
832
- brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
833
- end
834
- end
835
- else
836
- brick_routes_create.call(schema_name, v[:resource], options)
837
- sti_subclasses.fetch(class_name, nil)&.each do |sc| # Add any STI subclass routes for this relation
838
- brick_routes_create.call(schema_name, sc.underscore.tr('/', '_').pluralize, options)
839
- end
840
- end
841
843
  end
842
844
 
843
845
  if ::Brick.config.add_status && instance_variable_get(:@set).named_routes.names.exclude?(:brick_status)
@@ -857,7 +859,7 @@ In config/initializers/brick.rb appropriate entries would look something like:
857
859
  if Object.const_defined?('Rswag::Ui')
858
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
859
861
  first_endpoint_parts = nil
860
- (doc_endpoints = Rswag::Ui.config.config_object[:urls]&.uniq!)&.each do |doc_endpoint|
862
+ (doc_endpoints = Rswag::Ui.config.config_object[:urls])&.each do |doc_endpoint|
861
863
  puts "Mounting OpenApi 3.0 documentation endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
862
864
  send(:get, doc_endpoint[:url], { to: 'brick_openapi#index' })
863
865
  endpoint_parts = doc_endpoint[:url]&.split('/')
@@ -1192,8 +1194,13 @@ ActiveSupport.on_load(:active_record) do
1192
1194
  arsc.class_exec do
1193
1195
  def self.create(connection, callable = nil, &block)
1194
1196
  relation = (callable || block).call ::ActiveRecord::StatementCache::Params.new
1195
- bind_map = ::ActiveRecord::StatementCache::BindMap.new relation.bound_attributes
1196
- query_builder = connection.cacheable_query(self, relation.arel)
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)
1197
1204
  new query_builder, bind_map
1198
1205
  end
1199
1206
  end
@@ -1237,7 +1244,8 @@ ActiveSupport.on_load(:active_record) do
1237
1244
  end
1238
1245
  end
1239
1246
 
1240
- if Psych.respond_to?(:unsafe_load) && ActiveRecord.version < ::Gem::Version.new('6.1')
1247
+ if ActiveRecord.version < ::Gem::Version.new('6.1') &&
1248
+ Psych.method(:load).parameters.any? { |param| param.first == :key && param.last == :aliases }
1241
1249
  Psych.class_exec do
1242
1250
  class << self
1243
1251
  alias _original_load load
@@ -1279,7 +1287,9 @@ ActiveSupport.on_load(:active_record) do
1279
1287
  def initialize(base, associations, joins, eager_loading: true)
1280
1288
  araat = ::ActiveRecord::Associations::AliasTracker
1281
1289
  if araat.respond_to?(:create_with_joins) # Rails 5.0 and 5.1
1282
- @alias_tracker = araat.create_with_joins(base.connection, base.table_name, joins)
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)
1283
1293
  @eager_loading = eager_loading # (Unused in Rails 5.0)
1284
1294
  else # Rails 4.2
1285
1295
  @alias_tracker = araat.create(base.connection, joins)
@@ -1648,21 +1658,24 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
1648
1658
  end
1649
1659
 
1650
1660
  require 'active_model'
1651
- require 'active_model/type'
1652
- require 'active_model/type/value'
1653
- class ActiveModel::Type::Value
1654
- def initialize(*args, precision: nil, limit: nil, scale: nil)
1655
- @precision = precision
1656
- @scale = scale
1657
- @limit = limit
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
1658
1670
  end
1671
+ rescue LoadError => e # AR <= 4.2 doesn't have ActiveModel::Type
1659
1672
  end
1660
1673
 
1661
1674
  if Object.const_defined?('I18n')
1662
1675
  module I18n::Base
1663
1676
  alias _brick_translate translate
1664
1677
  def translate(key = nil, *args, throw: false, raise: false, locale: nil, **options)
1665
- options.merge!(args.pop) if args.length > 0 && args.last.is_a?(Hash)
1678
+ options.merge!(args.pop) if args.last.is_a?(Hash)
1666
1679
  _brick_translate(key = nil, throw: false, raise: false, locale: nil, **options)
1667
1680
  end
1668
1681
  end
@@ -1673,8 +1686,12 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
1673
1686
 
1674
1687
  # Creates the authenticity token for the current request.
1675
1688
  def form_authenticity_token(*args, form_options: {}) # :doc:
1676
- form_options.merge!(args.pop) if args.length > 0 && args.last.is_a?(Hash)
1677
- masked_authenticity_token(session, form_options: form_options)
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
1678
1695
  end
1679
1696
  end
1680
1697
 
@@ -1684,7 +1701,7 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
1684
1701
  encrypted = if method(:_encrypt).arity == 1
1685
1702
  _encrypt(value) # Rails <= 5.1
1686
1703
  else
1687
- if args.length > 0 && args.last.is_a?(Hash)
1704
+ if args.last.is_a?(Hash)
1688
1705
  expires_at ||= args.last[:expires_at]
1689
1706
  expires_in ||= args.last[:expires_in]
1690
1707
  purpose ||= args.last[:purpose]
@@ -1697,7 +1714,7 @@ if ActiveRecord.version < ::Gem::Version.new('6.0') && ruby_version >= ::Gem::Ve
1697
1714
  if const_defined?('Messages')
1698
1715
  class Messages::Metadata
1699
1716
  def self.wrap(message, *args, expires_at: nil, expires_in: nil, purpose: nil)
1700
- if args.length > 0 && args.last.is_a?(Hash)
1717
+ if args.last.is_a?(Hash)
1701
1718
  expires_at ||= args.last[:expires_at]
1702
1719
  expires_in ||= args.last[:expires_in]
1703
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.108
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-21 00:00:00.000000000 Z
11
+ date: 2023-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord