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,127 @@
|
|
1
|
+
require_relative 'intent'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
class OutputParameters
|
5
|
+
attr_reader :scoped_id, :parameter
|
6
|
+
|
7
|
+
def method_missing(name, *args, &block)
|
8
|
+
if @parameter.respond_to? name, false
|
9
|
+
@parameter.send(name, *args, &block)
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond_to_missing?(name, include_private = false)
|
16
|
+
if @parameter.respond_to? name, include_private
|
17
|
+
true
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.decorate(parameter, *args)
|
24
|
+
intent = case args.length
|
25
|
+
when 0
|
26
|
+
Intent.instance(:frontend)
|
27
|
+
when 1
|
28
|
+
Intent.resolve(args[0])
|
29
|
+
when 2
|
30
|
+
format = args[0]
|
31
|
+
restriction = args[1]
|
32
|
+
Intent.new format, restriction
|
33
|
+
else
|
34
|
+
msg = "ArgumentError: wrong number of arguments (given #{args.length + 1}, expected 1..3)"
|
35
|
+
raise ParamsReadyError, msg
|
36
|
+
end
|
37
|
+
new parameter, intent
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(parameter, intent, scoped_name = nil, scoped_id = nil)
|
41
|
+
raise ParamsReadyError, "Expected parameter '#{parameter.name}' to be frozen" unless parameter.frozen?
|
42
|
+
@parameter = parameter
|
43
|
+
@intent = Intent.resolve(intent)
|
44
|
+
@tree = {}
|
45
|
+
@scoped_name = scoped_name || @intent.hash_key(parameter).to_s
|
46
|
+
@scoped_id = scoped_id || @intent.hash_key(parameter).to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def scoped_name(multiple: false)
|
50
|
+
return @scoped_name unless multiple
|
51
|
+
@scoped_name + "[]"
|
52
|
+
end
|
53
|
+
|
54
|
+
def [](key)
|
55
|
+
if @tree.key? key
|
56
|
+
@tree[key]
|
57
|
+
elsif @parameter.respond_to? :[]
|
58
|
+
child = @parameter[key]
|
59
|
+
formatted_name = if @parameter.definition.is_a? Parameter::ArrayParameterDefinition::ArrayLike
|
60
|
+
key.to_s
|
61
|
+
else
|
62
|
+
@intent.hash_key(child).to_s
|
63
|
+
end
|
64
|
+
child_scoped_name = @scoped_name.empty? ? formatted_name : "#{@scoped_name}[#{formatted_name}]"
|
65
|
+
child_scoped_id = @scoped_id.empty? ? formatted_name : "#{@scoped_id}_#{formatted_name}"
|
66
|
+
intent = @parameter.intent_for_children(@intent)
|
67
|
+
decorated = OutputParameters.new(child, intent, child_scoped_name, child_scoped_id)
|
68
|
+
@tree[key] = decorated
|
69
|
+
decorated
|
70
|
+
else
|
71
|
+
raise ParamsReadyError, "Parameter '#{@parameter.name}' doesn't support square brackets access"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def flat_pairs(format = @intent.format, restriction: @intent.restriction, data: @intent.data)
|
76
|
+
self.class.flatten_hash(for_output(format, restriction: restriction, data: data), scoped_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.flatten_hash(hash, scope)
|
80
|
+
hash.flat_map do |key, value|
|
81
|
+
nested = scope.empty? ? key.to_s : "#{scope}[#{key}]"
|
82
|
+
if value.is_a? Hash
|
83
|
+
flatten_hash(value, nested)
|
84
|
+
else
|
85
|
+
[[nested, value]]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_hash(format = @intent.format, restriction: nil, data: @intent.data)
|
91
|
+
restriction = if restriction.nil?
|
92
|
+
Restriction.permit(name => @intent.restriction)
|
93
|
+
else
|
94
|
+
restriction
|
95
|
+
end
|
96
|
+
@parameter.to_hash(format, restriction: restriction, data: data)
|
97
|
+
end
|
98
|
+
|
99
|
+
def for_output(format = @intent.format, restriction: @intent.restriction, data: @intent.data)
|
100
|
+
@parameter.for_output(format, restriction: restriction, data: data)
|
101
|
+
end
|
102
|
+
|
103
|
+
def for_frontend(restriction: @intent.restriction, data: @intent.data)
|
104
|
+
@parameter.for_frontend(restriction: restriction, data: data)
|
105
|
+
end
|
106
|
+
|
107
|
+
def for_model(restriction: @intent.restriction)
|
108
|
+
@parameter.for_model(restriction: restriction)
|
109
|
+
end
|
110
|
+
|
111
|
+
def format(format = @intent)
|
112
|
+
@parameter.format(format)
|
113
|
+
end
|
114
|
+
|
115
|
+
def build_select(context: @intent.restriction, **opts)
|
116
|
+
@parameter.build_select(context: context, **opts)
|
117
|
+
end
|
118
|
+
|
119
|
+
def build_relation(context: @intent.restriction, **opts)
|
120
|
+
@parameter.build_relation(context: context, **opts)
|
121
|
+
end
|
122
|
+
|
123
|
+
def perform_count(context: @intent.restriction, **opts)
|
124
|
+
@parameter.perform_count(context: context, **opts)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ParamsReady
|
2
|
+
module Pagination
|
3
|
+
module AbstractPagination
|
4
|
+
def num_pages(count:)
|
5
|
+
raise ParamsReadyError, 'Negative count unexpected' if count < 0
|
6
|
+
(count.to_f / limit.to_f).ceil.to_i
|
7
|
+
end
|
8
|
+
|
9
|
+
def first_page
|
10
|
+
update_in(first_page_value, [])
|
11
|
+
end
|
12
|
+
|
13
|
+
def last_page(*args)
|
14
|
+
update_in(last_page_value(*args), [])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require_relative '../helpers/arel_builder'
|
2
|
+
require_relative '../../arel/cte_name'
|
3
|
+
|
4
|
+
module ParamsReady
|
5
|
+
module Pagination
|
6
|
+
class CursorBuilder
|
7
|
+
def initialize(keyset, arel_table, context)
|
8
|
+
@keyset = keyset.freeze
|
9
|
+
@arel_table = arel_table
|
10
|
+
@context = context
|
11
|
+
@select_list = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(key, column)
|
15
|
+
attribute = if @keyset.key? key
|
16
|
+
Literal.new(key, @keyset[key], column.pk)
|
17
|
+
else
|
18
|
+
Selector.new(key, column)
|
19
|
+
end
|
20
|
+
|
21
|
+
@select_list << attribute
|
22
|
+
end
|
23
|
+
|
24
|
+
def build
|
25
|
+
cursor = Cursor.new(@select_list, @arel_table, @context)
|
26
|
+
@select_list = nil
|
27
|
+
freeze
|
28
|
+
cursor
|
29
|
+
end
|
30
|
+
|
31
|
+
class Selector
|
32
|
+
attr_reader :key
|
33
|
+
attr_reader :column
|
34
|
+
|
35
|
+
def initialize(key, column)
|
36
|
+
@key = key
|
37
|
+
@column = column
|
38
|
+
freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
def expression(arel_table, context)
|
42
|
+
column.attribute(key, arel_table, context)
|
43
|
+
end
|
44
|
+
|
45
|
+
def rvalue(cte)
|
46
|
+
cte.project(key)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Literal
|
51
|
+
attr_reader :key
|
52
|
+
attr_reader :pk
|
53
|
+
|
54
|
+
def initialize(key, value, pk)
|
55
|
+
@key = key
|
56
|
+
@value = Arel::Nodes::Quoted.new(value)
|
57
|
+
@pk = pk
|
58
|
+
freeze
|
59
|
+
end
|
60
|
+
|
61
|
+
def quoted
|
62
|
+
@value
|
63
|
+
end
|
64
|
+
|
65
|
+
def value
|
66
|
+
@value.value
|
67
|
+
end
|
68
|
+
|
69
|
+
def rvalue(_)
|
70
|
+
@value
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Cursor
|
75
|
+
attr_reader :select_list, :selectors, :literals, :cte
|
76
|
+
|
77
|
+
def initialize(select_list, arel_table, context)
|
78
|
+
@hash = select_list_to_hash(select_list)
|
79
|
+
@selectors, @literals = select_list.partition { |attr| attr.is_a? Selector }
|
80
|
+
@arel_table = arel_table
|
81
|
+
@context = context
|
82
|
+
names = column_names(@selectors)
|
83
|
+
@cte_ref = Arel::Table.new(cte_reference(names))
|
84
|
+
@cte_def = cte_definition(@cte_ref, names)
|
85
|
+
|
86
|
+
freeze
|
87
|
+
end
|
88
|
+
|
89
|
+
def select_list_to_hash(select_list)
|
90
|
+
res = select_list.each_with_object({}) do |item, hash|
|
91
|
+
raise ParamsReadyError, "Repeated key in select list: '#{item.key}'" if hash.key? item.key
|
92
|
+
|
93
|
+
hash[item.key] = item
|
94
|
+
end
|
95
|
+
res.freeze
|
96
|
+
end
|
97
|
+
|
98
|
+
def cte_for_relation(relation)
|
99
|
+
return nil if selectors.empty?
|
100
|
+
|
101
|
+
expressions = column_expressions(selectors)
|
102
|
+
relation = relation.where(**active_record_predicates(literals))
|
103
|
+
.select(*expressions)
|
104
|
+
select = Arel::Nodes::SqlLiteral.new(relation.to_sql)
|
105
|
+
grouping = Arel::Nodes::Grouping.new(select)
|
106
|
+
as = Arel::Nodes::As.new(@cte_def, grouping)
|
107
|
+
Arel::Nodes::With.new([as])
|
108
|
+
end
|
109
|
+
|
110
|
+
def cte_for_query(query, arel_table)
|
111
|
+
return nil if selectors.empty?
|
112
|
+
|
113
|
+
query = query.deep_dup
|
114
|
+
expressions = column_expressions(selectors)
|
115
|
+
query = query.where(arel_predicates(literals, arel_table))
|
116
|
+
.project(*expressions)
|
117
|
+
grouping = Arel::Nodes::Grouping.new(query)
|
118
|
+
Arel::Nodes::As.new(@cte_def, grouping)
|
119
|
+
end
|
120
|
+
|
121
|
+
def active_record_predicates(literals)
|
122
|
+
literals.select do |literal|
|
123
|
+
literal.pk
|
124
|
+
end.map do |literal|
|
125
|
+
[literal.key, literal.value]
|
126
|
+
end.to_h
|
127
|
+
end
|
128
|
+
|
129
|
+
def arel_predicates(literals, arel_table)
|
130
|
+
literals.reduce(nil) do |query, literal|
|
131
|
+
next query unless literal.pk
|
132
|
+
|
133
|
+
predicate = arel_table[literal.key].eq(literal.quoted)
|
134
|
+
next predicate if query.nil?
|
135
|
+
|
136
|
+
query.and(predicate)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def column_names(selectors)
|
141
|
+
selectors.lazy.map(&:key).map(&:to_s).force
|
142
|
+
end
|
143
|
+
|
144
|
+
def column_expressions(selectors)
|
145
|
+
selectors.map do |selector|
|
146
|
+
selector.expression(@arel_table, @context)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def cte_reference(names)
|
151
|
+
unsafe_name = "#{names.join('_')}_cte"
|
152
|
+
Helpers::ArelBuilder.safe_name(unsafe_name)
|
153
|
+
end
|
154
|
+
|
155
|
+
def cte_definition(reference, names)
|
156
|
+
node = Arel::Nodes::SqlLiteral.new(names.join(', '))
|
157
|
+
grouping = Arel::Nodes::Grouping.new(node)
|
158
|
+
# The name must be literal, otherwise
|
159
|
+
# it will be quoted by the visitor
|
160
|
+
expression = "#{reference.name} #{grouping.to_sql}"
|
161
|
+
|
162
|
+
Arel::Nodes::CteName.new(expression)
|
163
|
+
end
|
164
|
+
|
165
|
+
def rvalue(key)
|
166
|
+
@hash[key].rvalue(@cte_ref)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require_relative '../error'
|
2
|
+
require_relative 'tendency'
|
3
|
+
require_relative 'nulls'
|
4
|
+
require_relative 'cursor'
|
5
|
+
require_relative 'keysets'
|
6
|
+
|
7
|
+
module ParamsReady
|
8
|
+
module Pagination
|
9
|
+
module Direction
|
10
|
+
def self.instance(dir)
|
11
|
+
case dir
|
12
|
+
when :bfr, :before then Before
|
13
|
+
when :aft, :after then After
|
14
|
+
else
|
15
|
+
raise ParamsReadyError, "Unexpected direction: '#{dir}'"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def cursor_predicates(keyset, ordering, arel_table, context)
|
20
|
+
primary_keys = ordering.definition.primary_keys.dup
|
21
|
+
return [nil, nil] unless check_primary_keys_presence(keyset, primary_keys)
|
22
|
+
|
23
|
+
cursor = build_cursor(keyset, ordering, arel_table, context)
|
24
|
+
columns = ordering.to_array_with_context(context)
|
25
|
+
|
26
|
+
predicate = cursor_predicate(columns, cursor, ordering, arel_table, context, primary_keys)
|
27
|
+
grouping = Arel::Nodes::Grouping.new(predicate)
|
28
|
+
[cursor, grouping]
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_primary_keys_presence(keyset, primary_keys)
|
32
|
+
primary_keys.all? do |pk|
|
33
|
+
keyset.key?(pk) && !keyset[pk].nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def cursor_predicate(columns, cursor, ordering, arel_table, context, primary_keys)
|
38
|
+
tuple, *rest = columns
|
39
|
+
key, column_ordering = tuple
|
40
|
+
column = ordering.definition.columns[key]
|
41
|
+
|
42
|
+
value_expression = cursor.rvalue(key)
|
43
|
+
column_expression = column.attribute(key, arel_table, context)
|
44
|
+
|
45
|
+
primary_keys.delete(key) if column.pk
|
46
|
+
|
47
|
+
if column.pk && primary_keys.empty?
|
48
|
+
pk_predicate(column_ordering, column_expression, value_expression)
|
49
|
+
else
|
50
|
+
nested = cursor_predicate(rest, cursor, ordering, arel_table, context, primary_keys)
|
51
|
+
if column.nulls == :default
|
52
|
+
non_nullable_predicate(column_ordering, column_expression, value_expression, nested)
|
53
|
+
else
|
54
|
+
nullable_predicate(column_ordering, column.nulls, column_expression, value_expression, nested)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_cursor(keyset, ordering, arel_table, context)
|
60
|
+
builder = CursorBuilder.new(keyset, arel_table, context)
|
61
|
+
ordering.to_array_with_context(context).each do |(key, _)|
|
62
|
+
column = ordering.definition.columns[key]
|
63
|
+
builder.add(key, column)
|
64
|
+
end
|
65
|
+
builder.build
|
66
|
+
end
|
67
|
+
|
68
|
+
def pk_predicate(ordering, column, value)
|
69
|
+
tendency(ordering).comparison_predicate(column, value)
|
70
|
+
end
|
71
|
+
|
72
|
+
def non_nullable_predicate(ordering, column, value, nested)
|
73
|
+
tendency(ordering).non_nullable_predicate(column, value, nested)
|
74
|
+
end
|
75
|
+
|
76
|
+
def nullable_predicate(ordering, nulls, column, value, nested)
|
77
|
+
strategy = nulls_strategy(nulls)
|
78
|
+
if_null = strategy.if_null_predicate(column, nested)
|
79
|
+
tendency = tendency(ordering)
|
80
|
+
expression = Arel::Nodes::Grouping.new(value)
|
81
|
+
if_not_null = strategy.if_not_null_predicate(tendency, column, value, nested)
|
82
|
+
Arel::Nodes::Case.new.when(expression.eq(nil))
|
83
|
+
.then(if_null)
|
84
|
+
.else(if_not_null)
|
85
|
+
end
|
86
|
+
|
87
|
+
module Before
|
88
|
+
extend Direction
|
89
|
+
|
90
|
+
def self.invert_ordering?
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.tendency(ordering)
|
95
|
+
case ordering
|
96
|
+
when :desc then Tendency::Growing
|
97
|
+
when :asc then Tendency::Falling
|
98
|
+
else
|
99
|
+
raise ParamsReadyError, "Unexpected ordering: '#{ordering}'"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.nulls_strategy(strategy)
|
104
|
+
case strategy
|
105
|
+
when :first then Nulls::Last
|
106
|
+
when :last then Nulls::First
|
107
|
+
else
|
108
|
+
raise ParamsReadyError, "Unexpected nulls strategy: '#{strategy}'"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.keysets(_, keysets, &block)
|
113
|
+
BeforeKeysets.new(keysets, &block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
module After
|
118
|
+
extend Direction
|
119
|
+
|
120
|
+
def self.invert_ordering?
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.tendency(ordering)
|
125
|
+
case ordering
|
126
|
+
when :asc then Tendency::Growing
|
127
|
+
when :desc then Tendency::Falling
|
128
|
+
else
|
129
|
+
raise ParamsReadyError, "Unexpected ordering: '#{ordering}'"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.nulls_strategy(strategy)
|
134
|
+
case strategy
|
135
|
+
when :first then Nulls::First
|
136
|
+
when :last then Nulls::Last
|
137
|
+
else
|
138
|
+
raise ParamsReadyError, "Unexpected nulls strategy: '#{strategy}'"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.keysets(last, keysets, &block)
|
143
|
+
AfterKeysets.new(last, keysets, &block)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|