brick 1.0.104 → 1.0.105

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: 6d30161a8558282149a49e7eafbd43bb175ce95574178c65a75323eaacf96422
4
- data.tar.gz: 6d56c5e77c2a0d120bc8e878bde9d33fdfa7d58bed690a21fea176d5d6b55d50
3
+ metadata.gz: 48fc69654d7cbdf5c7feb9ba7803b7a953c6c0ccd3c176614fe9a61994bb39e1
4
+ data.tar.gz: f3a4837d334cf97cb491cacd658cb6e6d8e3f3a5c640f80c151a083bf6811b7a
5
5
  SHA512:
6
- metadata.gz: 14bfffec6fd768d4b3abff2b3ceaeb2a2dca29b167edd64c2e57a63c72eaa70bf46fc8056af25fca86812bfac63d3b793bdeaf7f13a8c2ba7834ac9e65f1fb16
7
- data.tar.gz: 97f7c94051bb068c4d8bdb5e847e53576c8ebbe18d5c4c93e12d52566008ac612bb40f7088ba81fea21337a3c13c29f366fb993b77f2f88f9fbddea4ffb95982
6
+ metadata.gz: e51134710bae78f033b9dcf7827cd7c087cfd642ef8bc6244e2429f22158a80e9f804022bc703f55fa55f85cbc009ff25440289205ade1b415f5ba0af3d44c77
7
+ data.tar.gz: d6069676ad70e8401f7597b92b641f0f95e3c28fffa54747f630932500c778d7b4ac967c5bbd70059647d11d398598362d9c0bb5c82ef0500b1025371104a578
data/lib/brick/config.rb CHANGED
@@ -94,13 +94,13 @@ module Brick
94
94
  @mutex.synchronize { @enable_api = enable }
95
95
  end
96
96
 
97
- def api_root
97
+ def api_roots
98
98
  ver = api_version
99
- @mutex.synchronize { @api_root || "/api/#{ver}/" }
99
+ @mutex.synchronize { @api_roots || ["/api/#{ver}/"] }
100
100
  end
101
101
 
102
- def api_root=(path)
103
- @mutex.synchronize { @api_root = path }
102
+ def api_roots=(path)
103
+ @mutex.synchronize { @api_roots = path }
104
104
  end
105
105
 
106
106
  def api_version
@@ -1526,7 +1526,11 @@ class Object
1526
1526
  self.protect_from_forgery unless: -> { self.request.format.js? }
1527
1527
  unless is_avo
1528
1528
  self.define_method :index do
1529
- if (is_openapi || request.env['REQUEST_PATH'].start_with?(::Brick.api_root)) &&
1529
+ current_api_root = ::Brick.config.api_roots.find do |ar|
1530
+ request.path.start_with?(ar) || # Exact match?
1531
+ request.path.split('/')[-2] == ar.split('/').last # Version at least matches?
1532
+ end
1533
+ if (current_api_root || is_openapi) &&
1530
1534
  !params&.key?('_brick_schema') &&
1531
1535
  (referrer_params = request.env['HTTP_REFERER']&.split('?')&.last&.split('&')&.map { |x| x.split('=') }).present?
1532
1536
  if params
@@ -1538,6 +1542,7 @@ class Object
1538
1542
  _schema, @_is_show_schema_list = ::Brick.set_db_schema(params || api_params)
1539
1543
 
1540
1544
  if is_openapi
1545
+ current_api_ver = current_api_root.split('/').last&.[](1..-1).to_i
1541
1546
  json = { 'openapi': '3.0.1', 'info': { 'title': Rswag::Ui.config.config_object[:urls].last&.fetch(:name, 'API documentation'), 'version': ::Brick.config.api_version },
1542
1547
  'servers': [
1543
1548
  { 'url': '{scheme}://{defaultHost}', 'variables': {
@@ -1546,15 +1551,19 @@ class Object
1546
1551
  } }
1547
1552
  ]
1548
1553
  }
1549
- json['paths'] = relations.inject({}) do |s, relation|
1554
+ json['paths'] = relations.each_with_object({}) do |relation, s|
1550
1555
  unless ::Brick.config.enable_api == false
1556
+ next if (api_vers = relation.last.fetch(:api, nil)) &&
1557
+ !(api_ver_path = api_vers[current_api_ver])
1558
+
1559
+ relation_name = api_ver_path || relation.first.tr('.', '/')
1551
1560
  table_description = relation.last[:description]
1552
- s["#{::Brick.config.api_root}#{relation.first.tr('.', '/')}"] = {
1561
+ s["#{current_api_root}#{relation_name}"] = {
1553
1562
  'get': {
1554
1563
  'summary': "list #{relation.first}",
1555
1564
  'description': table_description,
1556
1565
  'parameters': relation.last[:cols].map do |k, v|
1557
- param = { 'name' => k, 'schema': { 'type': v.first } }
1566
+ param = { in: 'query', 'name' => k, 'schema': { 'type': v.first } }
1558
1567
  if (col_descrip = relation.last.fetch(:col_descrips, nil)&.fetch(k, nil))
1559
1568
  param['description'] = col_descrip
1560
1569
  end
@@ -1564,7 +1573,7 @@ class Object
1564
1573
  }
1565
1574
  }
1566
1575
 
1567
- s["#{::Brick.config.api_root}#{relation.first.tr('.', '/')}/{id}"] = {
1576
+ s["#{current_api_root}#{relation_name}/{id}"] = {
1568
1577
  'patch': {
1569
1578
  'summary': "update a #{relation.first.singularize}",
1570
1579
  'description': table_description,
@@ -1578,7 +1587,6 @@ class Object
1578
1587
  'responses': { '200': { 'description': 'successful' } }
1579
1588
  }
1580
1589
  } unless relation.last.fetch(:isView, nil)
1581
- s
1582
1590
  end
1583
1591
  end
1584
1592
  render inline: json.to_json, content_type: request.format
@@ -1592,9 +1600,10 @@ class Object
1592
1600
  end
1593
1601
  render inline: exported_csv, content_type: request.format
1594
1602
  return
1595
- elsif request.format == :js || request.path.start_with?('/api/') # Asking for JSON?
1603
+ elsif request.format == :js || current_api_root # Asking for JSON?
1604
+ # %%% Add: where, order, page, page_size, offset, limit
1596
1605
  data = (model.is_view? || !Object.const_defined?('DutyFree')) ? model.limit(1000) : model.df_export(model.brick_import_template)
1597
- render inline: data.to_json, content_type: request.format == '*/*' ? 'application/json' : request.format
1606
+ render inline: { data: data }.to_json, content_type: request.format == '*/*' ? 'application/json' : request.format
1598
1607
  return
1599
1608
  end
1600
1609
 
@@ -464,7 +464,7 @@ window.addEventListener(\"popstate\", linkSchemas);
464
464
  table_options << "<option value=\"#{prefix}brick_orphans\">(Orphans)</option>".html_safe if is_orphans
465
465
  table_options << "<option value=\"#{prefix}brick_orphans\">(Crosstab)</option>".html_safe if is_crosstab
466
466
  css = +"<style>
467
- #titleBox {
467
+ #titleSticky {
468
468
  position: sticky;
469
469
  display: inline-block;
470
470
  left: 0;
@@ -881,6 +881,7 @@ if (grid) {
881
881
  // });
882
882
  }
883
883
  function setHeaderSizes() {
884
+ document.getElementById(\"titleBox\").style.width = grid.clientWidth;
884
885
  // console.log(\"start\");
885
886
  // See if the headerTop is already populated
886
887
  // %%% Grab the TRs from headerTop, clear it out, do this stuff, add them back
@@ -1127,7 +1128,7 @@ erDiagram
1127
1128
  %></title>
1128
1129
  </head>
1129
1130
  <body>
1130
- <div id=\"titleBox\">
1131
+ <div id=\"titleBox\"><div id=\"titleSticky\">
1131
1132
  <p style=\"color: green\"><%= notice %></p>#{"
1132
1133
  #{schema_options}" if schema_options}
1133
1134
  <select id=\"tbl\">#{table_options}</select>
@@ -1182,7 +1183,7 @@ erDiagram
1182
1183
  });
1183
1184
  </script>
1184
1185
  <% end %>
1185
- </div>
1186
+ </div></div>
1186
1187
  #{erd_markup}
1187
1188
 
1188
1189
  <%= # Consider getting the name from the association -- hm.first.name -- if a more \"friendly\" alias should be used for a screwy table name
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 104
8
+ TINY = 105
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
@@ -334,12 +334,17 @@ module Brick
334
334
 
335
335
  # @api public
336
336
  def api_root=(path)
337
- Brick.config.api_root = path
337
+ Brick.config.api_roots = [path]
338
338
  end
339
339
 
340
340
  # @api public
341
- def api_root
342
- Brick.config.api_root
341
+ def api_roots=(paths)
342
+ Brick.config.api_roots = paths
343
+ end
344
+
345
+ # @api public
346
+ def api_roots
347
+ Brick.config.api_roots
343
348
  end
344
349
 
345
350
  # @api public
@@ -657,19 +662,65 @@ In config/initializers/brick.rb appropriate entries would look something like:
657
662
  # Turn something like {"::Spouse"=>"Person", "::Friend"=>"Person"} into {"Person"=>["Spouse", "Friend"]}
658
663
  s[v.last] << v.first[2..-1] unless v.first.end_with?('::')
659
664
  end
665
+ versioned_views = {} # Track which views have already been done for each api_root
660
666
  ::Brick.relations.each do |k, v|
661
667
  next if !(controller_name = v.fetch(:resource, nil)&.pluralize) || existing_controllers.key?(controller_name)
662
668
 
669
+ schema_name = v.fetch(:schema, nil)
663
670
  options = {}
664
671
  options[:only] = [:index, :show] if v.key?(:isView)
665
- # First do the API routes
672
+ # First do the API routes if necessary
666
673
  full_resource = nil
667
- if (schema_name = v.fetch(:schema, nil))
668
- full_resource = "#{schema_name}/#{v[:resource]}"
669
- send(:get, "#{::Brick.api_root}#{full_resource}", { to: "#{controller_prefix}#{schema_name}/#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
670
- else
671
- # Normally goes to something like: /api/v1/employees
672
- send(:get, "#{::Brick.api_root}#{v[:resource]}", { to: "#{controller_prefix}#{controller_name}#index" }) if Object.const_defined?('Rswag::Ui')
674
+ ::Brick.api_roots&.each do |api_root|
675
+ api_done_views = (versioned_views[api_root] ||= {})
676
+ found = nil
677
+ view_relation = nil
678
+ # If it's a view then see if there's a versioned one available by searching for resource names
679
+ # versioned with the closest number (equal to or less than) compared with our API version number.
680
+ if v.key?(:isView) && (ver = k.match(/^v([\d_]*)/).captures.first)[-1] == '_'
681
+ next if api_done_views.key?(unversioned = k[ver.length + 1..-1])
682
+
683
+ # # if ().length.positive? # Does it have a version number?
684
+ # try_num = (ver_num = (ver = ver[1..-1].gsub('_', '.')).to_d)
685
+
686
+ # Expect that the last item in the path generally holds versioning information
687
+ api_ver = api_root.split('/')[-1]&.gsub('_', '.')
688
+ vn_idx = api_ver.rindex(/[^\d._]/) # Position of the first numeric digit at the end of the version number
689
+ # Was: .to_d
690
+ api_ver_num = api_ver[vn_idx + 1..-1].gsub('_', '.').to_i # Attempt to turn something like "v3" into the decimal value 3
691
+ # puts [api_ver, vn_idx, api_ver_num, unversioned].inspect
692
+
693
+ next if ver.to_i > api_ver_num # Don't surface any newer views in an older API
694
+
695
+ api_ver_num -= 1 until api_ver_num.zero? ||
696
+ (view_relation = ::Brick.relations.fetch(
697
+ found = "v#{api_ver_num}_#{k[ver.length + 1..-1]}", nil
698
+ ))
699
+ api_done_views[unversioned] = nil # Mark that for this API version this view is done
700
+
701
+ # puts "Found #{found}" if view_relation
702
+ # If we haven't found "v3_view_name" or "v2_view_name" or so forth, at the last
703
+ # fall back to simply looking for "v_view_name", and then finally "view_name".
704
+ unversioned = "v_#{unversioned}"
705
+ view_relation ||= ::Brick.relations.fetch(found = unversioned,
706
+ ::Brick.relations.fetch(found = unversioned, nil)
707
+ )
708
+ if found && view_relation && k != (found = unversioned)
709
+ view_relation[:api][api_ver_num] = found
710
+ end
711
+ end
712
+
713
+ # view_ver_num = if (first_part = k.split('_').first) =~ /^v[\d_]+/
714
+ # first_part[1..-1].gsub('_', '.').to_i
715
+ # end
716
+ controller_name = view_relation.fetch(:resource, nil)&.pluralize if view_relation
717
+ if schema_name
718
+ full_resource = "#{schema_name}/#{found || v[:resource]}"
719
+ send(:get, "#{api_root}#{full_resource}", { to: "#{controller_prefix}#{schema_name}/#{controller_name}#index" })
720
+ else
721
+ # Normally goes to something like: /api/v1/employees
722
+ send(:get, "#{api_root}#{found || v[:resource]}", { to: "#{controller_prefix}#{controller_name}#index" })
723
+ end
673
724
  end
674
725
 
675
726
  # Track routes being built
@@ -716,15 +767,19 @@ In config/initializers/brick.rb appropriate entries would look something like:
716
767
  unless ::Brick.routes_done
717
768
  if Object.const_defined?('Rswag::Ui')
718
769
  rswag_path = ::Rails.application.routes.routes.find { |r| r.app.app == Rswag::Ui::Engine }&.instance_variable_get(:@path_formatter)&.instance_variable_get(:@parts)&.join
719
- if (doc_endpoint = Rswag::Ui.config.config_object[:urls]&.last)
770
+ first_endpoint_parts = nil
771
+ (doc_endpoints = Rswag::Ui.config.config_object[:urls]&.uniq!)&.each do |doc_endpoint|
720
772
  puts "Mounting OpenApi 3.0 documentation endpoint for \"#{doc_endpoint[:name]}\" on #{doc_endpoint[:url]}"
721
773
  send(:get, doc_endpoint[:url], { to: 'brick_openapi#index' })
722
774
  endpoint_parts = doc_endpoint[:url]&.split('/')
723
- if rswag_path && endpoint_parts
724
- puts "API documentation now available when navigating to: /#{endpoint_parts&.find(&:present?)}/index.html"
775
+ first_endpoint_parts ||= endpoint_parts
776
+ end
777
+ if doc_endpoints.present?
778
+ if rswag_path && first_endpoint_parts
779
+ puts "API documentation now available when navigating to: /#{first_endpoint_parts&.find(&:present?)}/index.html"
725
780
  else
726
781
  puts "In order to make documentation available you can put this into your routes.rb:"
727
- puts " mount Rswag::Ui::Engine => '/#{endpoint_parts&.find(&:present?) || 'api-docs'}'"
782
+ puts " mount Rswag::Ui::Engine => '/#{first_endpoint_parts&.find(&:present?) || 'api-docs'}'"
728
783
  end
729
784
  else
730
785
  sample_path = rswag_path || '/api-docs'
@@ -159,8 +159,9 @@ if ActiveRecord::Base.respond_to?(:brick_select)
159
159
  # Brick.enable_views = true # Setting this to \"false\" will disable views in development
160
160
 
161
161
  # # If The Brick sees that RSwag gem is present, it allows for API resources to be automatically served out.
162
- # # You can configure the root path for these resources:
163
- # ::Brick.api_root = '/api/v1/'
162
+ # # You can configure one or more root path(s) for these resources, and when there are multiple then an attempt
163
+ # # is made to return data from that version of the view or table name, or the most recent prior to that version:
164
+ # ::Brick.api_roots = ['/api/v1/']
164
165
  # # You may also want to add an OpenAPI 3.0 documentation endpoint using Rswag::Ui:
165
166
  # Rswag::Ui.configure do |config|
166
167
  # config.swagger_endpoint '/api-docs/v1/swagger.json', 'API V1 Docs'
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.104
4
+ version: 1.0.105
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-15 00:00:00.000000000 Z
11
+ date: 2023-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: 1.42.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: mysql2
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.5'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.5'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: pg
169
183
  requirement: !ruby/object:Gem::Requirement