pragma 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +23 -1
  4. data/README.md +22 -15
  5. data/lib/pragma.rb +21 -15
  6. data/lib/pragma/filter/base.rb +17 -0
  7. data/lib/pragma/filter/equals.rb +18 -0
  8. data/lib/pragma/filter/ilike.rb +18 -0
  9. data/lib/pragma/filter/like.rb +18 -0
  10. data/lib/pragma/filter/scope.rb +18 -0
  11. data/lib/pragma/filter/where.rb +18 -0
  12. data/lib/pragma/macro/classes.rb +98 -0
  13. data/lib/pragma/macro/contract/build.rb +25 -0
  14. data/lib/pragma/macro/contract/persist.rb +25 -0
  15. data/lib/pragma/macro/contract/validate.rb +25 -0
  16. data/lib/pragma/macro/decorator.rb +80 -0
  17. data/lib/pragma/macro/filtering.rb +45 -0
  18. data/lib/pragma/macro/model.rb +28 -0
  19. data/lib/pragma/macro/ordering.rb +81 -0
  20. data/lib/pragma/macro/pagination.rb +94 -0
  21. data/lib/pragma/macro/policy.rb +41 -0
  22. data/lib/pragma/operation/create.rb +1 -1
  23. data/lib/pragma/operation/destroy.rb +2 -2
  24. data/lib/pragma/operation/filter.rb +7 -0
  25. data/lib/pragma/operation/index.rb +3 -3
  26. data/lib/pragma/operation/macro.rb +7 -0
  27. data/lib/pragma/operation/show.rb +1 -1
  28. data/lib/pragma/operation/update.rb +1 -1
  29. data/lib/pragma/version.rb +1 -1
  30. metadata +21 -17
  31. data/lib/pragma/operation/filter/base.rb +0 -20
  32. data/lib/pragma/operation/filter/equals.rb +0 -13
  33. data/lib/pragma/operation/filter/ilike.rb +0 -13
  34. data/lib/pragma/operation/filter/like.rb +0 -13
  35. data/lib/pragma/operation/macro/classes.rb +0 -102
  36. data/lib/pragma/operation/macro/contract/build.rb +0 -27
  37. data/lib/pragma/operation/macro/contract/persist.rb +0 -27
  38. data/lib/pragma/operation/macro/contract/validate.rb +0 -27
  39. data/lib/pragma/operation/macro/decorator.rb +0 -82
  40. data/lib/pragma/operation/macro/filtering.rb +0 -47
  41. data/lib/pragma/operation/macro/model.rb +0 -30
  42. data/lib/pragma/operation/macro/ordering.rb +0 -84
  43. data/lib/pragma/operation/macro/pagination.rb +0 -96
  44. data/lib/pragma/operation/macro/policy.rb +0 -40
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'trailblazer/operation/model'
4
-
5
- module Pragma
6
- module Operation
7
- module Macro
8
- def self.Model(action = nil)
9
- step = lambda do |input, options|
10
- Trailblazer::Operation::Pipetree::Step.new(
11
- Trailblazer::Operation::Model.for(options['model.class'], action),
12
- 'model.class' => options['model.class'],
13
- 'model.action' => action
14
- ).call(input, options).tap do |result|
15
- unless result
16
- options['result.response'] = Pragma::Operation::Response::NotFound.new.decorate_with(
17
- Pragma::Decorator::Error
18
- )
19
- end
20
- end
21
- end
22
-
23
- [step, name: "model.#{action || 'build'}"]
24
- end
25
-
26
- module Model
27
- end
28
- end
29
- end
30
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pragma
4
- module Operation
5
- module Macro
6
- def self.Ordering
7
- step = ->(input, options) { Ordering.for(input, options) }
8
- [step, name: 'ordering']
9
- end
10
-
11
- module Ordering
12
- class << self
13
- def for(_input, options)
14
- set_defaults(options)
15
-
16
- unless validate_params(options)
17
- handle_invalid_contract(options)
18
- return false
19
- end
20
-
21
- order_column = order_column(options)
22
-
23
- if order_column
24
- options['model'] = options['model'].order(order_column => order_direction(options))
25
- end
26
-
27
- true
28
- end
29
-
30
- private
31
-
32
- def set_defaults(options)
33
- default_column = if options['model.class']&.method_defined?(:created_at)
34
- :created_at
35
- end
36
-
37
- {
38
- 'ordering.columns' => [default_column].compact,
39
- 'ordering.default_column' => default_column,
40
- 'ordering.default_direction' => :desc,
41
- 'ordering.column_param' => :order_property,
42
- 'ordering.direction_param' => :order_direction
43
- }.each_pair do |key, value|
44
- options[key] = value unless options[key]
45
- end
46
- end
47
-
48
- def validate_params(options)
49
- options['contract.ordering'] = Dry::Validation.Schema do
50
- optional(options['ordering.column_param']).filled do
51
- str? & included_in?(options['ordering.columns'].map(&:to_s))
52
- end
53
- optional(options['ordering.direction_param']).filled do
54
- str? & included_in?(%w[asc desc ASC DESC])
55
- end
56
- end
57
-
58
- options['result.contract.ordering'] = options['contract.ordering'].call(
59
- options['params']
60
- )
61
-
62
- options['result.contract.ordering'].errors.empty?
63
- end
64
-
65
- def handle_invalid_contract(options)
66
- options['result.response'] = Response::UnprocessableEntity.new(
67
- errors: options['result.contract.ordering'].errors
68
- ).decorate_with(Pragma::Decorator::Error)
69
- end
70
-
71
- def order_column(options)
72
- params = options['params']
73
- params[options['ordering.column_param']] || options['ordering.default_column']
74
- end
75
-
76
- def order_direction(options)
77
- params = options['params']
78
- params[options['ordering.direction_param']] || options['ordering.default_direction']
79
- end
80
- end
81
- end
82
- end
83
- end
84
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pragma
4
- module Operation
5
- module Macro
6
- def self.Pagination
7
- step = ->(input, options) { Pagination.for(input, options) }
8
- [step, name: 'pagination']
9
- end
10
-
11
- module Pagination
12
- class << self
13
- def for(_input, options)
14
- set_defaults(options)
15
- normalize_params(options)
16
-
17
- unless validate_params(options)
18
- handle_invalid_contract(options)
19
- return false
20
- end
21
-
22
- options['model'] = options['model'].paginate(
23
- page: page(options, **options),
24
- per_page: per_page(options, **options)
25
- )
26
- end
27
-
28
- private
29
-
30
- def set_defaults(options)
31
- {
32
- 'pagination.page_param' => :page,
33
- 'pagination.per_page_param' => :per_page,
34
- 'pagination.default_per_page' => 30,
35
- 'pagination.max_per_page' => 100
36
- }.each_pair do |key, value|
37
- options[key] = value unless options[key]
38
- end
39
- end
40
-
41
- def normalize_params(options)
42
- # This is required because Rails treats all incoming parameters as strings, since it
43
- # can't distinguish. Maybe there's a better way to do it?
44
- options['params'].tap do |p|
45
- %w[pagination.page_param pagination.per_page_param].each do |key|
46
- if p[options[key]] && p[options[key]].respond_to?(:to_i)
47
- p[options[key]] = p[options[key]].to_i
48
- end
49
- end
50
- end
51
- end
52
-
53
- def validate_params(options)
54
- options['contract.pagination'] = Dry::Validation.Schema do
55
- optional(options['pagination.page_param']).filled { int? & gteq?(1) }
56
- optional(options['pagination.per_page_param']).filled do
57
- int? & (gteq?(1) & lteq?(options['pagination.max_per_page']))
58
- end
59
- end
60
-
61
- options['result.contract.pagination'] = options['contract.pagination'].call(
62
- options['params']
63
- )
64
-
65
- options['result.contract.pagination'].errors.empty?
66
- end
67
-
68
- def handle_invalid_contract(options)
69
- options['result.response'] = Response::UnprocessableEntity.new(
70
- errors: options['result.contract.pagination'].errors
71
- ).decorate_with(Pragma::Decorator::Error)
72
- end
73
-
74
- def page(options, params:, **)
75
- return 1 if
76
- !params[options['pagination.page_param']] ||
77
- params[options['pagination.page_param']].blank?
78
-
79
- params[options['pagination.page_param']].to_i
80
- end
81
-
82
- def per_page(options, params:, **)
83
- return options['pagination.default_per_page'] if
84
- !params[options['pagination.per_page_param']] ||
85
- params[options['pagination.per_page_param']].blank?
86
-
87
- [
88
- params[options['pagination.per_page_param']].to_i,
89
- options['pagination.max_per_page']
90
- ].min
91
- end
92
- end
93
- end
94
- end
95
- end
96
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pragma
4
- module Operation
5
- module Macro
6
- def self.Policy(name: :default)
7
- step = ->(input, options) { Policy.for(input, name, options) }
8
- [step, name: "policy.#{name}"]
9
- end
10
-
11
- module Policy
12
- class << self
13
- def for(input, name, options)
14
- policy = options["policy.#{name}.class"].new(options['current_user'], options['model'])
15
-
16
- options["result.policy.#{name}"] = Trailblazer::Operation::Result.new(
17
- policy.send("#{input.class.operation_name}?"),
18
- 'policy' => policy
19
- )
20
-
21
- unless options["result.policy.#{name}"].success?
22
- handle_unauthorized!(options)
23
- return false
24
- end
25
-
26
- true
27
- end
28
-
29
- private
30
-
31
- def handle_unauthorized!(options)
32
- options['result.response'] = Pragma::Operation::Response::Forbidden.new.decorate_with(
33
- Pragma::Decorator::Error
34
- )
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end