standardapi 5.0.0.16 → 5.2.0.2
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 +5 -5
- data/README.md +25 -1
- data/lib/standard_api/controller.rb +30 -24
- data/lib/standard_api/helpers.rb +3 -3
- data/lib/standard_api/includes.rb +5 -2
- data/lib/standard_api/test_case/create_tests.rb +21 -4
- data/lib/standard_api/test_case/index_tests.rb +9 -21
- data/lib/standard_api/test_case/schema_tests.rb +1 -1
- data/lib/standard_api/test_case/update_tests.rb +2 -1
- data/lib/standard_api/test_case.rb +16 -7
- data/lib/standard_api/version.rb +1 -1
- data/lib/standard_api/views/application/_record.streamer +63 -0
- data/lib/standard_api/views/application/index.streamer +12 -0
- data/lib/standard_api/views/application/new.streamer +1 -0
- data/lib/standard_api/views/application/schema.json.jbuilder +3 -1
- data/lib/standard_api/views/application/schema.streamer +39 -0
- data/lib/standard_api/views/application/show.streamer +1 -0
- data/lib/standard_api.rb +1 -2
- metadata +41 -43
- data/lib/standard_api/views/application/settings.json.jbuilder +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 07e04cf1267208519f3837a0b7881786d55a053f3e3304e5e7599d01fb72102d
|
4
|
+
data.tar.gz: 7bf8e046a0ef987a912001df5075537961651d9ddcc6cccab31fb2a690b1e1cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 949c1c8abf9098956e5ceca14978b725b157fa604eeb8e4c60213e0eb84e841fd551088097bcedc8e39106442cd5ea4fd9f779f41fb05b41531556b7007bc3f5
|
7
|
+
data.tar.gz: 6c381c38daca817c906d11eda4f67c77d8bb2353f3c454f783da7a6d1fde3938335e4159e50f8c358ae46b33fd4492c2cfd6b1127cdfefd4ff8d2f1de9ab7697
|
data/README.md
CHANGED
@@ -7,10 +7,34 @@ interface to your Rails models.
|
|
7
7
|
|
8
8
|
gem install standardapi
|
9
9
|
|
10
|
-
In your Gemfile
|
10
|
+
In your Gemfile:
|
11
11
|
|
12
12
|
gem 'standardapi', require: 'standard_api'
|
13
13
|
|
14
|
+
In `config/application.rb:
|
15
|
+
|
16
|
+
require_relative 'boot'
|
17
|
+
|
18
|
+
require 'rails/all'
|
19
|
+
require 'standard_api/middleware/query_encoding'
|
20
|
+
|
21
|
+
# Require the gems listed in Gemfile, including any gems
|
22
|
+
# you've limited to :test, :development, or :production.
|
23
|
+
Bundler.require(*Rails.groups)
|
24
|
+
|
25
|
+
module Tester
|
26
|
+
class Application < Rails::Application
|
27
|
+
# Initialize configuration defaults for originally generated Rails version.
|
28
|
+
config.load_defaults 5.2
|
29
|
+
|
30
|
+
# Settings in config/environments/* take precedence over those specified here.
|
31
|
+
# Application configuration can go into files in config/initializers
|
32
|
+
# -- all .rb files in that directory are automatically loaded after loading
|
33
|
+
# the framework and any gems in your application.
|
34
|
+
config.middleware.insert_after Rack::MethodOverride, StandardAPI::Middleware::QueryEncoding
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
14
38
|
# Usage
|
15
39
|
|
16
40
|
StandardAPI is a module that can be included into any controller to expose a API
|
@@ -42,10 +42,15 @@ module StandardAPI
|
|
42
42
|
def create
|
43
43
|
record = model.new(model_params)
|
44
44
|
instance_variable_set("@#{model.model_name.singular}", record)
|
45
|
-
|
45
|
+
|
46
46
|
if record.save
|
47
47
|
if request.format == :html
|
48
|
-
redirect_to
|
48
|
+
redirect_to url_for(
|
49
|
+
controller: record.class.base_class.model_name.collection,
|
50
|
+
action: 'show',
|
51
|
+
id: record.id,
|
52
|
+
only_path: true
|
53
|
+
)
|
49
54
|
else
|
50
55
|
render :show, status: :created
|
51
56
|
end
|
@@ -64,7 +69,12 @@ module StandardAPI
|
|
64
69
|
|
65
70
|
if record.update_attributes(model_params)
|
66
71
|
if request.format == :html
|
67
|
-
redirect_to
|
72
|
+
redirect_to url_for(
|
73
|
+
controller: record.class.base_class.model_name.collection,
|
74
|
+
action: 'show',
|
75
|
+
id: record.id,
|
76
|
+
only_path: true
|
77
|
+
)
|
68
78
|
else
|
69
79
|
render :show, status: :ok
|
70
80
|
end
|
@@ -90,22 +100,6 @@ module StandardAPI
|
|
90
100
|
@model = name.sub(/Controller\z/, '').singularize.camelize.safe_constantize
|
91
101
|
end
|
92
102
|
|
93
|
-
def model_includes
|
94
|
-
if self.respond_to?("#{model.model_name.singular}_includes", true)
|
95
|
-
self.send "#{model.model_name.singular}_includes"
|
96
|
-
else
|
97
|
-
[]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def model_orders
|
102
|
-
if self.respond_to?("#{model.model_name.singular}_orders", true)
|
103
|
-
self.send "#{model.model_name.singular}_orders"
|
104
|
-
else
|
105
|
-
[]
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
103
|
end
|
110
104
|
|
111
105
|
private
|
@@ -119,11 +113,19 @@ module StandardAPI
|
|
119
113
|
end
|
120
114
|
|
121
115
|
def model_includes
|
122
|
-
self.
|
116
|
+
if self.respond_to?("#{model.model_name.singular}_includes", true)
|
117
|
+
self.send("#{model.model_name.singular}_includes")
|
118
|
+
else
|
119
|
+
[]
|
120
|
+
end
|
123
121
|
end
|
124
122
|
|
125
123
|
def model_orders
|
126
|
-
self.
|
124
|
+
if self.respond_to?("#{model.model_name.singular}_orders", true)
|
125
|
+
self.send("#{model.model_name.singular}_orders")
|
126
|
+
else
|
127
|
+
[]
|
128
|
+
end
|
127
129
|
end
|
128
130
|
|
129
131
|
def model_params
|
@@ -166,6 +168,10 @@ module StandardAPI
|
|
166
168
|
def required_orders
|
167
169
|
[]
|
168
170
|
end
|
171
|
+
|
172
|
+
def default_orders
|
173
|
+
nil
|
174
|
+
end
|
169
175
|
|
170
176
|
def orders
|
171
177
|
exluded_required_orders = required_orders.map(&:to_s)
|
@@ -189,8 +195,8 @@ module StandardAPI
|
|
189
195
|
if !exluded_required_orders.empty?
|
190
196
|
params[:order] = exluded_required_orders.unshift(params[:order])
|
191
197
|
end
|
192
|
-
|
193
|
-
@orders ||= StandardAPI::Orders.sanitize(params[:order], model_orders | required_orders)
|
198
|
+
|
199
|
+
@orders ||= StandardAPI::Orders.sanitize(params[:order] || default_orders, model_orders | required_orders)
|
194
200
|
end
|
195
201
|
|
196
202
|
def excludes
|
@@ -231,7 +237,7 @@ module StandardAPI
|
|
231
237
|
select.each do |func, column|
|
232
238
|
column = column == '*' ? Arel.star : column.to_sym
|
233
239
|
if functions.include?(func.to_s.downcase)
|
234
|
-
@selects << (model.arel_table[column].send(func)
|
240
|
+
@selects << (model.arel_table[column].send(func))
|
235
241
|
end
|
236
242
|
end
|
237
243
|
end
|
data/lib/standard_api/helpers.rb
CHANGED
@@ -19,7 +19,7 @@ module StandardAPI
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def cache_key(record, includes)
|
22
|
-
timestamp_keys = ['cached_at'] +
|
22
|
+
timestamp_keys = ['cached_at'] + record.class.column_names.select{|x| x.ends_with? "_cached_at"}
|
23
23
|
if includes.empty?
|
24
24
|
record.cache_key(*timestamp_keys)
|
25
25
|
else
|
@@ -58,9 +58,9 @@ module StandardAPI
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def cached_at_columns_for_includes(includes)
|
61
|
-
includes.select{|k,v| ![:where, :limit, :order].include?(k.to_sym) }.map
|
61
|
+
includes.select { |k,v| ![:where, :limit, :order].include?(k.to_sym) }.map do |k, v|
|
62
62
|
["#{k}_cached_at"] + cached_at_columns_for_includes(v).map { |v2| "#{k}_#{v2}" }
|
63
|
-
|
63
|
+
end.flatten
|
64
64
|
end
|
65
65
|
|
66
66
|
def includes_to_cache_key(relation, subincludes)
|
@@ -17,8 +17,11 @@ module StandardAPI
|
|
17
17
|
includes.flatten.compact.each { |v| normalized.merge!(normalize(v)) }
|
18
18
|
when Hash, ActionController::Parameters
|
19
19
|
includes.each_pair do |k, v|
|
20
|
-
if ['where', 'order'].include?(k.to_s) # Where and order are not normalized
|
21
|
-
normalized[k] = v
|
20
|
+
if ['where', 'order'].include?(k.to_s) # Where and order are not normalized (sanitation happens in activerecord-filter)
|
21
|
+
normalized[k] = case v
|
22
|
+
when Hash then v.to_h
|
23
|
+
when ActionController::Parameters then v.to_unsafe_h
|
24
|
+
end
|
22
25
|
else
|
23
26
|
normalized[k] = normalize(v)
|
24
27
|
end
|
@@ -4,7 +4,8 @@ module StandardAPI
|
|
4
4
|
extend ActiveSupport::Testing::Declarative
|
5
5
|
|
6
6
|
test '#create.json' do
|
7
|
-
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
7
|
+
attrs = attributes_for(singular_name, :nested).select{ |k,v| !model.readonly_attributes.include?(k.to_s) }
|
8
|
+
mask.each { |k, v| attrs[k] = v }
|
8
9
|
create_webmocks(attrs)
|
9
10
|
|
10
11
|
file_upload = attrs.any? { |k, v| v.is_a?(Rack::Test::UploadedFile) }
|
@@ -34,6 +35,7 @@ module StandardAPI
|
|
34
35
|
|
35
36
|
test '#create.json with nested attributes' do
|
36
37
|
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
38
|
+
mask.each { |k, v| attrs[k] = v }
|
37
39
|
create_webmocks(attrs)
|
38
40
|
|
39
41
|
file_upload = attrs.any? { |k, v| v.is_a?(Rack::Test::UploadedFile) }
|
@@ -59,7 +61,7 @@ module StandardAPI
|
|
59
61
|
end
|
60
62
|
|
61
63
|
test '#create.json with invalid attributes' do
|
62
|
-
trait =
|
64
|
+
trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
63
65
|
|
64
66
|
if !trait
|
65
67
|
Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
|
@@ -82,10 +84,26 @@ module StandardAPI
|
|
82
84
|
end
|
83
85
|
end
|
84
86
|
|
87
|
+
test '#create.html' do
|
88
|
+
return unless supports_format(:html)
|
89
|
+
|
90
|
+
attrs = attributes_for(singular_name, :nested).select{ |k,v| !model.readonly_attributes.include?(k.to_s) }
|
91
|
+
mask.each { |k, v| attrs[k] = v }
|
92
|
+
create_webmocks(attrs)
|
93
|
+
|
94
|
+
file_upload = attrs.any? { |k, v| v.is_a?(Rack::Test::UploadedFile) }
|
95
|
+
as = file_upload ? nil : :json
|
96
|
+
|
97
|
+
assert_difference("#{model.name}.count") do
|
98
|
+
post resource_path(:create), params: { singular_name => attrs }, as: :html
|
99
|
+
assert_response :redirect
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
85
103
|
test '#create.html with invalid attributes renders edit action' do
|
86
104
|
return unless supports_format(:html)
|
87
105
|
|
88
|
-
trait =
|
106
|
+
trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
89
107
|
|
90
108
|
if !trait
|
91
109
|
Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
|
@@ -99,7 +117,6 @@ module StandardAPI
|
|
99
117
|
assert_difference("#{model.name}.count", 0) do
|
100
118
|
post resource_path(:create), params: { singular_name => attrs }, as: :html
|
101
119
|
assert_response :bad_request
|
102
|
-
assert_equal response.body, 'properties#edit.html'
|
103
120
|
end
|
104
121
|
end
|
105
122
|
|
@@ -12,37 +12,26 @@ module StandardAPI
|
|
12
12
|
end
|
13
13
|
|
14
14
|
test '#index.json requires limit' do
|
15
|
-
|
16
|
-
|
17
|
-
return if !limit || limit == Float::INFINITY
|
15
|
+
return if !resource_limit || resource_limit == Float::INFINITY
|
18
16
|
|
19
17
|
begin
|
20
18
|
get resource_path(:index, format: :json)
|
21
19
|
assert_response :bad_request
|
22
20
|
rescue ActionController::ParameterMissing
|
23
21
|
end
|
24
|
-
|
25
|
-
# return if !controller_class.new.send(:resource_limit)
|
26
|
-
# if app.config.action_dispatch.show_exceptions
|
27
|
-
# assert_raises ActionController::ParameterMissing do
|
28
|
-
# get resource_path(:index, format: 'json')
|
29
|
-
# assert_response :bad_request
|
30
|
-
# end
|
31
|
-
# else
|
32
|
-
# get resource_path(:index, format: :json)
|
33
|
-
# assert_response :bad_request
|
34
|
-
# end
|
35
22
|
end
|
36
23
|
|
37
24
|
test '#index.json params[:limit]' do
|
38
25
|
get resource_path(:index, format: :json), params: { limit: 1 }
|
39
26
|
models = @controller.instance_variable_get("@#{plural_name}")
|
40
|
-
assert_equal model.limit(1).sort(
|
27
|
+
assert_equal model.filter(mask).limit(1).sort(default_orders).to_sql, models.to_sql
|
41
28
|
end
|
42
29
|
|
43
30
|
test '#index.json params[:limit] does not exceed maximum limit' do
|
31
|
+
return if !resource_limit || resource_limit == Float::INFINITY
|
32
|
+
|
44
33
|
assert_raises ActionController::UnpermittedParameters do
|
45
|
-
get resource_path(:index, format: :json), params: { limit:
|
34
|
+
get resource_path(:index, format: :json), params: { limit: resource_limit + 1 }
|
46
35
|
end
|
47
36
|
end
|
48
37
|
|
@@ -59,24 +48,23 @@ module StandardAPI
|
|
59
48
|
get resource_path(:index, format: :json), params: { limit: 1 }
|
60
49
|
|
61
50
|
orders.each do |order|
|
62
|
-
@controller.instance_variable_set('@orders', nil) # Hack for dealing with caching / multiple request per controller life
|
63
51
|
get resource_path(:index, format: :json), params: { limit: 10, order: order }
|
64
52
|
models = @controller.instance_variable_get("@#{plural_name}")
|
65
|
-
assert_equal model.sort(order).limit(10).sort(
|
66
|
-
|
53
|
+
assert_equal model.filter(mask).sort(order).limit(10).sort(order).to_sql, models.to_sql
|
54
|
+
end
|
67
55
|
end
|
68
56
|
|
69
57
|
test '#index.json params[:offset]' do
|
70
58
|
get resource_path(:index, format: :json), params: { limit: 10, offset: 13 }
|
71
59
|
models = @controller.instance_variable_get("@#{plural_name}")
|
72
|
-
assert_equal model.offset(13).limit(10).sort(
|
60
|
+
assert_equal model.filter(mask).offset(13).limit(10).sort(default_orders).to_sql, models.to_sql
|
73
61
|
end
|
74
62
|
|
75
63
|
test '#index.json params[:include]' do
|
76
64
|
travel_to Time.now do
|
77
65
|
create_model
|
78
66
|
get resource_path(:index, format: :json), params: { limit: 100, include: includes }
|
79
|
-
|
67
|
+
|
80
68
|
json = JSON.parse(response.body)[0]
|
81
69
|
assert json.is_a?(Hash)
|
82
70
|
includes.each do |included|
|
@@ -11,7 +11,7 @@ module StandardAPI
|
|
11
11
|
json = JSON(@response.body)
|
12
12
|
assert json['columns']
|
13
13
|
model.columns.map do |column|
|
14
|
-
assert json['columns'][column.name]['type']
|
14
|
+
assert json['columns'][column.name]['type'], "Missing `type` for \"#{model}\" attribute \"#{column.name}\""
|
15
15
|
end
|
16
16
|
assert json['limit']
|
17
17
|
end
|
@@ -46,6 +46,7 @@ module StandardAPI
|
|
46
46
|
test '#update.json with nested attributes' do
|
47
47
|
m = create_model
|
48
48
|
attrs = attributes_for(singular_name, :nested).select{|k,v| !model.readonly_attributes.include?(k.to_s) }
|
49
|
+
mask.each { |k, v| attrs[k] = v }
|
49
50
|
create_webmocks(attrs)
|
50
51
|
|
51
52
|
file_upload = attrs.any? { |k, v| v.is_a?(Rack::Test::UploadedFile) }
|
@@ -64,7 +65,7 @@ module StandardAPI
|
|
64
65
|
end
|
65
66
|
|
66
67
|
test '#update.json with invalid attributes' do
|
67
|
-
trait =
|
68
|
+
trait = FactoryBot.factories[singular_name].definition.defined_traits.any? { |x| x.name.to_s == 'invalid' }
|
68
69
|
|
69
70
|
if !trait
|
70
71
|
Rails.logger.try(:warn, "No invalid trait for #{model.name}. Skipping invalid tests")
|
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'active_support/test_case'
|
2
|
-
require 'rails-controller-testing'
|
3
|
-
Rails::Controller::Testing.install
|
4
2
|
|
5
3
|
require File.expand_path(File.join(__FILE__, '../test_case/calculate_tests'))
|
6
4
|
require File.expand_path(File.join(__FILE__, '../test_case/create_tests'))
|
@@ -45,7 +43,10 @@ module StandardAPI::TestCase
|
|
45
43
|
acc
|
46
44
|
end
|
47
45
|
|
48
|
-
|
46
|
+
test_cases = Dir.entries(File.expand_path(File.join(__FILE__, '..', 'test_case')))
|
47
|
+
test_cases.select! {|fn| fn.ends_with?('_tests.rb') }
|
48
|
+
test_cases.map! {|fn| fn.sub('_tests.rb', '') }
|
49
|
+
(klass.controller_class.action_methods & test_cases).each do |action|
|
49
50
|
if const_defined?("StandardAPI::TestCase::#{action.capitalize}Tests") && routes[klass.controller_class.controller_path][action]
|
50
51
|
klass.include("StandardAPI::TestCase::#{action.capitalize}Tests".constantize)
|
51
52
|
end
|
@@ -60,13 +61,21 @@ module StandardAPI::TestCase
|
|
60
61
|
count > 0
|
61
62
|
end
|
62
63
|
|
63
|
-
def
|
64
|
-
controller_class.new.send(:
|
64
|
+
def default_orders
|
65
|
+
controller_class.new.send(:default_orders)
|
66
|
+
end
|
67
|
+
|
68
|
+
def resource_limit
|
69
|
+
controller_class.new.send(:resource_limit)
|
65
70
|
end
|
66
71
|
|
67
72
|
def model
|
68
73
|
self.class.model
|
69
74
|
end
|
75
|
+
|
76
|
+
def mask
|
77
|
+
{}
|
78
|
+
end
|
70
79
|
|
71
80
|
def resource_path(action, options={})
|
72
81
|
url_for({
|
@@ -90,8 +99,8 @@ module StandardAPI::TestCase
|
|
90
99
|
self.class.controller_class
|
91
100
|
end
|
92
101
|
|
93
|
-
def create_model(
|
94
|
-
create(model.name.underscore,
|
102
|
+
def create_model(attrs={})
|
103
|
+
create(model.name.underscore, attrs.merge(mask))
|
95
104
|
end
|
96
105
|
|
97
106
|
def singular_name
|
data/lib/standard_api/version.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
json.object! do
|
2
|
+
|
3
|
+
record.attributes.each do |name, value|
|
4
|
+
# Skip if attribute is included in excludes
|
5
|
+
next if defined?(excludes) && excludes[record.model_name.singular.to_sym].try(:find) { |x| x.to_s == name.to_s }
|
6
|
+
json.set! name, value
|
7
|
+
end
|
8
|
+
|
9
|
+
includes.each do |inc, subinc|
|
10
|
+
next if [:where, :order, :limit].include?(inc.to_sym)
|
11
|
+
|
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
|
+
json.array! record.send(inc).filter(subinc[:where]).limit(subinc[:limit]).sort(subinc[:order]), partial: partial, as: partial.split('/').last, locals: { includes: subinc }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
when ActiveRecord::Reflection::BelongsToReflection, ActiveRecord::Reflection::HasOneReflection
|
23
|
+
can_cache = can_cache_relation?(record.class, inc, subinc)
|
24
|
+
if association.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
25
|
+
can_cache = can_cache && !record.send(association.foreign_key).nil?
|
26
|
+
end
|
27
|
+
json.cache_if!(can_cache, can_cache ? association_cache_key(record, inc, subinc) : nil) do
|
28
|
+
value = record.send(inc)
|
29
|
+
if value.nil?
|
30
|
+
json.set! inc, nil
|
31
|
+
else
|
32
|
+
partial = model_partial(value)
|
33
|
+
json.set! inc do
|
34
|
+
json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
else
|
40
|
+
if record.respond_to?(inc)
|
41
|
+
value = record.send(inc)
|
42
|
+
if value.nil?
|
43
|
+
json.set! inc, nil
|
44
|
+
elsif value.is_a?(ActiveModel::Model)
|
45
|
+
json.set! inc do
|
46
|
+
partial = model_partial(value)
|
47
|
+
json.partial! partial, partial.split('/').last.to_sym => value, includes: subinc
|
48
|
+
end
|
49
|
+
else
|
50
|
+
json.set! inc, value.as_json
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
if !record.errors.blank?
|
58
|
+
errs = record.errors.to_hash
|
59
|
+
errs.default_proc = nil
|
60
|
+
json.set! 'errors', errs
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
if !includes.empty? && can_cache?(model, includes)
|
2
|
+
partial = model_partial(model)
|
3
|
+
record_name = partial.split('/').last.to_sym
|
4
|
+
locals = { record_name => nil, :includes => includes}
|
5
|
+
|
6
|
+
json.cache_collection! instance_variable_get("@#{model.model_name.plural}"), key: proc {|record| cache_key(record, includes) } do |record|
|
7
|
+
locals[record_name] = record
|
8
|
+
json.partial! partial, locals
|
9
|
+
end
|
10
|
+
else
|
11
|
+
json.array! instance_variable_get("@#{model.model_name.plural}"), partial: model_partial(model), as: model_partial(model).split('/').last, includes: includes
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! model_partial(model), model_partial(model).split('/').last.to_sym => instance_variable_get("@#{model.model_name.singular}"), includes: includes
|
@@ -3,6 +3,7 @@ mapping = {
|
|
3
3
|
'time without time zone' => 'datetime',
|
4
4
|
'text' => 'string',
|
5
5
|
'json' => 'hash',
|
6
|
+
'bigint' => 'integer',
|
6
7
|
'integer' => 'integer',
|
7
8
|
'character varying(255)' => 'string',
|
8
9
|
'character varying(128)' => 'string',
|
@@ -17,7 +18,8 @@ mapping = {
|
|
17
18
|
'double precision' => 'decimal',
|
18
19
|
'ltree' => 'string',
|
19
20
|
'boolean' => 'boolean',
|
20
|
-
'geometry' => 'ewkb'
|
21
|
+
'geometry' => 'ewkb',
|
22
|
+
'uuid' => 'string'
|
21
23
|
}
|
22
24
|
|
23
25
|
json.set! 'columns' do
|
@@ -0,0 +1,39 @@
|
|
1
|
+
mapping = {
|
2
|
+
'timestamp without time zone' => 'datetime',
|
3
|
+
'time without time zone' => 'datetime',
|
4
|
+
'text' => 'string',
|
5
|
+
'json' => 'hash',
|
6
|
+
'integer' => 'integer',
|
7
|
+
'character varying(255)' => 'string',
|
8
|
+
'character varying(128)' => 'string',
|
9
|
+
'character varying(50)' => 'string',
|
10
|
+
'character varying' => 'string',
|
11
|
+
'jsonb' => 'hash',
|
12
|
+
'inet' => 'string', #TODO: should be inet
|
13
|
+
'hstore' => 'hash',
|
14
|
+
'date' => 'datetime',
|
15
|
+
'numeric(16,2)' => 'decimal',
|
16
|
+
'numeric' => 'decimal',
|
17
|
+
'double precision' => 'decimal',
|
18
|
+
'ltree' => 'string',
|
19
|
+
'boolean' => 'boolean',
|
20
|
+
'geometry' => 'ewkb',
|
21
|
+
'uuid' => 'string'
|
22
|
+
}
|
23
|
+
|
24
|
+
json.object! do
|
25
|
+
json.set! 'columns' do
|
26
|
+
json.object! do
|
27
|
+
model.columns.each do |column|
|
28
|
+
json.set! column.name, {
|
29
|
+
type: mapping[column.sql_type],
|
30
|
+
primary_key: column.name == model.primary_key,
|
31
|
+
null: column.null,
|
32
|
+
array: column.array
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
json.set! 'limit', resource_limit
|
39
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
json.partial! model_partial(model), model_partial(model).split('/').last.to_sym => instance_variable_get("@#{model.model_name.singular}"), includes: includes
|
data/lib/standard_api.rb
CHANGED
@@ -2,8 +2,7 @@ require 'rails'
|
|
2
2
|
require 'action_view'
|
3
3
|
require 'action_pack'
|
4
4
|
require 'action_controller'
|
5
|
-
|
6
|
-
require 'jbuilder/railtie'
|
5
|
+
|
7
6
|
require 'active_record/filter'
|
8
7
|
require 'active_record/sort'
|
9
8
|
require 'active_support/core_ext/hash/indifferent_access'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standardapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Bracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,120 +16,114 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5.
|
19
|
+
version: '5.2'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 5.
|
22
|
+
version: 5.2.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '5.
|
29
|
+
version: '5.2'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.
|
32
|
+
version: 5.2.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '5.
|
39
|
+
version: '5.2'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 5.
|
42
|
+
version: 5.2.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '5.
|
49
|
+
version: '5.2'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 5.
|
52
|
+
version: 5.2.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: actionpack
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '5.
|
59
|
+
version: '5.2'
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 5.
|
62
|
+
version: 5.2.0
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '5.
|
69
|
+
version: '5.2'
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version: 5.
|
72
|
+
version: 5.2.0
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
74
|
name: activerecord-sort
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
77
|
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: '5.
|
79
|
+
version: '5.2'
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 5.
|
82
|
+
version: 5.2.0
|
83
83
|
type: :runtime
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '5.
|
89
|
+
version: '5.2'
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 5.
|
92
|
+
version: 5.2.0
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: activerecord-filter
|
95
95
|
requirement: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
97
|
- - "~>"
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: '5.
|
99
|
+
version: '5.2'
|
100
100
|
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 5.
|
102
|
+
version: 5.2.0
|
103
103
|
type: :runtime
|
104
104
|
prerelease: false
|
105
105
|
version_requirements: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: '5.
|
109
|
+
version: '5.2'
|
110
110
|
- - ">="
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version: 5.
|
112
|
+
version: 5.2.0
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
|
-
name:
|
114
|
+
name: pg
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
|
-
- - "~>"
|
118
|
-
- !ruby/object:Gem::Version
|
119
|
-
version: '2.6'
|
120
117
|
- - ">="
|
121
118
|
- !ruby/object:Gem::Version
|
122
|
-
version:
|
123
|
-
type: :
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
124
121
|
prerelease: false
|
125
122
|
version_requirements: !ruby/object:Gem::Requirement
|
126
123
|
requirements:
|
127
|
-
- - "~>"
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: '2.6'
|
130
124
|
- - ">="
|
131
125
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
126
|
+
version: '0'
|
133
127
|
- !ruby/object:Gem::Dependency
|
134
128
|
name: bundler
|
135
129
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,7 +139,7 @@ dependencies:
|
|
145
139
|
- !ruby/object:Gem::Version
|
146
140
|
version: '0'
|
147
141
|
- !ruby/object:Gem::Dependency
|
148
|
-
name:
|
142
|
+
name: jbuilder
|
149
143
|
requirement: !ruby/object:Gem::Requirement
|
150
144
|
requirements:
|
151
145
|
- - ">="
|
@@ -159,7 +153,7 @@ dependencies:
|
|
159
153
|
- !ruby/object:Gem::Version
|
160
154
|
version: '0'
|
161
155
|
- !ruby/object:Gem::Dependency
|
162
|
-
name:
|
156
|
+
name: rake
|
163
157
|
requirement: !ruby/object:Gem::Requirement
|
164
158
|
requirements:
|
165
159
|
- - ">="
|
@@ -173,7 +167,7 @@ dependencies:
|
|
173
167
|
- !ruby/object:Gem::Version
|
174
168
|
version: '0'
|
175
169
|
- !ruby/object:Gem::Dependency
|
176
|
-
name: minitest
|
170
|
+
name: minitest
|
177
171
|
requirement: !ruby/object:Gem::Requirement
|
178
172
|
requirements:
|
179
173
|
- - ">="
|
@@ -187,7 +181,7 @@ dependencies:
|
|
187
181
|
- !ruby/object:Gem::Version
|
188
182
|
version: '0'
|
189
183
|
- !ruby/object:Gem::Dependency
|
190
|
-
name:
|
184
|
+
name: minitest-reporters
|
191
185
|
requirement: !ruby/object:Gem::Requirement
|
192
186
|
requirements:
|
193
187
|
- - ">="
|
@@ -201,7 +195,7 @@ dependencies:
|
|
201
195
|
- !ruby/object:Gem::Version
|
202
196
|
version: '0'
|
203
197
|
- !ruby/object:Gem::Dependency
|
204
|
-
name:
|
198
|
+
name: simplecov
|
205
199
|
requirement: !ruby/object:Gem::Requirement
|
206
200
|
requirements:
|
207
201
|
- - ">="
|
@@ -215,7 +209,7 @@ dependencies:
|
|
215
209
|
- !ruby/object:Gem::Version
|
216
210
|
version: '0'
|
217
211
|
- !ruby/object:Gem::Dependency
|
218
|
-
name:
|
212
|
+
name: factory_bot_rails
|
219
213
|
requirement: !ruby/object:Gem::Requirement
|
220
214
|
requirements:
|
221
215
|
- - ">="
|
@@ -229,7 +223,7 @@ dependencies:
|
|
229
223
|
- !ruby/object:Gem::Version
|
230
224
|
version: '0'
|
231
225
|
- !ruby/object:Gem::Dependency
|
232
|
-
name:
|
226
|
+
name: faker
|
233
227
|
requirement: !ruby/object:Gem::Requirement
|
234
228
|
requirements:
|
235
229
|
- - ">="
|
@@ -243,7 +237,7 @@ dependencies:
|
|
243
237
|
- !ruby/object:Gem::Version
|
244
238
|
version: '0'
|
245
239
|
- !ruby/object:Gem::Dependency
|
246
|
-
name:
|
240
|
+
name: byebug
|
247
241
|
requirement: !ruby/object:Gem::Requirement
|
248
242
|
requirements:
|
249
243
|
- - ">="
|
@@ -257,7 +251,7 @@ dependencies:
|
|
257
251
|
- !ruby/object:Gem::Version
|
258
252
|
version: '0'
|
259
253
|
- !ruby/object:Gem::Dependency
|
260
|
-
name:
|
254
|
+
name: mocha
|
261
255
|
requirement: !ruby/object:Gem::Requirement
|
262
256
|
requirements:
|
263
257
|
- - ">="
|
@@ -299,11 +293,15 @@ files:
|
|
299
293
|
- lib/standard_api/test_case/update_tests.rb
|
300
294
|
- lib/standard_api/version.rb
|
301
295
|
- lib/standard_api/views/application/_record.json.jbuilder
|
296
|
+
- lib/standard_api/views/application/_record.streamer
|
302
297
|
- lib/standard_api/views/application/index.json.jbuilder
|
298
|
+
- lib/standard_api/views/application/index.streamer
|
303
299
|
- lib/standard_api/views/application/new.json.jbuilder
|
300
|
+
- lib/standard_api/views/application/new.streamer
|
304
301
|
- lib/standard_api/views/application/schema.json.jbuilder
|
305
|
-
- lib/standard_api/views/application/
|
302
|
+
- lib/standard_api/views/application/schema.streamer
|
306
303
|
- lib/standard_api/views/application/show.json.jbuilder
|
304
|
+
- lib/standard_api/views/application/show.streamer
|
307
305
|
homepage: https://github.com/waratuman/standardapi
|
308
306
|
licenses:
|
309
307
|
- MIT
|
@@ -326,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
326
324
|
version: '0'
|
327
325
|
requirements: []
|
328
326
|
rubyforge_project:
|
329
|
-
rubygems_version: 2.
|
327
|
+
rubygems_version: 2.7.6
|
330
328
|
signing_key:
|
331
329
|
specification_version: 4
|
332
330
|
summary: StandardAPI makes it easy to expose a query interface for your Rails models
|
File without changes
|