praxis 0.21 → 2.0.pre.3
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 +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
|