ruby-informix 0.6.2-i386-mswin32 → 0.7.0-i386-mswin32

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.
@@ -0,0 +1,280 @@
1
+ # $Id: interval.rb,v 1.3 2008/03/29 20:32:57 santana Exp $
2
+ #
3
+ # Copyright (c) 2008, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
+ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ module Informix
31
+ # The +IntervalBase+ class is used for sending and retrieving INTERVAL
32
+ # values to/from Informix.
33
+ #
34
+ # It can be used in some expressions with +Numeric+, +Date+, +DateTime+ and
35
+ # +Time+.
36
+ class IntervalBase
37
+ include Comparable
38
+
39
+ attr_reader :val
40
+
41
+ # IntervalBase.new(val) => interval
42
+ #
43
+ # Creates an +Interval+ object with +val+ as value.
44
+ def initialize(val)
45
+ return @val = val if Numeric === val
46
+ raise TypeError, "Expected Numeric"
47
+ end
48
+
49
+ def +@; self end
50
+ def -@; self.class.new(-@val) end
51
+
52
+ # Adds an +Interval+ object to a +Numeric+ or another compatible +Interval+
53
+ #
54
+ # interval + numeric => interval
55
+ # interval + interval => interval
56
+ def +(obj)
57
+ case obj
58
+ when Numeric
59
+ self.class.new(@val + obj)
60
+ when self.class
61
+ self.class.new(@val + obj.val)
62
+ else
63
+ raise TypeError, "#{self.class} cannot be added to #{obj.class}"
64
+ end
65
+ end
66
+
67
+ # Multiplies an +Interval+ object by a +Numeric+
68
+ #
69
+ # interval*numeric => interval
70
+ def *(n)
71
+ return self.class.new(@val*n) if Numeric === n
72
+ raise TypeError, "Expected Numeric"
73
+ end
74
+
75
+ # Divides an +Interval+ object by a +Numeric+
76
+ #
77
+ # interval/numeric => interval
78
+ def /(n)
79
+ return self.class.new(@val/n) if Numeric === n
80
+ raise TypeError, "Expected Numeric"
81
+ end
82
+
83
+ # Compares two compatible +Interval+ objects.
84
+ #
85
+ # interval1 <=> interval2 => true or false
86
+ def <=>(ivl)
87
+ return @val <=> ivl.val if self.class === ivl
88
+ raise ArgumentError, "Incompatible qualifiers"
89
+ end
90
+
91
+ # Returns the fields of an +Interval+ object as an +Array+
92
+ #
93
+ # invl.to_a => array
94
+ def to_a; @fields end
95
+
96
+ end # class IntervalBase
97
+
98
+ # The +IntervalYTM+ class is an Interval class dedicated only to
99
+ # represent intervals in the scope YEAR TO MONTH.
100
+ class IntervalYTM < IntervalBase
101
+ attr_reader :years, :months
102
+
103
+ # Creates an IntervalYTM object with +val+ as value.
104
+ #
105
+ # IntervalYTM.new(val) => interval
106
+ def initialize(val)
107
+ super
108
+ @val = val.to_i
109
+ @years, @months = @val.abs.divmod 12
110
+ if @val < 0
111
+ @years = -@years
112
+ @months = -@months
113
+ end
114
+ @fields = [ @years, @months ]
115
+ end
116
+
117
+ # interval + date => date
118
+ # interval + datetime => datetime
119
+ def +(obj)
120
+ case obj
121
+ when Date, DateTime
122
+ obj >> @val
123
+ else
124
+ super
125
+ end
126
+ end
127
+
128
+ # Returns an ANSI SQL standards compliant string representation
129
+ #
130
+ # invl.to_s => string
131
+ def to_s; "%d-%02d" % [@years, @months.abs] end
132
+
133
+ # Converts a invl to years
134
+ #
135
+ # invl.to_years => numeric
136
+ def to_years; Rational === @val ? @val/12 : @val/12.0 end
137
+
138
+ # Converts invl to months
139
+ #
140
+ # invl.to_months => numeric
141
+ def to_months; @val end
142
+ end # class IntervalYTM
143
+
144
+ # The +IntervalDTS+ class is an Interval class dedicated only to
145
+ # represent intervals in the scope DAY TO SECOND.
146
+ class IntervalDTS < IntervalBase
147
+ attr_reader :days, :hours, :minutes, :seconds
148
+
149
+ # Creates an IntervalDTS object with +val+ as value.
150
+ #
151
+ # IntervalDTS.new(val) => interval
152
+ def initialize(val)
153
+ super
154
+ @days, @hours = @val.abs.divmod(24*60*60)
155
+ @hours, @minutes = @hours.divmod(60*60)
156
+ @minutes, @seconds = @minutes.divmod(60)
157
+ if @val < 0
158
+ @days = -@days; @hours = -@hours; @minutes = -@minutes;
159
+ @seconds = -@seconds
160
+ end
161
+ @fields = [ @days, @hours, @minutes, @seconds ]
162
+ end
163
+
164
+ # interval + datetime => datetime
165
+ # interval + time => time
166
+ def +(obj)
167
+ case obj
168
+ when DateTime
169
+ obj + (Rational === @val ? @val/86400 : @val/86400.0)
170
+ when Time
171
+ obj + @val
172
+ else
173
+ super
174
+ end
175
+ end
176
+
177
+ # Returns an ANSI SQL standards compliant string representation
178
+ #
179
+ # invl.to_s => string
180
+ def to_s
181
+ "%d %02d:%02d:%08.5f" % [@days, @hours.abs, @minutes.abs, @seconds.abs]
182
+ end
183
+
184
+ # Converts invl to days
185
+ #
186
+ # invl.to_days => numeric
187
+ def to_days; Rational === @val ? @val/60/60/24 : @val/60.0/60/24 end
188
+
189
+ # Converts invl to hours
190
+ #
191
+ # invl.to_hours => numeric
192
+ def to_hours; Rational === @val ? @val/60/60 : @val/60.0/60 end
193
+
194
+ # Converts invl to minutes
195
+ #
196
+ # invl.to_minutes => numeric
197
+ def to_minutes; Rational === @val ? @val/60 : @val/60.0 end
198
+
199
+ # Converts invl to seconds
200
+ #
201
+ # invl.to_seconds => numeric
202
+ def to_seconds; @val end
203
+ end # class IntervalDTS
204
+
205
+ # The +Interval+ module provides shortcuts for creating +IntervalYTM+ and
206
+ # +IntervalDTS+ objects
207
+ module Interval
208
+ # Shortcut to create an IntervalYTM object.
209
+ #
210
+ # Interval.year_to_month(years = 0, months = 0) => interval
211
+ # Interval.year_to_month(:years => yy, :months => mm) => interval
212
+ #
213
+ # Interval.year_to_month(5) #=> '5-00'
214
+ # Interval.year_to_month(0, 3) #=> '0-03'
215
+ # Interval.year_to_month(5, 3) #=> '5-03'
216
+ # Interval.year_to_month(:years => 5.5) #=> '5-06'
217
+ # Interval.year_to_month(:months => 3) #=> '0-03'
218
+ # Interval.year_to_month(:years => 5.5, :months => 5) #=> '5-11'
219
+ def self.year_to_month(*args)
220
+ if args.size == 1 && Hash === args[0]
221
+ years, months = args[0][:years], args[0][:months]
222
+ elsif args.size <= 2 && args.all? {|e| Numeric === e }
223
+ years, months = args
224
+ else
225
+ raise TypeError, "Expected Numerics or a Hash"
226
+ end
227
+ years ||= 0; months ||= 0
228
+ if ![years, months].all? {|e| Numeric === e && e >= 0 }
229
+ raise ArgumentError, "Expected Numerics >= 0"
230
+ end
231
+ from_months(years*12 + months.to_i)
232
+ end
233
+
234
+ # Shortcut to create an IntervalYTM object.
235
+ #
236
+ # Interval.from_months(3) #=> '0-03'
237
+ # Interval.from_months(71) #=> '5-11'
238
+ def self.from_months(months)
239
+ IntervalYTM.new(months)
240
+ end
241
+
242
+ # Shortcut to create an IntervalDTS object.
243
+ #
244
+ # Interval.day_to_second(days = 0, hours = 0,
245
+ # minutes = 0, seconds = 0) => interval
246
+ # Interval.day_to_second(:days => dd, :hours => hh,
247
+ # :minutes => mm, :seconds => ss) => interval
248
+ #
249
+ # Interval.day_to_second(5, 3) # => '5 03:00:00.00000'
250
+ # Interval.day_to_second(0, 2, 0, 30) # => '0 02:00:30.00000'
251
+ # Interval.day_to_second(:hours=>2.5) # => '0 02:30:00.00000'
252
+ # Interval.day_to_second(:seconds=>Rational(151,10))# => '0 00:00:15.10000'
253
+ # Interval.day_to_second(:seconds=> 20.13) # => '0 00:00:20.13000'
254
+ # Interval.day_to_second(:days=>1.5, :hours=>2) # => '1 14:00:00.00000'
255
+ def self.day_to_second(*args)
256
+ if args.size == 1 && Hash === args[0]
257
+ h = args[0]
258
+ days, hours, minutes, seconds = h[:days], h[:hours], h[:minutes],
259
+ h[:seconds]
260
+ elsif args.size <= 5 && args.all? {|e| Numeric === e || e.nil? }
261
+ days, hours, minutes, seconds = args
262
+ else
263
+ raise TypeError, "Expected Numerics or a Hash"
264
+ end
265
+ days ||= 0; hours ||= 0; minutes ||= 0; seconds ||= 0
266
+ if ![days, hours, minutes, seconds].all? {|e| Numeric === e && e >= 0 }
267
+ raise ArgumentError, "Expected Numerics >= 0"
268
+ end
269
+ from_seconds(days*24*60*60 + hours*60*60 + minutes*60 + seconds)
270
+ end
271
+
272
+ # Shortcut to create an IntervalDTS object.
273
+ #
274
+ # Interval.from_seconds(9000) #=> '0 02:30:00.00000'
275
+ # Interval.from_seconds(Rational(151, 10)) #=> '0 00:00:15.10000'
276
+ def self.from_seconds(seconds)
277
+ IntervalDTS.new(seconds)
278
+ end
279
+ end # module Interval
280
+ end # module Informix
@@ -0,0 +1,306 @@
1
+ # $Id: scrollcursor.rb,v 1.4 2008/03/29 07:35:03 santana Exp $
2
+ #
3
+ # Copyright (c) 2008, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
+ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ require 'informixc'
31
+
32
+ module Informix
33
+ class ScrollCursor < SequentialCursor
34
+ # Returns the record at _index_, or returns a subarray starting at _start_
35
+ # and continuing for _length_ records. Negative indices count backward from
36
+ # the end of the cursor (-1 is the last element). Returns nil if the
37
+ # (starting) index is out of range.
38
+ #
39
+ # <b>Warning</b>: if the (starting) index is negative and out of range, the
40
+ # position in the cursor is set to the last record. Otherwise the current
41
+ # position in the cursor is preserved.
42
+ #
43
+ # cursor[index] => array or nil
44
+ # cursor[start, length] => array or nil
45
+ # cursor.slice(index) => array or nil
46
+ # cursor.slice(start, length) => array or nil
47
+ def slice(*args)
48
+ slice0(args, Array)
49
+ end
50
+
51
+ alias [] slice
52
+
53
+ # Returns the record at _index_. Negative indices count backward from
54
+ # the end of the cursor (-1 is the last element). Returns nil if the index
55
+ # is out of range.
56
+ #
57
+ # Stores the record fetched always in the same Array object.
58
+ #
59
+ # <b>Warning</b>: if the index is negative and out of range, the
60
+ # position in the cursor is set to the last record. Otherwise the current
61
+ # position in the cursor is preserved.
62
+ #
63
+ # cursor.slice!(index) => array or nil
64
+ def slice!(index)
65
+ entry(index, Array, true)
66
+ end
67
+
68
+ # Returns the record at _index_, or returns a subarray starting at _start_
69
+ # and continuing for _length_ records. Negative indices count backward from
70
+ # the end of the cursor (-1 is the last element). Returns nil if the
71
+ # (starting) index is out of range.
72
+ #
73
+ # <b>Warning</b>: if the (starting) index is negative and out of range, the
74
+ # position in the cursor is set to the last record. Otherwise the current
75
+ # position in the cursor is preserved.
76
+ #
77
+ # cursor.slice_hash(index) => hash or nil
78
+ # cursor.slice_hash(start, length) => array or nil
79
+ def slice_hash(*args)
80
+ slice0(args, Hash)
81
+ end
82
+
83
+ # Returns the record at _index_. Negative indices count backward from
84
+ # the end of the cursor (-1 is the last element). Returns nil if the index
85
+ # is out of range.
86
+ #
87
+ # Stores the record fetched always in the same Hash object.
88
+ #
89
+ # <b>Warning</b>: if the index is negative and out of range, the
90
+ # position in the cursor is set to the last record. Otherwise the current
91
+ # position in the cursor is preserved.
92
+ #
93
+ # cursor.slice_hash!(index) => hash or nil
94
+ def slice_hash!(index)
95
+ entry(index, Hash, true)
96
+ end
97
+
98
+ # Returns the previous _offset_ th record. Negative indices count
99
+ # forward from the current position. Returns nil if the _offset_ is out of
100
+ # range.
101
+ #
102
+ # cursor.prev(offset = 1) => array or nil
103
+ def prev(offset = 1)
104
+ rel(-offset, Array, false)
105
+ end
106
+
107
+ # Returns the previous _offset_ th record. Negative indices count
108
+ # forward from the current position. Returns nil if the _offset_ is out of
109
+ # range.
110
+ #
111
+ # Stores the record fetched always in the same Array object.
112
+ #
113
+ # cursor.prev!(offset = 1) => array or nil
114
+ def prev!(offset = 1)
115
+ rel(-offset, Array, true)
116
+ end
117
+
118
+ # Returns the previous _offset_ th record. Negative indices count
119
+ # forward from the current position. Returns nil if the _offset_ is out of
120
+ # range.
121
+ #
122
+ # cursor.prev_hash(offset = 1) => hash or nil
123
+ def prev_hash(offset = 1)
124
+ rel(-offset, Hash, false)
125
+ end
126
+
127
+ # Returns the previous _offset_ th record. Negative indices count
128
+ # forward from the current position. Returns nil if the _offset_ is out of
129
+ # range.
130
+ #
131
+ # Stores the record fetched always in the same Hash object.
132
+ #
133
+ # cursor.prev_hash!(offset = 1) => hash or nil
134
+ def prev_hash!(offset = 1)
135
+ rel(-offset, Hash, true)
136
+ end
137
+
138
+ # Returns the next _offset_ th record. Negative indices count
139
+ # backward from the current position. Returns nil if the _offset_ is out of
140
+ # range.
141
+ #
142
+ # cursor.next(offset = 1) => array or nil
143
+ def next(offset = 1)
144
+ rel(offset, Array, false)
145
+ end
146
+
147
+ # Returns the next _offset_ th record. Negative indices count
148
+ # backward from the current position. Returns nil if the _offset_ is out of
149
+ # range.
150
+ #
151
+ # Stores the record fetched always in the same Array object.
152
+ #
153
+ # cursor.next!(offset = 1) => array or nil
154
+ def next!(offset = 1)
155
+ rel(offset, Array, true)
156
+ end
157
+
158
+ # Returns the next _offset_ th record. Negative indices count
159
+ # backward from the current position. Returns nil if the _offset_ is out of
160
+ # range.
161
+ #
162
+ # cursor.next_hash(offset = 1) => hash or nil
163
+ def next_hash(offset = 1)
164
+ rel(offset, Hash, false)
165
+ end
166
+
167
+ # Returns the next _offset_ th record. Negative indices count
168
+ # backward from the current position. Returns nil if the _offset_ is out of
169
+ # range.
170
+ #
171
+ # cursor.next_hash!(offset = 1) => hash or nil
172
+ def next_hash!(offset = 1)
173
+ rel(offset, Hash, true)
174
+ end
175
+
176
+ # Returns the first record of the cursor. If the cursor is empty,
177
+ # returns nil.
178
+ #
179
+ # cursor.first => array or nil
180
+ def first
181
+ entry(0, Array, false)
182
+ end
183
+
184
+ # Returns the first record of the cursor. If the cursor is empty,
185
+ # returns nil.
186
+ #
187
+ # Stores the record fetched always in the same Array object.
188
+ #
189
+ # cursor.first! => array or nil
190
+ def first!
191
+ entry(0, Array, true)
192
+ end
193
+
194
+ # Returns the first record of the cursor. If the cursor is empty,
195
+ # returns nil.
196
+ #
197
+ # cursor.first_hash => hash or nil
198
+ def first_hash
199
+ entry(0, Hash, false)
200
+ end
201
+
202
+ # Returns the first record of the cursor. If the cursor is empty,
203
+ # returns nil.
204
+ #
205
+ # Stores the record fetched always in the same Hash object.
206
+ #
207
+ # cursor.first_hash! => hash or nil
208
+ def first_hash!
209
+ entry(0, Hash, true)
210
+ end
211
+
212
+ # Returns the last record of the cursor. If the cursor is empty,
213
+ # returns nil.
214
+ #
215
+ # cursor.last => array or nil
216
+ def last
217
+ entry(-1, Array, false)
218
+ end
219
+
220
+ # Returns the last record of the cursor. If the cursor is empty,
221
+ # returns nil.
222
+ #
223
+ # Stores the record fetched always in the same Array object.
224
+ #
225
+ # cursor.last! => array or nil
226
+ def last!
227
+ entry(-1, Array, true)
228
+ end
229
+
230
+ # Returns the last record of the cursor. If the cursor is empty,
231
+ # returns nil.
232
+ #
233
+ # cursor.last_hash => hash or nil
234
+ def last_hash
235
+ entry(-1, Hash, false)
236
+ end
237
+
238
+ # Returns the last record of the cursor. If the cursor is empty,
239
+ # returns nil.
240
+ #
241
+ # Stores the record fetched always in the same Hash object.
242
+ #
243
+ # cursor.last_hash! => hash or nil
244
+ def last_hash!
245
+ entry(-1, Hash, true)
246
+ end
247
+
248
+ # Returns the current record of the cursor. If the cursor is empty,
249
+ # returns nil.
250
+ #
251
+ # cursor.current => array or nil
252
+ def current
253
+ entry(nil, Array, false)
254
+ end
255
+
256
+ # Returns the current record of the cursor. If the cursor is empty,
257
+ # returns nil.
258
+ #
259
+ # Stores the record fetched always in the same Array object.
260
+ #
261
+ # cursor.current! => array or nil
262
+ def current!
263
+ entry(nil, Array, true)
264
+ end
265
+
266
+ # Returns the current record of the cursor. If the cursor is empty,
267
+ # returns nil.
268
+ #
269
+ # cursor.current_hash => hash or nil
270
+ def current_hash
271
+ entry(nil, Hash, false)
272
+ end
273
+
274
+ # Returns the current record of the cursor. If the cursor is empty,
275
+ # returns nil.
276
+ #
277
+ # Stores the record fetched always in the same Hash object.
278
+ #
279
+ # cursor.current_hash! => hash or nil
280
+ def current_hash!
281
+ entry(nil, Hash, true)
282
+ end
283
+
284
+ private
285
+
286
+ # Provides the Array-like functionality for scroll cursors when using the
287
+ # cursor[start, length] syntax
288
+ def subseq(start, length, type) #:nodoc:
289
+ first = entry(start, type, false)
290
+ return if first.nil?
291
+
292
+ records = length > 1 ? fetch_many0(length - 1, type) : []
293
+ records.unshift(first)
294
+ end
295
+
296
+ # Base function for slice and slice_hash methods
297
+ def slice0(args, type) #:nodoc:
298
+ return entry(args[0], type, false) if args.size == 1
299
+ if args.size == 2
300
+ return subseq(args[0], args[1], type) unless args[1] < 0
301
+ raise(ArgumentError, "length must be positive")
302
+ end
303
+ raise(ArgumentError, "wrong number of arguments (%d for 2)", args.size)
304
+ end
305
+ end # class ScrollCursor
306
+ end # module Informix