standardapi 6.0.0.26 → 6.1.0

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -6
  3. data/lib/standard_api.rb +5 -0
  4. data/lib/standard_api/access_control_list.rb +114 -0
  5. data/lib/standard_api/active_record/connection_adapters/postgresql/schema_statements.rb +21 -0
  6. data/lib/standard_api/controller.rb +75 -78
  7. data/lib/standard_api/errors.rb +9 -0
  8. data/lib/standard_api/helpers.rb +66 -13
  9. data/lib/standard_api/includes.rb +9 -0
  10. data/lib/standard_api/middleware/query_encoding.rb +3 -3
  11. data/lib/standard_api/railtie.rb +13 -2
  12. data/lib/standard_api/route_helpers.rb +5 -5
  13. data/lib/standard_api/test_case.rb +24 -14
  14. data/lib/standard_api/test_case/calculate_tests.rb +10 -4
  15. data/lib/standard_api/test_case/create_tests.rb +13 -15
  16. data/lib/standard_api/test_case/index_tests.rb +14 -4
  17. data/lib/standard_api/test_case/schema_tests.rb +25 -3
  18. data/lib/standard_api/test_case/show_tests.rb +1 -0
  19. data/lib/standard_api/test_case/update_tests.rb +8 -9
  20. data/lib/standard_api/version.rb +1 -1
  21. data/lib/standard_api/views/application/_record.json.jbuilder +33 -30
  22. data/lib/standard_api/views/application/_record.streamer +36 -34
  23. data/lib/standard_api/views/application/_schema.json.jbuilder +68 -0
  24. data/lib/standard_api/views/application/_schema.streamer +78 -0
  25. data/lib/standard_api/views/application/new.streamer +1 -1
  26. data/lib/standard_api/views/application/schema.json.jbuilder +1 -12
  27. data/lib/standard_api/views/application/schema.streamer +1 -16
  28. data/test/standard_api/caching_test.rb +43 -0
  29. data/test/standard_api/helpers_test.rb +172 -0
  30. data/test/standard_api/performance.rb +39 -0
  31. data/test/standard_api/route_helpers_test.rb +33 -0
  32. data/test/standard_api/standard_api_test.rb +699 -0
  33. data/test/standard_api/test_app.rb +1 -0
  34. data/test/standard_api/test_app/app/controllers/acl/account_acl.rb +15 -0
  35. data/test/standard_api/test_app/app/controllers/acl/property_acl.rb +27 -0
  36. data/test/standard_api/test_app/app/controllers/acl/reference_acl.rb +7 -0
  37. data/test/standard_api/test_app/controllers.rb +13 -45
  38. data/test/standard_api/test_app/models.rb +38 -4
  39. data/test/standard_api/test_app/test/factories.rb +4 -3
  40. data/test/standard_api/test_app/views/photos/_photo.json.jbuilder +1 -0
  41. data/test/standard_api/test_app/views/photos/_photo.streamer +18 -0
  42. data/test/standard_api/test_app/views/photos/_schema.json.jbuilder +1 -0
  43. data/test/standard_api/test_app/views/photos/_schema.streamer +3 -0
  44. data/test/standard_api/test_app/views/photos/schema.json.jbuilder +1 -1
  45. data/test/standard_api/test_app/views/photos/schema.streamer +1 -0
  46. data/test/standard_api/test_helper.rb +238 -0
  47. metadata +33 -17
  48. data/test/standard_api/test_app/log/test.log +0 -129516
@@ -37,10 +37,10 @@ module StandardAPI
37
37
 
38
38
  test '#index.json params[:limit] does not exceed maximum limit' do
39
39
  return if !resource_limit || resource_limit == Float::INFINITY
40
-
41
- assert_raises ActionController::UnpermittedParameters do
42
- get resource_path(:index, format: :json), params: { limit: resource_limit + 1 }
43
- end
40
+
41
+ get resource_path(:index, format: :json), params: { limit: resource_limit + 1 }
42
+ assert_response :bad_request
43
+ assert_equal 'found unpermitted parameters: :limit, 1001', response.body
44
44
  end
45
45
 
46
46
  test '#index.json params[:where]' do
@@ -69,9 +69,12 @@ module StandardAPI
69
69
  end
70
70
 
71
71
  test '#index.json params[:include]' do
72
+ next if includes.empty?
73
+
72
74
  travel_to Time.now do
73
75
  create_model
74
76
  get resource_path(:index, format: :json), params: { limit: 100, include: includes }
77
+ assert_response :ok
75
78
 
76
79
  json = JSON.parse(response.body)[0]
77
80
  assert json.is_a?(Hash)
@@ -128,6 +131,13 @@ module StandardAPI
128
131
  models = @controller.instance_variable_get("@#{plural_name}")
129
132
  assert_equal model.where(id: m.id).sort(required_orders).to_sql, models.to_sql
130
133
  @controller.current_mask.delete(plural_name)
134
+
135
+ @controller.current_mask[plural_name.to_sym] = { id: m.id }
136
+ get :index, format: :json
137
+ models = @controller.instance_variable_get("@#{plural_name}")
138
+ assert_equal model.where(id: m.id).sort(required_orders).to_sql, models.to_sql
139
+ @controller.current_mask.delete(plural_name.to_sym)
140
+
131
141
  end
132
142
  end
133
143
  end
@@ -9,13 +9,35 @@ module StandardAPI
9
9
  get resource_path(:schema, format: :json)
10
10
  assert_response :ok
11
11
  json = JSON(@response.body)
12
- assert json['columns']
12
+ assert json['attributes']
13
+
13
14
  model.columns.map do |column|
14
- assert json['columns'][column.name]['type'], "Missing `type` for \"#{model}\" attribute \"#{column.name}\""
15
+ actual_column = json['attributes'][column.name]
16
+ assert_not_nil actual_column['type'], "Missing `type` for \"#{model}\" attribute \"#{column.name}\""
17
+ assert_equal_or_nil model.primary_key == column.name, actual_column['primary_key']
18
+ assert_equal_or_nil column.null, actual_column['null']
19
+ assert_equal_or_nil column.array, actual_column['array']
20
+ assert_equal_or_nil column.comment, actual_column['comment']
21
+
22
+ if column.default
23
+ default = model.connection.lookup_cast_type_from_column(column).deserialize(column.default)
24
+ assert_equal default, actual_column['default']
25
+ else
26
+ assert_nil column.default
27
+ end
15
28
  end
29
+
16
30
  assert json['limit']
31
+ assert_equal_or_nil model.connection.table_comment(model.table_name), json['comment']
17
32
  end
18
33
 
34
+ def assert_equal_or_nil(expected, actual, msg=nil)
35
+ if expected.nil?
36
+ assert_nil actual, msg
37
+ else
38
+ assert_equal expected, actual, msg
39
+ end
40
+ end
19
41
  end
20
42
  end
21
- end
43
+ end
@@ -15,6 +15,7 @@ module StandardAPI
15
15
  test '#show.json params[:include]' do
16
16
  m = create_model
17
17
  get resource_path(:show, id: m.id, include: includes, format: :json)
18
+ assert_response :ok
18
19
 
19
20
  json = JSON.parse(response.body)
20
21
  includes.each do |included|
@@ -16,7 +16,7 @@ module StandardAPI
16
16
  put resource_path(:update, :id => m.id, format: format), params: { singular_name => attrs }, as: as
17
17
  assert_response :ok, "Updating #{m.class.name} with #{attrs.inspect}"
18
18
 
19
- view_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
19
+ update_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
20
20
  message = "Model / Attribute: #{m.class.name}##{key}"
21
21
  if value.is_a?(BigDecimal)
22
22
  assert_equal_or_nil normalize_attribute(m, key, attrs[key.to_sym]).to_s.to_f, value.to_s.to_f, message
@@ -34,7 +34,7 @@ module StandardAPI
34
34
  get resource_path(:show, id: m.id), as: :json
35
35
 
36
36
  return if @controller.method(:update).owner != StandardAPI
37
-
37
+
38
38
  attrs = attributes_for(singular_name).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
39
39
  create_webmocks(attrs)
40
40
 
@@ -57,9 +57,9 @@ module StandardAPI
57
57
  assert_response :ok, "Updating #{m.class.name} with #{attrs.inspect}"
58
58
 
59
59
  # (m.attribute_names & attrs.keys.map(&:to_s)).each do |test_key|
60
- view_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
60
+ update_attributes(m.reload).select { |x| attrs.keys.map(&:to_s).include?(x) }.each do |key, value|
61
61
  message = "Model / Attribute: #{m.class.name}##{key}"
62
- assert_equal_or_nil normalize_attribute(m, key, attrs[key.to_sym]), value, message
62
+ assert_equal_or_nil normalize_attribute(m, key, attrs[key.to_sym]), normalize_attribute(m, key, value), message
63
63
  end
64
64
  assert JSON.parse(@response.body).is_a?(Hash)
65
65
  end
@@ -68,8 +68,7 @@ module StandardAPI
68
68
  trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
69
69
 
70
70
  if !trait
71
- Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
72
- warn("No invalid trait for #{model.name}. Skipping invalid tests")
71
+ skip("No invalid trait for #{model.name}. Skipping invalid tests")
73
72
  return
74
73
  end
75
74
 
@@ -94,7 +93,7 @@ module StandardAPI
94
93
 
95
94
  put resource_path(:update, :id => m.id, format: format), params: { include: includes, singular_name => attrs }, as: as
96
95
  assert_response :ok, "Updating #{m.class.name} with #{attrs.inspect}"
97
-
96
+
98
97
  controller_model = @controller.instance_variable_get("@#{singular_name}")
99
98
  json = JSON.parse(response.body)
100
99
  includes.each do |included|
@@ -104,7 +103,7 @@ module StandardAPI
104
103
  next if !association
105
104
 
106
105
  if ['belongs_to', 'has_one'].include?(association.macro.to_s)
107
- view_attributes(controller_model.send(included)) do |key, value|
106
+ update_attributes(controller_model.send(included)) do |key, value|
108
107
  message = "Model / Attribute: #{controller_model.send(included).class.name}##{key}"
109
108
  assert_equal json[included.to_s][key.to_s], value, message
110
109
  end
@@ -118,7 +117,7 @@ module StandardAPI
118
117
  nil
119
118
  end
120
119
 
121
- view_attributes(m).each do |key, value|
120
+ update_attributes(m).each do |key, value|
122
121
  message = "Model / Attribute: #{m.class.name}##{key}"
123
122
  if m_json[key.to_s].nil?
124
123
  assert_nil normalize_to_json(m, key, value), message
@@ -1,3 +1,3 @@
1
1
  module StandardAPI
2
- VERSION = '6.0.0.26'
2
+ VERSION = '6.1.0'
3
3
  end
@@ -6,39 +6,42 @@ end
6
6
 
7
7
  includes.each do |inc, subinc|
8
8
  next if ["limit", "offset", "order", "when", "where", "distinct", "distinct_on"].include?(inc)
9
-
9
+
10
10
  case association = record.class.reflect_on_association(inc)
11
- when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::ThroughReflection
12
- can_cache = can_cache_relation?(record.class, inc, subinc)
13
- json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
14
- partial = model_partial(association.klass)
11
+ when ActiveRecord::Reflection::AbstractReflection
12
+ if association.collection?
13
+ can_cache = can_cache_relation?(record, inc, subinc)
15
14
  json.set! inc do
16
- # TODO limit causes preloaded assocations to reload
17
- sub_records = record.send(inc)
18
-
19
- sub_records = sub_records.limit(subinc['limit']) if subinc['limit']
20
- sub_records = sub_records.offset(subinc['offset']) if subinc['offset']
21
- sub_records = sub_records.order(subinc['order']) if subinc['order']
22
- sub_records = sub_records.filter(subinc['where']) if subinc['where']
23
- sub_records = sub_records.distinct if subinc['distinct']
24
- sub_records = sub_records.distinct_on(subinc['distinct_on']) if subinc['distinct_on']
15
+ json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
16
+ partial = model_partial(association.klass)
17
+
18
+ # TODO limit causes preloaded assocations to reload
19
+ sub_records = record.send(inc)
25
20
 
26
- json.array! sub_records, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
21
+ sub_records = sub_records.limit(subinc['limit']) if subinc['limit']
22
+ sub_records = sub_records.offset(subinc['offset']) if subinc['offset']
23
+ sub_records = sub_records.reorder(subinc['order']) if subinc['order']
24
+ sub_records = sub_records.filter(subinc['where']) if subinc['where']
25
+ sub_records = sub_records.distinct if subinc['distinct']
26
+ sub_records = sub_records.distinct_on(subinc['distinct_on']) if subinc['distinct_on']
27
+
28
+ json.array! sub_records, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
29
+ end
27
30
  end
28
- end
29
- when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
30
- can_cache = can_cache_relation?(record.class, inc, subinc)
31
- if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
32
- can_cache = can_cache && !record.send(association.foreign_key).nil?
33
- end
34
- json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
35
- value = record.send(inc)
36
- if value.nil?
37
- json.set! inc, nil
38
- else
39
- partial = model_partial(value)
40
- json.set! inc do
41
- json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
31
+ else
32
+ can_cache = can_cache_relation?(record, inc, subinc)
33
+ if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
34
+ can_cache = can_cache && !record.send(association.foreign_key).nil?
35
+ end
36
+ json.set! inc do
37
+ json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
38
+ value = record.send(inc)
39
+ if value.nil?
40
+ json.null!
41
+ else
42
+ partial = model_partial(value)
43
+ json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
44
+ end
42
45
  end
43
46
  end
44
47
  end
@@ -57,7 +60,7 @@ includes.each do |inc, subinc|
57
60
  end
58
61
  end
59
62
  end
60
-
63
+
61
64
  end
62
65
 
63
66
  if !record.errors.blank?
@@ -1,5 +1,5 @@
1
1
  json.object! do
2
-
2
+
3
3
  record.attributes.each do |name, value|
4
4
  # Skip if attribute is included in excludes
5
5
  next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name.to_s }
@@ -8,39 +8,41 @@ json.object! do
8
8
 
9
9
  includes.each do |inc, subinc|
10
10
  next if ["limit", "offset", "order", "when", "where", "distinct", "distinct_on"].include?(inc)
11
-
11
+
12
12
  case association = record.class.reflect_on_association(inc)
13
- when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::ThroughReflection
14
- can_cache = can_cache_relation?(record.class, inc, subinc)
15
- json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
16
- partial = model_partial(association.klass)
17
- json.set! inc do
18
- # TODO limit causes preloaded assocations to reload
19
- sub_records = record.send(inc)
13
+ when ActiveRecord::Reflection::AbstractReflection
14
+ if association.collection?
15
+ can_cache = can_cache_relation?(record, inc, subinc)
16
+ json.cache_if!(can_cache, can_cache ? [inc, association_cache_key(record, inc, subinc)] : nil) do
17
+ json.set! inc do
18
+ partial = model_partial(association.klass)
19
+ # TODO limit causes preloaded assocations to reload
20
+ sub_records = record.send(inc)
20
21
 
21
- sub_records = sub_records.limit(subinc['limit']) if subinc['limit']
22
- sub_records = sub_records.offset(subinc['offset']) if subinc['offset']
23
- sub_records = sub_records.order(subinc['order']) if subinc['order']
24
- sub_records = sub_records.filter(subinc['where']) if subinc['where']
25
- sub_records = sub_records.distinct if subinc['distinct']
26
- sub_records = sub_records.distinct_on(subinc['distinct_on']) if subinc['distinct_on']
22
+ sub_records = sub_records.limit(subinc["limit"]) if subinc["limit"]
23
+ sub_records = sub_records.offset(subinc["offset"]) if subinc["offset"]
24
+ sub_records = sub_records.reorder(subinc["order"]) if subinc["order"]
25
+ sub_records = sub_records.filter(subinc["where"]) if subinc["where"]
26
+ sub_records = sub_records.distinct if subinc["distinct"]
27
+ sub_records = sub_records.distinct_on(subinc["distinct_on"]) if subinc["distinct_on"]
27
28
 
28
- json.array! sub_records, partial: partial, as: partial.split('/').last, locals: { includes: subinc }
29
+ json.array! sub_records, partial: partial, as: partial.split("/").last, locals: { includes: subinc }
30
+ end
29
31
  end
30
- end
31
- when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
32
- can_cache = can_cache_relation?(record.class, inc, subinc)
33
- if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
34
- can_cache = can_cache && !record.send(association.foreign_key).nil?
35
- end
36
- json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
37
- value = record.send(inc)
38
- if value.nil?
39
- json.set! inc, nil
40
- else
41
- partial = model_partial(value)
32
+ else
33
+ can_cache = can_cache_relation?(record, inc, subinc)
34
+ if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
35
+ can_cache = can_cache && !record.send(association.foreign_key).nil?
36
+ end
37
+ json.cache_if!(can_cache, can_cache ? [inc, association_cache_key(record, inc, subinc)] : nil) do
42
38
  json.set! inc do
43
- json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
39
+ value = record.send(inc)
40
+ if value.nil?
41
+ json.value! nil
42
+ else
43
+ partial = model_partial(value)
44
+ json.partial! partial, partial.split("/").last.to_sym => value, includes: subinc
45
+ end
44
46
  end
45
47
  end
46
48
  end
@@ -52,20 +54,20 @@ json.object! do
52
54
  elsif value.is_a?(ActiveModel::Model)
53
55
  json.set! inc do
54
56
  partial = model_partial(value)
55
- json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
57
+ json.partial! partial, partial.split("/").last.to_sym => value, includes: subinc
56
58
  end
57
59
  else
58
60
  json.set! inc, value.as_json
59
61
  end
60
62
  end
61
63
  end
62
-
64
+
63
65
  end
64
-
66
+
65
67
  if !record.errors.blank?
66
68
  errs = record.errors.to_hash
67
69
  errs.default_proc = nil
68
- json.set! 'errors', errs
70
+ json.set! "errors", errs
69
71
  end
70
-
72
+
71
73
  end
@@ -0,0 +1,68 @@
1
+ if model.nil? && controller_name == "application"
2
+ routes = Rails.application.routes.routes.reject(&:internal).collect do |route|
3
+ { name: route.name,
4
+ verb: route.verb,
5
+ path: route.path.spec.to_s.gsub(/\(\.format\)\Z/, ''),
6
+ controller: route.requirements[:controller],
7
+ action: route.requirements[:action],
8
+ array: ['index'].include?(route.requirements[:action]) }
9
+ end
10
+
11
+ json.set! 'comment', ActiveRecord::Base.connection.database_comment
12
+
13
+ json.set! 'routes' do
14
+ json.array!(routes) do |route|
15
+ controller = if controller_name = route[:controller]
16
+ begin
17
+ controller_param = controller_name.underscore
18
+ const_name = "#{controller_param.camelize}Controller"
19
+ const = ActiveSupport::Dependencies.constantize(const_name)
20
+ if const.ancestors.include?(StandardAPI::Controller)
21
+ const
22
+ else
23
+ nil
24
+ end
25
+ rescue NameError
26
+ end
27
+ end
28
+
29
+ next if controller.nil?
30
+
31
+ resource_limit = controller.resource_limit if controller.respond_to?(:resource_limit)
32
+
33
+ json.set! 'path', route[:path]
34
+ json.set! 'method', route[:verb]
35
+ json.set! 'model', controller.model&.name
36
+ json.set! 'array', route[:array]
37
+ json.set! 'limit', resource_limit
38
+ end
39
+ end
40
+
41
+ json.set! 'models' do
42
+ models.each do |model|
43
+ json.set! model.name do
44
+ json.partial! partial: schema_partial(model), model: model
45
+ end
46
+ end
47
+ end
48
+
49
+ else
50
+
51
+ json.set! 'attributes' do
52
+ model.columns.each do |column|
53
+ json.set! column.name, {
54
+ type: json_column_type(column.sql_type),
55
+ default: column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil,
56
+ primary_key: column.name == model.primary_key,
57
+ null: column.null,
58
+ array: column.array,
59
+ comment: column.comment
60
+ }
61
+ end
62
+ end
63
+
64
+ json.set! 'limit', resource_limit # This should be removed?
65
+ json.set! 'comment', model.connection.table_comment(model.table_name)
66
+
67
+ end
68
+
@@ -0,0 +1,78 @@
1
+ if model.nil? && controller_name == "application"
2
+ routes = Rails.application.routes.routes.reject(&:internal).collect do |route|
3
+ { name: route.name,
4
+ verb: route.verb,
5
+ path: route.path.spec.to_s.gsub(/\(\.:format\)\Z/, ''),
6
+ controller: route.requirements[:controller],
7
+ action: route.requirements[:action],
8
+ array: ['index'].include?(route.requirements[:action]) }
9
+ end
10
+
11
+ json.object! do
12
+ json.set! 'comment', ActiveRecord::Base.connection.database_comment
13
+
14
+ json.set! 'routes' do
15
+ json.array!(routes) do |route|
16
+ controller = if controller_name = route[:controller]
17
+ begin
18
+ controller_param = controller_name.underscore
19
+ const_name = "#{controller_param.camelize}Controller"
20
+ const = ActiveSupport::Dependencies.constantize(const_name)
21
+ if const.ancestors.include?(StandardAPI::Controller)
22
+ const
23
+ else
24
+ nil
25
+ end
26
+ rescue NameError
27
+ end
28
+ end
29
+
30
+ next if controller.nil?
31
+
32
+ resource_limit = controller.resource_limit if controller.respond_to?(:resource_limit)
33
+
34
+ json.object! do
35
+ json.set! 'path', route[:path]
36
+ json.set! 'method', route[:verb]
37
+ json.set! 'model', controller.model&.name
38
+ json.set! 'array', route[:array]
39
+ json.set! 'limit', resource_limit
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ json.set! 'models' do
46
+ json.object! do
47
+ models.each do |model|
48
+ json.set! model.name do
49
+ json.partial!(schema_partial(model), model: model)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+ else
57
+
58
+ json.object! do
59
+ json.set! 'attributes' do
60
+ json.object! do
61
+ model.columns.each do |column|
62
+ json.set! column.name, {
63
+ type: json_column_type(column.sql_type),
64
+ default: column.default ? model.connection.lookup_cast_type_from_column(column).deserialize(column.default) : nil,
65
+ primary_key: column.name == model.primary_key,
66
+ null: column.null,
67
+ array: column.array,
68
+ comment: column.comment
69
+ }
70
+ end
71
+ end
72
+ end
73
+
74
+ json.set! 'limit', resource_limit
75
+ json.set! 'comment', model.connection.table_comment(model.table_name)
76
+ end
77
+
78
+ end