params_ready 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/arel/cte_name.rb +20 -0
  3. data/lib/params_ready.rb +36 -0
  4. data/lib/params_ready/builder.rb +140 -0
  5. data/lib/params_ready/error.rb +31 -0
  6. data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
  7. data/lib/params_ready/extensions/collection.rb +43 -0
  8. data/lib/params_ready/extensions/delegation.rb +25 -0
  9. data/lib/params_ready/extensions/finalizer.rb +26 -0
  10. data/lib/params_ready/extensions/freezer.rb +49 -0
  11. data/lib/params_ready/extensions/hash.rb +46 -0
  12. data/lib/params_ready/extensions/late_init.rb +38 -0
  13. data/lib/params_ready/extensions/registry.rb +44 -0
  14. data/lib/params_ready/extensions/undefined.rb +15 -0
  15. data/lib/params_ready/format.rb +130 -0
  16. data/lib/params_ready/helpers/arel_builder.rb +68 -0
  17. data/lib/params_ready/helpers/conditional_block.rb +31 -0
  18. data/lib/params_ready/helpers/find_in_hash.rb +22 -0
  19. data/lib/params_ready/helpers/key_map.rb +176 -0
  20. data/lib/params_ready/helpers/memo.rb +42 -0
  21. data/lib/params_ready/helpers/options.rb +39 -0
  22. data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
  23. data/lib/params_ready/helpers/parameter_storage_class_methods.rb +36 -0
  24. data/lib/params_ready/helpers/parameter_user_class_methods.rb +31 -0
  25. data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
  26. data/lib/params_ready/helpers/rule.rb +57 -0
  27. data/lib/params_ready/helpers/storage.rb +30 -0
  28. data/lib/params_ready/helpers/usage_rule.rb +18 -0
  29. data/lib/params_ready/input_context.rb +31 -0
  30. data/lib/params_ready/intent.rb +70 -0
  31. data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
  32. data/lib/params_ready/marshaller/builder_module.rb +9 -0
  33. data/lib/params_ready/marshaller/collection.rb +165 -0
  34. data/lib/params_ready/marshaller/definition_module.rb +63 -0
  35. data/lib/params_ready/marshaller/hash_marshallers.rb +100 -0
  36. data/lib/params_ready/marshaller/hash_set_marshallers.rb +96 -0
  37. data/lib/params_ready/marshaller/parameter_module.rb +11 -0
  38. data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
  39. data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
  40. data/lib/params_ready/ordering/column.rb +60 -0
  41. data/lib/params_ready/ordering/ordering.rb +276 -0
  42. data/lib/params_ready/output_parameters.rb +127 -0
  43. data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
  44. data/lib/params_ready/pagination/cursor.rb +171 -0
  45. data/lib/params_ready/pagination/direction.rb +148 -0
  46. data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
  47. data/lib/params_ready/pagination/keysets.rb +70 -0
  48. data/lib/params_ready/pagination/nulls.rb +31 -0
  49. data/lib/params_ready/pagination/offset_pagination.rb +130 -0
  50. data/lib/params_ready/pagination/tendency.rb +28 -0
  51. data/lib/params_ready/parameter/abstract_hash_parameter.rb +204 -0
  52. data/lib/params_ready/parameter/array_parameter.rb +197 -0
  53. data/lib/params_ready/parameter/definition.rb +264 -0
  54. data/lib/params_ready/parameter/hash_parameter.rb +63 -0
  55. data/lib/params_ready/parameter/hash_set_parameter.rb +101 -0
  56. data/lib/params_ready/parameter/parameter.rb +456 -0
  57. data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
  58. data/lib/params_ready/parameter/state.rb +132 -0
  59. data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
  60. data/lib/params_ready/parameter/value_parameter.rb +182 -0
  61. data/lib/params_ready/parameter_definer.rb +14 -0
  62. data/lib/params_ready/parameter_user.rb +43 -0
  63. data/lib/params_ready/query/array_grouping.rb +68 -0
  64. data/lib/params_ready/query/custom_predicate.rb +102 -0
  65. data/lib/params_ready/query/exists_predicate.rb +103 -0
  66. data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
  67. data/lib/params_ready/query/grouping.rb +177 -0
  68. data/lib/params_ready/query/join_clause.rb +87 -0
  69. data/lib/params_ready/query/nullness_predicate.rb +71 -0
  70. data/lib/params_ready/query/polymorph_predicate.rb +77 -0
  71. data/lib/params_ready/query/predicate.rb +203 -0
  72. data/lib/params_ready/query/predicate_operator.rb +132 -0
  73. data/lib/params_ready/query/relation.rb +337 -0
  74. data/lib/params_ready/query/structured_grouping.rb +58 -0
  75. data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
  76. data/lib/params_ready/query_context.rb +21 -0
  77. data/lib/params_ready/restriction.rb +252 -0
  78. data/lib/params_ready/result.rb +109 -0
  79. data/lib/params_ready/value/coder.rb +181 -0
  80. data/lib/params_ready/value/constraint.rb +198 -0
  81. data/lib/params_ready/value/custom.rb +56 -0
  82. data/lib/params_ready/value/validator.rb +68 -0
  83. metadata +181 -0
@@ -0,0 +1,58 @@
1
+ require_relative '../parameter/hash_parameter'
2
+ require_relative '../parameter/value_parameter'
3
+ require_relative 'fixed_operator_predicate'
4
+ require_relative 'nullness_predicate'
5
+ require_relative 'grouping'
6
+
7
+ module ParamsReady
8
+ module Query
9
+ class StructuredGrouping < Parameter::HashParameter
10
+ include Parameter::GroupingLike
11
+ def predicates
12
+ return [] if is_nil?
13
+
14
+ definition.predicates.keys.map do |name|
15
+ parameter = child(name)
16
+ next nil unless parameter.is_definite?
17
+ parameter
18
+ end.compact
19
+ end
20
+
21
+ def operator
22
+ self[:operator].unwrap
23
+ end
24
+
25
+ def context_for_predicates(restriction)
26
+ intent_for_children(restriction)
27
+ end
28
+ end
29
+
30
+ class StructuredGroupingBuilder < Builder
31
+ include GroupingLike
32
+ include Parameter::AbstractHashParameterBuilder::HashLike
33
+ PredicateRegistry.register_predicate :structured_grouping_predicate, self
34
+
35
+ def self.instance(name, altn: nil)
36
+ new StructuredGroupingDefinition.new(name, altn: altn)
37
+ end
38
+ end
39
+
40
+ class StructuredGroupingDefinition < Parameter::HashParameterDefinition
41
+ attr_reader :arel_table, :predicates
42
+
43
+ def initialize(*args, **opts)
44
+ @predicates = {}
45
+ super *args, **opts
46
+ end
47
+
48
+ def add_predicate(predicate)
49
+ raise ParamsReadyError, "Predicate name taken: '#{predicate.name}" if predicates.key? predicate.name
50
+ predicates[predicate.name] = predicate
51
+ end
52
+
53
+ parameter_class StructuredGrouping
54
+
55
+ freeze_variables :predicates
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,125 @@
1
+ require_relative 'predicate'
2
+ require_relative '../parameter/hash_parameter'
3
+ require_relative '../parameter/value_parameter'
4
+ require_relative '../value/validator'
5
+ require_relative 'predicate_operator'
6
+
7
+ module ParamsReady
8
+ module Query
9
+ class VariableOperatorPredicate < Parameter::AbstractParameter
10
+ include Predicate::DelegatingPredicate
11
+ include Predicate::HavingAttribute
12
+
13
+ def initialize(definition)
14
+ super definition
15
+ @data = definition.hash_parameter.create
16
+ end
17
+
18
+ def build_query(select_expression, context: nil)
19
+ operator.to_query(select_expression, value)
20
+ end
21
+
22
+ def perform_test(record, attribute_name)
23
+ operator.test(record, attribute_name, value)
24
+ end
25
+
26
+ def value
27
+ @data[:value].unwrap
28
+ end
29
+
30
+ def operator
31
+ @data[:operator].unwrap
32
+ end
33
+
34
+ def inspect_content
35
+ op, val = if is_definite?
36
+ op = @data[:operator].unwrap_or(nil)&.name || '?'
37
+ val = @data[:value].unwrap_or('?')
38
+ else
39
+ %w[? ?]
40
+ end
41
+ "#{definition.attribute_name} #{op} #{val}"
42
+ end
43
+ end
44
+
45
+ class OperatorCoder < Value::Coder
46
+ def self.coerce(value, context)
47
+ return value if value.class == Class && value < PredicateOperator
48
+ identifier = value.to_sym
49
+ PredicateRegistry.operator(identifier, context)
50
+ end
51
+
52
+ def self.format(value, intent)
53
+ intent.hash_key(value)
54
+ end
55
+
56
+ def self.strict_default?
57
+ false
58
+ end
59
+ end
60
+
61
+ Parameter::ValueParameterBuilder.register_coder :predicate_operator, OperatorCoder
62
+
63
+ class VariableOperatorPredicateBuilder < AbstractPredicateBuilder
64
+ PredicateRegistry.register_predicate :variable_operator_predicate, self
65
+ include HavingType
66
+ include HavingAttribute
67
+ include DelegatingBuilder[:hash_parameter_builder]
68
+
69
+ def self.instance(name, altn: nil, attr: nil)
70
+ new VariableOperatorPredicateDefinition.new name, altn: altn, attribute_name: attr
71
+ end
72
+
73
+ def data_object_handles
74
+ [:value, :val]
75
+ end
76
+
77
+ def operators(*arr, &block)
78
+ @definition.set_operators(arr, &block)
79
+ end
80
+ end
81
+
82
+ class VariableOperatorPredicateDefinition < AbstractPredicateDefinition
83
+ include HavingAttribute
84
+
85
+ attr_reader :hash_parameter_builder
86
+ attr_reader :hash_parameter
87
+
88
+ def initialize(*args, attribute_name: nil, **opts)
89
+ super *args, **opts
90
+ @attribute_name = attribute_name
91
+ @hash_parameter_builder = Builder.builder(:hash).instance(name, altn: altn)
92
+ @operator_parameter_builder = Builder.builder(:predicate_operator).instance(:operator, altn: :op)
93
+ end
94
+
95
+ def set_type(type)
96
+ @type = type
97
+ @hash_parameter_builder.add @type.finish
98
+ end
99
+
100
+ def set_operators(array, &block)
101
+ context = Format.instance(:backend)
102
+
103
+ operators = array.map do |name|
104
+ PredicateRegistry.operator(name, context)
105
+ end
106
+ @operator_parameter_builder.include do
107
+ constrain :enum, operators
108
+ end
109
+ @operator_parameter_builder.include(&block) unless block.nil?
110
+ @hash_parameter_builder.add @operator_parameter_builder.build
111
+ end
112
+
113
+ def finish
114
+ @hash_parameter = @hash_parameter_builder.build
115
+ @hash_parameter_builder = nil
116
+ @operator_parameter_builder = nil
117
+ @type = nil
118
+
119
+ super
120
+ end
121
+
122
+ parameter_class VariableOperatorPredicate
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,21 @@
1
+ require 'forwardable'
2
+ require_relative 'restriction'
3
+
4
+ module ParamsReady
5
+ class QueryContext
6
+ include Restriction::Wrapper
7
+ extend Forwardable
8
+ attr_reader :data
9
+ def_delegator :data, :[]
10
+
11
+ def initialize(restriction, data = {})
12
+ @data = data.freeze
13
+ raise ParamsReadyError, "Restriction expected, got: #{restriction.inspect}" unless restriction.is_a? Restriction
14
+ @restriction = restriction.freeze
15
+ end
16
+
17
+ def clone(restriction:)
18
+ QueryContext.new restriction, data
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,252 @@
1
+ module ParamsReady
2
+ class Restriction
3
+ module Wrapper
4
+ extend Forwardable
5
+ attr_reader :restriction
6
+ def_delegators :restriction, :name_permitted?, :permitted?, :permissions_for
7
+
8
+ def delegate(*args)
9
+ return self if @restriction.everything?
10
+
11
+ new_restriction = @restriction.delegate(*args)
12
+ clone(restriction: new_restriction)
13
+ end
14
+
15
+ def for_children(parameter)
16
+ return self if @restriction.everything?
17
+
18
+ new_restriction = @restriction.for_children parameter
19
+ clone(restriction: new_restriction)
20
+ end
21
+
22
+ def permit_all
23
+ return self if @restriction.everything?
24
+
25
+ clone(restriction: Restriction.blanket_permission)
26
+ end
27
+
28
+ def permit(*list)
29
+ restriction = Restriction.permit(*list)
30
+ return self if @restriction.everything? && restriction.everything?
31
+
32
+ clone(restriction: restriction)
33
+ end
34
+
35
+ def prohibit(*list)
36
+ restriction = Restriction.prohibit(*list)
37
+ return self if @restriction.everything? && restriction.everything?
38
+
39
+ clone(restriction: restriction)
40
+ end
41
+
42
+ def to_restriction
43
+ @restriction
44
+ end
45
+ end
46
+
47
+ class Everything
48
+ def self.key?(_)
49
+ true
50
+ end
51
+
52
+ def self.[](_)
53
+ Everything
54
+ end
55
+
56
+ def self.dup
57
+ self
58
+ end
59
+ end
60
+
61
+ class Nothing
62
+ def self.key?(_)
63
+ false
64
+ end
65
+
66
+ def self.[](_)
67
+ Nothing
68
+ end
69
+
70
+ def self.dup
71
+ self
72
+ end
73
+ end
74
+
75
+ def self.blanket_permission
76
+ @blanket_permission ||= Allowlist.new
77
+ end
78
+
79
+ def self.permit(*args)
80
+ Allowlist.instance(*args)
81
+ end
82
+
83
+ def self.prohibit(*args)
84
+ Denylist.instance(*args)
85
+ end
86
+
87
+ def self.from_array(arr)
88
+ arr.each_with_object({}) do |element, restriction|
89
+ case element
90
+ when String, Symbol
91
+ restriction[element.to_sym] = Everything
92
+ when Hash
93
+ element.each do |key, value|
94
+ restriction[key.to_sym] = value
95
+ end
96
+ else
97
+ raise TypeError.new("Unexpected as restriction item: #{element}")
98
+ end
99
+ end
100
+ end
101
+
102
+ def self.instance(*list)
103
+ return blanket_permission if list.length == 1 && list[0] == default
104
+
105
+ restriction_list = if list.length == 1 && list[0].is_a?(Regexp)
106
+ list[0]
107
+ else
108
+ from_array(list)
109
+ end
110
+ new restriction_list
111
+ end
112
+
113
+ attr_reader :restriction
114
+
115
+ def initialize(restriction = self.class.default)
116
+ @restriction = if restriction.is_a? self.class
117
+ restriction.restriction
118
+ else
119
+ restriction.freeze
120
+ end
121
+ freeze
122
+ end
123
+
124
+ def hash
125
+ @restriction.hash
126
+ end
127
+
128
+ def everything?
129
+ @restriction == self.class.default
130
+ end
131
+
132
+ def name_listed?(name)
133
+ if @restriction.is_a? Regexp
134
+ name =~ @restriction
135
+ else
136
+ @restriction.key?(name)
137
+ end
138
+ end
139
+
140
+ def permitted?(parameter)
141
+ name = parameter.name
142
+ return false unless name_permitted?(name)
143
+ return true unless parameter.respond_to? :permission_depends_on
144
+
145
+ children = parameter.permission_depends_on
146
+ intent = parameter.intent_for_children(self)
147
+ children.all? do |child|
148
+ intent.permitted?(child)
149
+ end
150
+ end
151
+
152
+ def delegate(parent, delegate_name, *others)
153
+ return self if everything?
154
+
155
+ list = restriction_list_for(parent)
156
+
157
+ self.class.instance({ delegate_name => list }, *others)
158
+ end
159
+
160
+ def for_children(parameter)
161
+ return self if everything?
162
+
163
+ list = restriction_list_for(parameter)
164
+ if list.is_a? Restriction
165
+ list
166
+ else
167
+ self.class.instance(*list)
168
+ end
169
+ end
170
+
171
+ def restriction_list_for(parameter)
172
+ name = parameter.name
173
+ raise ParamsReadyError, "Parameter '#{name}' not permitted" unless name_permitted? name
174
+ restriction_list_for_name(name)
175
+ end
176
+
177
+ def to_restriction
178
+ self
179
+ end
180
+
181
+ def permit_all
182
+ self.class.permit_all
183
+ end
184
+
185
+ def self.permit_all
186
+ new default
187
+ end
188
+
189
+ class Allowlist < Restriction
190
+ def self.default
191
+ Everything
192
+ end
193
+
194
+ def name_permitted?(name)
195
+ name_listed?(name)
196
+ end
197
+
198
+ def permit(*args)
199
+ self.class.permit(*args)
200
+ end
201
+
202
+ def ==(other)
203
+ return false unless other.is_a? self.class
204
+ return true if object_id == other.object_id
205
+
206
+ restriction == other.restriction
207
+ end
208
+
209
+ protected
210
+
211
+ def restriction_list_for_name(name)
212
+ if @restriction.is_a? Regexp
213
+ self.class.default
214
+ else
215
+ @restriction[name]
216
+ end
217
+ end
218
+ end
219
+
220
+ class Denylist < Restriction
221
+ def self.default
222
+ Nothing
223
+ end
224
+
225
+ def name_permitted?(name)
226
+ return true unless name_listed?(name)
227
+ return false unless @restriction.is_a?(Hash)
228
+ return true if @restriction[name].is_a?(Array)
229
+ return true if @restriction[name].is_a?(Symbol)
230
+ return true if @restriction[name] == self.class.default
231
+
232
+ false
233
+ end
234
+
235
+ def prohibit(*args)
236
+ self.class.prohibit(*args)
237
+ end
238
+
239
+ protected
240
+
241
+ def restriction_list_for_name(name)
242
+ if @restriction.is_a? Regexp
243
+ self.class.default
244
+ elsif @restriction[name].nil?
245
+ self.class.default
246
+ else
247
+ @restriction[name]
248
+ end
249
+ end
250
+ end
251
+ end
252
+ end