Kùzu query result class
These objects contain one result set from either a Kuzu::Connection#query
call or Kuzu::PreparedStatement#execute
. If there are multiple result sets, you can fetch the next one by calling Kuzu::Result#next_set
. You can use has_next_set?
to test for a following set.
Tuple values are converted to corresponding Ruby objects:
Kuzu Type |
Ruby Type |
INT8 |
Integer |
INT16 |
Integer |
INT32 |
Integer |
INT64 |
Integer |
INT128 |
Integer |
UINT8 |
Integer |
UINT16 |
Integer |
UINT32 |
Integer |
UINT64 |
Integer |
FLOAT |
Float |
DOUBLE |
Float |
DECIMAL |
Float |
BOOLEAN |
TrueClass or FalseClass |
UUID |
String (UTF-8 encoding) |
STRING |
String (UTF-8 encoding) |
NULL |
NilClass |
DATE |
Date |
TIMESTAMP |
Time |
INTERVAL |
Float (interval in seconds) |
STRUCT |
OpenStruct via the ostruct standard library |
MAP |
Hash |
UNION |
(not yet handled) |
BLOB |
String (ASCII_8BIT encoding) |
SERIAL |
Integer |
NODE |
Kuzu::Node |
REL |
Kuzu::Rel |
RECURSIVE_REL |
Kuzu::RecursiveRel |
LIST |
Array |
ARRAY |
Array |
Kuzu::Result.from_next_set( result ) → result2
Return a Kuzu::Result
for the next result set after the specified result
. Returns nil
if there is no next result set..
static VALUE
rkuzu_result_s_from_next_set( VALUE klass, VALUE result )
{
rkuzu_query_result *start_result = rkuzu_get_result( result );
rkuzu_query_result *next_result;
VALUE result_obj;
if ( RTEST(start_result->next_result) ) {
return start_result->next_result;
}
if ( !kuzu_query_result_has_next_query_result(&start_result->result) ) {
return Qnil;
}
next_result = rkuzu_result_alloc();
if ( kuzu_query_result_get_next_query_result(&start_result->result, &next_result->result) != KuzuSuccess ) {
char *err_detail = kuzu_query_result_get_error_message( &next_result->result );
char errmsg[ 4096 ] = "\0";
snprintf( errmsg, 4096, "Could not fetch next query result set: %s.", err_detail );
xfree( next_result );
next_result = NULL;
kuzu_destroy_string( err_detail );
rb_raise( rkuzu_eQueryError, "%s", errmsg );
}
DEBUG_GC( ">>> allocated result %p\n", next_result );
result_obj = rb_class_new_instance( 0, 0, klass );
RTYPEDDATA_DATA( result_obj ) = next_result;
next_result->connection = start_result->connection;
next_result->previous_result = result;
start_result->next_result = result_obj;
return result_obj;
}
from_prepared_statement( statement, &block )
Execute the given statement
and return the Kuzu::Result
. If a block is given, the result will instead be yielded to it, finished when it returns, and the return value of the block will be returned instead.
def self::from_prepared_statement( statement, &block )
return statement.execute( &block )
end
from_query( connection, query, &block )
Execute the given query
via the specified connection
and return the Kuzu::Result
. If a block is given, the result will instead be yielded to it, finished when it returns, and the return value of the block will be returned instead.
def self::from_query( connection, query, &block )
return connection.query( query, &block )
end
wrap_block_result( result, &block )
If the block
is provided, yield result
to it and then call finish
on it, returning the block
result. If block
is not given, just return result
.
def self::wrap_block_result( result, &block )
return result unless block
begin
rval = block.call( result )
ensure
result.finish
end
return rval
end
Index operator: fetch the tuple at index
of the current result set.
def []( index )
return self.tuples[ index ]
end
Fetch the names of the columns in the result as an Array of Strings.
def column_names
return @column_names ||= self.get_column_names
end
Iterate over each tuple of the result, yielding it to the block
. If no block
is given, return an Enumerator that will yield them instead.
def each( &block )
enum = self.tuple_enum
return enum.each( &block ) if block
return enum
end
Iterate over each result set in the results, yielding it to the block. If no block
is given, return an Enumerator tht will yield each set as its own Result
.
def each_set( &block )
enum = self.next_set_enum
return enum.each( &block ) if block
return enum
end
Discard a result and free up its memory. An exception is raised if the result is used after this call.
static VALUE
rkuzu_result_finish( VALUE self )
{
rkuzu_query_result *result = CHECK_RESULT( self );
kuzu_query_result *i_result = &result->result;
VALUE related_res;
if ( !result->finished ) {
DEBUG_GC( ">>> Finishing %p\n", result );
result->finished = true;
if ( i_result->_query_result != NULL ) {
kuzu_query_result_destroy( i_result );
}
if ( RTEST(result->previous_result) ) {
related_res = result->previous_result;
result->previous_result = Qnil;
rb_funcall( related_res, rb_intern("finish"), 0 );
}
if ( RTEST(result->next_result) ) {
related_res = result->next_result;
result->next_result = Qnil;
rb_funcall( related_res, rb_intern("finish"), 0 );
}
}
return Qtrue;
}
finished? → true or false
Returns true
if the receiver has been finished.
static VALUE
rkuzu_result_finished_p( VALUE self )
{
rkuzu_query_result *result = CHECK_RESULT( self );
if ( result->finished ) {
return Qtrue;
} else {
return Qfalse;
}
}
Returns the names of the columns of the results as an Array of Strings.
static VALUE
rkuzu_result_get_column_names( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
uint64_t col_count = kuzu_query_result_get_num_columns( &result->result );
char *name;
VALUE rval = rb_ary_new();
for ( uint64_t i = 0 ; i < col_count ; i++ ) {
if ( kuzu_query_result_get_column_name(&result->result, i, &name) != KuzuSuccess ) {
rb_raise( rkuzu_eError, "couldn't fetch name of column %lu", i );
}
rb_ary_push( rval, rb_str_new2(name) );
}
return rval;
}
Returns the next tuple of the query result values if there is one, otherwise returns nil
.
static VALUE
rkuzu_result_get_next_values( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
kuzu_flat_tuple tuple;
kuzu_logical_type column_type;
kuzu_value column_value;
uint64_t column_count = kuzu_query_result_get_num_columns( &result->result );
VALUE current_value = Qnil,
rval = rb_ary_new();
if ( !kuzu_query_result_has_next(&result->result) ) {
return Qnil;
}
if ( kuzu_query_result_get_next(&result->result, &tuple) != KuzuSuccess ) {
char *err_detail = kuzu_query_result_get_error_message( &result->result );
char errmsg[ 4096 ] = "\0";
snprintf( errmsg, 4096, "Could not fetch next tuple: %s.", err_detail );
kuzu_destroy_string( err_detail );
rb_raise( rkuzu_eQueryError, "%s", errmsg );
}
for ( uint64_t i = 0 ; i < column_count ; i++ ) {
kuzu_query_result_get_column_data_type( &result->result, i, &column_type );
kuzu_flat_tuple_get_value( &tuple, i, &column_value );
current_value = rkuzu_convert_logical_kuzu_value_to_ruby( &column_type, &column_value );
rb_ary_push( rval, current_value );
}
kuzu_flat_tuple_destroy( &tuple );
return rval;
}
has_next? → true or false
Returns true if we have not consumed all tuples in the query result, false otherwise.
static VALUE
rkuzu_result_has_next_p( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
if ( kuzu_query_result_has_next(&result->result) ) {
return Qtrue;
} else {
return Qfalse;
}
}
has_next_set? → true or false
Returns true if there was more than one result set in the results, and the current set is not the last one. You can call next_set
to move on to the next result set.
static VALUE
rkuzu_result_has_next_set_p( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
if ( kuzu_query_result_has_next_query_result(&result->result) ) {
return Qtrue;
} else {
return Qfalse;
}
}
Return a string representation of the receiver suitable for debugging.
def inspect
if self.finished?
details = " (finished)"
else
details = " success: %p (%d tuples of %d columns)" % [
self.success?,
self.num_tuples,
self.num_columns,
]
end
default = super
return default.sub( />/, details + '>' )
end
Get the next tuple of the result as a Hash.
def next
values = self.get_next_values or return nil
pairs = self.column_names.zip( values )
return Hash[ pairs ]
end
Return the next result set after this one as a Kuzu::Result
, or nil
if there is no next set.
def next_set
return nil unless self.has_next_set?
return self.class.from_next_set( self )
end
Returns the number of columns in the query result.
static VALUE
rkuzu_result_num_columns( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
const uint64_t count = kuzu_query_result_get_num_columns( &result->result );
return ULONG2NUM( count );
}
Returns the number of tuples in the query result.
static VALUE
rkuzu_result_num_tuples( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
const uint64_t count = kuzu_query_result_get_num_tuples( &result->result );
return ULONG2NUM( count );
}
Return a Kuzu::QuerySummary
for the query that generated the Result
.
def query_summary
return Kuzu::QuerySummary.from_result( self )
end
Resets the iterator of the query result to the beginning.
static VALUE
rkuzu_result_reset_iterator( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
kuzu_query_result_reset_iterator( &result->result );
return Qtrue;
}
Returns true if the query is executed successful, false otherwise.
static VALUE
rkuzu_result_success_p( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
if ( kuzu_query_result_is_success(&result->result) ) {
return Qtrue;
} else {
return Qfalse;
}
}
Returns the result as a String.
static VALUE
rkuzu_result_to_s( VALUE self )
{
rkuzu_query_result *result = rkuzu_get_result( self );
char *string = kuzu_query_result_to_string( &result->result );
VALUE rval = rb_str_new2( string );
kuzu_destroy_string( string );
return rval;
}
Return the tuples from the current result set. This method is memoized for efficiency.
def tuples
return @_tuples ||= self.to_a
end
Protected Instance Methods
Return an Enumerator that yields a Result
for each set.
def next_set_enum
self.log.debug "Fetching a result set Enumerator"
result = self
return Enumerator.new do |yielder|
while result
yielder.yield( result )
result = result.next_set
end
end
end
Return an Enumerator that yields result tuples as Hashes.
def tuple_enum
self.log.debug "Fetching a tuple Enumerator"
return Enumerator.new do |yielder|
self.reset_iterator
while self.has_next?
tuple = self.next
yielder.yield( tuple )
end
end
end