praxis 0.21 → 2.0.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +8 -15
- data/CHANGELOG.md +328 -299
- data/CONTRIBUTING.md +4 -4
- data/README.md +11 -9
- data/lib/api_browser/app/js/directives/attribute_table.js +2 -1
- data/lib/api_browser/app/js/directives/conditional_requirements.js +13 -0
- data/lib/api_browser/app/js/directives/type_placeholder.js +10 -1
- data/lib/api_browser/app/js/factories/normalize_attributes.js +4 -2
- data/lib/api_browser/app/js/factories/template_for.js +5 -2
- data/lib/api_browser/app/js/filters/has_requirement.js +14 -0
- data/lib/api_browser/app/js/filters/tag_requirement.js +13 -0
- data/lib/api_browser/app/sass/praxis.scss +11 -0
- data/lib/api_browser/app/views/action.html +2 -2
- data/lib/api_browser/app/views/directives/attribute_description/member_options.html +2 -2
- data/lib/api_browser/app/views/directives/attribute_table.html +1 -1
- data/lib/api_browser/app/views/type.html +1 -1
- data/lib/api_browser/app/views/type/details.html +2 -2
- data/lib/api_browser/app/views/types/embedded/array.html +2 -0
- data/lib/api_browser/app/views/types/embedded/default.html +3 -1
- data/lib/api_browser/app/views/types/embedded/requirements.html +6 -0
- data/lib/api_browser/app/views/types/embedded/single_req.html +9 -0
- data/lib/api_browser/app/views/types/embedded/struct.html +14 -2
- data/lib/api_browser/app/views/types/standalone/array.html +1 -1
- data/lib/api_browser/app/views/types/standalone/struct.html +2 -1
- data/lib/api_browser/package.json +1 -1
- data/lib/praxis.rb +9 -3
- data/lib/praxis/action_definition.rb +1 -1
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
- data/lib/praxis/application.rb +1 -9
- data/lib/praxis/bootloader.rb +1 -4
- data/lib/praxis/config.rb +1 -1
- data/lib/praxis/dispatcher.rb +10 -6
- data/lib/praxis/docs/generator.rb +2 -1
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +180 -0
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +273 -0
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
- data/lib/praxis/extensions/field_selection.rb +1 -9
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +51 -0
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +61 -0
- data/lib/praxis/extensions/rails_compat.rb +2 -0
- data/lib/praxis/extensions/rails_compat/request_methods.rb +19 -0
- data/lib/praxis/handlers/xml.rb +1 -1
- data/lib/praxis/mapper/active_model_compat.rb +98 -0
- data/lib/praxis/mapper/resource.rb +242 -0
- data/lib/praxis/mapper/selector_generator.rb +149 -0
- data/lib/praxis/mapper/sequel_compat.rb +76 -0
- data/lib/praxis/media_type_identifier.rb +2 -1
- data/lib/praxis/middleware_app.rb +20 -2
- data/lib/praxis/multipart/parser.rb +14 -2
- data/lib/praxis/notifications.rb +1 -1
- data/lib/praxis/plugins/mapper_plugin.rb +64 -0
- data/lib/praxis/plugins/rails_plugin.rb +104 -0
- data/lib/praxis/request.rb +7 -1
- data/lib/praxis/request_superclassing.rb +11 -0
- data/lib/praxis/resource_definition.rb +5 -5
- data/lib/praxis/response.rb +1 -1
- data/lib/praxis/route.rb +1 -1
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/trait.rb +1 -1
- data/lib/praxis/types/media_type_common.rb +2 -2
- data/lib/praxis/types/multipart.rb +1 -1
- data/lib/praxis/types/multipart_array.rb +2 -2
- data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +14 -13
- data/spec/functional_spec.rb +4 -7
- data/spec/praxis/action_definition_spec.rb +1 -1
- data/spec/praxis/application_spec.rb +1 -1
- data/spec/praxis/collection_spec.rb +3 -2
- data/spec/praxis/config_spec.rb +2 -2
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +106 -0
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +147 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_active_model.rb +130 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_sequel.rb +106 -0
- data/spec/praxis/handlers/xml_spec.rb +2 -2
- data/spec/praxis/mapper/resource_spec.rb +169 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +293 -0
- data/spec/praxis/media_type_spec.rb +0 -10
- data/spec/praxis/middleware_app_spec.rb +29 -9
- data/spec/praxis/request_stages/action_spec.rb +8 -1
- data/spec/praxis/response_definition_spec.rb +7 -4
- data/spec/praxis/response_spec.rb +1 -1
- data/spec/praxis/responses/internal_server_error_spec.rb +2 -2
- data/spec/praxis/responses/validation_error_spec.rb +2 -2
- data/spec/praxis/router_spec.rb +1 -1
- data/spec/spec_app/app/controllers/instances.rb +1 -1
- data/spec/spec_app/config/environment.rb +3 -21
- data/spec/spec_helper.rb +11 -15
- data/spec/support/be_deep_equal_matcher.rb +39 -0
- data/spec/support/spec_resources.rb +124 -0
- data/tasks/thor/templates/generator/empty_app/Gemfile +3 -3
- metadata +102 -77
- data/.ruby-version +0 -1
- data/lib/praxis/extensions/mapper_selectors.rb +0 -16
- data/lib/praxis/media_type_collection.rb +0 -127
- data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
- data/lib/praxis/stats.rb +0 -113
- data/spec/praxis/media_type_collection_spec.rb +0 -157
- data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
- data/spec/praxis/stats_spec.rb +0 -9
- data/spec/spec_app/app/models/person.rb +0 -3
@@ -52,16 +52,6 @@ describe Praxis::MediaType do
|
|
52
52
|
subject(:address_klass) { address.class }
|
53
53
|
|
54
54
|
context '#identifier' do
|
55
|
-
context 'in praxis v0' do
|
56
|
-
it 'should be a kind of String' do
|
57
|
-
if Praxis::VERSION =~ /^0/
|
58
|
-
expect(subject.identifier).to be_kind_of(String)
|
59
|
-
else
|
60
|
-
raise 'Please remove this spec which is no longer pertinent'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
55
|
context 'in praxis v1.0 and beyond' do
|
66
56
|
it 'should be a kind of Praxis::MediaTypeIdentifier' do
|
67
57
|
pending('interface-breaking change') if Praxis::VERSION =~ /^0/
|
@@ -2,35 +2,55 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Praxis::MiddlewareApp do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
let(:init_args){ { root: 'here'} }
|
6
|
+
let(:middleware) { Praxis::MiddlewareApp.for( **init_args ) }
|
7
|
+
let(:instance){ middleware.new(target)}
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
context '.for' do
|
10
|
+
it 'does not initialize the Application instance yet' do
|
11
|
+
expect( Praxis::Application.instance ).to_not receive(:setup)
|
12
|
+
middleware
|
12
13
|
end
|
13
14
|
it 'returns its class' do
|
14
|
-
expect(
|
15
|
+
expect( middleware ).to be < Praxis::MiddlewareApp
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
18
19
|
context 'instantiated' do
|
20
|
+
subject{ instance }
|
19
21
|
let(:target_response){ [201,{}] }
|
20
22
|
let(:target){ double("target app", call: target_response) }
|
21
|
-
subject(:instance){ Praxis::MiddlewareApp.new(target)}
|
22
23
|
it 'saves the target app' do
|
23
24
|
expect(subject.target).to be(target)
|
24
25
|
end
|
26
|
+
it 'does not initialize the Application instance yet' do
|
27
|
+
expect( Praxis::Application.instance ).to_not receive(:setup)
|
28
|
+
subject
|
29
|
+
end
|
30
|
+
|
25
31
|
context '.call' do
|
26
32
|
let(:env){ {} }
|
27
33
|
let(:praxis_response){ [200,{}] }
|
28
|
-
subject(:response){
|
34
|
+
subject(:response){ instance.call(env) }
|
29
35
|
before do
|
30
36
|
# always invokes the praxis app
|
31
37
|
expect( Praxis::Application.instance ).to receive(:call).with( env ).once.and_return(praxis_response)
|
32
38
|
end
|
33
39
|
|
40
|
+
context 'when it has not been setup yet' do
|
41
|
+
it 'initializes the application singleton with the passed parameters' do
|
42
|
+
expect( Praxis::Application.instance ).to receive(:setup).with( init_args ).once
|
43
|
+
subject
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context 'when it has already been setup' do
|
47
|
+
it 'does NOT call instance setup' do
|
48
|
+
middleware.setup
|
49
|
+
expect( Praxis::Application.instance ).to_not receive(:setup)
|
50
|
+
subject
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
34
54
|
context 'properly handled (non-404 and 405) responses from praxis' do
|
35
55
|
it 'are returned straight through' do
|
36
56
|
expect( response ).to be(praxis_response)
|
@@ -26,7 +26,14 @@ describe Praxis::RequestStages::Action do
|
|
26
26
|
|
27
27
|
context '.execute' do
|
28
28
|
before do
|
29
|
-
expect(controller).to receive(action_stage.name)
|
29
|
+
expect(controller).to receive(action_stage.name) do |args|
|
30
|
+
if args
|
31
|
+
expect(args).to eq({})
|
32
|
+
else
|
33
|
+
expect(args).to eq(nil)
|
34
|
+
end
|
35
|
+
end.and_return(controller_response)
|
36
|
+
|
30
37
|
end
|
31
38
|
let(:controller_response){ controller.response }
|
32
39
|
|
@@ -448,7 +448,7 @@ describe Praxis::ResponseDefinition do
|
|
448
448
|
context 'with legacy multipart response' do
|
449
449
|
subject(:response) { Praxis::Responses::Ok.new(status: response_status, headers: response_headers) }
|
450
450
|
|
451
|
-
let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, 'Content-Type' => 'application/special'}
|
451
|
+
let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, 'Content-Type' => 'application/special'},**{}) }
|
452
452
|
|
453
453
|
before do
|
454
454
|
response_definition.parts like: :ok, media_type: 'application/special'
|
@@ -463,7 +463,7 @@ describe Praxis::ResponseDefinition do
|
|
463
463
|
end
|
464
464
|
|
465
465
|
context 'with invalid part' do
|
466
|
-
let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, "Location" => "somewhere"}
|
466
|
+
let(:part) { Praxis::MultipartPart.new('done', {'Status' => 200, "Location" => "somewhere"}) }
|
467
467
|
|
468
468
|
it 'validates' do
|
469
469
|
expect {
|
@@ -494,6 +494,7 @@ describe Praxis::ResponseDefinition do
|
|
494
494
|
let(:location) { %r{/my/url/} }
|
495
495
|
let(:headers) { {'Header1' => 'Value1'} }
|
496
496
|
let(:parts) { nil }
|
497
|
+
let(:parts_block) { nil }
|
497
498
|
|
498
499
|
let(:response) do
|
499
500
|
Praxis::ResponseDefinition.new(:custom) do
|
@@ -505,7 +506,9 @@ describe Praxis::ResponseDefinition do
|
|
505
506
|
before do
|
506
507
|
response.description(description) if description
|
507
508
|
response.location(location) if location
|
508
|
-
|
509
|
+
if parts || parts_block
|
510
|
+
parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
|
511
|
+
end
|
509
512
|
response.headers(headers) if headers
|
510
513
|
end
|
511
514
|
|
@@ -572,7 +575,7 @@ describe Praxis::ResponseDefinition do
|
|
572
575
|
its([:status]){ should == 200 }
|
573
576
|
end
|
574
577
|
context 'using a full response definition block' do
|
575
|
-
let(:
|
578
|
+
let(:parts_block) do
|
576
579
|
Proc.new do
|
577
580
|
status 234
|
578
581
|
media_type 'custom_media'
|
@@ -117,7 +117,7 @@ describe Praxis::Response do
|
|
117
117
|
end
|
118
118
|
|
119
119
|
context 'multipart responses' do
|
120
|
-
let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400, "Location" => "somewhere"}
|
120
|
+
let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400, "Location" => "somewhere"}) }
|
121
121
|
|
122
122
|
context '#add_part' do
|
123
123
|
|
@@ -8,7 +8,7 @@ describe Praxis::Responses::InternalServerError do
|
|
8
8
|
it 'always sets the json content type' do
|
9
9
|
expect(response.name).to be(:internal_server_error)
|
10
10
|
expect(response.status).to be(500)
|
11
|
-
expect(response.body).to
|
11
|
+
expect(response.body).to be_nil
|
12
12
|
expect(response.headers).to have_key('Content-Type')
|
13
13
|
expect(response.headers['Content-Type']).to eq('application/json')
|
14
14
|
expect(response.instance_variable_get(:@error)).to be(nil)
|
@@ -52,7 +52,7 @@ describe Praxis::Responses::InternalServerError do
|
|
52
52
|
|
53
53
|
subject(:response) { Praxis::Responses::InternalServerError.new(error: error) }
|
54
54
|
before do
|
55
|
-
expect(response.body).to
|
55
|
+
expect(response.body).to be_nil
|
56
56
|
response.format!
|
57
57
|
end
|
58
58
|
|
@@ -9,7 +9,7 @@ describe Praxis::Responses::ValidationError do
|
|
9
9
|
it 'always sets the json content type' do
|
10
10
|
expect(response.name).to be(:validation_error)
|
11
11
|
expect(response.status).to be(400)
|
12
|
-
expect(response.body).to
|
12
|
+
expect(response.body).to be_nil
|
13
13
|
expect(response.headers).to have_key('Content-Type')
|
14
14
|
expect(response.headers['Content-Type']).to eq('application/json')
|
15
15
|
expect(response.instance_variable_get(:@errors)).to be(nil)
|
@@ -24,7 +24,7 @@ describe Praxis::Responses::ValidationError do
|
|
24
24
|
let(:exception){ nil }
|
25
25
|
subject(:response) { Praxis::Responses::ValidationError.new(summary: summary, errors: errors, exception: exception) }
|
26
26
|
before do
|
27
|
-
expect(response.body).to
|
27
|
+
expect(response.body).to be_nil
|
28
28
|
end
|
29
29
|
context 'when errors' do
|
30
30
|
it 'it fills the errors key' do
|
data/spec/praxis/router_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Praxis::Router do
|
|
6
6
|
let(:action){ double("action", resource_definition: resource_definition ) }
|
7
7
|
let(:target){ double("target", action: action ) }
|
8
8
|
let(:args){ {version: "1.0"} }
|
9
|
-
subject(:matcher){ Praxis::Router::VersionMatcher.new(target
|
9
|
+
subject(:matcher){ Praxis::Router::VersionMatcher.new(target,**args) }
|
10
10
|
|
11
11
|
context '.initialize' do
|
12
12
|
let(:args){ {} }
|
@@ -21,35 +21,17 @@ Praxis::Application.configure do |application|
|
|
21
21
|
application.bootloader.use SimpleAuthenticationPlugin, config_file: 'config/authentication.yml'
|
22
22
|
application.bootloader.use AuthorizationPlugin
|
23
23
|
|
24
|
-
|
25
|
-
adapter_name = 'sqlite'
|
26
|
-
db_name = ':memory:'
|
27
|
-
connection_opts = if RUBY_PLATFORM !~ /java/
|
28
|
-
{ adapter: adapter_name , database: db_name }
|
29
|
-
else
|
30
|
-
require 'jdbc/sqlite3'
|
31
|
-
{ adapter: 'jdbc', uri: "jdbc:#{adapter_name}:#{db_name}" }
|
32
|
-
end
|
33
|
-
|
34
|
-
application.bootloader.use Praxis::Plugins::PraxisMapperPlugin, {
|
35
|
-
config_data: {
|
36
|
-
repositories: { default: connection_opts },
|
37
|
-
log_stats: 'detailed'
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
24
|
# enable "development-mode" options
|
42
25
|
application.config.praxis.validate_responses = true
|
43
26
|
application.config.praxis.validate_response_bodies = true
|
44
27
|
application.config.praxis.show_exceptions = true
|
45
28
|
|
46
|
-
# FIXME: until we have a better way to unit test such a feature...
|
47
29
|
# Silly callback code pieces to test that the deferred callbacks work even for sub-stages
|
48
|
-
application.bootloader.after :app, :
|
49
|
-
|
30
|
+
application.bootloader.after :app, :controllers do
|
31
|
+
$after_app_controllers = :worked
|
50
32
|
end
|
51
33
|
application.bootloader.after :app do
|
52
|
-
raise "After sub-stage hooks not working!" unless
|
34
|
+
raise "After sub-stage hooks not working!" unless $after_app_controllers == :worked
|
53
35
|
end
|
54
36
|
|
55
37
|
|
data/spec/spec_helper.rb
CHANGED
@@ -19,26 +19,32 @@ require 'rack/test'
|
|
19
19
|
require 'rspec/its'
|
20
20
|
require 'rspec/collection_matchers'
|
21
21
|
|
22
|
-
|
23
|
-
|
24
22
|
Dir["#{File.dirname(__FILE__)}/../lib/praxis/plugins/*.rb"].each do |file|
|
25
23
|
require file
|
26
24
|
end
|
27
25
|
|
26
|
+
|
28
27
|
Dir["#{File.dirname(__FILE__)}/support/*.rb"].each do |file|
|
29
28
|
require file
|
30
29
|
end
|
31
30
|
|
31
|
+
def suppress_output
|
32
|
+
original_stdout, original_stderr = $stdout.clone, $stderr.clone
|
33
|
+
$stderr.reopen File.new('/dev/null', 'w')
|
34
|
+
$stdout.reopen File.new('/dev/null', 'w')
|
35
|
+
yield
|
36
|
+
ensure
|
37
|
+
$stdout.reopen original_stdout
|
38
|
+
$stderr.reopen original_stderr
|
39
|
+
end
|
32
40
|
|
33
41
|
RSpec.configure do |config|
|
34
42
|
config.include Rack::Test::Methods
|
35
43
|
|
36
44
|
config.before(:suite) do
|
45
|
+
Praxis::Mapper::Resource.finalize!
|
37
46
|
Praxis::Blueprint.caching_enabled = true
|
38
47
|
Praxis::Application.instance.setup(root:'spec/spec_app')
|
39
|
-
|
40
|
-
# create the table
|
41
|
-
setup_database!
|
42
48
|
end
|
43
49
|
|
44
50
|
config.before(:each) do
|
@@ -53,13 +59,3 @@ RSpec.configure do |config|
|
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
56
|
-
# create the test db schema
|
57
|
-
def setup_database!
|
58
|
-
mapper = Praxis::Application.instance.plugins[:praxis_mapper]
|
59
|
-
Sequel.connect(mapper.config.repositories["default"]['connection_settings'].dump) do |db|
|
60
|
-
db.create_table! :people do
|
61
|
-
primary_key :id
|
62
|
-
string :name
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Copied verbatim from: https://github.com/amogil/rspec-deep-ignore-order-matcher
|
2
|
+
|
3
|
+
RSpec::Matchers.define :be_deep_equal do |expected|
|
4
|
+
match { |actual| match? actual, expected }
|
5
|
+
|
6
|
+
failure_message do |actual|
|
7
|
+
"expected that #{actual} would be deep equal with #{expected}"
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message_when_negated do |actual|
|
11
|
+
"expected that #{actual} would not be deep equal with #{expected}"
|
12
|
+
end
|
13
|
+
|
14
|
+
description do
|
15
|
+
"be deep equal with #{expected}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def match?(actual, expected)
|
19
|
+
return arrays_match?(actual, expected) if expected.is_a?(Array) && actual.is_a?(Array)
|
20
|
+
return hashes_match?(actual, expected) if expected.is_a?(Hash) && actual.is_a?(Hash)
|
21
|
+
expected == actual
|
22
|
+
end
|
23
|
+
|
24
|
+
def arrays_match?(actual, expected)
|
25
|
+
exp = expected.clone
|
26
|
+
actual.each do |a|
|
27
|
+
index = exp.find_index { |e| match? a, e }
|
28
|
+
return false if index.nil?
|
29
|
+
exp.delete_at(index)
|
30
|
+
end
|
31
|
+
exp.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def hashes_match?(actual, expected)
|
35
|
+
return false unless actual.keys.sort == expected.keys.sort
|
36
|
+
actual.each { |key, value| return false unless match? value, expected[key] }
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
require 'praxis/mapper/active_model_compat'
|
4
|
+
class SimpleModel < OpenStruct
|
5
|
+
include Praxis::Mapper::ActiveModelCompat
|
6
|
+
def self._praxis_associations
|
7
|
+
{
|
8
|
+
parent: {
|
9
|
+
model: ParentModel,
|
10
|
+
primary_key: :id,
|
11
|
+
type: :many_to_one,
|
12
|
+
local_key_columns: [:parent_id],
|
13
|
+
remote_key_columns: [:id]
|
14
|
+
},
|
15
|
+
other_model: {
|
16
|
+
model: OtherModel,
|
17
|
+
primary_key: :id,
|
18
|
+
type: :many_to_one,
|
19
|
+
local_key_columns: [:other_model_id],
|
20
|
+
remote_key_columns: [:id]
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class OtherModel < OpenStruct
|
27
|
+
include Praxis::Mapper::ActiveModelCompat
|
28
|
+
def self._praxis_associations
|
29
|
+
{
|
30
|
+
parent: {
|
31
|
+
model: ParentModel,
|
32
|
+
primary_key: :id,
|
33
|
+
type: :many_to_one,
|
34
|
+
local_key_columns: [:parent_id],
|
35
|
+
remote_key_columns: [:id]
|
36
|
+
},
|
37
|
+
simple_models: {
|
38
|
+
model: SimpleModel,
|
39
|
+
primary_key: :id,
|
40
|
+
type: :many_to_many,
|
41
|
+
local_key_columns: [:id],
|
42
|
+
remote_key_columns: [:id] # The through table is in the middle where the FKs are...
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ParentModel < OpenStruct
|
49
|
+
include Praxis::Mapper::ActiveModelCompat
|
50
|
+
def self._praxis_associations
|
51
|
+
{
|
52
|
+
simple_children: {
|
53
|
+
model: SimpleModel,
|
54
|
+
primary_key: :id,
|
55
|
+
type: :one_to_many,
|
56
|
+
local_key_columns: [:id],
|
57
|
+
remote_key_columns: [:parent_id]
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class YamlArrayModel < OpenStruct
|
64
|
+
include Praxis::Mapper::ActiveModelCompat
|
65
|
+
def self._praxis_associations
|
66
|
+
{
|
67
|
+
parents: {
|
68
|
+
model: ParentModel,
|
69
|
+
primary_key: :id,
|
70
|
+
type: :one_to_many,
|
71
|
+
local_key_columns: [:id],
|
72
|
+
remote_key_columns: [:parent_id]
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# A set of resource classes for use in specs
|
79
|
+
class BaseResource < Praxis::Mapper::Resource
|
80
|
+
def href
|
81
|
+
base_href = '' # "/api"
|
82
|
+
base_href + "/#{self.class.collection_name}/#{self.id}"
|
83
|
+
end
|
84
|
+
|
85
|
+
property :href, dependencies: [:id]
|
86
|
+
end
|
87
|
+
|
88
|
+
class OtherResource < BaseResource
|
89
|
+
model OtherModel
|
90
|
+
|
91
|
+
property :display_name, dependencies: [:name]
|
92
|
+
end
|
93
|
+
|
94
|
+
class ParentResource < BaseResource
|
95
|
+
model ParentModel
|
96
|
+
end
|
97
|
+
|
98
|
+
class SimpleResource < BaseResource
|
99
|
+
model SimpleModel
|
100
|
+
|
101
|
+
resource_delegate :other_model => [:other_attribute]
|
102
|
+
|
103
|
+
def other_resource
|
104
|
+
self.other_model
|
105
|
+
end
|
106
|
+
|
107
|
+
property :aliased_method, dependencies: [:column1, :other_model]
|
108
|
+
property :other_resource, dependencies: [:other_model]
|
109
|
+
|
110
|
+
property :parent, dependencies: [:parent, :added_column]
|
111
|
+
|
112
|
+
property :name, dependencies: [:simple_name]
|
113
|
+
property :direct_other_name, dependencies: [ 'other_model.name' ]
|
114
|
+
property :aliased_other_name, dependencies: [ 'other_model.display_name' ]
|
115
|
+
|
116
|
+
property :everything, dependencies: [:*]
|
117
|
+
property :everything_from_parent, dependencies: ['parent.*']
|
118
|
+
property :circular_dep, dependencies: [ :circular_dep, :column1 ]
|
119
|
+
property :no_deps, dependencies: []
|
120
|
+
end
|
121
|
+
|
122
|
+
class YamlArrayResource < BaseResource
|
123
|
+
model YamlArrayModel
|
124
|
+
end
|