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.
- checksums.yaml +7 -0
- data/lib/arel/cte_name.rb +20 -0
- data/lib/params_ready.rb +36 -0
- data/lib/params_ready/builder.rb +140 -0
- data/lib/params_ready/error.rb +31 -0
- data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
- data/lib/params_ready/extensions/collection.rb +43 -0
- data/lib/params_ready/extensions/delegation.rb +25 -0
- data/lib/params_ready/extensions/finalizer.rb +26 -0
- data/lib/params_ready/extensions/freezer.rb +49 -0
- data/lib/params_ready/extensions/hash.rb +46 -0
- data/lib/params_ready/extensions/late_init.rb +38 -0
- data/lib/params_ready/extensions/registry.rb +44 -0
- data/lib/params_ready/extensions/undefined.rb +15 -0
- data/lib/params_ready/format.rb +130 -0
- data/lib/params_ready/helpers/arel_builder.rb +68 -0
- data/lib/params_ready/helpers/conditional_block.rb +31 -0
- data/lib/params_ready/helpers/find_in_hash.rb +22 -0
- data/lib/params_ready/helpers/key_map.rb +176 -0
- data/lib/params_ready/helpers/memo.rb +42 -0
- data/lib/params_ready/helpers/options.rb +39 -0
- data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
- data/lib/params_ready/helpers/parameter_storage_class_methods.rb +36 -0
- data/lib/params_ready/helpers/parameter_user_class_methods.rb +31 -0
- data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
- data/lib/params_ready/helpers/rule.rb +57 -0
- data/lib/params_ready/helpers/storage.rb +30 -0
- data/lib/params_ready/helpers/usage_rule.rb +18 -0
- data/lib/params_ready/input_context.rb +31 -0
- data/lib/params_ready/intent.rb +70 -0
- data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
- data/lib/params_ready/marshaller/builder_module.rb +9 -0
- data/lib/params_ready/marshaller/collection.rb +165 -0
- data/lib/params_ready/marshaller/definition_module.rb +63 -0
- data/lib/params_ready/marshaller/hash_marshallers.rb +100 -0
- data/lib/params_ready/marshaller/hash_set_marshallers.rb +96 -0
- data/lib/params_ready/marshaller/parameter_module.rb +11 -0
- data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
- data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
- data/lib/params_ready/ordering/column.rb +60 -0
- data/lib/params_ready/ordering/ordering.rb +276 -0
- data/lib/params_ready/output_parameters.rb +127 -0
- data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
- data/lib/params_ready/pagination/cursor.rb +171 -0
- data/lib/params_ready/pagination/direction.rb +148 -0
- data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
- data/lib/params_ready/pagination/keysets.rb +70 -0
- data/lib/params_ready/pagination/nulls.rb +31 -0
- data/lib/params_ready/pagination/offset_pagination.rb +130 -0
- data/lib/params_ready/pagination/tendency.rb +28 -0
- data/lib/params_ready/parameter/abstract_hash_parameter.rb +204 -0
- data/lib/params_ready/parameter/array_parameter.rb +197 -0
- data/lib/params_ready/parameter/definition.rb +264 -0
- data/lib/params_ready/parameter/hash_parameter.rb +63 -0
- data/lib/params_ready/parameter/hash_set_parameter.rb +101 -0
- data/lib/params_ready/parameter/parameter.rb +456 -0
- data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
- data/lib/params_ready/parameter/state.rb +132 -0
- data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
- data/lib/params_ready/parameter/value_parameter.rb +182 -0
- data/lib/params_ready/parameter_definer.rb +14 -0
- data/lib/params_ready/parameter_user.rb +43 -0
- data/lib/params_ready/query/array_grouping.rb +68 -0
- data/lib/params_ready/query/custom_predicate.rb +102 -0
- data/lib/params_ready/query/exists_predicate.rb +103 -0
- data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
- data/lib/params_ready/query/grouping.rb +177 -0
- data/lib/params_ready/query/join_clause.rb +87 -0
- data/lib/params_ready/query/nullness_predicate.rb +71 -0
- data/lib/params_ready/query/polymorph_predicate.rb +77 -0
- data/lib/params_ready/query/predicate.rb +203 -0
- data/lib/params_ready/query/predicate_operator.rb +132 -0
- data/lib/params_ready/query/relation.rb +337 -0
- data/lib/params_ready/query/structured_grouping.rb +58 -0
- data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
- data/lib/params_ready/query_context.rb +21 -0
- data/lib/params_ready/restriction.rb +252 -0
- data/lib/params_ready/result.rb +109 -0
- data/lib/params_ready/value/coder.rb +181 -0
- data/lib/params_ready/value/constraint.rb +198 -0
- data/lib/params_ready/value/custom.rb +56 -0
- data/lib/params_ready/value/validator.rb +68 -0
- metadata +181 -0
@@ -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
|