praxis 2.0.pre.29 → 2.0.pre.30
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/.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
|