pragma 2.1.1 → 2.2.0

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.
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