Class: RDBI::Result

Inherits:
Object
  • Object
show all
Extended by:
MethLab
Includes:
Enumerable
Defined in:
lib/rdbi/result.rb

Overview

RDBI::Result encapsulates results from a statement.

Results in RDBI::Result are row-oriented and may be transformable by Result Drivers (RDBI::Result::Driver). They are fetched as a unit or in order.

The RDBI::Result API is deliberately architected to loosely resemble that of IO or File.

Just give me the data!

Have a peek at RDBI::Result#fetch.

Result Counts

Multiple kinds of counts are represented in each result:

  • A count of the results provided

  • A count of the affected rows.

To elaborate, the “affected rows” is a count of rows that were altered by the statement from a DML result such as INSERT or UPDATE. In some cases, statements will both alter rows and yield results, which is why this value is not switched depending on the kind of statement.

Result Drivers

Result drivers are subclasses of RDBI::Result::Driver that take the result as input and yield a transformed input: data structures such a hashes, or even wilder results such as CSV or JSON or YAML. Given the ability to sanely transform row-oriented input, result drivers effectively have the power to do anything.

Accessing result drivers is as easy as using a secondary form of RDBI::Result#fetch or more explicitly with the RDBI::Result#as call.

Defined Under Namespace

Classes: Driver

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sth, binds, data, schema, type_hash) ⇒ Result

Creates a new RDBI::Result. Please refer to RDBI::Statement#new_execution for instructions on how this is typically used and how the contents are passed to the constructor.


81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rdbi/result.rb', line 81

def initialize(sth, binds, data, schema, type_hash)
  @schema         = schema
  @data           = data
  @result_count   = data.size
  @affected_count = data.affected_count
  @sth            = sth
  @binds          = binds
  @type_hash      = type_hash
  @mutex          = Mutex.new
  @driver         = RDBI::Result::Driver::Array
  @fetch_handle   = nil
  as(@driver)
end

Instance Attribute Details

#affected_countObject (readonly)

The count of affected rows by a DML statement (see RDBI::Result main documentation)


54
55
56
# File 'lib/rdbi/result.rb', line 54

def affected_count
  @affected_count
end

#bindsObject (readonly)

The binds used in the statement that yielded this Result.


60
61
62
# File 'lib/rdbi/result.rb', line 60

def binds
  @binds
end

#driverObject (readonly)

The RDBI::Result::Driver currently associated with this Result.


48
49
50
# File 'lib/rdbi/result.rb', line 48

def driver
  @driver
end

#result_countObject (readonly)

The count of results (see RDBI::Result main documentation)


51
52
53
# File 'lib/rdbi/result.rb', line 51

def result_count
  @result_count
end

#schemaObject (readonly)

The RDBI::Schema structure associated with this result.


42
43
44
# File 'lib/rdbi/result.rb', line 42

def schema
  @schema
end

#sthObject (readonly)

The RDBI::Statement that yielded this result.


45
46
47
# File 'lib/rdbi/result.rb', line 45

def sth
  @sth
end

#type_hashObject (readonly)

The mapping of types for each positional argument in the Result.


57
58
59
# File 'lib/rdbi/result.rb', line 57

def type_hash
  @type_hash
end

Instance Method Details

#as(driver_klass, *args) ⇒ Object

:call-seq:

as(String)
as(Symbol)
as(Class)
as([Class, String, or Symbol], *driver_arguments)

Replace the Result Driver. See RDBI::Result's main docs and RDBI::Result::Driver for more information on Result Drivers.

You may pass:

  • A Symbol or String which is shorthand for loading from the RDBI::Result::Driver namespace – for example: “CSV” will result in the class RDBI::Result::Driver::CSV.

  • A full class name.

There are no naming requirements; the String/Symbol form is just shorthand for convention.

Any additional arguments will be passed to the driver's constructor.


156
157
158
159
160
161
162
163
# File 'lib/rdbi/result.rb', line 156

def as(driver_klass, *args)

  driver_klass  = RDBI::Util.class_from_class_or_symbol(driver_klass, RDBI::Result::Driver)

  @data.rewind
  @driver       = driver_klass
  @fetch_handle = driver_klass.new(self, *args)
end

#coerce_to_arrayObject

Coerce the underlying result to an array, fetching all values.


130
131
132
# File 'lib/rdbi/result.rb', line 130

def coerce_to_array
  @data.coerce_to_array
end

#eachObject

Iterator for Enumerable methods. Yields a row at a time.


114
115
116
117
118
# File 'lib/rdbi/result.rb', line 114

def each
  @data.each do |row|
    yield(row)
  end
end

#fetch(row_count = 1, driver_klass = nil, *args) ⇒ Object Also known as: read

:call-seq:

fetch()
fetch(Integer)
fetch(:first)
fetch(:last)
fetch(:all)
fetch(:rest)
fetch(amount, [Class, String, or Symbol], *driver_arguments)

fetch is the way people will typically interact with this class. It yields some or all of the results depending on the arguments given. Additionally, it can be supplemented with the arguments passed to RDBI::Result#as to one-off select a result driver.

The initial argument can be none or one of many options:

  • An Integer n requests n rows from the result and increments the index.

  • No argument uses an Integer count of 1.

  • :first yields the first row of the result, regardless of the index.

  • :last yields the last row of the result, regardless of the index.

  • :all yields the whole set of rows, regardless of the index.

  • :rest yields all the items that have not been fetched, determined by the index.

  • :first and :last return nil if there are no results. All others will return an empty array.

The index

I bet you're wondering what that is now, right? Well, the index is essentially a running row count that is altered by certain fetch operations. This makes sequential fetches much simpler.

The index is largely implemented by RDBI::Cursor (and Database Driver subclasses)

Items that do not use the index do not affect it.

Result Drivers will always rewind the index, as this implicates a “point of no return” state change. You may always return to the original driver you were using, but the index position will be lost.

The default result driver is RDBI::Result::Driver::Array.


208
209
210
211
212
213
214
# File 'lib/rdbi/result.rb', line 208

def fetch(row_count=1, driver_klass=nil, *args)
  if driver_klass
    as(driver_klass, *args)
  end

  @fetch_handle.fetch(row_count)
end

#finishObject

This call finishes the result and the RDBI::Statement handle, scheduling any unpreserved data for garbage collection.


245
246
247
248
249
250
251
252
253
# File 'lib/rdbi/result.rb', line 245

def finish
  @sth.finish
  @data.finish
  @data   = nil
  @sth    = nil
  @driver = nil
  @binds  = nil
  @schema = nil
end

#has_dataObject

:attr_reader: has_data?

Does this result have data?


74
# File 'lib/rdbi/result.rb', line 74

inline(:has_data, :has_data?) { @data.size > 0 }

#raw_fetch(row_count) ⇒ Object

raw_fetch is a straight array fetch without driver interaction. If you think you need this, please still read the fetch documentation as there is a considerable amount of overlap.

This is generally used by Result Drivers to transform results.


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rdbi/result.rb', line 225

def raw_fetch(row_count)
  final_res = case row_count
              when :all
                @data.all
              when :rest
                @data.rest
              when :first
                [@data.first]
              when :last
                [@data.last]
              else
                @data.fetch(row_count)
              end
  RDBI::Util.deep_copy(final_res)
end

#reloadObject

Reload the result. This will:

  • Execute the statement that yielded this result again, with the original binds

  • Replace the results and other attributes with the new results.


101
102
103
104
105
106
107
108
109
# File 'lib/rdbi/result.rb', line 101

def reload
  @data.finish
  res = @sth.execute(*@binds)
  @data           = res.instance_variable_get(:@data)
  @type_hash      = res.instance_variable_get(:@type_hash)
  @schema         = res.instance_variable_get(:@schema)
  @result_count   = res.instance_variable_get(:@result_count)
  @affected_count = res.instance_variable_get(:@affected_count)
end

#rewindObject

Reset the index.


123
124
125
# File 'lib/rdbi/result.rb', line 123

def rewind
  @data.rewind
end