nanoarrow 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0668ff2aa2561742313b8be3995876831289201eef98b073cb0ee6c089098b41'
4
- data.tar.gz: 809ea605cd7c610f8db96d17c162a4d76ce8b68418af623bae58c563603cf96c
3
+ metadata.gz: a01c23d857a3993f98281df9c297cc68e27550cdd19eff8844dc088389e73375
4
+ data.tar.gz: 272666407eaab6685a2739e4e318a9f17df6f3284a2b5438cd5a6729d9ca6345
5
5
  SHA512:
6
- metadata.gz: d90231519749a6f5c45cb5355b6d31afcbb8682bf0e33d7230603b1afe9e0f7e3fb62c191cba5ebf2cbc5a1d5888725ec365e9d359e4945a9fce47f5fbd0e239
7
- data.tar.gz: c19adf7d83b663c0f1cb675f780729f26563a67d6e9ea24535a71e550e2f06860740becb3634f86707daae5cc38583a807332c59db640c5bf623463c948de8f1
6
+ metadata.gz: 86fcf358b4353c6b7047907a691c0742e3404c0030f7f486bd60295746c8ac6ede47630cbb4d88585166f1ac5e900ad9be688952613251efbeca26027746202c
7
+ data.tar.gz: cc2e9133a58184ec28159268840d5831eec8b2fd445986da2f36b2c7743ffa567e581979771f4294481ff9af82e2c504d6358d5856ef3cf0d679b3b103f61e29
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.1.1 (2026-07-21)
2
+
3
+ - Added support for more types
4
+
1
5
  ## 0.1.0 (2026-07-18)
2
6
 
3
7
  - First release
@@ -94,6 +94,7 @@ void Init_array(void)
94
94
  rb_define_alloc_func(cCArray, array_allocate);
95
95
  rb_define_method(cCArray, "schema", array_schema, 0);
96
96
  rb_define_method(cCArray, "valid?", array_is_valid, 0);
97
+ rb_define_method(cCArray, "assert_valid", array_assert_valid, 0);
97
98
  rb_define_method(cCArray, "length", array_length, 0);
98
99
  rb_define_method(cCArray, "child", array_child, 1);
99
100
  }
@@ -231,6 +231,164 @@ static VALUE array_builder_append_bytes(VALUE self, VALUE obj)
231
231
  return self;
232
232
  }
233
233
 
234
+ static VALUE array_builder_append_decimals(VALUE self, VALUE obj, VALUE bitwidth, VALUE precision, VALUE scale)
235
+ {
236
+ array_builder_t* builder;
237
+ GetArrayBuilder(self, builder);
238
+
239
+ int pi = NUM2INT(precision);
240
+ int si = NUM2INT(scale);
241
+ VALUE pad = rb_str_new_cstr("0");
242
+
243
+ struct ArrowDecimal decimal;
244
+ ArrowDecimalInit(&decimal, NUM2INT(bitwidth), pi, si);
245
+
246
+ Check_Type(obj, T_ARRAY);
247
+
248
+ for (long i = 0; i < RARRAY_LEN(obj); i++)
249
+ {
250
+ VALUE v = rb_ary_entry(obj, i);
251
+ int code;
252
+
253
+ if (NIL_P(v))
254
+ code = ArrowArrayAppendNull(builder->ptr, 1);
255
+ else
256
+ {
257
+ VALUE split = rb_funcall(v, rb_intern("split"), 0);
258
+ VALUE sign = rb_ary_entry(split, 0);
259
+ VALUE digits = rb_ary_entry(split, 1);
260
+ VALUE base = rb_ary_entry(split, 2);
261
+ VALUE exponent = rb_ary_entry(split, 3);
262
+
263
+ if (NUM2INT(base) != 10)
264
+ raise_todo();
265
+
266
+ Check_Type(digits, T_STRING);
267
+
268
+ // exceeds precision
269
+ // TODO better error
270
+ if (RSTRING_LEN(digits) > pi)
271
+ raise_todo();
272
+
273
+ int target = si + NUM2INT(exponent);
274
+
275
+ // exceeds scale
276
+ // TODO either round in Ruby or better error
277
+ if (RSTRING_LEN(digits) > target)
278
+ raise_todo();
279
+
280
+ digits = rb_funcall(digits, rb_intern("ljust"), 2, INT2NUM(target), pad);
281
+
282
+ struct ArrowStringView sv;
283
+ sv.data = StringValuePtr(digits);
284
+ sv.size_bytes = RSTRING_LEN(digits);
285
+ code = ArrowDecimalSetDigits(&decimal, sv);
286
+ raise_error_not_ok("ArrowDecimalSetDigits()", code);
287
+
288
+ if (NUM2INT(sign) == -1)
289
+ ArrowDecimalNegate(&decimal);
290
+
291
+ code = ArrowArrayAppendDecimal(builder->ptr, &decimal);
292
+ }
293
+
294
+ raise_error_not_ok("ArrowArrayAppendDecimal()", code);
295
+ }
296
+
297
+ return self;
298
+ }
299
+
300
+ static VALUE array_builder_set_offset(VALUE self, VALUE offset)
301
+ {
302
+ array_builder_t* builder;
303
+ GetArrayBuilder(self, builder);
304
+
305
+ rb_funcall(builder->c_array, rb_intern("assert_valid"), 0);
306
+ builder->ptr->offset = NUM2LL(offset);
307
+ return self;
308
+ }
309
+
310
+ static VALUE array_builder_set_length(VALUE self, VALUE length)
311
+ {
312
+ array_builder_t* builder;
313
+ GetArrayBuilder(self, builder);
314
+
315
+ rb_funcall(builder->c_array, rb_intern("assert_valid"), 0);
316
+ builder->ptr->length = NUM2LL(length);
317
+ return self;
318
+ }
319
+
320
+ static VALUE array_builder_set_null_count(VALUE self, VALUE null_count)
321
+ {
322
+ array_builder_t* builder;
323
+ GetArrayBuilder(self, builder);
324
+
325
+ rb_funcall(builder->c_array, rb_intern("assert_valid"), 0);
326
+ builder->ptr->null_count = NUM2LL(null_count);
327
+ return self;
328
+ }
329
+
330
+ static VALUE array_builder_resolve_null_count(VALUE self)
331
+ {
332
+ array_builder_t* builder;
333
+ GetArrayBuilder(self, builder);
334
+
335
+ rb_funcall(builder->c_array, rb_intern("assert_valid"), 0);
336
+
337
+ VALUE format = rb_funcall(rb_funcall(builder->c_array, rb_intern("schema"), 0), rb_intern("format"), 0);
338
+ if (RTEST(rb_funcall(format, rb_intern("start_with?"), 1, rb_str_new_cstr("+us:"))) || RTEST(rb_funcall(format, rb_intern("start_with?"), 1, rb_str_new_cstr("+ud:"))))
339
+ return self;
340
+
341
+ if (builder->ptr->null_count != -1)
342
+ return self;
343
+
344
+ struct ArrowBuffer* validity_buffer = ArrowArrayBuffer(builder->ptr, 0);
345
+ if (validity_buffer->size_bytes == 0)
346
+ {
347
+ builder->ptr->null_count = 0;
348
+ return self;
349
+ }
350
+
351
+ int64_t bits = builder->ptr->offset + builder->ptr->length;
352
+ int64_t bytes_required = (bits >> 3) + ((bits & 7) != 0);
353
+
354
+ if (validity_buffer->size_bytes < bytes_required)
355
+ rb_raise(rb_eArgError, "validity bitmap mismatch");
356
+
357
+ int64_t count = ArrowBitCountSet(
358
+ validity_buffer->data,
359
+ builder->ptr->offset,
360
+ builder->ptr->length
361
+ );
362
+ builder->ptr->null_count = builder->ptr->length - count;
363
+
364
+ return self;
365
+ }
366
+
367
+ static VALUE array_builder_set_child(VALUE self, VALUE idx, VALUE c_array)
368
+ {
369
+ array_builder_t* builder;
370
+ GetArrayBuilder(self, builder);
371
+
372
+ array_t* c_array_ptr;
373
+ GetArray(c_array, c_array_ptr);
374
+
375
+ VALUE child = rb_funcall(builder->c_array, rb_intern("child"), 1, idx);
376
+ array_t* child_ptr;
377
+ GetArray(child, child_ptr);
378
+ if (child_ptr->ptr->release != NULL)
379
+ ArrowArrayRelease(child_ptr->ptr);
380
+
381
+ // TODO move to parameter
382
+ VALUE move = Qfalse;
383
+
384
+ if (!RTEST(move))
385
+ c_array_shallow_copy(c_array_ptr->base, c_array_ptr->ptr, child_ptr->ptr);
386
+ else
387
+ ArrowArrayMove(c_array_ptr->ptr, child_ptr->ptr);
388
+
389
+ return self;
390
+ }
391
+
234
392
  static VALUE array_builder_finish(VALUE self)
235
393
  {
236
394
  array_builder_t* builder;
@@ -264,5 +422,11 @@ void Init_array_builder(void)
264
422
  rb_define_method(cCArrayBuilder, "append_doubles", array_builder_append_doubles, 1);
265
423
  rb_define_method(cCArrayBuilder, "append_strings", array_builder_append_strings, 1);
266
424
  rb_define_method(cCArrayBuilder, "append_bytes", array_builder_append_bytes, 1);
425
+ rb_define_method(cCArrayBuilder, "append_decimals", array_builder_append_decimals, 4);
426
+ rb_define_method(cCArrayBuilder, "set_offset", array_builder_set_offset, 1);
427
+ rb_define_method(cCArrayBuilder, "set_length", array_builder_set_length, 1);
428
+ rb_define_method(cCArrayBuilder, "set_null_count", array_builder_set_null_count, 1);
429
+ rb_define_method(cCArrayBuilder, "resolve_null_count", array_builder_resolve_null_count, 0);
430
+ rb_define_method(cCArrayBuilder, "set_child", array_builder_set_child, 2);
267
431
  rb_define_method(cCArrayBuilder, "finish", array_builder_finish, 0);
268
432
  }
@@ -76,6 +76,41 @@ static VALUE array_view_set_array(VALUE self, VALUE array)
76
76
  return self;
77
77
  }
78
78
 
79
+ static VALUE array_view_n_children(VALUE self)
80
+ {
81
+ array_view_t* view;
82
+ GetArrayView(self, view);
83
+
84
+ return LL2NUM(view->ptr->n_children);
85
+ }
86
+
87
+ static VALUE array_view_child(VALUE self, VALUE idx)
88
+ {
89
+ array_view_t* view;
90
+ GetArrayView(self, view);
91
+
92
+ int64_t i = NUM2LL(idx);
93
+ if (i < 0 || i >= view->ptr->n_children)
94
+ rb_raise(rb_eIndexError, "out of range");
95
+
96
+ VALUE child = array_view_allocate(cCArrayView);
97
+ array_view_t* child_ptr;
98
+ GetArrayView(child, child_ptr);
99
+ child_ptr->base = view->base;
100
+ child_ptr->ptr = view->ptr->children[i];
101
+
102
+ return child;
103
+ }
104
+
105
+ static VALUE array_view_children(VALUE self)
106
+ {
107
+ int64_t n_children = NUM2LL(array_view_n_children(self));
108
+ VALUE children = rb_ary_new();
109
+ for (int64_t i = 0; i < n_children; i++)
110
+ rb_ary_push(children, array_view_child(self, LL2NUM(i)));
111
+ return children;
112
+ }
113
+
79
114
  static VALUE array_view_each_bool(VALUE self)
80
115
  {
81
116
  array_view_t* view;
@@ -162,16 +197,50 @@ static VALUE array_view_each_binary(VALUE self)
162
197
  return self;
163
198
  }
164
199
 
200
+ static VALUE array_view_each_decimal(VALUE self, VALUE bitwidth, VALUE precision, VALUE scale)
201
+ {
202
+ array_view_t* view;
203
+ GetArrayView(self, view);
204
+
205
+ struct ArrowDecimal decimal;
206
+ ArrowDecimalInit(&decimal, NUM2INT(bitwidth), NUM2INT(precision), NUM2INT(scale));
207
+
208
+ struct ArrowBuffer buffer;
209
+ ArrowBufferInit(&buffer);
210
+
211
+ for (int64_t i = 0; i < view->ptr->length; i++)
212
+ {
213
+ VALUE v;
214
+ if (ArrowArrayViewIsNull(view->ptr, i))
215
+ v = Qnil;
216
+ else
217
+ {
218
+ ArrowArrayViewGetDecimalUnsafe(view->ptr, i, &decimal);
219
+ int code = ArrowDecimalAppendStringToBuffer(&decimal, &buffer);
220
+ raise_error_not_ok("ArrowDecimalAppendStringToBuffer()", code);
221
+ v = rb_str_new((char*) buffer.data, buffer.size_bytes);
222
+ ArrowBufferReset(&buffer);
223
+ }
224
+ rb_yield(v);
225
+ }
226
+
227
+ return self;
228
+ }
229
+
165
230
  void Init_array_view(void)
166
231
  {
167
232
  cCArrayView = rb_define_class_under(mNanoarrow, "CArrayView", rb_cObject);
168
233
  rb_define_alloc_func(cCArrayView, array_view_allocate);
169
234
  rb_define_singleton_method(cCArrayView, "from_schema", array_view_from_schema, 1);
170
235
  rb_define_method(cCArrayView, "set_array", array_view_set_array, 1);
236
+ rb_define_method(cCArrayView, "n_children", array_view_n_children, 0);
237
+ rb_define_method(cCArrayView, "child", array_view_child, 1);
238
+ rb_define_method(cCArrayView, "children", array_view_children, 0);
171
239
  rb_define_method(cCArrayView, "each_bool", array_view_each_bool, 0);
172
240
  rb_define_method(cCArrayView, "each_int", array_view_each_int, 0);
173
241
  rb_define_method(cCArrayView, "each_uint", array_view_each_uint, 0);
174
242
  rb_define_method(cCArrayView, "each_double", array_view_each_double, 0);
175
243
  rb_define_method(cCArrayView, "each_string", array_view_each_string, 0);
176
244
  rb_define_method(cCArrayView, "each_binary", array_view_each_binary, 0);
245
+ rb_define_method(cCArrayView, "each_decimal", array_view_each_decimal, 3);
177
246
  }
@@ -77,7 +77,10 @@ static VALUE capsule_name(VALUE self)
77
77
  capsule_t* capsule;
78
78
  GetCapsule(self, capsule);
79
79
 
80
- return rb_utf8_str_new_cstr(capsule->name);
80
+ if (capsule->name != NULL)
81
+ return rb_utf8_str_new_cstr(capsule->name);
82
+ else
83
+ return Qnil;
81
84
  }
82
85
 
83
86
  void Init_capsule(void)
@@ -227,6 +227,15 @@ static VALUE schema_child(VALUE self, VALUE rb_i)
227
227
  return obj;
228
228
  }
229
229
 
230
+ static VALUE schema_children(VALUE self)
231
+ {
232
+ int64_t n_children = NUM2LL(schema_n_children(self));
233
+ VALUE children = rb_ary_new();
234
+ for (int64_t i = 0; i < n_children; i++)
235
+ rb_ary_push(children, schema_child(self, LL2NUM(i)));
236
+ return children;
237
+ }
238
+
230
239
  static VALUE schema_dictionary(VALUE self)
231
240
  {
232
241
  schema_t* schema;
@@ -273,8 +282,41 @@ static VALUE schema_arrow_c_schema(VALUE self)
273
282
  return schema_capsule;
274
283
  }
275
284
 
276
- static VALUE schema_modify(VALUE self, VALUE format, VALUE name, VALUE flags, VALUE nullable, VALUE metadata, VALUE children, VALUE dictionary, VALUE validate)
285
+ static VALUE schema_modify(int argc, VALUE* argv, VALUE self)
277
286
  {
287
+ VALUE kwargs;
288
+ rb_scan_args(argc, argv, "0:", &kwargs);
289
+
290
+ ID keywords[8];
291
+ VALUE values[8];
292
+ keywords[0] = rb_intern("format");
293
+ keywords[1] = rb_intern("name");
294
+ keywords[2] = rb_intern("flags");
295
+ keywords[3] = rb_intern("nullable");
296
+ keywords[4] = rb_intern("metadata");
297
+ keywords[5] = rb_intern("children");
298
+ keywords[6] = rb_intern("dictionary");
299
+ keywords[7] = rb_intern("validate");
300
+ rb_get_kwargs(kwargs, keywords, 0, 8, values);
301
+
302
+ for (int i = 0; i < 8; i++)
303
+ {
304
+ if (values[i] == Qundef)
305
+ values[i] = Qnil;
306
+ }
307
+
308
+ VALUE format = values[0];
309
+ VALUE name = values[1];
310
+ VALUE flags = values[2];
311
+ VALUE nullable = values[3];
312
+ VALUE metadata = values[4];
313
+ VALUE children = values[5];
314
+ VALUE dictionary = values[6];
315
+ VALUE validate = values[7];
316
+
317
+ if (NIL_P(validate))
318
+ validate = Qtrue;
319
+
278
320
  VALUE builder = rb_funcall(cCSchemaBuilder, rb_intern("allocate"), 0);
279
321
 
280
322
  if (NIL_P(format))
@@ -306,11 +348,34 @@ static VALUE schema_modify(VALUE self, VALUE format, VALUE name, VALUE flags, VA
306
348
 
307
349
  if (NIL_P(children))
308
350
  {
309
- if (NUM2LL(rb_funcall(self, rb_intern("n_children"), 0)) > 0)
310
- raise_todo();
351
+ int64_t n_children = NUM2LL(rb_funcall(self, rb_intern("n_children"), 0));
352
+ if (n_children > 0)
353
+ {
354
+ rb_funcall(builder, rb_intern("allocate_children"), 1, LL2NUM(n_children));
355
+ VALUE self_children = rb_funcall(self, rb_intern("children"), 0);
356
+ for (long i = 0; i < RARRAY_LEN(self_children); i++)
357
+ rb_funcall(builder, rb_intern("set_child"), 3, LONG2NUM(i), Qnil, rb_ary_entry(self_children, i));
358
+ }
359
+ }
360
+ else if (RB_TYPE_P(children, T_HASH))
361
+ {
362
+ // not as efficient as rb_hash_foreach, but simpler
363
+ VALUE keys = rb_funcall(children, rb_intern("keys"), 0);
364
+ Check_Type(keys, T_ARRAY);
365
+ rb_funcall(builder, rb_intern("allocate_children"), 1, LONG2NUM(RARRAY_LEN(keys)));
366
+ for (long i = 0; i < RARRAY_LEN(keys); i++)
367
+ {
368
+ VALUE key = rb_ary_entry(keys, i);
369
+ rb_funcall(builder, rb_intern("set_child"), 3, LONG2NUM(i), key, rb_hash_lookup(children, key));
370
+ }
311
371
  }
312
372
  else
313
- raise_todo();
373
+ {
374
+ Check_Type(children, T_ARRAY);
375
+ rb_funcall(builder, rb_intern("allocate_children"), 1, LONG2NUM(RARRAY_LEN(children)));
376
+ for (long i = 0; i < RARRAY_LEN(children); i++)
377
+ rb_funcall(builder, rb_intern("set_child"), 3, LONG2NUM(i), Qnil, rb_ary_entry(children, i));
378
+ }
314
379
 
315
380
  if (NIL_P(dictionary))
316
381
  {
@@ -338,9 +403,10 @@ void Init_schema(void)
338
403
  rb_define_method(cCSchema, "metadata", schema_metadata, 0);
339
404
  rb_define_method(cCSchema, "n_children", schema_n_children, 0);
340
405
  rb_define_method(cCSchema, "child", schema_child, 1);
406
+ rb_define_method(cCSchema, "children", schema_children, 0);
341
407
  rb_define_method(cCSchema, "dictionary", schema_dictionary, 0);
342
408
  rb_define_method(cCSchema, "to_s", schema_to_s, 0);
343
409
  rb_define_method(cCSchema, "arrow_c_schema", schema_arrow_c_schema, 0);
344
- rb_define_method(cCSchema, "modify", schema_modify, 8);
410
+ rb_define_method(cCSchema, "modify", schema_modify, -1);
345
411
  rb_define_method(cCSchema, "assert_valid", schema_assert_valid, 0);
346
412
  }
@@ -183,6 +183,75 @@ static VALUE schema_builder_set_name(VALUE self, VALUE name)
183
183
  return self;
184
184
  }
185
185
 
186
+ static VALUE schema_builder_allocate_children(VALUE self, VALUE n)
187
+ {
188
+ schema_builder_t* builder;
189
+ GetSchemaBuilder(self, builder);
190
+
191
+ schema_assert_valid(builder->c_schema);
192
+
193
+ int code = ArrowSchemaAllocateChildren(builder->ptr, NUM2LL(n));
194
+ raise_error_not_ok("ArrowSchemaAllocateChildren()", code);
195
+
196
+ return self;
197
+ }
198
+
199
+ static VALUE schema_builder_set_child(VALUE self, VALUE idx, VALUE name, VALUE child_src)
200
+ {
201
+ schema_builder_t* builder;
202
+ GetSchemaBuilder(self, builder);
203
+
204
+ schema_assert_valid(builder->c_schema);
205
+
206
+ int64_t i = NUM2LL(idx);
207
+ if (i < 0 || i >= builder->ptr->n_children)
208
+ rb_raise(rb_eIndexError, "Index out of range");
209
+
210
+ if (builder->ptr->children[i]->release != NULL)
211
+ ArrowSchemaRelease(builder->ptr->children[i]);
212
+
213
+ schema_t* child_src_ptr;
214
+ GetSchema(child_src, child_src_ptr);
215
+
216
+ int code = ArrowSchemaDeepCopy(child_src_ptr->ptr, builder->ptr->children[i]);
217
+ raise_error_not_ok("ArrowSchemaDeepCopy()", code);
218
+
219
+ if (!NIL_P(name))
220
+ {
221
+ Check_Type(name, T_STRING);
222
+ code = ArrowSchemaSetName(builder->ptr->children[i], StringValueCStr(name));
223
+ raise_error_not_ok("ArrowSchemaSetName()", code);
224
+ }
225
+
226
+ return self;
227
+ }
228
+
229
+ static VALUE schema_builder_set_dictionary(VALUE self, VALUE dictionary)
230
+ {
231
+ schema_builder_t* builder;
232
+ GetSchemaBuilder(self, builder);
233
+
234
+ schema_assert_valid(builder->c_schema);
235
+
236
+ int code;
237
+ if (builder->ptr->dictionary == NULL)
238
+ {
239
+ code = ArrowSchemaAllocateDictionary(builder->ptr);
240
+ raise_error_not_ok("ArrowSchemaAllocateDictionary()", code);
241
+ }
242
+
243
+ if (builder->ptr->dictionary->release != NULL)
244
+ ArrowSchemaRelease(builder->ptr->dictionary);
245
+
246
+ schema_t* dictionary_ptr;
247
+ GetSchema(dictionary, dictionary_ptr);
248
+
249
+ code = ArrowSchemaDeepCopy(dictionary_ptr->ptr, builder->ptr->dictionary);
250
+ raise_error_not_ok("ArrowSchemaDeepCopy()", code);
251
+
252
+ return self;
253
+ }
254
+
186
255
  static VALUE schema_builder_set_flags(VALUE self, VALUE flags)
187
256
  {
188
257
  schema_builder_t* builder;
@@ -205,6 +274,32 @@ static VALUE schema_builder_set_nullable(VALUE self, VALUE nullable)
205
274
  return self;
206
275
  }
207
276
 
277
+ static VALUE schema_builder_set_dictionary_ordered(VALUE self, VALUE dictionary_ordered)
278
+ {
279
+ schema_builder_t* builder;
280
+ GetSchemaBuilder(self, builder);
281
+
282
+ if (RTEST(dictionary_ordered))
283
+ builder->ptr->flags |= ARROW_FLAG_DICTIONARY_ORDERED;
284
+ else
285
+ builder->ptr->flags &= ~ARROW_FLAG_DICTIONARY_ORDERED;
286
+
287
+ return self;
288
+ }
289
+
290
+ static VALUE schema_builder_set_map_keys_sorted(VALUE self, VALUE map_keys_sorted)
291
+ {
292
+ schema_builder_t* builder;
293
+ GetSchemaBuilder(self, builder);
294
+
295
+ if (RTEST(map_keys_sorted))
296
+ builder->ptr->flags |= ARROW_FLAG_MAP_KEYS_SORTED;
297
+ else
298
+ builder->ptr->flags &= ~ARROW_FLAG_MAP_KEYS_SORTED;
299
+
300
+ return self;
301
+ }
302
+
208
303
  static VALUE schema_builder_validate(VALUE self)
209
304
  {
210
305
  schema_builder_t* builder;
@@ -244,8 +339,13 @@ void Init_schema_builder(void)
244
339
  rb_define_method(cCSchemaBuilder, "set_type_date_time", schema_builder_set_type_date_time, 3);
245
340
  rb_define_method(cCSchemaBuilder, "set_format", schema_builder_set_format, 1);
246
341
  rb_define_method(cCSchemaBuilder, "set_name", schema_builder_set_name, 1);
342
+ rb_define_method(cCSchemaBuilder, "allocate_children", schema_builder_allocate_children, 1);
343
+ rb_define_method(cCSchemaBuilder, "set_child", schema_builder_set_child, 3);
344
+ rb_define_method(cCSchemaBuilder, "set_dictionary", schema_builder_set_dictionary, 1);
247
345
  rb_define_method(cCSchemaBuilder, "set_flags", schema_builder_set_flags, 1);
248
346
  rb_define_method(cCSchemaBuilder, "set_nullable", schema_builder_set_nullable, 1);
347
+ rb_define_method(cCSchemaBuilder, "set_dictionary_ordered", schema_builder_set_dictionary_ordered, 1);
348
+ rb_define_method(cCSchemaBuilder, "set_map_keys_sorted", schema_builder_set_map_keys_sorted, 1);
249
349
  rb_define_method(cCSchemaBuilder, "validate", schema_builder_validate, 0);
250
350
  rb_define_method(cCSchemaBuilder, "finish", schema_builder_finish, 0);
251
351
  }
@@ -87,6 +87,30 @@ module Nanoarrow
87
87
  @c_builder.append_ints(obj)
88
88
  end
89
89
 
90
+ def append_decimals(obj)
91
+ obj = obj.map { |v| (v.nil? || v.is_a?(BigDecimal)) ? v : BigDecimal(v.to_s) }
92
+ bitwidth = @schema_view.type_id == Type::DECIMAL128 ? 128 : 256
93
+ @c_builder.append_decimals(obj, bitwidth, @schema_view.decimal_precision, @schema_view.decimal_scale)
94
+ end
95
+
96
+ def append_struct(obj)
97
+ keys = @schema.children.map(&:name)
98
+ objs = keys.map { |k| obj.map { |v| v.nil? ? v : v.fetch(k) } }
99
+
100
+ # check for extra keys
101
+ obj.each do |v|
102
+ if !v.nil? && v.except(*keys).any?
103
+ raise ArgumentError, "extra keys"
104
+ end
105
+ end
106
+
107
+ arrays = @schema.children.zip(objs).map { |s, v| Utils.c_array(v, s) }
108
+ arrays.each_with_index do |a, i|
109
+ @c_builder.set_child(i, a)
110
+ end
111
+ @c_builder.set_length(objs[0].length)
112
+ end
113
+
90
114
  ARRAY_BUILDER_FROM_ITERABLE_METHOD = {
91
115
  Type::BOOL => :append_bools,
92
116
  Type::INT8 => :append_ints,
@@ -109,7 +133,10 @@ module Nanoarrow
109
133
  Type::FIXED_SIZE_BINARY => :append_bytes,
110
134
  Type::DATE32 => :append_dates,
111
135
  Type::DATE64 => :append_dates,
112
- Type::TIMESTAMP => :append_timestamps
136
+ Type::TIMESTAMP => :append_timestamps,
137
+ Type::DECIMAL128 => :append_decimals,
138
+ Type::DECIMAL256 => :append_decimals,
139
+ Type::STRUCT => :append_struct
113
140
  }
114
141
  end
115
142
  end
@@ -1,9 +1,14 @@
1
1
  module Nanoarrow
2
2
  class ArrayViewBaseIterator
3
- def initialize(schema)
3
+ def initialize(schema, array_view: nil)
4
4
  @schema = Utils.c_schema(schema)
5
5
  @schema_view = Utils.c_schema_view(schema)
6
- @array_view = CArrayView.from_schema(@schema)
6
+
7
+ if array_view.nil?
8
+ @array_view = CArrayView.from_schema(@schema)
9
+ else
10
+ @array_view = array_view
11
+ end
7
12
  end
8
13
 
9
14
  def set_array(array)
@@ -23,11 +28,15 @@ module Nanoarrow
23
28
  end
24
29
  end
25
30
 
26
- def initialize(schema)
27
- super(schema)
31
+ def initialize(schema, array_view: nil)
32
+ super(schema, array_view: array_view)
33
+
34
+ @children = @schema.children.zip(@array_view.children).map { |s, v| make_child(s, v) }
28
35
  end
29
36
 
30
37
  def each(&block)
38
+ return to_enum(:each) unless block_given?
39
+
31
40
  type_id = @schema_view.type_id
32
41
  if !ITEMS_ITER_LOOKUP.include?(type_id)
33
42
  raise KeyError, "Can't resolve iterator for type #{@schema_view.type.inspect}"
@@ -39,6 +48,10 @@ module Nanoarrow
39
48
 
40
49
  private
41
50
 
51
+ def make_child(schema, array_view)
52
+ self.class.new(schema, array_view: array_view)
53
+ end
54
+
42
55
  def each_bool(&block)
43
56
  @array_view.each_bool(&block)
44
57
  end
@@ -85,6 +98,21 @@ module Nanoarrow
85
98
  @array_view.each_int(&wrap)
86
99
  end
87
100
 
101
+ def each_decimal(&block)
102
+ bitwidth = @schema_view.type_id == Type::DECIMAL128 ? 128 : 256
103
+ wrap = ->(v) { block.call(v.nil? ? v : BigDecimal(v)) }
104
+ @array_view.each_decimal(bitwidth, @schema_view.decimal_precision, @schema_view.decimal_scale, &wrap)
105
+ end
106
+
107
+ def each_struct(&block)
108
+ if @children.any?
109
+ keys = @schema.children.map(&:name)
110
+ @children[0].each.zip(*@children[1..]) do |v|
111
+ block.call(v[0].nil? ? nil : keys.zip(v).to_h)
112
+ end
113
+ end
114
+ end
115
+
88
116
  ITEMS_ITER_LOOKUP = {
89
117
  Type::BOOL => :each_bool,
90
118
  Type::INT8 => :each_int,
@@ -108,6 +136,9 @@ module Nanoarrow
108
136
  Type::DATE32 => :each_date,
109
137
  Type::DATE64 => :each_date,
110
138
  Type::TIMESTAMP => :each_timestamp,
139
+ Type::DECIMAL128 => :each_decimal,
140
+ Type::DECIMAL256 => :each_decimal,
141
+ Type::STRUCT => :each_struct
111
142
  }
112
143
  end
113
144
  end
@@ -18,7 +18,7 @@ module Nanoarrow
18
18
  end
19
19
 
20
20
  if !name.nil? || !nullable.nil? || !metadata.nil? || !fields.nil?
21
- @c_schema = @c_schema.modify(nil, name, nil, nullable, metadata, fields, nil, true)
21
+ @c_schema = @c_schema.modify(name:, nullable:, metadata:, children: clean_fields(fields))
22
22
  end
23
23
 
24
24
  @c_schema_view = CSchemaView.new(@c_schema)
@@ -81,5 +81,17 @@ module Nanoarrow
81
81
  def arrow_c_schema
82
82
  @c_schema.arrow_c_schema
83
83
  end
84
+
85
+ private
86
+
87
+ def clean_fields(fields)
88
+ if fields.nil?
89
+ fields
90
+ elsif fields.is_a?(Hash)
91
+ fields.transform_values { |v| Utils.c_schema(v) }
92
+ else
93
+ fields.map { |v| Utils.c_schema(v) }
94
+ end
95
+ end
84
96
  end
85
97
  end
@@ -147,11 +147,17 @@ module Nanoarrow
147
147
  Schema.new(Type::DICTIONARY, index_type:, value_type:, dictionary_ordered:)
148
148
  end
149
149
 
150
- def self.sparse_union(fields, nullable: true)
151
- Schema.new(Type::SPARSE_UNION, fields:, nullable:)
152
- end
153
-
154
- def self.dense_union(fields, nullable: true)
155
- Schema.new(Type::DENSE_UNION, fields:, nullable:)
150
+ def self.sparse_union(fields, type_codes: nil, nullable: true)
151
+ if type_codes.nil?
152
+ type_codes = fields.size.times.to_a
153
+ end
154
+ Schema.new(Type::SPARSE_UNION, fields:, type_codes:, nullable:)
155
+ end
156
+
157
+ def self.dense_union(fields, type_codes: nil, nullable: true)
158
+ if type_codes.nil?
159
+ type_codes = fields.size.times.to_a
160
+ end
161
+ Schema.new(Type::DENSE_UNION, fields:, type_codes:, nullable:)
156
162
  end
157
163
  end
@@ -90,25 +90,61 @@ module Nanoarrow
90
90
  factory.set_type_fixed_size(type, Integer(params.delete(:byte_width)))
91
91
 
92
92
  elsif type == Type::LIST
93
- raise Todo
93
+ factory.set_format("+l")
94
+ factory.allocate_children(1)
95
+ factory.set_child(0, "item", c_schema(params.delete(:value_type)))
94
96
 
95
97
  elsif type == Type::LARGE_LIST
96
- raise Todo
98
+ factory.set_format("+L")
99
+ factory.allocate_children(1)
100
+ factory.set_child(0, "item", c_schema(params.delete(:value_type)))
97
101
 
98
102
  elsif type == Type::FIXED_SIZE_LIST
99
- raise Todo
103
+ fixed_size = Integer(params.delete(:list_size))
104
+ factory.set_format("+w:%d" % fixed_size)
105
+ factory.allocate_children(1)
106
+ factory.set_child(0, "item", c_schema(params.delete(:value_type)))
100
107
 
101
108
  elsif type == Type::MAP
102
- raise Todo
109
+ key_schema = c_schema(params.delete(:key_type))
110
+ value_schema = c_schema(params.delete(:value_type))
111
+
112
+ entries = CSchemaBuilder.allocate
113
+ entries.set_format("+s")
114
+ entries.set_nullable(false)
115
+ entries.allocate_children(2)
116
+ entries.set_child(0, "key", key_schema.modify(nullable: false))
117
+ entries.set_child(1, "value", value_schema)
118
+
119
+ factory.set_format("+m")
120
+ factory.allocate_children(1)
121
+ factory.set_child(0, "entries", entries.finish)
122
+ factory.set_nullable(false)
123
+
124
+ if params.include?(:keys_sorted)
125
+ factory.set_map_keys_sorted(params.delete(:keys_sorted))
126
+ end
103
127
 
104
128
  elsif type == Type::DICTIONARY
105
- raise Todo
129
+ index_type = c_schema(params.delete(:index_type))
130
+ factory.set_format(index_type.format)
131
+
132
+ value_type = c_schema(params.delete(:value_type))
133
+ factory.set_dictionary(value_type)
134
+
135
+ if params.delete(:dictionary_ordered)
136
+ factory.set_dictionary_ordered(true)
137
+ end
106
138
 
107
139
  elsif type == Type::SPARSE_UNION
108
- raise Todo
140
+ type_codes = params.delete(:type_codes)
141
+ type_codes_str = type_codes.map { |code| Integer(code) }.join(",")
142
+ factory.set_format("+us:#{type_codes_str}")
109
143
 
110
144
  elsif type == Type::DENSE_UNION
111
- raise Todo
145
+ type_codes = params.delete(:type_codes)
146
+ type_codes_str = type_codes.map { |code| Integer(code) }.join(",")
147
+ factory.set_format("+ud:#{type_codes_str}")
112
148
 
113
149
  else
114
150
  factory.set_type(type)
@@ -1,3 +1,3 @@
1
1
  module Nanoarrow
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoarrow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane