Class: DBI::Row

Inherits:
Array
  • Object
show all
Defined in:
lib/dbi/row.rb

Overview

DBI::Row is the representation of a row in a result set returned by the database.

It is responsible for containing and representing the result set, converting it to native Ruby types, and providing methods to sanely move through itself.

The DBI::Row class is a delegate of Array, rather than a subclass, because there are times when it should act like an Array, and others when it should act like a Hash (and still others where it should act like String, Regexp, etc). It also needs to store metadata about the row, such as column data type and index information, that users can then access.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(columns, column_types, size_or_array = nil, convert_types = true) ⇒ Row

DBI::Row.new(columns, column_types, size_or_array=nil)

Returns a new DBI::Row object using columns. The size_or_array argument may either be an Integer or an Array. If it is not provided, it defaults to the length of columns.

Column types is a corresponding Array of Class/Module objects that conform to the DBI::Type interface. These will be used to convert types as they are returned.

DBI::Row is a delegate of the Array class, so all of the Array instance methods are available to your DBI::Row object (keeping in mind that initialize, [], and []= have been explicitly overridden).



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/dbi/row.rb', line 33

def initialize(columns, column_types, size_or_array=nil, convert_types=true)
    @column_types = column_types
    @convert_types = convert_types
    size_or_array ||= columns.size 
    
    # The '@column_map' is used to map column names to integer values so
    # that users can reference row values by name or number.

    @column_map   = {}
    @column_names = columns
    columns.each_with_index { |c,i| @column_map[c] = i }

    case size_or_array
    when Integer
        super(@arr = Array.new(size_or_array))
    when Array
        super(@arr = size_or_array.dup)
        set_values(size_or_array.dup)
    else
        raise TypeError, "parameter must be either Integer or Array"
    end
end

Instance Attribute Details

#column_namesObject (readonly) Also known as: field_names

Returns the value of attribute column_names



17
18
19
# File 'lib/dbi/row.rb', line 17

def column_names
  @column_names
end

Instance Method Details

#[](*args) ⇒ Object

Row#[]

row row row row[arg, arg] row[arg, arg, ???]

Sample: Row.new(, ["Daniel", "Berger", "36"])

Retrieves row elements. Exactly what it retrieves depends on the kind and number of arguments used.

Zero arguments will raise an ArgumentError.

One argument will return a single result. This can be a String, Symbol, Integer, Range or Regexp and the appropriate result will be returned. Strings, Symbols and Regexps act like hash lookups, while Integers and Ranges act like Array index lookups.

Two arguments will act like the second form of Array#[], i.e it takes two integers, with the first number the starting point and the second number the length, and returns an array of values.

If three or more arguments are provided, an array of results is returned. The behavior for each argument is that of a single argument, i.e. Strings, Symbols, and Regexps act like hash lookups, while Integers and Ranges act like Array index lookups.

If no results are found, or an unhandled type is passed, then nil (or a nil element) is returned.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/dbi/row.rb', line 157

def [](*args)
    begin
        case args.length
        when 0
            err = "wrong # of arguments(#{args.size} for at least 1)"
            raise ArgumentError, err
        when 1
            case args[0]
            when Array
                args[0].collect { |e| self[e] }
            when Regexp
                self[@column_names.grep(args[0])] 
            else
                @arr[conv_param(args[0])]
            end
            # We explicitly check for a length of 2 in order to properly
            # simulate the second form of Array#[].
        when 2
            @arr[conv_param(args[0]), conv_param(args[1])]
        else
            results = []
            args.flatten.each{ |arg|
                case arg
                when Integer
                    results.push(@arr[arg])
                when Regexp
                    results.push(self[@column_names.grep(arg)])
                else
                    results.push(self[conv_param(arg)])
                end
            }
            results.flatten
        end
    rescue TypeError
        nil
    end
end

#[]=(key, value_or_length, obj = nil) ⇒ Object

Assign a value to a Row object by element. You can assign using a single element reference, or by using a start and length similar to the second form of Array#[]=.

row = ???kirk??? row = ???haines??? row[0, 2] = ???test???



203
204
205
206
207
208
209
# File 'lib/dbi/row.rb', line 203

def []=(key, value_or_length, obj=nil)
    if obj
        @arr[conv_param(key), conv_param(value_or_length)] = obj
    else
        @arr[conv_param(key)] = value_or_length
    end
end

#__getobj__Object



213
214
215
# File 'lib/dbi/row.rb', line 213

def __getobj__
    @arr
end

#__setobj__(obj) ⇒ Object



217
218
219
# File 'lib/dbi/row.rb', line 217

def __setobj__(obj)
    @delegate_dc_obj = @arr = obj
end

#by_field(field_name) ⇒ Object

Value of the field named field_name or nil if not found.



117
118
119
120
121
122
123
# File 'lib/dbi/row.rb', line 117

def by_field(field_name)
    begin
        @arr[@column_map[field_name.to_s]]
    rescue TypeError
        nil
    end
end

#by_index(index) ⇒ Object

Retrieve a value by index (rather than name).

Deprecated. Since Row delegates to Array, just use Row#at.



112
113
114
# File 'lib/dbi/row.rb', line 112

def by_index(index)
    @arr[index]
end

#cloneObject

See Object#clone.

#clone and #dup here, however, are both deep copies via Marshal.



226
227
228
# File 'lib/dbi/row.rb', line 226

def clone
    Marshal.load(Marshal.dump(self))
end

#clone_with(new_values) ⇒ Object

Create a new row with 'new_values', reusing the field name hash. Initial cloning is done deeply, via Marshal.



100
101
102
103
104
105
# File 'lib/dbi/row.rb', line 100

def clone_with(new_values)
    obj = clone
    obj.set_values(new_values)

    return obj
end

#convert_types(arr) ⇒ Object

converts the types in the array to their specified representation from column types provided at construction time.



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/dbi/row.rb', line 58

def convert_types(arr)
    return arr.dup unless @convert_types

    if arr.size != @column_types.size
        raise TypeError, "Type mapping is not consistent with result"
    end
    new_arr = []
    arr.each_with_index do |item, i|
        new_arr.push((@column_types[i] || DBI::Type::Varchar).parse(item))
    end

    return new_arr
end

#dupObject



230
231
232
233
234
235
236
237
238
239
240
# File 'lib/dbi/row.rb', line 230

def dup
    row = self.class.allocate
    row.instance_variable_set :@column_types,  @column_types
    row.instance_variable_set :@convert_types, @convert_types
    row.instance_variable_set :@column_map,    @column_map
    row.instance_variable_set :@column_names,  @column_names
    # this is the only one we actually dup...
    row.instance_variable_set :@arr,           arr = @arr.dup
    row.instance_variable_set :@_dc_obj,       arr
    row
end

#each_with_nameObject

Yields a column value by name (rather than index), along with the column name itself.



80
81
82
83
84
# File 'lib/dbi/row.rb', line 80

def each_with_name
    @arr.each_with_index do |v, i|
        yield v, @column_names[i]
    end 
end

#set_values(new_values) ⇒ Object

Replaces the contents of the internal array with new_values. elements are type converted at this time.



74
75
76
# File 'lib/dbi/row.rb', line 74

def set_values(new_values)
    @arr.replace(convert_types(new_values))
end

#to_aObject

returns the underlying array (duplicated)



87
88
89
# File 'lib/dbi/row.rb', line 87

def to_a
    @arr.dup
end

#to_hObject

Returns the Row object as a hash, created by #each_with_name.



92
93
94
95
96
# File 'lib/dbi/row.rb', line 92

def to_h
    hash = {}
    each_with_name{ |v, n| hash[n] = v}
    hash
end