safrano 0.4.3 → 0.4.4
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 +6 -2
- data/lib/odata/batch.rb +9 -7
- data/lib/odata/collection.rb +136 -642
- data/lib/odata/collection_filter.rb +16 -40
- data/lib/odata/collection_media.rb +56 -37
- 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 +53 -117
- data/lib/odata/error.rb +142 -37
- data/lib/odata/expand.rb +20 -17
- data/lib/odata/filter/base.rb +4 -1
- data/lib/odata/filter/error.rb +43 -27
- data/lib/odata/filter/parse.rb +33 -25
- data/lib/odata/filter/sequel.rb +97 -56
- data/lib/odata/filter/sequel_function_adapter.rb +50 -49
- data/lib/odata/filter/token.rb +10 -10
- data/lib/odata/filter/tree.rb +75 -41
- data/lib/odata/function_import.rb +166 -0
- data/lib/odata/model_ext.rb +618 -0
- data/lib/odata/navigation_attribute.rb +9 -24
- 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 +15 -7
- data/lib/safrano.rb +18 -38
- data/lib/safrano/contract.rb +143 -0
- data/lib/safrano/core.rb +12 -94
- data/lib/safrano/core_ext.rb +13 -0
- data/lib/safrano/deprecation.rb +73 -0
- data/lib/safrano/multipart.rb +25 -20
- data/lib/safrano/rack_app.rb +61 -62
- data/lib/safrano/{odata_rack_builder.rb → rack_builder.rb} +18 -1
- data/lib/safrano/request.rb +95 -37
- data/lib/safrano/response.rb +4 -2
- data/lib/safrano/sequel_join_by_paths.rb +2 -2
- data/lib/safrano/service.rb +132 -94
- data/lib/safrano/version.rb +3 -1
- data/lib/sequel/plugins/join_by_paths.rb +6 -19
- metadata +24 -5
data/lib/odata/filter/parse.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './token
|
4
|
-
require_relative './tree
|
5
|
-
require_relative './error
|
3
|
+
require_relative './token'
|
4
|
+
require_relative './tree'
|
5
|
+
require_relative './error'
|
6
6
|
|
7
|
-
# top level
|
8
|
-
module
|
7
|
+
# top level Safrano namespace
|
8
|
+
module Safrano
|
9
9
|
# for handling $filter
|
10
10
|
module Filter
|
11
11
|
# Parser for $filter input
|
12
12
|
class Parser
|
13
13
|
include Token
|
14
14
|
attr_reader :cursor
|
15
|
+
attr_reader :error
|
16
|
+
|
15
17
|
def initialize(input)
|
16
18
|
@tree = RootTree.new
|
17
19
|
@cursor = @tree
|
@@ -20,10 +22,14 @@ module OData
|
|
20
22
|
@binop_stack = []
|
21
23
|
end
|
22
24
|
|
25
|
+
def server_error
|
26
|
+
(@error = ::Safrano::ServerError)
|
27
|
+
end
|
28
|
+
|
23
29
|
def grow_at_cursor(child)
|
24
|
-
|
30
|
+
return server_error if @cursor.nil?
|
25
31
|
|
26
|
-
@cursor.attach(child)
|
32
|
+
@cursor.attach(child).tap_error { |err| return (@error = err) }
|
27
33
|
@cursor = child
|
28
34
|
end
|
29
35
|
|
@@ -42,7 +48,7 @@ module OData
|
|
42
48
|
def insert_before_cursor(node)
|
43
49
|
left = detach_cursor
|
44
50
|
grow_at_cursor(node)
|
45
|
-
@cursor.attach(left)
|
51
|
+
@cursor.attach(left).tap_error { |err| return (@error = err) }
|
46
52
|
end
|
47
53
|
|
48
54
|
def invalid_separator_error(tok, typ)
|
@@ -58,12 +64,7 @@ module OData
|
|
58
64
|
end
|
59
65
|
|
60
66
|
def with_accepted(tok, typ)
|
61
|
-
|
62
|
-
if acc
|
63
|
-
yield
|
64
|
-
else
|
65
|
-
@error = err
|
66
|
-
end
|
67
|
+
(err = @cursor.accept?(tok, typ)) ? (@error = err) : yield
|
67
68
|
end
|
68
69
|
|
69
70
|
def build
|
@@ -71,15 +72,19 @@ module OData
|
|
71
72
|
case typ
|
72
73
|
when :FuncTree
|
73
74
|
with_accepted(tok, typ) { grow_at_cursor(FuncTree.new(tok)) }
|
75
|
+
|
74
76
|
when :Delimiter
|
75
77
|
case tok
|
76
78
|
when '('
|
77
79
|
with_accepted(tok, typ) do
|
78
80
|
grow_at_cursor(IdentityFuncTree.new) unless @cursor.is_a? FuncTree
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
unless @error
|
82
|
+
openarg = ArgTree.new('(')
|
83
|
+
@stack << openarg
|
84
|
+
grow_at_cursor(openarg)
|
85
|
+
end
|
82
86
|
end
|
87
|
+
|
83
88
|
when ')'
|
84
89
|
break invalid_closing_delimiter_error(tok, typ) unless (@cursor = @stack.pop)
|
85
90
|
|
@@ -123,6 +128,7 @@ module OData
|
|
123
128
|
end
|
124
129
|
insert_before_cursor(binoptr)
|
125
130
|
end
|
131
|
+
|
126
132
|
when :BinopArithm
|
127
133
|
with_accepted(tok, typ) do
|
128
134
|
binoptr = BinopArithm.new(tok)
|
@@ -162,19 +168,21 @@ module OData
|
|
162
168
|
@cursor.update_state(tok, typ)
|
163
169
|
grow_at_cursor(FPNumber.new(tok))
|
164
170
|
end
|
171
|
+
|
165
172
|
when :unmatchedQuote
|
166
173
|
break unmatched_quote_error(tok, typ)
|
174
|
+
|
175
|
+
when :space
|
176
|
+
with_accepted(tok, typ) do
|
177
|
+
@cursor.update_state(tok, typ)
|
178
|
+
end
|
167
179
|
else
|
168
|
-
|
180
|
+
server_error
|
169
181
|
end
|
170
|
-
break if @error
|
171
|
-
end
|
172
|
-
begin
|
173
|
-
@tree.check_types unless @error
|
174
|
-
rescue ErrorInvalidArgumentType => e
|
175
|
-
@error = e
|
182
|
+
break(@error) if @error
|
176
183
|
end
|
177
|
-
@error
|
184
|
+
(@error = @tree.check_types) unless @error
|
185
|
+
@error ? @error : Contract.valid(@tree)
|
178
186
|
end
|
179
187
|
end
|
180
188
|
end
|
data/lib/odata/filter/sequel.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './base
|
4
|
-
require_relative './sequel_function_adapter
|
3
|
+
require_relative './base'
|
4
|
+
require_relative './sequel_function_adapter'
|
5
5
|
|
6
|
-
module
|
6
|
+
module Safrano
|
7
7
|
module Filter
|
8
8
|
# Base class for Leaves, Trees, RootTrees etc
|
9
9
|
# class Node
|
@@ -16,8 +16,9 @@ module OData
|
|
16
16
|
# RootTrees have childrens but no parent
|
17
17
|
class RootTree
|
18
18
|
def apply_to_dataset(dtcx, jh)
|
19
|
-
|
20
|
-
|
19
|
+
@children.first.leuqes(jh).if_valid do |filtexpr|
|
20
|
+
jh.dataset(dtcx).where(filtexpr).select_all(jh.start_model.table_name)
|
21
|
+
end
|
21
22
|
end
|
22
23
|
|
23
24
|
def sequel_expr(jh)
|
@@ -36,62 +37,102 @@ module OData
|
|
36
37
|
def leuqes(jh)
|
37
38
|
case @value
|
38
39
|
when :startswith
|
39
|
-
|
40
|
-
|
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
|
+
|
41
45
|
when :endswith
|
42
|
-
|
43
|
-
|
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
|
+
|
44
51
|
when :substringof
|
45
52
|
|
46
53
|
# there are multiple possible argument types (but all should return edm.string)
|
47
54
|
if args[0].is_a?(QString)
|
48
55
|
# substringof('Rhum', name) -->
|
49
56
|
# name contains substr 'Rhum'
|
50
|
-
|
51
|
-
|
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
|
+
|
52
62
|
# special non standard (ui5 client) case ?
|
53
63
|
elsif args[0].is_a?(Literal) && args[1].is_a?(Literal)
|
54
|
-
|
55
|
-
|
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
|
68
|
+
|
56
69
|
elsif args[1].is_a?(QString)
|
57
70
|
substringof_sig2(jh) # adapter specific
|
58
71
|
else
|
59
72
|
# TODO... actually not supported?
|
60
|
-
raise
|
73
|
+
raise Safrano::Filter::Parser::ErrorFunctionArgumentType
|
61
74
|
end
|
62
75
|
when :concat
|
63
|
-
|
64
|
-
|
76
|
+
Contract.collect_result!(args[0].leuqes(jh),
|
77
|
+
args[1].leuqes(jh)) do |l0, l1|
|
78
|
+
Sequel.join([l0, l1])
|
79
|
+
end
|
80
|
+
|
65
81
|
when :length
|
66
|
-
|
82
|
+
args.first.leuqes(jh)
|
83
|
+
.map_result! { |l| Sequel.char_length(l) }
|
84
|
+
|
67
85
|
when :trim
|
68
|
-
|
86
|
+
args.first.leuqes(jh)
|
87
|
+
.map_result! { |l| Sequel.trim(l) }
|
88
|
+
|
69
89
|
when :toupper
|
70
|
-
|
90
|
+
args.first.leuqes(jh)
|
91
|
+
.map_result! { |l| Sequel.function(:upper, l) }
|
92
|
+
|
71
93
|
when :tolower
|
72
|
-
|
94
|
+
args.first.leuqes(jh)
|
95
|
+
.map_result! { |l| Sequel.function(:lower, l) }
|
96
|
+
|
73
97
|
# all datetime funcs are adapter specific (because sqlite does not have extract)
|
74
98
|
when :year
|
75
|
-
|
99
|
+
args.first.leuqes(jh)
|
100
|
+
.map_result! { |l| year(l) }
|
101
|
+
|
76
102
|
when :month
|
77
|
-
|
103
|
+
args.first.leuqes(jh)
|
104
|
+
.map_result! { |l| month(l) }
|
105
|
+
|
78
106
|
when :second
|
79
|
-
|
107
|
+
args.first.leuqes(jh)
|
108
|
+
.map_result! { |l| second(l) }
|
109
|
+
|
80
110
|
when :minute
|
81
|
-
|
111
|
+
args.first.leuqes(jh)
|
112
|
+
.map_result! { |l| minute(l) }
|
113
|
+
|
82
114
|
when :hour
|
83
|
-
|
115
|
+
args.first.leuqes(jh)
|
116
|
+
.map_result! { |l| hour(l) }
|
117
|
+
|
84
118
|
when :day
|
85
|
-
|
119
|
+
args.first.leuqes(jh)
|
120
|
+
.map_result! { |l| day(l) }
|
121
|
+
|
86
122
|
# math functions
|
87
123
|
when :round
|
88
|
-
|
124
|
+
args.first.leuqes(jh)
|
125
|
+
.map_result! { |l| Sequel.function(:round, l) }
|
126
|
+
|
89
127
|
when :floor
|
90
|
-
|
128
|
+
args.first.leuqes(jh)
|
129
|
+
.if_valid { |l| floor(l) }
|
130
|
+
|
91
131
|
when :ceiling
|
92
|
-
|
132
|
+
args.first.leuqes(jh)
|
133
|
+
.if_valid { |l| ceiling(l) }
|
93
134
|
else
|
94
|
-
|
135
|
+
Safrano::FilterParseError
|
95
136
|
end
|
96
137
|
end
|
97
138
|
end
|
@@ -110,9 +151,9 @@ module OData
|
|
110
151
|
def leuqes(jh)
|
111
152
|
case @value
|
112
153
|
when :not
|
113
|
-
|
154
|
+
@children.first.leuqes(jh).map_result! { |l| Sequel.~(l) }
|
114
155
|
else
|
115
|
-
|
156
|
+
Safrano::FilterParseError
|
116
157
|
end
|
117
158
|
end
|
118
159
|
end
|
@@ -138,12 +179,12 @@ module OData
|
|
138
179
|
when :and
|
139
180
|
:AND
|
140
181
|
else
|
141
|
-
|
182
|
+
return Safrano::FilterParseError
|
142
183
|
end
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
184
|
+
Contract.collect_result!(@children[0].leuqes(jh),
|
185
|
+
@children[1].leuqes(jh)) do |c0, c1|
|
186
|
+
Sequel::SQL::BooleanExpression.new(leuqes_op, c0, c1)
|
187
|
+
end
|
147
188
|
end
|
148
189
|
end
|
149
190
|
|
@@ -162,12 +203,12 @@ module OData
|
|
162
203
|
when :mod
|
163
204
|
:%
|
164
205
|
else
|
165
|
-
|
206
|
+
return Safrano::FilterParseError
|
166
207
|
end
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
208
|
+
Contract.collect_result!(@children[0].leuqes(jh),
|
209
|
+
@children[1].leuqes(jh)) do |c0, c1|
|
210
|
+
Sequel::SQL::NumericExpression.new(leuqes_op, c0, c1)
|
211
|
+
end
|
171
212
|
end
|
172
213
|
end
|
173
214
|
|
@@ -178,42 +219,42 @@ module OData
|
|
178
219
|
# Numbers (floating point, ints, dec)
|
179
220
|
class FPNumber
|
180
221
|
def leuqes(_jh)
|
181
|
-
Sequel.lit(@value)
|
222
|
+
success Sequel.lit(@value)
|
182
223
|
end
|
183
224
|
|
184
225
|
def leuqes_starts_like(_jh)
|
185
|
-
"#{@value}%"
|
226
|
+
success "#{@value}%"
|
186
227
|
end
|
187
228
|
|
188
229
|
def leuqes_ends_like(_jh)
|
189
|
-
"%#{@value}"
|
230
|
+
success "%#{@value}"
|
190
231
|
end
|
191
232
|
|
192
233
|
def leuqes_substringof_sig1(_jh)
|
193
|
-
"%#{@value}%"
|
234
|
+
success "%#{@value}%"
|
194
235
|
end
|
195
236
|
end
|
196
237
|
|
197
238
|
# Literals are unquoted words
|
198
239
|
class Literal
|
199
240
|
def leuqes(jh)
|
200
|
-
|
241
|
+
return Safrano::FilterParseErrorWrongColumnName unless jh.start_model.db_schema.key?(@value.to_sym)
|
201
242
|
|
202
|
-
Sequel[jh.start_model.table_name][@value.to_sym]
|
243
|
+
success Sequel[jh.start_model.table_name][@value.to_sym]
|
203
244
|
end
|
204
245
|
|
205
246
|
# non stantard extensions to support things like
|
206
247
|
# substringof(Rhum, name) ????
|
207
248
|
def leuqes_starts_like(_jh)
|
208
|
-
"#{@value}%"
|
249
|
+
success "#{@value}%"
|
209
250
|
end
|
210
251
|
|
211
252
|
def leuqes_ends_like(_jh)
|
212
|
-
"%#{@value}"
|
253
|
+
success "%#{@value}"
|
213
254
|
end
|
214
255
|
|
215
256
|
def leuqes_substringof_sig1(_jh)
|
216
|
-
"%#{@value}%"
|
257
|
+
success "%#{@value}%"
|
217
258
|
end
|
218
259
|
|
219
260
|
def as_string
|
@@ -226,26 +267,26 @@ module OData
|
|
226
267
|
def leuqes(jh)
|
227
268
|
jh.add(@path)
|
228
269
|
talias = jh.start_model.get_alias_sym(@path)
|
229
|
-
Sequel[talias][@attrib.to_sym]
|
270
|
+
success Sequel[talias][@attrib.to_sym]
|
230
271
|
end
|
231
272
|
end
|
232
273
|
|
233
274
|
# Quoted Strings
|
234
275
|
class QString
|
235
276
|
def leuqes(_jh)
|
236
|
-
@value
|
277
|
+
success @value
|
237
278
|
end
|
238
279
|
|
239
280
|
def leuqes_starts_like(_jh)
|
240
|
-
"#{@value}%"
|
281
|
+
success "#{@value}%"
|
241
282
|
end
|
242
283
|
|
243
284
|
def leuqes_ends_like(_jh)
|
244
|
-
"%#{@value}"
|
285
|
+
success "%#{@value}"
|
245
286
|
end
|
246
287
|
|
247
288
|
def leuqes_substringof_sig1(_jh)
|
248
|
-
"%#{@value}%"
|
289
|
+
success "%#{@value}%"
|
249
290
|
end
|
250
291
|
end
|
251
292
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './tree
|
4
|
-
require_relative './sequel
|
3
|
+
require_relative './tree'
|
4
|
+
require_relative './sequel'
|
5
5
|
|
6
|
-
module
|
6
|
+
module Safrano
|
7
7
|
module Filter
|
8
8
|
# sqlite adapter specific function handler
|
9
9
|
module FuncTreeSqlite
|
@@ -11,10 +11,11 @@ module OData
|
|
11
11
|
# substringof(name, '__Route du Rhum__') -->
|
12
12
|
# '__Route du Rhum__' contains name as a substring
|
13
13
|
# sqlite uses instr()
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
Contract.collect_result!(args[1].leuqes(jh),
|
15
|
+
args[0].leuqes(jh)) do |l1, l0|
|
16
|
+
substr_func = Sequel.function(:instr, l1, l0)
|
17
|
+
Sequel::SQL::BooleanExpression.new(:>, substr_func, 0)
|
18
|
+
end
|
18
19
|
end
|
19
20
|
# %d day of month: 00
|
20
21
|
# %f fractional seconds: SS.SSS
|
@@ -31,77 +32,73 @@ module OData
|
|
31
32
|
# %% %
|
32
33
|
|
33
34
|
# sqlite does not have extract but recommends to use strftime
|
34
|
-
def year(
|
35
|
-
Sequel.function(:strftime, '%Y',
|
35
|
+
def year(lq)
|
36
|
+
Sequel.function(:strftime, '%Y', lq).cast(:integer)
|
36
37
|
end
|
37
38
|
|
38
|
-
def month(
|
39
|
-
Sequel.function(:strftime, '%m',
|
39
|
+
def month(lq)
|
40
|
+
Sequel.function(:strftime, '%m', lq).cast(:integer)
|
40
41
|
end
|
41
42
|
|
42
|
-
def second(
|
43
|
-
Sequel.function(:strftime, '%S',
|
43
|
+
def second(lq)
|
44
|
+
Sequel.function(:strftime, '%S', lq).cast(:integer)
|
44
45
|
end
|
45
46
|
|
46
|
-
def minute(
|
47
|
-
Sequel.function(:strftime, '%M',
|
47
|
+
def minute(lq)
|
48
|
+
Sequel.function(:strftime, '%M', lq).cast(:integer)
|
48
49
|
end
|
49
50
|
|
50
|
-
def hour(
|
51
|
-
Sequel.function(:strftime, '%H',
|
51
|
+
def hour(lq)
|
52
|
+
Sequel.function(:strftime, '%H', lq).cast(:integer)
|
52
53
|
end
|
53
54
|
|
54
|
-
def day(
|
55
|
-
Sequel.function(:strftime, '%d',
|
55
|
+
def day(lq)
|
56
|
+
Sequel.function(:strftime, '%d', lq).cast(:integer)
|
56
57
|
end
|
57
58
|
|
58
|
-
def floor(
|
59
|
-
|
59
|
+
def floor(_lq)
|
60
|
+
Safrano::FilterFunctionNotImplementedError.new("$filter function 'floor' is not implemented in sqlite adapter")
|
60
61
|
end
|
61
62
|
|
62
|
-
def ceiling(
|
63
|
-
|
63
|
+
def ceiling(_lq)
|
64
|
+
Safrano::FilterFunctionNotImplementedError.new("$filter function 'ceiling' is not implemented in sqlite adapter")
|
64
65
|
end
|
65
66
|
end
|
66
67
|
# re-useable module with math floor/ceil functions for those adapters having these SQL funcs
|
67
68
|
module MathFloorCeilFuncTree
|
68
|
-
def floor(
|
69
|
-
Sequel.function(:floor,
|
69
|
+
def floor(lq)
|
70
|
+
success Sequel.function(:floor, lq)
|
70
71
|
end
|
71
72
|
|
72
|
-
def ceiling(
|
73
|
-
Sequel.function(:ceil,
|
73
|
+
def ceiling(lq)
|
74
|
+
success Sequel.function(:ceil, lq)
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
77
78
|
# re-useable module with Datetime functions with extract()
|
78
79
|
module DateTimeFuncTreeExtract
|
79
|
-
def year(
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
def year(jh)
|
84
|
-
args.first.leuqes(jh).extract(:year)
|
80
|
+
def year(lq)
|
81
|
+
lq.extract(:year)
|
85
82
|
end
|
86
83
|
|
87
|
-
def month(
|
88
|
-
|
84
|
+
def month(lq)
|
85
|
+
lq.extract(:month)
|
89
86
|
end
|
90
87
|
|
91
|
-
def second(
|
92
|
-
|
88
|
+
def second(lq)
|
89
|
+
lq.extract(:second)
|
93
90
|
end
|
94
91
|
|
95
|
-
def minute(
|
96
|
-
|
92
|
+
def minute(lq)
|
93
|
+
lq.extract(:minute)
|
97
94
|
end
|
98
95
|
|
99
|
-
def hour(
|
100
|
-
|
96
|
+
def hour(lq)
|
97
|
+
lq.extract(:hour)
|
101
98
|
end
|
102
99
|
|
103
|
-
def day(
|
104
|
-
|
100
|
+
def day(lq)
|
101
|
+
lq.extract(:day)
|
105
102
|
end
|
106
103
|
end
|
107
104
|
|
@@ -111,9 +108,11 @@ module OData
|
|
111
108
|
# substringof(name, '__Route du Rhum__') -->
|
112
109
|
# '__Route du Rhum__' contains name as a substring
|
113
110
|
# postgres does not know instr() but has strpos
|
114
|
-
|
115
|
-
|
116
|
-
|
111
|
+
Contract.collect_result!(args[1].leuqes(jh),
|
112
|
+
args[0].leuqes(jh)) do |l1, l0|
|
113
|
+
substr_func = Sequel.function(:strpos, l1, l0)
|
114
|
+
Sequel::SQL::BooleanExpression.new(:>, substr_func, 0)
|
115
|
+
end
|
117
116
|
end
|
118
117
|
|
119
118
|
# postgres uses extract()
|
@@ -132,9 +131,11 @@ module OData
|
|
132
131
|
# substringof(name, '__Route du Rhum__') -->
|
133
132
|
# '__Route du Rhum__' contains name as a substring
|
134
133
|
# instr() seems to be the most common substring func
|
135
|
-
|
136
|
-
|
137
|
-
|
134
|
+
Contract.collect_result!(args[1].leuqes(jh),
|
135
|
+
args[0].leuqes(jh)) do |l1, l0|
|
136
|
+
substr_func = Sequel.function(:instr, l1, l0)
|
137
|
+
Sequel::SQL::BooleanExpression.new(:>, substr_func, 0)
|
138
|
+
end
|
138
139
|
end
|
139
140
|
|
140
141
|
# XYZ uses extract() ?
|