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,67 @@
|
|
1
|
+
require_relative 'collection'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
module Marshaller
|
5
|
+
class PolymorphMarshallers
|
6
|
+
class HashMarshaller
|
7
|
+
attr_reader :type_identifier
|
8
|
+
|
9
|
+
def self.instance(type_identifier:)
|
10
|
+
marshaller = new type_identifier
|
11
|
+
marshaller.freeze
|
12
|
+
[Hash, marshaller]
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(type_identifier)
|
16
|
+
@type_identifier = type_identifier.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
def reserved?(name)
|
20
|
+
name == type_identifier
|
21
|
+
end
|
22
|
+
|
23
|
+
def canonicalize(definition, hash, context, validator)
|
24
|
+
raise ParamsReadyError, "Type key can't be retrieved" unless hash.length == 1
|
25
|
+
key = hash.keys.first
|
26
|
+
value = hash.values.first
|
27
|
+
value = type(definition, key, value, context, validator)
|
28
|
+
|
29
|
+
|
30
|
+
[value, validator]
|
31
|
+
end
|
32
|
+
|
33
|
+
def type(definition, key, value, context, validator)
|
34
|
+
type_key = key.to_sym == type_identifier ? value : key
|
35
|
+
prototype = definition.type(type_key, context)
|
36
|
+
raise ParamsReadyError, "Unexpected type for #{definition.name}: #{type_key}" if prototype.nil?
|
37
|
+
|
38
|
+
type = prototype.create
|
39
|
+
return type if type_key == value
|
40
|
+
type.set_from_input(value, context, validator)
|
41
|
+
type
|
42
|
+
end
|
43
|
+
|
44
|
+
def marshal(parameter, intent)
|
45
|
+
type = parameter.send(:bare_value)
|
46
|
+
|
47
|
+
hash = type.to_hash_if_eligible(intent)
|
48
|
+
return hash unless hash.nil?
|
49
|
+
|
50
|
+
value = type.hash_key(intent)
|
51
|
+
{ type_identifier => value }
|
52
|
+
end
|
53
|
+
|
54
|
+
freeze
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.collection
|
58
|
+
@collection ||= begin
|
59
|
+
c = ClassCollection.new Hash
|
60
|
+
c.add_factory :hash, HashMarshaller
|
61
|
+
c.freeze
|
62
|
+
c
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require_relative 'collection'
|
2
|
+
require_relative '../extensions/undefined'
|
3
|
+
require_relative '../extensions/hash'
|
4
|
+
|
5
|
+
module ParamsReady
|
6
|
+
module Marshaller
|
7
|
+
class TupleMarshallers
|
8
|
+
module AbstractMarshaller
|
9
|
+
def self.marshal_fields(fields, intent)
|
10
|
+
fields.map do |field|
|
11
|
+
field.format(intent)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def marshal(parameter, intent)
|
16
|
+
fields = parameter.send(:bare_value)
|
17
|
+
fields = AbstractMarshaller.marshal_fields(fields, intent)
|
18
|
+
do_marshal(fields, intent)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ArrayMarshaller
|
23
|
+
extend AbstractMarshaller
|
24
|
+
|
25
|
+
def self.canonicalize(definition, array, context, validator, freeze: false)
|
26
|
+
if array.length != definition.arity
|
27
|
+
raise ParamsReadyError, "Unexpected array length: #{array.length}"
|
28
|
+
end
|
29
|
+
|
30
|
+
canonical = definition.fields.each_with_index.map do |field_definition, index|
|
31
|
+
element = field_definition.create
|
32
|
+
element.set_from_input(array[index], context, validator)
|
33
|
+
element.freeze if freeze
|
34
|
+
element
|
35
|
+
end
|
36
|
+
[canonical, validator]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.do_marshal(fields, _)
|
40
|
+
fields
|
41
|
+
end
|
42
|
+
|
43
|
+
freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
module HashMarshaller
|
47
|
+
extend AbstractMarshaller
|
48
|
+
|
49
|
+
def self.canonicalize(definition, hash, context, validator)
|
50
|
+
array = (0...definition.arity).map do |idx|
|
51
|
+
Extensions::Hash.indifferent_access(hash, idx, Extensions::Undefined)
|
52
|
+
end
|
53
|
+
ArrayMarshaller.canonicalize(definition, array, context, validator)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.do_marshal(fields, _)
|
57
|
+
fields.each_with_index.map do |field, index|
|
58
|
+
[index.to_s, field]
|
59
|
+
end.to_h
|
60
|
+
end
|
61
|
+
|
62
|
+
freeze
|
63
|
+
end
|
64
|
+
|
65
|
+
class StringMarshaller
|
66
|
+
include AbstractMarshaller
|
67
|
+
|
68
|
+
attr_reader :separator
|
69
|
+
|
70
|
+
def self.instance(separator:)
|
71
|
+
instance = new separator
|
72
|
+
[String, instance.freeze]
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(separator)
|
76
|
+
@separator = separator.to_s.freeze
|
77
|
+
end
|
78
|
+
|
79
|
+
def canonicalize(definition, string, context, validator)
|
80
|
+
array = string.split(separator)
|
81
|
+
ArrayMarshaller.canonicalize(definition, array, context, validator)
|
82
|
+
end
|
83
|
+
|
84
|
+
def do_marshal(fields, _)
|
85
|
+
fields.join(separator)
|
86
|
+
end
|
87
|
+
|
88
|
+
freeze
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.collection
|
92
|
+
@collection ||= begin
|
93
|
+
c = ClassCollection.new Array
|
94
|
+
c.add_instance Array, ArrayMarshaller
|
95
|
+
c.add_instance Hash, HashMarshaller
|
96
|
+
c.add_factory :string, StringMarshaller
|
97
|
+
c.freeze
|
98
|
+
c
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative '../error'
|
2
|
+
require_relative '../helpers/arel_builder'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
module Ordering
|
6
|
+
class Column
|
7
|
+
DIRECTIONS = Set.new %i(none asc desc)
|
8
|
+
|
9
|
+
attr_reader :ordering, :table, :nulls, :required, :pk
|
10
|
+
|
11
|
+
NULLS_FIRST = { null: 0, not_null: 1 }.freeze
|
12
|
+
NULLS_LAST = { null: 1, not_null: 0 }.freeze
|
13
|
+
|
14
|
+
def initialize(ordering, arel_table:, expression:, nulls: :default, required: false, pk: false)
|
15
|
+
raise ParamsReadyError, "Invalid ordering value: #{ordering}" unless DIRECTIONS.include? ordering
|
16
|
+
@ordering = ordering
|
17
|
+
@table = arel_table
|
18
|
+
@expression = expression
|
19
|
+
@nulls = nulls
|
20
|
+
@required = required
|
21
|
+
@pk = pk
|
22
|
+
end
|
23
|
+
|
24
|
+
def expression(name)
|
25
|
+
@expression || name
|
26
|
+
end
|
27
|
+
|
28
|
+
def attribute(name, default_table, context)
|
29
|
+
arel_table = table || default_table
|
30
|
+
arel_builder = Helpers::ArelBuilder.instance(expression(name), arel_table: arel_table)
|
31
|
+
arel_builder.to_arel(arel_table, context, self)
|
32
|
+
end
|
33
|
+
|
34
|
+
def clauses(attribute, direction, inverted: false)
|
35
|
+
clause = attribute.send direction
|
36
|
+
if nulls == :default
|
37
|
+
[clause]
|
38
|
+
else
|
39
|
+
values = null_substitution_values(nulls, inverted)
|
40
|
+
|
41
|
+
nulls_last = Arel::Nodes::Case.new
|
42
|
+
.when(attribute.eq(nil)).then(values[:null])
|
43
|
+
.else(values[:not_null])
|
44
|
+
[nulls_last, clause]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def null_substitution_values(policy, inverted)
|
49
|
+
case [policy, inverted]
|
50
|
+
when [:first, false], [:last, true]
|
51
|
+
NULLS_FIRST
|
52
|
+
when [:last, false], [:first, true]
|
53
|
+
NULLS_LAST
|
54
|
+
else
|
55
|
+
raise ParamsReadyError, "Unimplemented null handling policy: '#{nulls}' (inverted: #{inverted})"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
require 'set'
|
2
|
+
require_relative '../parameter/definition'
|
3
|
+
require_relative '../builder'
|
4
|
+
require_relative '../parameter/parameter'
|
5
|
+
require_relative 'column'
|
6
|
+
|
7
|
+
module ParamsReady
|
8
|
+
module Ordering
|
9
|
+
class OrderingParameter < Parameter::ArrayParameter
|
10
|
+
def_delegators :definition, :required?
|
11
|
+
|
12
|
+
def marshal(intent)
|
13
|
+
arr = to_array(intent)
|
14
|
+
return arr unless intent.marshal?(name_for_formatter)
|
15
|
+
|
16
|
+
arr.join(definition.class::COLUMN_DELIMITER)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_array(intent = Intent.instance(:backend))
|
20
|
+
arr = bare_value
|
21
|
+
arr.map do |tuple|
|
22
|
+
name = tuple.first.unwrap
|
23
|
+
next unless intent.name_permitted?(name) || definition.required?(name)
|
24
|
+
|
25
|
+
tuple.format(intent)
|
26
|
+
end.compact
|
27
|
+
end
|
28
|
+
|
29
|
+
def by_columns
|
30
|
+
bare_value.each_with_object(Hash.new(:none)) do |tuple, hash|
|
31
|
+
hash[tuple[0].unwrap] = tuple[1].unwrap
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def toggle_schema(schema)
|
36
|
+
case schema
|
37
|
+
when :desc
|
38
|
+
[:desc, :asc]
|
39
|
+
when :asc
|
40
|
+
[:asc, :desc]
|
41
|
+
else
|
42
|
+
[:none, :none]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def filtered(name)
|
47
|
+
bare_value.map do |tuple|
|
48
|
+
tuple.format(Intent.instance(:backend))
|
49
|
+
end.partition do |item|
|
50
|
+
next item[0] == name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def prepend_item(name, direction, array)
|
55
|
+
return array if direction == :none
|
56
|
+
[[name, direction], *array]
|
57
|
+
end
|
58
|
+
|
59
|
+
def inverted_order_value
|
60
|
+
bare_value.map do |tuple|
|
61
|
+
name = tuple.first.unwrap
|
62
|
+
case tuple.second.unwrap
|
63
|
+
when :asc
|
64
|
+
[name, :desc]
|
65
|
+
when :desc
|
66
|
+
[name, :asc]
|
67
|
+
else
|
68
|
+
raise ParamsReadyError, "Unexpected ordering: '#{tuple.second.unwrap}'"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def inverted_order
|
74
|
+
update_in(inverted_order_value, [])
|
75
|
+
end
|
76
|
+
|
77
|
+
def toggled_order_value(name)
|
78
|
+
drop, save = filtered(name)
|
79
|
+
|
80
|
+
old_dir = drop.count > 0 ? drop.first[1] : :none
|
81
|
+
primary, secondary = toggle_schema(definition.columns[name.to_sym].ordering)
|
82
|
+
new_dir = old_dir == primary ? secondary : primary
|
83
|
+
|
84
|
+
prepend_item(name, new_dir, save)
|
85
|
+
end
|
86
|
+
|
87
|
+
def toggled_order(name)
|
88
|
+
update_in(toggled_order_value(name), [])
|
89
|
+
end
|
90
|
+
|
91
|
+
def reordered_value(name, new_dir)
|
92
|
+
_, save = filtered(name)
|
93
|
+
prepend_item(name, new_dir, save)
|
94
|
+
end
|
95
|
+
|
96
|
+
def reordered(name, new_dir)
|
97
|
+
update_in(reordered_value(name, new_dir), [])
|
98
|
+
end
|
99
|
+
|
100
|
+
def restriction_from_context(context)
|
101
|
+
restriction = context.to_restriction
|
102
|
+
return restriction if restriction.name_permitted? :ordering || !required?
|
103
|
+
|
104
|
+
Restriction.permit({ ordering: [] })
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_arel(default_table, context: Restriction.blanket_permission, inverted: false)
|
108
|
+
ordering = inverted ? inverted_order : self
|
109
|
+
ordering.to_array_with_context(context).flat_map do |(column_name, direction)|
|
110
|
+
column = definition.columns[column_name]
|
111
|
+
attribute = column.attribute(column_name, default_table, context)
|
112
|
+
column.clauses(attribute, direction, inverted: inverted)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_array_with_context(context)
|
117
|
+
intent = Intent.instance(:backend).clone(restriction: restriction_from_context(context))
|
118
|
+
to_array(intent.for_children(self))
|
119
|
+
end
|
120
|
+
|
121
|
+
def order_for(name)
|
122
|
+
order = bare_value.find do |tuple|
|
123
|
+
tuple[0].unwrap == name
|
124
|
+
end
|
125
|
+
return :none if order.nil?
|
126
|
+
|
127
|
+
order[1].unwrap
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class OrderingParameterBuilder < Builder
|
132
|
+
def self.instance
|
133
|
+
new OrderingParameterDefinition.new({})
|
134
|
+
end
|
135
|
+
|
136
|
+
def column(name, ordering, arel_table: nil, expression: nil, nulls: :default, required: false, pk: false)
|
137
|
+
@definition.add_column(
|
138
|
+
name,
|
139
|
+
ordering,
|
140
|
+
arel_table: arel_table,
|
141
|
+
expression: expression,
|
142
|
+
nulls: nulls,
|
143
|
+
required: required,
|
144
|
+
pk: pk
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def default(*array)
|
149
|
+
super array
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class OrderingParameterDefinition < Parameter::ArrayParameterDefinition
|
154
|
+
COLUMN_DELIMITER = '|'
|
155
|
+
FIELD_DELIMITER = '-'
|
156
|
+
attr_reader :columns, :primary_keys
|
157
|
+
|
158
|
+
parameter_class OrderingParameter
|
159
|
+
|
160
|
+
def initialize(columns, default = Extensions::Undefined)
|
161
|
+
invalid = columns.values.uniq.reject do |column|
|
162
|
+
column.is_a? Column
|
163
|
+
end
|
164
|
+
raise ParamsReadyError, "Invalid ordering values: #{invalid.join(", ")}" unless invalid.length == 0
|
165
|
+
@columns = columns.transform_keys { |k| k.to_sym }
|
166
|
+
@required_columns = nil
|
167
|
+
@primary_keys = Set.new
|
168
|
+
super :ordering, altn: :ord, prototype: nil, default: default
|
169
|
+
end
|
170
|
+
|
171
|
+
def set_default(value)
|
172
|
+
raise ParamsReadyError, "Prototype for ordering expected to be nil" unless @prototype.nil?
|
173
|
+
set_required_columns
|
174
|
+
|
175
|
+
@prototype = create_prototype columns
|
176
|
+
super value
|
177
|
+
end
|
178
|
+
|
179
|
+
def set_required_columns
|
180
|
+
return unless @required_columns.nil?
|
181
|
+
|
182
|
+
@required_columns = @columns.select do |_name, value|
|
183
|
+
value.required
|
184
|
+
end.map do |name, _value|
|
185
|
+
name
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def required?(name = nil)
|
190
|
+
return !@required_columns.empty? if name.nil?
|
191
|
+
|
192
|
+
@required_columns.member?(name)
|
193
|
+
end
|
194
|
+
|
195
|
+
def add_column(
|
196
|
+
name,
|
197
|
+
ordering,
|
198
|
+
expression:,
|
199
|
+
arel_table:,
|
200
|
+
nulls: :default,
|
201
|
+
required: false,
|
202
|
+
pk: false
|
203
|
+
)
|
204
|
+
raise ParamsReadyError, "Column name taken: #{name}" if @columns.key? name
|
205
|
+
raise ParamsReadyError, "Can't add column after default defined" unless @default == Extensions::Undefined
|
206
|
+
@primary_keys << name if pk == true
|
207
|
+
|
208
|
+
column = Column.new(
|
209
|
+
ordering,
|
210
|
+
expression: expression,
|
211
|
+
arel_table: arel_table,
|
212
|
+
nulls: nulls,
|
213
|
+
required: required,
|
214
|
+
pk: pk
|
215
|
+
)
|
216
|
+
@columns[name] = column
|
217
|
+
end
|
218
|
+
|
219
|
+
def create_prototype(columns)
|
220
|
+
Builder.define_tuple(:column) do
|
221
|
+
marshal using: :string, separator: FIELD_DELIMITER
|
222
|
+
field :symbol, :column_name do
|
223
|
+
constrain Value::EnumConstraint.new(columns.keys)
|
224
|
+
end
|
225
|
+
field :symbol, :column_ordering do
|
226
|
+
constrain Value::EnumConstraint.new(Column::DIRECTIONS)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def try_canonicalize(input, context, validator = nil, freeze: false)
|
232
|
+
input ||= [%w(none none)]
|
233
|
+
canonical, validator = case input
|
234
|
+
when String
|
235
|
+
raise ParamsReadyError, "Freeze option expected to be false" if freeze
|
236
|
+
array = input.split(COLUMN_DELIMITER)
|
237
|
+
try_canonicalize(array, context, validator, freeze: false)
|
238
|
+
when Array
|
239
|
+
super
|
240
|
+
else
|
241
|
+
raise ParamsReadyError, "Unexpected type for #{name}: #{input.class.name}"
|
242
|
+
end
|
243
|
+
unique_columns = unique_columns(canonical)
|
244
|
+
with_required = with_required(unique_columns)
|
245
|
+
[with_required.values, validator]
|
246
|
+
end
|
247
|
+
|
248
|
+
def unique_columns(array)
|
249
|
+
array.each_with_object({}) do |column, hash|
|
250
|
+
name = column.first.unwrap
|
251
|
+
next if hash.key? name
|
252
|
+
|
253
|
+
hash[name] = column
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def with_required(hash)
|
258
|
+
@required_columns.each_with_object(hash) do |name, result|
|
259
|
+
next if result.key? name
|
260
|
+
column = @columns[name]
|
261
|
+
_, tuple = @prototype.from_input([name, column.ordering])
|
262
|
+
hash[name] = tuple
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def finish
|
267
|
+
raise ParamsReadyError, "No ordering column defined" if @columns.empty?
|
268
|
+
set_required_columns
|
269
|
+
set_default([]) unless default_defined?
|
270
|
+
super
|
271
|
+
end
|
272
|
+
|
273
|
+
freeze_variables :columns, :required_columns, :primary_keys, :prototype
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|