params_ready 0.0.1

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 (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,9 @@
1
+ module ParamsReady
2
+ module Marshaller
3
+ module BuilderModule
4
+ def marshal(to: nil, using: nil, **opts)
5
+ @definition.set_marshaller(to: to, using: using, **opts)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,165 @@
1
+ require_relative '../error'
2
+ require_relative '../extensions/hash'
3
+
4
+ module ParamsReady
5
+ module Marshaller
6
+ class InstanceCollection
7
+ attr_reader :default, :instances
8
+
9
+ def initialize(canonical, default = nil, instances = {})
10
+ @canonical = canonical
11
+ @default = default
12
+ @instances = instances
13
+ end
14
+
15
+ def canonicalize(definition, input, context, validator, **opts)
16
+ value_class = infer_class(input)
17
+ marshaller = instance(value_class)
18
+ raise ParamsReadyError, "Unexpected type for #{definition.name}: #{value_class.name}" if marshaller.nil?
19
+
20
+ marshaller.canonicalize(definition, input, context, validator, **opts)
21
+ end
22
+
23
+ def marshal_canonical(parameter, format, **opts)
24
+ marshaller = instance @canonical
25
+ if marshaller.nil?
26
+ value = parameter.send(:bare_value)
27
+ raise ParamsReadyError, "Value is not canonical" unless value.is_a? @canonical
28
+ value
29
+ else
30
+ marshaller.marshal(parameter, format, **opts)
31
+ end
32
+ end
33
+
34
+ def marshal(parameter, format, **opts)
35
+ default.marshal(parameter, format, **opts)
36
+ end
37
+
38
+ def infer_class(value)
39
+ if instances.key? value.class
40
+ value.class
41
+ elsif value.is_a?(Hash) || Extensions::Hash.acts_as_hash?(value)
42
+ Hash
43
+ else
44
+ value.class
45
+ end
46
+ end
47
+
48
+ def add_instance(value_class, instance)
49
+ raise ParamsReadyError, "Marshaller must be frozen" unless instance.frozen?
50
+
51
+ @instances[value_class] = instance
52
+ end
53
+
54
+ def instance(value_class)
55
+ @instances[value_class]
56
+ end
57
+
58
+ def instance?(value_class)
59
+ @instances.key?(value_class)
60
+ end
61
+
62
+ def default=(instance)
63
+ raise ParamsReadyError, "Default already defined" if default?
64
+ raise ParamsReadyError, "Marshaller must be frozen" unless instance.frozen?
65
+
66
+ @default = instance
67
+ end
68
+
69
+ def default!(value_class)
70
+ instance = instance(value_class)
71
+ raise ParamsReadyError, "No marshaller for class '#{value_class.name}'" if instance.nil?
72
+ self.default = instance
73
+ end
74
+
75
+ def default?
76
+ !@default.nil?
77
+ end
78
+
79
+ def reverse_merge(other)
80
+ clone = self.class.new(@canonical, @default, @instances.dup)
81
+ populate_clone(clone, other)
82
+ end
83
+
84
+ def populate_clone(clone, other)
85
+ if other.default? && !clone.default?
86
+ clone.default = other.default
87
+ end
88
+
89
+ other.instances.each do |value_class, i|
90
+ next if clone.instance?(value_class)
91
+
92
+ clone.add_instance value_class, i
93
+ end
94
+
95
+ clone
96
+ end
97
+
98
+ def freeze
99
+ @instance.freeze
100
+ super
101
+ end
102
+ end
103
+
104
+ class ClassCollection < InstanceCollection
105
+ attr_reader :factories
106
+
107
+ def initialize(canonical, default = nil, instances = {}, factories = {})
108
+ @factories = factories
109
+ super canonical, default, instances
110
+ end
111
+
112
+ def instance_collection
113
+ InstanceCollection.new(@canonical, nil, @instances.dup)
114
+ end
115
+
116
+ def add_factory(name, factory)
117
+ name = name.to_sym
118
+ raise ParamsReadyError, "Name '#{name}' already taken" if factory?(name)
119
+ raise ParamsReadyError, "Factory must be frozen" unless factory.frozen?
120
+
121
+ @factories[name] = factory
122
+ end
123
+
124
+ def add_instance(value_class, instance)
125
+ raise ParamsReadyError, "Marshaller for '#{value_class.name}' already exists" if instance?(value_class)
126
+
127
+ super
128
+ end
129
+
130
+ def build_instance(name, **opts)
131
+ factory(name).instance(**opts)
132
+ end
133
+
134
+ def factory(name)
135
+ @factories[name]
136
+ end
137
+
138
+ def factory?(name)
139
+ @factories.key? name
140
+ end
141
+
142
+ def freeze
143
+ @factories.freeze
144
+ super
145
+ end
146
+
147
+ def reverse_merge(other)
148
+ clone = self.class.new(@canonical, @default, @instances.dup, @factories.dup)
149
+ populate_clone(clone, other)
150
+ end
151
+
152
+ def populate_clone(clone, other)
153
+ merged = super
154
+
155
+ other.factories.each do |value_class, f|
156
+ next if merged.factory?(value_class)
157
+
158
+ clone.add_factory value_class, f
159
+ end
160
+
161
+ merged
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,63 @@
1
+ module ParamsReady
2
+ module Marshaller
3
+ module DefinitionModule
4
+ def self.[](collection)
5
+ mod = Module.new
6
+ mod.include self
7
+ mod.define_method :class_marshallers do
8
+ collection
9
+ end
10
+ mod
11
+ end
12
+
13
+ attr_reader :marshallers
14
+
15
+ def initialize(*args, marshaller: nil, **options)
16
+ @marshallers = class_marshallers.instance_collection
17
+ set_marshaller(**marshaller) unless marshaller.nil?
18
+
19
+ super *args, **options
20
+ end
21
+
22
+ def set_marshaller(to: nil, using: nil, **opts)
23
+ if using.is_a? Symbol
24
+ raise ParamsReadyError, "Expected ':to' argument to be nil, got #{to.class.name}" unless to.nil?
25
+ default_class, instance = class_marshallers.build_instance(using, **opts)
26
+ @marshallers.add_instance(default_class, instance)
27
+ @marshallers.default!(default_class)
28
+ elsif using.nil?
29
+ @marshallers.default!(to)
30
+ else
31
+ @marshallers.add_instance(to, using)
32
+ @marshallers.default!(to)
33
+ end
34
+ end
35
+
36
+ def marshal(parameter, intent, **opts)
37
+ if intent.marshal?(name_for_formatter)
38
+ @marshallers.marshal(parameter, intent, **opts)
39
+ else
40
+ @marshallers.marshal_canonical(parameter, intent, **opts)
41
+ end
42
+ end
43
+
44
+ def try_canonicalize(input, context, validator = nil, **opts)
45
+ @marshallers.canonicalize(self, input, context, validator, **opts)
46
+ end
47
+
48
+ def finish
49
+ unless @marshallers.default?
50
+ if class_marshallers.default?
51
+ @marshallers.default = class_marshallers.default
52
+ end
53
+ end
54
+ super
55
+ end
56
+
57
+ def freeze
58
+ @marshallers.freeze
59
+ super
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,100 @@
1
+ require 'json'
2
+ require 'base64'
3
+ require_relative 'collection'
4
+
5
+ module ParamsReady
6
+ module Marshaller
7
+ class HashMarshallers
8
+ module AbstractMarshaller
9
+ def extract_bare_value(parameter, intent)
10
+ parameter.names.keys.reduce({}) do |result, name|
11
+ c = parameter[name]
12
+ hash = c.to_hash_if_eligible(intent)
13
+ if hash.nil?
14
+ result
15
+ else
16
+ result.deep_merge(hash)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module Base64Marshaller
23
+ def self.instance
24
+ [String, self]
25
+ end
26
+
27
+ def self.canonicalize(definition, string, context, validator)
28
+ json = Base64.urlsafe_decode64(string)
29
+ hash = JSON.parse(json)
30
+ HashMarshaller.canonicalize(definition, hash, context, validator)
31
+ end
32
+
33
+ def self.marshal(parameter, intent)
34
+ hash = HashMarshaller.marshal(parameter, intent)
35
+ json = JSON.generate(hash)
36
+ Base64.urlsafe_encode64(json)
37
+ end
38
+
39
+ freeze
40
+ end
41
+
42
+ module HashMarshaller
43
+ extend AbstractMarshaller
44
+
45
+ def self.canonicalize(definition, hash, context, validator, freeze: false)
46
+ hash = if definition.respond_to?(:remap?) && definition.remap?(context)
47
+ definition.key_map.to_standard(hash)
48
+ else
49
+ hash
50
+ end
51
+
52
+ value = definition.names.each_with_object({}) do |(name, child_def), result|
53
+ child = child_def.create
54
+ child.set_from_hash(hash, validator: validator&.for_child(name), context: context)
55
+ child.freeze if freeze
56
+ result[name] = child
57
+ end
58
+ [value, validator]
59
+ end
60
+
61
+ def self.marshal(parameter, intent)
62
+ value = extract_bare_value(parameter, intent)
63
+
64
+ definition = parameter.definition
65
+
66
+ if value == {}
67
+ if intent.marshal?(definition.name_for_formatter)
68
+ if definition.optional? || definition.default_defined?
69
+ parameter.class::EMPTY_HASH
70
+ elsif intent.omit?(parameter)
71
+ nil
72
+ else
73
+ value
74
+ end
75
+ else
76
+ value
77
+ end
78
+ elsif definition.respond_to?(:remap?) && definition.remap?(intent)
79
+ definition.key_map.to_alternative(value)
80
+ else
81
+ value
82
+ end
83
+ end
84
+
85
+ freeze
86
+ end
87
+
88
+ def self.collection
89
+ @collection ||= begin
90
+ c = ClassCollection.new Hash
91
+ c.add_instance Hash, HashMarshaller
92
+ c.add_factory :base64, Base64Marshaller
93
+ c.default!(Hash)
94
+ c.freeze
95
+ c
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,96 @@
1
+ require_relative 'collection'
2
+ require_relative 'hash_marshallers'
3
+
4
+ module ParamsReady
5
+ module Marshaller
6
+ class HashSetMarshallers
7
+ module AbstractMarshaller
8
+ def canonicalize_collection(definition, context, validator, freeze: false)
9
+ hash = {}
10
+ definition.names.each do |name, definition|
11
+ child = definition.create
12
+ value = yield child
13
+ child.set_from_input(value, context, validator)
14
+ child.freeze if freeze
15
+ hash[name] = child
16
+ end
17
+ [hash, validator]
18
+ end
19
+ end
20
+
21
+ module HashMarshaller
22
+ extend AbstractMarshaller
23
+
24
+ def self.canonicalize(definition, hash, context, validator)
25
+ canonicalize_collection(definition, context, validator) do |child|
26
+ _, value = child.find_in_hash(hash, context)
27
+ value
28
+ end
29
+ end
30
+
31
+ def self.marshal(parameter, intent)
32
+ if intent.marshal? parameter.name_for_formatter
33
+ HashMarshallers::HashMarshaller.marshal(parameter, intent)
34
+ else
35
+ SetMarshaller.marshal(parameter, intent)
36
+ end
37
+ end
38
+
39
+ freeze
40
+ end
41
+
42
+ module SetMarshaller
43
+ extend AbstractMarshaller
44
+
45
+ def self.canonicalize(definition, set, context, validator, freeze: false)
46
+ canonicalize_collection(definition, context, validator, freeze: freeze) do |child|
47
+ value = definition.values[child.name]
48
+ set.member?(value) || set.member?(value.to_s)
49
+ end
50
+ end
51
+
52
+ def self.marshal(parameter, intent)
53
+ intent = parameter.class.intent_for_set(intent)
54
+
55
+ members = parameter.send(:bare_value).select do |_, m|
56
+ m.unwrap_or(false) == true && m.eligible_for_output?(intent)
57
+ end.map do |key, _|
58
+ parameter.definition.values[key]
59
+ end
60
+
61
+ members.to_set
62
+ end
63
+
64
+ freeze
65
+ end
66
+
67
+ module ArrayMarshaller
68
+ extend AbstractMarshaller
69
+
70
+ def self.canonicalize(definition, array, context, validator)
71
+ set = array.to_set
72
+ SetMarshaller.canonicalize(definition, set, context, validator)
73
+ end
74
+
75
+ def self.marshal(parameter, intent)
76
+ set = SetMarshaller.marshal(parameter, intent)
77
+ set.to_a
78
+ end
79
+
80
+ freeze
81
+ end
82
+
83
+ def self.collection
84
+ @collection ||= begin
85
+ c = ClassCollection.new Hash
86
+ c.add_instance Hash, HashMarshaller
87
+ c.add_instance Set, SetMarshaller
88
+ c.add_instance Array, ArrayMarshaller
89
+ c.default!(Hash)
90
+ c.freeze
91
+ c
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,11 @@
1
+ module ParamsReady
2
+ module Marshaller
3
+ module ParameterModule
4
+ def marshal(intent)
5
+ return nil if is_nil?
6
+
7
+ definition.marshal(self, intent)
8
+ end
9
+ end
10
+ end
11
+ end