praxis 2.0.pre.29 → 2.0.pre.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +24 -0
- data/SELECTOR_NOTES.txt +0 -0
- data/lib/praxis/application.rb +4 -0
- data/lib/praxis/blueprint.rb +13 -1
- data/lib/praxis/blueprint_attribute_group.rb +29 -0
- data/lib/praxis/docs/open_api/schema_object.rb +8 -7
- data/lib/praxis/endpoint_definition.rb +1 -1
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +11 -11
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +0 -1
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +1 -1
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +54 -4
- data/lib/praxis/extensions/pagination/ordering_params.rb +38 -10
- data/lib/praxis/extensions/pagination/pagination_handler.rb +3 -3
- data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +1 -1
- data/lib/praxis/mapper/resource.rb +155 -14
- data/lib/praxis/mapper/selector_generator.rb +248 -46
- data/lib/praxis/media_type_identifier.rb +1 -1
- data/lib/praxis/multipart/part.rb +2 -2
- data/lib/praxis/plugins/mapper_plugin.rb +4 -3
- data/lib/praxis/renderer.rb +1 -1
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/tasks/console.rb +21 -26
- data/lib/praxis/types/multipart_array.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/lib/praxis.rb +1 -0
- data/praxis.gemspec +1 -1
- data/spec/functional_library_spec.rb +187 -0
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +11 -1
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +16 -4
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +0 -2
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +0 -2
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +111 -25
- data/spec/praxis/extensions/pagination/ordering_params_spec.rb +70 -0
- data/spec/praxis/mapper/resource_spec.rb +40 -4
- data/spec/praxis/mapper/selector_generator_spec.rb +979 -296
- data/spec/praxis/request_stages/action_spec.rb +1 -1
- data/spec/spec_app/app/controllers/authors.rb +37 -0
- data/spec/spec_app/app/controllers/books.rb +31 -0
- data/spec/spec_app/app/resources/author.rb +21 -0
- data/spec/spec_app/app/resources/base.rb +14 -0
- data/spec/spec_app/app/resources/book.rb +43 -0
- data/spec/spec_app/app/resources/tag.rb +9 -0
- data/spec/spec_app/app/resources/tagging.rb +9 -0
- data/spec/spec_app/config/environment.rb +16 -1
- data/spec/spec_app/design/media_types/author.rb +13 -0
- data/spec/spec_app/design/media_types/book.rb +22 -0
- data/spec/spec_app/design/media_types/tag.rb +11 -0
- data/spec/spec_app/design/media_types/tagging.rb +10 -0
- data/spec/spec_app/design/resources/authors.rb +35 -0
- data/spec/spec_app/design/resources/books.rb +39 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/spec_resources.rb +20 -7
- data/spec/{praxis/extensions/support → support}/spec_resources_active_model.rb +14 -0
- metadata +24 -7
- /data/spec/{functional_spec.rb → functional_cloud_spec.rb} +0 -0
- /data/spec/{praxis/extensions/support → support}/spec_resources_sequel.rb +0 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require_relative '../../../support/spec_media_types'
|
5
|
+
|
6
|
+
describe Praxis::Extensions::Pagination::OrderingParams do
|
7
|
+
let(:blog_ordering_type) { Praxis::Types::OrderingParams.for(Blog) }
|
8
|
+
|
9
|
+
context '#validate' do
|
10
|
+
context 'full enforcement and nested relationships' do
|
11
|
+
let(:order_attr) do
|
12
|
+
Attributor::Attribute.new(blog_ordering_type) do
|
13
|
+
by_fields :id, 'recent_posts.title', 'recent_posts.author.first'
|
14
|
+
enforce_for :all
|
15
|
+
end
|
16
|
+
end
|
17
|
+
it 'works for allowed fields' do
|
18
|
+
['id', 'recent_posts.title', 'recent_posts.author.first'].each do |str|
|
19
|
+
expect(order_attr.load(str).validate).to be_empty
|
20
|
+
end
|
21
|
+
end
|
22
|
+
it 'enforces all components' do
|
23
|
+
# Allowed at any position
|
24
|
+
expect(order_attr.load('recent_posts.title,id').validate).to be_empty
|
25
|
+
# Not allowed even in second position if it isn't on the list
|
26
|
+
expect(order_attr.load('recent_posts.title,name').validate).to_not be_empty
|
27
|
+
end
|
28
|
+
it 'fails for valid but unallowed fields' do
|
29
|
+
['name', 'recent_posts.id'].each do |str|
|
30
|
+
expect(order_attr.load(str).validate).to_not be_empty
|
31
|
+
end
|
32
|
+
end
|
33
|
+
it 'fails for invalid fields' do
|
34
|
+
['nothing', 'badassoc.none'].each do |str|
|
35
|
+
expect(order_attr.load(str).validate).to_not be_empty
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
context 'first-only enforcement' do
|
40
|
+
let(:order_attr) do
|
41
|
+
Attributor::Attribute.new(blog_ordering_type) do
|
42
|
+
by_fields :id, 'recent_posts.title'
|
43
|
+
enforce_for :first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
it 'enforces only first components' do
|
47
|
+
# It does not allow 'name' if it is in the first position
|
48
|
+
expect(order_attr.load('name,recent_posts.title').validate).to_not be_empty
|
49
|
+
# Allows 'name' if it is not in the first position
|
50
|
+
expect(order_attr.load('recent_posts.title,name').validate).to be_empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context 'default enforcement' do
|
54
|
+
let(:order_attr) do
|
55
|
+
Attributor::Attribute.new(blog_ordering_type)
|
56
|
+
end
|
57
|
+
it 'allows any attribute of the mediatype' do
|
58
|
+
%w[id name href description].each do |str|
|
59
|
+
expect(order_attr.load(str).validate).to be_empty
|
60
|
+
end
|
61
|
+
end
|
62
|
+
it 'enforces only first components' do
|
63
|
+
# It allows non-defined field in second position
|
64
|
+
expect(order_attr.load('name,recent_posts.title').validate).to be_empty
|
65
|
+
# It does not allow non-defined field in first position
|
66
|
+
expect(order_attr.load('recent_posts.title,name').validate).to_not be_empty
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -18,19 +18,55 @@ describe Praxis::Mapper::Resource do
|
|
18
18
|
subject(:properties) { resource.properties }
|
19
19
|
|
20
20
|
it 'includes directly-set properties' do
|
21
|
-
expect(properties[:other_resource]).to eq(dependencies: [:other_model]
|
21
|
+
expect(properties[:other_resource]).to eq(dependencies: [:other_model])
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'includes aliases as well if different from name' do
|
25
|
-
expect(properties[:aliased_association]).to eq(dependencies:
|
25
|
+
expect(properties[:aliased_association]).to eq(dependencies: nil, as: :other_model)
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'inherits from a superclass' do
|
29
|
-
expect(properties[:href]).to eq(dependencies: [:id]
|
29
|
+
expect(properties[:href]).to eq(dependencies: [:id])
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'properly overrides a property from the parent' do
|
33
|
-
expect(properties[:name]).to eq(dependencies: [:
|
33
|
+
expect(properties[:name]).to eq(dependencies: [:nested_name])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'using strings for names' do
|
38
|
+
let(:bad_resource) do
|
39
|
+
Class.new(Praxis::Mapper::Resource) do
|
40
|
+
property 'iamastring', dependencies: %i[foo]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
it 'complains with the proper message right at definition time' do
|
44
|
+
expect { bad_resource }.to raise_error(
|
45
|
+
RuntimeError,
|
46
|
+
/Error defining property 'iamastring'.*Property names must be symbols, not strings/
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
context 'detect_invalid_properties' do
|
51
|
+
subject { resource.detect_invalid_properties }
|
52
|
+
let(:resource) do
|
53
|
+
Class.new(Praxis::Mapper::Resource) do
|
54
|
+
model SimpleModel
|
55
|
+
property :parent
|
56
|
+
property :other_model, dependencies: %i[foo bar]
|
57
|
+
def other_model
|
58
|
+
_something = foo && bar
|
59
|
+
record.other_model
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
# Validates that defining properties that are direct associations shouldn't be done unless
|
64
|
+
# there is an overriden method that takes over (and therefore might need the dependencies defined for what it needs)
|
65
|
+
it 'detects the invalid ones' do
|
66
|
+
# Parent is defined, but it is already an association (and no overriden method for it)
|
67
|
+
expect(subject).to match(/Bad definition of property 'parent'/)
|
68
|
+
# Other model is an association, but it is overriden, so that's a valid way to specify properties
|
69
|
+
expect(subject).to_not match(/Bad definition of property 'other_model'/)
|
34
70
|
end
|
35
71
|
end
|
36
72
|
end
|