safrano 0.4.2 → 0.5.0
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 +4 -4
- data/lib/core_ext/Dir/iter.rb +18 -0
- data/lib/core_ext/Hash/transform.rb +21 -0
- data/lib/core_ext/Integer/edm.rb +13 -0
- data/lib/core_ext/REXML/Document/output.rb +16 -0
- data/lib/core_ext/String/convert.rb +25 -0
- data/lib/core_ext/String/edm.rb +13 -0
- data/lib/core_ext/dir.rb +3 -0
- data/lib/core_ext/hash.rb +3 -0
- data/lib/core_ext/integer.rb +3 -0
- data/lib/core_ext/rexml.rb +3 -0
- data/lib/core_ext/string.rb +5 -0
- data/lib/odata/attribute.rb +15 -10
- data/lib/odata/batch.rb +9 -7
- data/lib/odata/collection.rb +140 -591
- data/lib/odata/collection_filter.rb +18 -42
- data/lib/odata/collection_media.rb +111 -54
- data/lib/odata/collection_order.rb +5 -2
- data/lib/odata/common_logger.rb +2 -0
- data/lib/odata/complex_type.rb +152 -0
- data/lib/odata/edm/primitive_types.rb +184 -0
- data/lib/odata/entity.rb +123 -172
- data/lib/odata/error.rb +183 -32
- data/lib/odata/expand.rb +20 -17
- data/lib/odata/filter/base.rb +74 -0
- data/lib/odata/filter/error.rb +49 -6
- data/lib/odata/filter/parse.rb +41 -25
- data/lib/odata/filter/sequel.rb +133 -62
- data/lib/odata/filter/sequel_function_adapter.rb +148 -0
- data/lib/odata/filter/token.rb +26 -19
- data/lib/odata/filter/tree.rb +106 -52
- data/lib/odata/function_import.rb +168 -0
- data/lib/odata/model_ext.rb +639 -0
- data/lib/odata/navigation_attribute.rb +13 -26
- data/lib/odata/relations.rb +5 -5
- data/lib/odata/select.rb +17 -5
- data/lib/odata/transition.rb +71 -0
- data/lib/odata/url_parameters.rb +100 -24
- data/lib/odata/walker.rb +20 -10
- data/lib/safrano.rb +18 -38
- data/lib/safrano/contract.rb +143 -0
- data/lib/safrano/core.rb +23 -107
- data/lib/safrano/core_ext.rb +13 -0
- data/lib/safrano/deprecation.rb +73 -0
- data/lib/safrano/multipart.rb +29 -33
- data/lib/safrano/rack_app.rb +66 -65
- data/lib/safrano/{odata_rack_builder.rb → rack_builder.rb} +18 -2
- data/lib/safrano/request.rb +96 -45
- data/lib/safrano/response.rb +4 -2
- data/lib/safrano/sequel_join_by_paths.rb +2 -2
- data/lib/safrano/service.rb +240 -130
- data/lib/safrano/version.rb +3 -1
- data/lib/sequel/plugins/join_by_paths.rb +6 -19
- metadata +32 -11
data/lib/odata/filter/error.rb
CHANGED
@@ -1,18 +1,31 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../error'
|
4
|
+
|
5
|
+
module Safrano
|
2
6
|
class SequelAdapterError < StandardError
|
3
7
|
attr_reader :inner
|
8
|
+
|
4
9
|
def initialize(err)
|
5
10
|
@inner = err
|
6
11
|
end
|
7
12
|
end
|
13
|
+
|
8
14
|
module Filter
|
9
15
|
class Parser
|
10
16
|
# Parser errors
|
11
|
-
|
17
|
+
|
18
|
+
class Error
|
19
|
+
def Error.http_code
|
20
|
+
const_get(:HTTP_CODE)
|
21
|
+
end
|
22
|
+
HTTP_CODE = 400
|
23
|
+
|
12
24
|
attr_reader :tok
|
13
25
|
attr_reader :typ
|
14
26
|
attr_reader :cur_val
|
15
27
|
attr_reader :cur_typ
|
28
|
+
|
16
29
|
def initialize(tok, typ, cur)
|
17
30
|
@tok = tok
|
18
31
|
@typ = typ
|
@@ -24,31 +37,61 @@ module OData
|
|
24
37
|
end
|
25
38
|
# Invalid Tokens
|
26
39
|
class ErrorInvalidToken < Error
|
40
|
+
include ::Safrano::ErrorInstance
|
41
|
+
def initialize(tok, typ, cur)
|
42
|
+
super
|
43
|
+
@msg = "Bad Request: invalid token #{tok} in $filter"
|
44
|
+
end
|
27
45
|
end
|
28
46
|
# Unmached closed
|
29
47
|
class ErrorUnmatchedClose < Error
|
48
|
+
include ::Safrano::ErrorInstance
|
49
|
+
def initialize(tok, typ, cur)
|
50
|
+
super
|
51
|
+
@msg = "Bad Request: unmatched #{tok} in $filter"
|
52
|
+
end
|
30
53
|
end
|
31
54
|
|
32
|
-
class ErrorFunctionArgumentType
|
55
|
+
class ErrorFunctionArgumentType
|
56
|
+
include ::Safrano::ErrorInstance
|
33
57
|
end
|
34
58
|
|
35
|
-
class ErrorWrongColumnName
|
59
|
+
class ErrorWrongColumnName
|
60
|
+
include ::Safrano::ErrorInstance
|
61
|
+
end
|
62
|
+
|
63
|
+
# attempt to add a child to a Leave
|
64
|
+
class ErrorLeaveChild
|
65
|
+
include ::Safrano::ErrorInstance
|
36
66
|
end
|
37
67
|
|
38
68
|
# Invalid function arity
|
39
69
|
class ErrorInvalidArity < Error
|
70
|
+
include ::Safrano::ErrorInstance
|
71
|
+
def initialize(tok, typ, cur)
|
72
|
+
super
|
73
|
+
@msg = "Bad Request: wrong number of parameters for function #{cur.parent.value.to_s} in $filter"
|
74
|
+
end
|
40
75
|
end
|
41
76
|
# Invalid separator in this context (missing parenthesis?)
|
42
77
|
class ErrorInvalidSeparator < Error
|
78
|
+
include ::Safrano::ErrorInstance
|
43
79
|
end
|
44
80
|
|
45
81
|
# unmatched quot3
|
46
82
|
class UnmatchedQuoteError < Error
|
83
|
+
include ::Safrano::ErrorInstance
|
84
|
+
def initialize(tok, typ, cur)
|
85
|
+
super
|
86
|
+
@msg = "Bad Request: unbalanced quotes #{tok} in $filter"
|
87
|
+
end
|
47
88
|
end
|
48
89
|
|
49
90
|
# wrong type of function argument
|
50
|
-
class ErrorInvalidArgumentType <
|
51
|
-
|
91
|
+
class ErrorInvalidArgumentType < Error
|
92
|
+
include ::Safrano::ErrorInstance
|
93
|
+
|
94
|
+
def initialize(tree, expected:, actual:)
|
52
95
|
@tree = tree
|
53
96
|
@expected = expected
|
54
97
|
@actual = actual
|
data/lib/odata/filter/parse.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
-
|
2
|
-
require_relative './tree.rb'
|
3
|
-
require_relative './error.rb'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
require_relative './token'
|
4
|
+
require_relative './tree'
|
5
|
+
require_relative './error'
|
6
|
+
|
7
|
+
# top level Safrano namespace
|
8
|
+
module Safrano
|
7
9
|
# for handling $filter
|
8
10
|
module Filter
|
9
11
|
# Parser for $filter input
|
10
12
|
class Parser
|
11
13
|
include Token
|
12
14
|
attr_reader :cursor
|
15
|
+
attr_reader :error
|
16
|
+
|
13
17
|
def initialize(input)
|
14
18
|
@tree = RootTree.new
|
15
19
|
@cursor = @tree
|
@@ -18,10 +22,14 @@ module OData
|
|
18
22
|
@binop_stack = []
|
19
23
|
end
|
20
24
|
|
25
|
+
def server_error
|
26
|
+
(@error = ::Safrano::ServerError)
|
27
|
+
end
|
28
|
+
|
21
29
|
def grow_at_cursor(child)
|
22
|
-
|
30
|
+
return server_error if @cursor.nil?
|
23
31
|
|
24
|
-
@cursor.attach(child)
|
32
|
+
@cursor.attach(child).tap_error { |err| return (@error = err) }
|
25
33
|
@cursor = child
|
26
34
|
end
|
27
35
|
|
@@ -40,7 +48,7 @@ module OData
|
|
40
48
|
def insert_before_cursor(node)
|
41
49
|
left = detach_cursor
|
42
50
|
grow_at_cursor(node)
|
43
|
-
@cursor.attach(left)
|
51
|
+
@cursor.attach(left).tap_error { |err| return (@error = err) }
|
44
52
|
end
|
45
53
|
|
46
54
|
def invalid_separator_error(tok, typ)
|
@@ -56,12 +64,7 @@ module OData
|
|
56
64
|
end
|
57
65
|
|
58
66
|
def with_accepted(tok, typ)
|
59
|
-
|
60
|
-
if acc
|
61
|
-
yield
|
62
|
-
else
|
63
|
-
@error = err
|
64
|
-
end
|
67
|
+
(err = @cursor.accept?(tok, typ)) ? (@error = err) : yield
|
65
68
|
end
|
66
69
|
|
67
70
|
def build
|
@@ -69,15 +72,19 @@ module OData
|
|
69
72
|
case typ
|
70
73
|
when :FuncTree
|
71
74
|
with_accepted(tok, typ) { grow_at_cursor(FuncTree.new(tok)) }
|
75
|
+
|
72
76
|
when :Delimiter
|
73
77
|
case tok
|
74
78
|
when '('
|
75
79
|
with_accepted(tok, typ) do
|
76
80
|
grow_at_cursor(IdentityFuncTree.new) unless @cursor.is_a? FuncTree
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
unless @error
|
82
|
+
openarg = ArgTree.new('(')
|
83
|
+
@stack << openarg
|
84
|
+
grow_at_cursor(openarg)
|
85
|
+
end
|
80
86
|
end
|
87
|
+
|
81
88
|
when ')'
|
82
89
|
break invalid_closing_delimiter_error(tok, typ) unless (@cursor = @stack.pop)
|
83
90
|
|
@@ -121,6 +128,7 @@ module OData
|
|
121
128
|
end
|
122
129
|
insert_before_cursor(binoptr)
|
123
130
|
end
|
131
|
+
|
124
132
|
when :BinopArithm
|
125
133
|
with_accepted(tok, typ) do
|
126
134
|
binoptr = BinopArithm.new(tok)
|
@@ -143,6 +151,12 @@ module OData
|
|
143
151
|
grow_at_cursor(Literal.new(tok))
|
144
152
|
end
|
145
153
|
|
154
|
+
when :NullLiteral
|
155
|
+
with_accepted(tok, typ) do
|
156
|
+
@cursor.update_state(tok, typ)
|
157
|
+
grow_at_cursor(NullLiteral.new(tok))
|
158
|
+
end
|
159
|
+
|
146
160
|
when :Qualit
|
147
161
|
with_accepted(tok, typ) do
|
148
162
|
@cursor.update_state(tok, typ)
|
@@ -160,19 +174,21 @@ module OData
|
|
160
174
|
@cursor.update_state(tok, typ)
|
161
175
|
grow_at_cursor(FPNumber.new(tok))
|
162
176
|
end
|
177
|
+
|
163
178
|
when :unmatchedQuote
|
164
179
|
break unmatched_quote_error(tok, typ)
|
180
|
+
|
181
|
+
when :space
|
182
|
+
with_accepted(tok, typ) do
|
183
|
+
@cursor.update_state(tok, typ)
|
184
|
+
end
|
165
185
|
else
|
166
|
-
|
186
|
+
server_error
|
167
187
|
end
|
168
|
-
break if @error
|
169
|
-
end
|
170
|
-
begin
|
171
|
-
@tree.check_types unless @error
|
172
|
-
rescue ErrorInvalidArgumentType => e
|
173
|
-
@error = e
|
188
|
+
break(@error) if @error
|
174
189
|
end
|
175
|
-
@error
|
190
|
+
(@error = @tree.check_types) unless @error
|
191
|
+
@error ? @error : Contract.valid(@tree)
|
176
192
|
end
|
177
193
|
end
|
178
194
|
end
|
data/lib/odata/filter/sequel.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './base'
|
4
|
+
require_relative './sequel_function_adapter'
|
5
|
+
|
6
|
+
module Safrano
|
3
7
|
module Filter
|
4
8
|
# Base class for Leaves, Trees, RootTrees etc
|
5
|
-
class Node
|
6
|
-
end
|
9
|
+
# class Node
|
10
|
+
# end
|
7
11
|
|
8
12
|
# Leaves are Nodes with a parent but no children
|
9
|
-
class Leave < Node
|
10
|
-
end
|
13
|
+
# class Leave < Node
|
14
|
+
# end
|
11
15
|
|
12
16
|
# RootTrees have childrens but no parent
|
13
17
|
class RootTree
|
14
18
|
def apply_to_dataset(dtcx, jh)
|
15
|
-
|
16
|
-
|
19
|
+
@children.first.leuqes(jh).if_valid do |filtexpr|
|
20
|
+
jh.dataset(dtcx).where(filtexpr).select_all(jh.start_model.table_name)
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def sequel_expr(jh)
|
@@ -26,57 +31,108 @@ module OData
|
|
26
31
|
end
|
27
32
|
|
28
33
|
# For functions... should have a single child---> the argument list
|
34
|
+
# note: Adapter specific function helpers like year() or substringof_sig2()
|
35
|
+
# need to be mixed in on startup (eg. on publish finalize)
|
29
36
|
class FuncTree < Tree
|
30
37
|
def leuqes(jh)
|
31
38
|
case @value
|
32
39
|
when :startswith
|
33
|
-
|
34
|
-
|
40
|
+
Contract.collect_result!(args[0].leuqes(jh),
|
41
|
+
args[1].leuqes_starts_like(jh)) do |l0, l1|
|
42
|
+
Sequel.like(l0, l1)
|
43
|
+
end
|
44
|
+
|
35
45
|
when :endswith
|
36
|
-
|
37
|
-
|
46
|
+
Contract.collect_result!(args[0].leuqes(jh),
|
47
|
+
args[1].leuqes_ends_like(jh)) do |l0, l1|
|
48
|
+
Sequel.like(l0, l1)
|
49
|
+
end
|
50
|
+
|
38
51
|
when :substringof
|
39
52
|
|
40
53
|
# there are multiple possible argument types (but all should return edm.string)
|
41
54
|
if args[0].is_a?(QString)
|
42
55
|
# substringof('Rhum', name) -->
|
43
56
|
# name contains substr 'Rhum'
|
44
|
-
|
45
|
-
|
57
|
+
Contract.collect_result!(args[1].leuqes(jh),
|
58
|
+
args[0].leuqes_substringof_sig1(jh)) do |l1, l0|
|
59
|
+
Sequel.like(l1, l0)
|
60
|
+
end
|
61
|
+
|
46
62
|
# special non standard (ui5 client) case ?
|
47
63
|
elsif args[0].is_a?(Literal) && args[1].is_a?(Literal)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# '__Route du Rhum__' contains name as a substring
|
53
|
-
# TODO... check if the database supports instr (how?)
|
54
|
-
# othewise use substr(postgresql) or whatevr?
|
55
|
-
instr_substr_func = if Sequel::Model.db.adapter_scheme == :postgres
|
56
|
-
Sequel.function(:strpos, args[1].leuqes(jh), args[0].leuqes(jh))
|
57
|
-
else
|
58
|
-
Sequel.function(:instr, args[1].leuqes(jh), args[0].leuqes(jh))
|
59
|
-
end
|
60
|
-
|
61
|
-
Sequel::SQL::BooleanExpression.new(:>, instr_substr_func, 0)
|
64
|
+
Contract.collect_result!(args[1].leuqes(jh),
|
65
|
+
args[0].leuqes_substringof_sig1(jh)) do |l1, l0|
|
66
|
+
Sequel.like(l1, l0)
|
67
|
+
end
|
62
68
|
|
69
|
+
elsif args[1].is_a?(QString)
|
70
|
+
substringof_sig2(jh) # adapter specific
|
63
71
|
else
|
64
72
|
# TODO... actually not supported?
|
65
|
-
raise
|
73
|
+
raise Safrano::Filter::Parser::ErrorFunctionArgumentType
|
66
74
|
end
|
67
75
|
when :concat
|
68
|
-
|
69
|
-
|
76
|
+
Contract.collect_result!(args[0].leuqes(jh),
|
77
|
+
args[1].leuqes(jh)) do |l0, l1|
|
78
|
+
Sequel.join([l0, l1])
|
79
|
+
end
|
80
|
+
|
70
81
|
when :length
|
71
|
-
|
82
|
+
args.first.leuqes(jh)
|
83
|
+
.map_result! { |l| Sequel.char_length(l) }
|
84
|
+
|
72
85
|
when :trim
|
73
|
-
|
86
|
+
args.first.leuqes(jh)
|
87
|
+
.map_result! { |l| Sequel.trim(l) }
|
88
|
+
|
74
89
|
when :toupper
|
75
|
-
|
90
|
+
args.first.leuqes(jh)
|
91
|
+
.map_result! { |l| Sequel.function(:upper, l) }
|
92
|
+
|
76
93
|
when :tolower
|
77
|
-
|
94
|
+
args.first.leuqes(jh)
|
95
|
+
.map_result! { |l| Sequel.function(:lower, l) }
|
96
|
+
|
97
|
+
# all datetime funcs are adapter specific (because sqlite does not have extract)
|
98
|
+
when :year
|
99
|
+
args.first.leuqes(jh)
|
100
|
+
.map_result! { |l| year(l) }
|
101
|
+
|
102
|
+
when :month
|
103
|
+
args.first.leuqes(jh)
|
104
|
+
.map_result! { |l| month(l) }
|
105
|
+
|
106
|
+
when :second
|
107
|
+
args.first.leuqes(jh)
|
108
|
+
.map_result! { |l| second(l) }
|
109
|
+
|
110
|
+
when :minute
|
111
|
+
args.first.leuqes(jh)
|
112
|
+
.map_result! { |l| minute(l) }
|
113
|
+
|
114
|
+
when :hour
|
115
|
+
args.first.leuqes(jh)
|
116
|
+
.map_result! { |l| hour(l) }
|
117
|
+
|
118
|
+
when :day
|
119
|
+
args.first.leuqes(jh)
|
120
|
+
.map_result! { |l| day(l) }
|
121
|
+
|
122
|
+
# math functions
|
123
|
+
when :round
|
124
|
+
args.first.leuqes(jh)
|
125
|
+
.map_result! { |l| Sequel.function(:round, l) }
|
126
|
+
|
127
|
+
when :floor
|
128
|
+
args.first.leuqes(jh)
|
129
|
+
.if_valid { |l| floor(l) }
|
130
|
+
|
131
|
+
when :ceiling
|
132
|
+
args.first.leuqes(jh)
|
133
|
+
.if_valid { |l| ceiling(l) }
|
78
134
|
else
|
79
|
-
|
135
|
+
Safrano::FilterParseError
|
80
136
|
end
|
81
137
|
end
|
82
138
|
end
|
@@ -95,9 +151,9 @@ module OData
|
|
95
151
|
def leuqes(jh)
|
96
152
|
case @value
|
97
153
|
when :not
|
98
|
-
|
154
|
+
@children.first.leuqes(jh).map_result! { |l| Sequel.~(l) }
|
99
155
|
else
|
100
|
-
|
156
|
+
Safrano::FilterParseError
|
101
157
|
end
|
102
158
|
end
|
103
159
|
end
|
@@ -123,12 +179,19 @@ module OData
|
|
123
179
|
when :and
|
124
180
|
:AND
|
125
181
|
else
|
126
|
-
|
182
|
+
return Safrano::FilterParseError
|
127
183
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
184
|
+
Contract.collect_result!(@children[0].leuqes(jh),
|
185
|
+
@children[1].leuqes(jh)) do |c0, c1|
|
186
|
+
if c1 == NullLiteral::LEUQES
|
187
|
+
if @value == :eq
|
188
|
+
leuqes_op = :IS
|
189
|
+
elsif @value == :ne
|
190
|
+
leuqes_op = :'IS NOT'
|
191
|
+
end
|
192
|
+
end
|
193
|
+
Sequel::SQL::BooleanExpression.new(leuqes_op, c0, c1)
|
194
|
+
end
|
132
195
|
end
|
133
196
|
end
|
134
197
|
|
@@ -147,12 +210,12 @@ module OData
|
|
147
210
|
when :mod
|
148
211
|
:%
|
149
212
|
else
|
150
|
-
|
213
|
+
return Safrano::FilterParseError
|
151
214
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
215
|
+
Contract.collect_result!(@children[0].leuqes(jh),
|
216
|
+
@children[1].leuqes(jh)) do |c0, c1|
|
217
|
+
Sequel::SQL::NumericExpression.new(leuqes_op, c0, c1)
|
218
|
+
end
|
156
219
|
end
|
157
220
|
end
|
158
221
|
|
@@ -163,42 +226,42 @@ module OData
|
|
163
226
|
# Numbers (floating point, ints, dec)
|
164
227
|
class FPNumber
|
165
228
|
def leuqes(_jh)
|
166
|
-
Sequel.lit(@value)
|
229
|
+
success Sequel.lit(@value)
|
167
230
|
end
|
168
231
|
|
169
232
|
def leuqes_starts_like(_jh)
|
170
|
-
"#{@value}%"
|
233
|
+
success "#{@value}%"
|
171
234
|
end
|
172
235
|
|
173
236
|
def leuqes_ends_like(_jh)
|
174
|
-
"%#{@value}"
|
237
|
+
success "%#{@value}"
|
175
238
|
end
|
176
239
|
|
177
240
|
def leuqes_substringof_sig1(_jh)
|
178
|
-
"%#{@value}%"
|
241
|
+
success "%#{@value}%"
|
179
242
|
end
|
180
243
|
end
|
181
244
|
|
182
245
|
# Literals are unquoted words
|
183
246
|
class Literal
|
184
247
|
def leuqes(jh)
|
185
|
-
|
248
|
+
return Safrano::FilterParseErrorWrongColumnName unless jh.start_model.db_schema.key?(@value.to_sym)
|
186
249
|
|
187
|
-
Sequel[jh.start_model.table_name][@value.to_sym]
|
250
|
+
success Sequel[jh.start_model.table_name][@value.to_sym]
|
188
251
|
end
|
189
252
|
|
190
253
|
# non stantard extensions to support things like
|
191
254
|
# substringof(Rhum, name) ????
|
192
255
|
def leuqes_starts_like(_jh)
|
193
|
-
"#{@value}%"
|
256
|
+
success "#{@value}%"
|
194
257
|
end
|
195
258
|
|
196
259
|
def leuqes_ends_like(_jh)
|
197
|
-
"%#{@value}"
|
260
|
+
success "%#{@value}"
|
198
261
|
end
|
199
262
|
|
200
263
|
def leuqes_substringof_sig1(_jh)
|
201
|
-
"%#{@value}%"
|
264
|
+
success "%#{@value}%"
|
202
265
|
end
|
203
266
|
|
204
267
|
def as_string
|
@@ -206,31 +269,39 @@ module OData
|
|
206
269
|
end
|
207
270
|
end
|
208
271
|
|
272
|
+
# Null
|
273
|
+
class NullLiteral
|
274
|
+
def leuqes(jh)
|
275
|
+
# Sequel's representation of NULL
|
276
|
+
success LEUQES
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
209
280
|
# Qualit (qualified lits) are words separated by /
|
210
281
|
class Qualit
|
211
282
|
def leuqes(jh)
|
212
283
|
jh.add(@path)
|
213
284
|
talias = jh.start_model.get_alias_sym(@path)
|
214
|
-
Sequel[talias][@attrib.to_sym]
|
285
|
+
success Sequel[talias][@attrib.to_sym]
|
215
286
|
end
|
216
287
|
end
|
217
288
|
|
218
289
|
# Quoted Strings
|
219
290
|
class QString
|
220
291
|
def leuqes(_jh)
|
221
|
-
@value
|
292
|
+
success @value
|
222
293
|
end
|
223
294
|
|
224
295
|
def leuqes_starts_like(_jh)
|
225
|
-
"#{@value}%"
|
296
|
+
success "#{@value}%"
|
226
297
|
end
|
227
298
|
|
228
299
|
def leuqes_ends_like(_jh)
|
229
|
-
"%#{@value}"
|
300
|
+
success "%#{@value}"
|
230
301
|
end
|
231
302
|
|
232
303
|
def leuqes_substringof_sig1(_jh)
|
233
|
-
"%#{@value}%"
|
304
|
+
success "%#{@value}%"
|
234
305
|
end
|
235
306
|
end
|
236
307
|
end
|