ruby-kuzu 0.0.1

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,24 @@
1
+ /*
2
+ * rel.c - Kuzu::Rel (relationship) class
3
+ *
4
+ */
5
+
6
+ #include "kuzu_ext.h"
7
+
8
+ VALUE rkuzu_cKuzuRel;
9
+
10
+
11
+ /*
12
+ * Document-class: Kuzu::Rel
13
+ */
14
+ void
15
+ rkuzu_init_rel( void )
16
+ {
17
+ #ifdef FOR_RDOC
18
+ rkuzu_mKuzu = rb_define_module( "Kuzu" );
19
+ #endif
20
+
21
+ rkuzu_cKuzuRel = rb_define_class_under( rkuzu_mKuzu, "Rel", rb_cObject );
22
+
23
+ rb_require( "kuzu/rel" );
24
+ }
@@ -0,0 +1,514 @@
1
+ /*
2
+ * result.c - Kuzu::Result class
3
+ */
4
+
5
+ #include "kuzu_ext.h"
6
+
7
+ #define CHECK_RESULT(self) ((rkuzu_query_result *)rb_check_typeddata((self), &rkuzu_result_type))
8
+ // #define DEBUG_GC(msg, ptr) fprintf( stderr, msg, ptr )
9
+ #define DEBUG_GC(msg, ptr)
10
+
11
+
12
+ VALUE rkuzu_cKuzuResult;
13
+
14
+
15
+ static void rkuzu_result_free( void * );
16
+ static void rkuzu_result_mark( void * );
17
+
18
+ static const rb_data_type_t rkuzu_result_type = {
19
+ .wrap_struct_name = "Kuzu::Result",
20
+ .function = {
21
+ .dfree = rkuzu_result_free,
22
+ .dmark = rkuzu_result_mark,
23
+ },
24
+ .data = NULL,
25
+ };
26
+
27
+
28
+ /*
29
+ * Fetch function
30
+ */
31
+ rkuzu_query_result *
32
+ rkuzu_get_result( VALUE result_obj )
33
+ {
34
+ rkuzu_query_result *res = CHECK_RESULT( result_obj );
35
+
36
+ if ( res->finished ) {
37
+ DEBUG_GC( "XXX Getting a FINISHED result %p\n", res );
38
+ rb_raise( rkuzu_eFinishedError, "result has been finished.\n" );
39
+ } else {
40
+ DEBUG_GC( ">>> Result %p is NOT finished.\n", res );
41
+ }
42
+
43
+ return res;
44
+ }
45
+
46
+
47
+ /*
48
+ * Allocation function
49
+ */
50
+ static rkuzu_query_result *
51
+ rkuzu_result_alloc( void )
52
+ {
53
+ rkuzu_query_result *ptr = ALLOC( rkuzu_query_result );
54
+
55
+ ptr->connection = Qnil;
56
+ ptr->query = Qnil;
57
+ ptr->statement = Qnil;
58
+ ptr->previous_result = Qnil;
59
+ ptr->next_result = Qnil;
60
+ ptr->finished = false;
61
+
62
+ return ptr;
63
+ }
64
+
65
+
66
+ /*
67
+ * dmark function
68
+ */
69
+ static void
70
+ rkuzu_result_mark( void *ptr )
71
+ {
72
+ rkuzu_query_result *result = (rkuzu_query_result *)ptr;
73
+
74
+ if ( ptr ) {
75
+ rb_gc_mark( result->connection );
76
+ rb_gc_mark( result->query );
77
+ rb_gc_mark( result->statement );
78
+ rb_gc_mark( result->previous_result );
79
+ rb_gc_mark( result->next_result );
80
+ }
81
+ }
82
+
83
+
84
+ /*
85
+ * dfree function
86
+ */
87
+ static void
88
+ rkuzu_result_free( void *ptr )
89
+ {
90
+ if ( ptr ) {
91
+ rkuzu_query_result *result = (rkuzu_query_result *)ptr;
92
+
93
+ // Can't kuzu_query_result_destroy here because the database or connection
94
+ // might already have been destroyed.
95
+
96
+ /*
97
+ kuzu_query_result *i_result = &result->result;
98
+
99
+ if ( i_result->_is_owned_by_cpp != NULL ) {
100
+ DEBUG_GC( ">>> destroying query_result %p\n", ptr );
101
+ kuzu_query_result_destroy( i_result );
102
+ }
103
+ */
104
+
105
+ if ( !result->finished ) {
106
+ DEBUG_GC( "*** Possibly leaking result %p\n", result );
107
+ }
108
+
109
+ DEBUG_GC( ">>> Freeing result %p\n", ptr );
110
+ xfree( ptr );
111
+ ptr = NULL;
112
+ }
113
+ }
114
+
115
+
116
+ /*
117
+ * ::allocate function
118
+ */
119
+ static VALUE
120
+ rkuzu_result_s_allocate( VALUE klass )
121
+ {
122
+ return TypedData_Wrap_Struct( klass, &rkuzu_result_type, NULL );
123
+ }
124
+
125
+
126
+ VALUE
127
+ rkuzu_result_from_query( VALUE klass, VALUE connection, VALUE query, kuzu_query_result result )
128
+ {
129
+ rkuzu_query_result *ptr = rkuzu_result_alloc();
130
+ DEBUG_GC( ">>> allocated result %p\n", ptr );
131
+
132
+ VALUE result_obj = rb_class_new_instance( 0, 0, klass );
133
+ RTYPEDDATA_DATA( result_obj ) = ptr;
134
+
135
+ ptr->connection = connection;
136
+ ptr->query = query;
137
+ ptr->result = result;
138
+
139
+ return result_obj;
140
+ }
141
+
142
+
143
+ VALUE
144
+ rkuzu_result_from_prepared_statement( VALUE klass, VALUE connection, VALUE statement, kuzu_query_result result )
145
+ {
146
+ rkuzu_query_result *ptr = rkuzu_result_alloc();
147
+ DEBUG_GC( ">>> allocated result %p\n", ptr );
148
+
149
+ VALUE result_obj = rb_class_new_instance( 0, 0, klass );
150
+ RTYPEDDATA_DATA( result_obj ) = ptr;
151
+
152
+ ptr->connection = connection;
153
+ ptr->statement = statement;
154
+ ptr->result = result;
155
+
156
+ return result_obj;
157
+ }
158
+
159
+
160
+
161
+ /*
162
+ * call-seq:
163
+ * Kuzu::Result.from_next_set( result ) -> result2
164
+ *
165
+ * Return a Kuzu::Result for the next result set after the specified +result+.
166
+ * Returns `nil` if there is no next result set..
167
+ *
168
+ */
169
+ static VALUE
170
+ rkuzu_result_s_from_next_set( VALUE klass, VALUE result )
171
+ {
172
+ rkuzu_query_result *start_result = rkuzu_get_result( result );
173
+ rkuzu_query_result *next_result;
174
+ VALUE result_obj;
175
+
176
+ if ( RTEST(start_result->next_result) ) {
177
+ return start_result->next_result;
178
+ }
179
+
180
+ if ( !kuzu_query_result_has_next_query_result(&start_result->result) ) {
181
+ return Qnil;
182
+ }
183
+
184
+ next_result = rkuzu_result_alloc();
185
+
186
+ if ( kuzu_query_result_get_next_query_result(&start_result->result, &next_result->result) != KuzuSuccess ) {
187
+ char *err_detail = kuzu_query_result_get_error_message( &next_result->result );
188
+ char errmsg[ 4096 ] = "\0";
189
+
190
+ snprintf( errmsg, 4096, "Could not fetch next query result set: %s.", err_detail );
191
+
192
+ xfree( next_result );
193
+ next_result = NULL;
194
+ kuzu_destroy_string( err_detail );
195
+
196
+ rb_raise( rkuzu_eQueryError, "%s", errmsg );
197
+ }
198
+
199
+ DEBUG_GC( ">>> allocated result %p\n", next_result );
200
+
201
+ result_obj = rb_class_new_instance( 0, 0, klass );
202
+ RTYPEDDATA_DATA( result_obj ) = next_result;
203
+
204
+ next_result->connection = start_result->connection;
205
+ next_result->previous_result = result;
206
+
207
+ start_result->next_result = result_obj;
208
+
209
+ return result_obj;
210
+ }
211
+
212
+
213
+ /*
214
+ * call-seq:
215
+ * result.success? -> true or false
216
+ *
217
+ * Returns true if the query is executed successful, false otherwise.
218
+ *
219
+ */
220
+ static VALUE
221
+ rkuzu_result_success_p( VALUE self )
222
+ {
223
+ rkuzu_query_result *result = rkuzu_get_result( self );
224
+
225
+ if ( kuzu_query_result_is_success(&result->result) ) {
226
+ return Qtrue;
227
+ } else {
228
+ return Qfalse;
229
+ }
230
+ }
231
+
232
+
233
+ /*
234
+ * call-seq:
235
+ * result.num_columns -> integer
236
+ *
237
+ * Returns the number of columns in the query result.
238
+ *
239
+ */
240
+ static VALUE
241
+ rkuzu_result_num_columns( VALUE self )
242
+ {
243
+ rkuzu_query_result *result = rkuzu_get_result( self );
244
+ const uint64_t count = kuzu_query_result_get_num_columns( &result->result );
245
+
246
+ return ULONG2NUM( count );
247
+ }
248
+
249
+
250
+ /*
251
+ * call-seq:
252
+ * result.num_tuples -> integer
253
+ *
254
+ * Returns the number of tuples in the query result.
255
+ *
256
+ */
257
+ static VALUE
258
+ rkuzu_result_num_tuples( VALUE self )
259
+ {
260
+ rkuzu_query_result *result = rkuzu_get_result( self );
261
+ const uint64_t count = kuzu_query_result_get_num_tuples( &result->result );
262
+
263
+ return ULONG2NUM( count );
264
+ }
265
+
266
+
267
+ /*
268
+ * call-seq:
269
+ * result.to_s -> string
270
+ *
271
+ * Returns the result as a String.
272
+ *
273
+ */
274
+ static VALUE
275
+ rkuzu_result_to_s( VALUE self )
276
+ {
277
+ rkuzu_query_result *result = rkuzu_get_result( self );
278
+ char *string = kuzu_query_result_to_string( &result->result );
279
+
280
+ VALUE rval = rb_str_new2( string );
281
+ kuzu_destroy_string( string );
282
+
283
+ return rval;
284
+ }
285
+
286
+
287
+ /*
288
+ * call-seq:
289
+ * result.has_next? -> true or false
290
+ *
291
+ * Returns true if we have not consumed all tuples in the query result, false
292
+ * otherwise.
293
+ *
294
+ */
295
+ static VALUE
296
+ rkuzu_result_has_next_p( VALUE self )
297
+ {
298
+ rkuzu_query_result *result = rkuzu_get_result( self );
299
+
300
+ if ( kuzu_query_result_has_next(&result->result) ) {
301
+ return Qtrue;
302
+ } else {
303
+ return Qfalse;
304
+ }
305
+ }
306
+
307
+
308
+ /*
309
+ * call-seq:
310
+ * result.has_next_set? -> true or false
311
+ *
312
+ * Returns true if there was more than one result set in the results, and
313
+ * the current set is not the last one. You can call #next_set to move on to
314
+ * the next result set.
315
+ *
316
+ */
317
+ static VALUE
318
+ rkuzu_result_has_next_set_p( VALUE self )
319
+ {
320
+ rkuzu_query_result *result = rkuzu_get_result( self );
321
+
322
+ if ( kuzu_query_result_has_next_query_result(&result->result) ) {
323
+ return Qtrue;
324
+ } else {
325
+ return Qfalse;
326
+ }
327
+ }
328
+
329
+
330
+ /*
331
+ * call-seq:
332
+ * result.reset_iterator
333
+ *
334
+ * Resets the iterator of the query result to the beginning.
335
+ *
336
+ */
337
+ static VALUE
338
+ rkuzu_result_reset_iterator( VALUE self )
339
+ {
340
+ rkuzu_query_result *result = rkuzu_get_result( self );
341
+ kuzu_query_result_reset_iterator( &result->result );
342
+ return Qtrue;
343
+ }
344
+
345
+
346
+ /*
347
+ * call-seq:
348
+ * result.get_next_values
349
+ *
350
+ * Returns the next tuple of the query result values if there is one, otherwise
351
+ * returns `nil`.
352
+ *
353
+ */
354
+ static VALUE
355
+ rkuzu_result_get_next_values( VALUE self )
356
+ {
357
+ rkuzu_query_result *result = rkuzu_get_result( self );
358
+ kuzu_flat_tuple tuple;
359
+ kuzu_logical_type column_type;
360
+ kuzu_value column_value;
361
+ uint64_t column_count = kuzu_query_result_get_num_columns( &result->result );
362
+ VALUE current_value = Qnil,
363
+ rval = rb_ary_new();
364
+
365
+ if ( !kuzu_query_result_has_next(&result->result) ) {
366
+ return Qnil;
367
+ }
368
+
369
+ if ( kuzu_query_result_get_next(&result->result, &tuple) != KuzuSuccess ) {
370
+ char *err_detail = kuzu_query_result_get_error_message( &result->result );
371
+ char errmsg[ 4096 ] = "\0";
372
+
373
+ snprintf( errmsg, 4096, "Could not fetch next tuple: %s.", err_detail );
374
+
375
+ kuzu_destroy_string( err_detail );
376
+
377
+ rb_raise( rkuzu_eQueryError, "%s", errmsg );
378
+ }
379
+
380
+ for ( uint64_t i = 0 ; i < column_count ; i++ ) {
381
+ kuzu_query_result_get_column_data_type( &result->result, i, &column_type );
382
+ kuzu_flat_tuple_get_value( &tuple, i, &column_value );
383
+
384
+ current_value = rkuzu_convert_logical_kuzu_value_to_ruby( &column_type, &column_value );
385
+ rb_ary_push( rval, current_value );
386
+ }
387
+
388
+ kuzu_flat_tuple_destroy( &tuple );
389
+
390
+ return rval;
391
+ }
392
+
393
+
394
+ /*
395
+ * call-seq:
396
+ * result.get_column_names
397
+ *
398
+ * Returns the names of the columns of the results as an Array of Strings.
399
+ *
400
+ */
401
+ static VALUE
402
+ rkuzu_result_get_column_names( VALUE self )
403
+ {
404
+ rkuzu_query_result *result = rkuzu_get_result( self );
405
+ uint64_t col_count = kuzu_query_result_get_num_columns( &result->result );
406
+ char *name;
407
+ VALUE rval = rb_ary_new();
408
+
409
+ for ( uint64_t i = 0 ; i < col_count ; i++ ) {
410
+ if ( kuzu_query_result_get_column_name(&result->result, i, &name) != KuzuSuccess ) {
411
+ rb_raise( rkuzu_eError, "couldn't fetch name of column %llu", i );
412
+ }
413
+ rb_ary_push( rval, rb_str_new2(name) );
414
+ }
415
+
416
+ return rval;
417
+ }
418
+
419
+
420
+ /*
421
+ * call-seq:
422
+ * result.finish
423
+ *
424
+ * Discard a result and free up its memory. An exception is raised if the result
425
+ * is used after this call.
426
+ *
427
+ */
428
+ static VALUE
429
+ rkuzu_result_finish( VALUE self )
430
+ {
431
+ rkuzu_query_result *result = CHECK_RESULT( self );
432
+ kuzu_query_result *i_result = &result->result;
433
+ VALUE related_res;
434
+
435
+ if ( !result->finished ) {
436
+ DEBUG_GC( ">>> Finishing %p\n", result );
437
+ result->finished = true;
438
+ if ( i_result->_query_result != NULL ) {
439
+ kuzu_query_result_destroy( i_result );
440
+ }
441
+
442
+ if ( RTEST(result->previous_result) ) {
443
+ related_res = result->previous_result;
444
+ result->previous_result = Qnil;
445
+ rb_funcall( related_res, rb_intern("finish"), 0 );
446
+ }
447
+ if ( RTEST(result->next_result) ) {
448
+ related_res = result->next_result;
449
+ result->next_result = Qnil;
450
+ rb_funcall( related_res, rb_intern("finish"), 0 );
451
+ }
452
+ }
453
+
454
+ return Qtrue;
455
+ }
456
+
457
+
458
+ /*
459
+ * call-seq:
460
+ * result.finished? -> true or false
461
+ *
462
+ * Returns +true+ if the receiver has been finished.
463
+ *
464
+ */
465
+ static VALUE
466
+ rkuzu_result_finished_p( VALUE self )
467
+ {
468
+ rkuzu_query_result *result = CHECK_RESULT( self );
469
+ if ( result->finished ) {
470
+ return Qtrue;
471
+ } else {
472
+ return Qfalse;
473
+ }
474
+ }
475
+
476
+
477
+ /*
478
+ * Document-class: Kuzu::Result
479
+ */
480
+ void
481
+ rkuzu_init_result( void )
482
+ {
483
+ #ifdef FOR_RDOC
484
+ rkuzu_mKuzu = rb_define_module( "Kuzu" );
485
+ #endif
486
+
487
+ rkuzu_cKuzuResult = rb_define_class_under( rkuzu_mKuzu, "Result", rb_cObject );
488
+
489
+ VALUE enumerable = rb_const_get( rb_cObject, rb_intern("Enumerable") );
490
+ rb_include_module( rkuzu_cKuzuResult, enumerable );
491
+
492
+ rb_define_alloc_func( rkuzu_cKuzuResult, rkuzu_result_s_allocate );
493
+ rb_undef_method( CLASS_OF(rkuzu_cKuzuResult), "new" );
494
+
495
+ rb_define_singleton_method( rkuzu_cKuzuResult, "from_next_set", rkuzu_result_s_from_next_set, 1 );
496
+
497
+ rb_define_method( rkuzu_cKuzuResult, "success?", rkuzu_result_success_p, 0 );
498
+
499
+ rb_define_method( rkuzu_cKuzuResult, "num_columns", rkuzu_result_num_columns, 0 );
500
+ rb_define_method( rkuzu_cKuzuResult, "num_tuples", rkuzu_result_num_tuples, 0 );
501
+ rb_define_method( rkuzu_cKuzuResult, "to_s", rkuzu_result_to_s, 0 );
502
+
503
+ rb_define_method( rkuzu_cKuzuResult, "has_next?", rkuzu_result_has_next_p, 0 );
504
+ rb_define_method( rkuzu_cKuzuResult, "has_next_set?", rkuzu_result_has_next_set_p, 0 );
505
+
506
+ rb_define_method( rkuzu_cKuzuResult, "reset_iterator", rkuzu_result_reset_iterator, 0 );
507
+ rb_define_method( rkuzu_cKuzuResult, "get_next_values", rkuzu_result_get_next_values, 0 );
508
+ rb_define_method( rkuzu_cKuzuResult, "get_column_names", rkuzu_result_get_column_names, 0 );
509
+
510
+ rb_define_method( rkuzu_cKuzuResult, "finish", rkuzu_result_finish, 0 );
511
+ rb_define_method( rkuzu_cKuzuResult, "finished?", rkuzu_result_finished_p, 0 );
512
+
513
+ rb_require( "kuzu/result" );
514
+ }