rroonga 12.0.0 → 12.0.8

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.
@@ -1,6 +1,6 @@
1
1
  /* -*- coding: utf-8; mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
2
  /*
3
- Copyright (C) 2009-2021 Sutou Kouhei <kou@clear-code.com>
3
+ Copyright (C) 2009-2022 Sutou Kouhei <kou@clear-code.com>
4
4
  Copyright (C) 2014-2016 Masafumi Yokoyama <yokoyama@clear-code.com>
5
5
  Copyright (C) 2019 Horimoto Yasuhiro <horimoto@clear-code.com>
6
6
 
@@ -255,6 +255,36 @@ rb_grn_table_inspect (VALUE self)
255
255
  * * `:lz4`: Compressed by LZ4.
256
256
  * * `:zstd`: Compressed by Zstandard.
257
257
  * * `:zstandard`: Compressed by Zstandard.
258
+ * @option options :weight_float32 [Boolean] (false)
259
+ * It specifies whether weight is stored as 32 bit float or not.
260
+ *
261
+ * You can't use this option for scalar column.
262
+ *
263
+ * @since 12.0.2
264
+ * @option options [:add, :ignore, :nil, nil] :missing_mode (nil)
265
+ * It specifies how to process missing value.
266
+ *
267
+ * * `:add`, `nil`: Correspond to `MISSING_ADD`
268
+ * * `:ignore`: Correspond to `MISSING_IGNORE`
269
+ * * `:nil`: Correspond to `MISSING_NIL`
270
+ *
271
+ * See
272
+ * https://groonga.org/docs/reference/commands/column_create.html#column-create-missing-mode
273
+ * for each `MISSING_*` values.
274
+ *
275
+ * @since 12.0.2
276
+ * @option options [:error, :warn, :ignore, nil] :invalid_mode (nil)
277
+ * It specifies how to process invalid value.
278
+ *
279
+ * * `:add`, `nil`: Correspond to `INVALID_ERROR`
280
+ * * `:warn`: Correspond to `INVALID_WARN`
281
+ * * `:ignore`: Correspond to `INVALID_IGNORE`
282
+ *
283
+ * See
284
+ * https://groonga.org/docs/reference/commands/column_create.html#column-create-invalid-mode
285
+ * for each `INVALID_*` values.
286
+ *
287
+ * @since 12.0.2
258
288
  *
259
289
  * @return [Groonga::FixSizeColumn, Groonga::VariableSizeColumn]
260
290
  */
@@ -269,6 +299,9 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self)
269
299
  grn_column_flags flags = 0;
270
300
  VALUE rb_name, rb_value_type;
271
301
  VALUE options, rb_path, rb_persistent, rb_compress, rb_type, rb_with_weight;
302
+ VALUE rb_weight_float32;
303
+ VALUE rb_missing_mode;
304
+ VALUE rb_invalid_mode;
272
305
  VALUE columns;
273
306
  VALUE rb_column;
274
307
 
@@ -288,6 +321,9 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self)
288
321
  "type", &rb_type,
289
322
  "with_weight", &rb_with_weight,
290
323
  "compress", &rb_compress,
324
+ "weight_float32", &rb_weight_float32,
325
+ "missing_mode", &rb_missing_mode,
326
+ "invalid_mode", &rb_invalid_mode,
291
327
  NULL);
292
328
 
293
329
  value_type = RVAL2GRNOBJECT(rb_value_type, &context);
@@ -347,6 +383,43 @@ rb_grn_table_define_column (int argc, VALUE *argv, VALUE self)
347
383
  rb_grn_inspect(rb_compress));
348
384
  }
349
385
 
386
+ if (RVAL2CBOOL(rb_weight_float32)) {
387
+ if (flags & GRN_OBJ_COLUMN_VECTOR) {
388
+ flags |= GRN_OBJ_WEIGHT_FLOAT32;
389
+ } else {
390
+ rb_raise(rb_eArgError,
391
+ "can't use 32 bit float weight for scalar column");
392
+ }
393
+ }
394
+
395
+ if (NIL_P(rb_missing_mode) ||
396
+ rb_grn_equal_option(rb_missing_mode, "add")) {
397
+ flags |= GRN_OBJ_MISSING_ADD;
398
+ } else if (rb_grn_equal_option(rb_missing_mode, "ignore")) {
399
+ flags |= GRN_OBJ_MISSING_IGNORE;
400
+ } else if (rb_grn_equal_option(rb_missing_mode, "nil")) {
401
+ flags |= GRN_OBJ_MISSING_NIL;
402
+ } else {
403
+ rb_raise(rb_eArgError,
404
+ "invalid missing mode: %s: "
405
+ "available types: [:add, :ignore, :nil, nil]",
406
+ rb_grn_inspect(rb_missing_mode));
407
+ }
408
+
409
+ if (NIL_P(rb_invalid_mode) ||
410
+ rb_grn_equal_option(rb_invalid_mode, "error")) {
411
+ flags |= GRN_OBJ_INVALID_ERROR;
412
+ } else if (rb_grn_equal_option(rb_invalid_mode, "warn")) {
413
+ flags |= GRN_OBJ_INVALID_WARN;
414
+ } else if (rb_grn_equal_option(rb_invalid_mode, "ignore")) {
415
+ flags |= GRN_OBJ_INVALID_IGNORE;
416
+ } else {
417
+ rb_raise(rb_eArgError,
418
+ "invalid invalid mode: %s: "
419
+ "available types: [:add, :warn, :ignore, nil]",
420
+ rb_grn_inspect(rb_invalid_mode));
421
+ }
422
+
350
423
  column = grn_column_create(context, table, name, name_size,
351
424
  path, flags, value_type);
352
425
  if (context->rc) {
@@ -639,15 +712,11 @@ rb_grn_table_get_columns (int argc, VALUE *argv, VALUE self)
639
712
  {
640
713
  grn_ctx *context = NULL;
641
714
  grn_obj *table;
642
- grn_obj *columns;
643
- grn_obj *key_type;
644
- grn_rc rc;
715
+ grn_hash *columns;
645
716
  int n;
646
- grn_table_cursor *cursor;
647
717
  VALUE rb_prefix, rb_columns;
648
718
  char *prefix = NULL;
649
719
  unsigned prefix_size = 0;
650
- VALUE exception;
651
720
 
652
721
  rb_grn_table_deconstruct(SELF(self), &table, &context,
653
722
  NULL, NULL,
@@ -661,23 +730,27 @@ rb_grn_table_get_columns (int argc, VALUE *argv, VALUE self)
661
730
  prefix_size = RSTRING_LEN(rb_prefix);
662
731
  }
663
732
 
664
- key_type = grn_ctx_at(context, GRN_DB_SHORT_TEXT);
665
- columns = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_HASH_KEY,
666
- key_type, 0);
733
+ columns = grn_hash_create(context,
734
+ NULL,
735
+ sizeof(grn_id),
736
+ 0,
737
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
667
738
  rb_grn_context_check(context, self);
668
- n = grn_table_columns(context, table, prefix, prefix_size, columns);
739
+ n = grn_table_columns(context,
740
+ table,
741
+ prefix,
742
+ prefix_size,
743
+ (grn_obj *)columns);
669
744
  rb_grn_context_check(context, self);
670
745
 
671
746
  rb_columns = rb_ary_new2(n);
672
747
  if (n == 0) {
673
- grn_obj_unlink(context, columns);
748
+ grn_hash_close(context, columns);
674
749
  return rb_columns;
675
750
  }
676
751
 
677
- cursor = grn_table_cursor_open(context, columns, NULL, 0, NULL, 0,
678
- 0, -1, GRN_CURSOR_ASCENDING);
679
- rb_grn_context_check(context, self);
680
- while (grn_table_cursor_next(context, cursor) != GRN_ID_NIL) {
752
+ VALUE exception = RUBY_Qnil;
753
+ GRN_HASH_EACH_BEGIN(context, columns, cursor, id) {
681
754
  void *key;
682
755
  grn_id *column_id;
683
756
  grn_obj *column;
@@ -685,14 +758,12 @@ rb_grn_table_get_columns (int argc, VALUE *argv, VALUE self)
685
758
  grn_user_data *user_data;
686
759
  grn_bool need_to_set_name = GRN_FALSE;
687
760
 
688
- grn_table_cursor_get_key(context, cursor, &key);
761
+ grn_hash_cursor_get_key(context, cursor, &key);
689
762
  column_id = key;
690
763
  column = grn_ctx_at(context, *column_id);
691
764
  exception = rb_grn_context_to_exception(context, self);
692
- if (!NIL_P(exception)) {
693
- grn_table_cursor_close(context, cursor);
694
- grn_obj_unlink(context, columns);
695
- rb_exc_raise(exception);
765
+ if (!RB_NIL_P(exception)) {
766
+ break;
696
767
  }
697
768
 
698
769
  user_data = grn_obj_user_data(context, column);
@@ -711,13 +782,12 @@ rb_grn_table_get_columns (int argc, VALUE *argv, VALUE self)
711
782
  }
712
783
 
713
784
  rb_ary_push(rb_columns, rb_column);
785
+ } GRN_HASH_EACH_END(context, cursor);
786
+ grn_hash_close(context, columns);
787
+ if (!RB_NIL_P(exception)) {
788
+ rb_exc_raise(exception);
714
789
  }
715
- rc = grn_table_cursor_close(context, cursor);
716
- grn_obj_unlink(context, columns);
717
- if (rc != GRN_SUCCESS) {
718
- rb_grn_context_check(context, self);
719
- rb_grn_rc_check(rc, self);
720
- }
790
+ rb_grn_context_check(context, self);
721
791
 
722
792
  return rb_columns;
723
793
  }
@@ -1,6 +1,6 @@
1
1
  /* -*- coding: utf-8; mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
2
  /*
3
- Copyright (C) 2009-2021 Sutou Kouhei <kou@clear-code.com>
3
+ Copyright (C) 2009-2022 Sutou Kouhei <kou@clear-code.com>
4
4
  Copyright (C) 2014-2016 Masafumi Yokoyama <yokoyama@clear-code.com>
5
5
 
6
6
  This library is free software; you can redistribute it and/or
@@ -193,23 +193,24 @@ rb_grn_variable_size_column_array_reference (VALUE self, VALUE rb_id)
193
193
  rb_value = rb_ary_new2(n);
194
194
  for (i = 0; i < n; i++) {
195
195
  VALUE rb_element_value;
196
- unsigned int weight = 0;
196
+ float weight = 0.0;
197
197
  grn_id domain;
198
198
  VALUE rb_element;
199
199
 
200
200
  if (value->header.type == GRN_UVECTOR) {
201
201
  grn_id id;
202
- id = grn_uvector_get_element(context, value, i, &weight);
202
+ id = grn_uvector_get_element_record(context, value, i, &weight);
203
203
  rb_element_value = rb_grn_record_new(rb_range, id, Qnil);
204
204
  } else {
205
205
  const char *element_value;
206
206
  unsigned int element_value_length;
207
- element_value_length = grn_vector_get_element(context,
208
- value,
209
- i,
210
- &element_value,
211
- &weight,
212
- &domain);
207
+ element_value_length =
208
+ grn_vector_get_element_float(context,
209
+ value,
210
+ i,
211
+ &element_value,
212
+ &weight,
213
+ &domain);
213
214
  rb_element_value = rb_str_new(element_value, element_value_length);
214
215
  }
215
216
 
@@ -217,9 +218,15 @@ rb_grn_variable_size_column_array_reference (VALUE self, VALUE rb_id)
217
218
  rb_hash_aset(rb_element,
218
219
  RB_GRN_INTERN("value"),
219
220
  rb_element_value);
220
- rb_hash_aset(rb_element,
221
- RB_GRN_INTERN("weight"),
222
- UINT2NUM(weight));
221
+ if (flags & GRN_OBJ_WEIGHT_FLOAT32) {
222
+ rb_hash_aset(rb_element,
223
+ RB_GRN_INTERN("weight"),
224
+ rb_float_new(weight));
225
+ } else {
226
+ rb_hash_aset(rb_element,
227
+ RB_GRN_INTERN("weight"),
228
+ UINT2NUM((uint32_t)weight));
229
+ }
223
230
 
224
231
  rb_ary_push(rb_value, rb_element);
225
232
  }
@@ -240,22 +247,22 @@ hash_element_to_vector_element(VALUE key, VALUE value, VALUE user_data)
240
247
  {
241
248
  HashElementToVectorElementData *data =
242
249
  (HashElementToVectorElementData *)user_data;
243
- unsigned int weight;
250
+ float weight;
244
251
 
245
- weight = NUM2UINT(value);
252
+ weight = (float)NUM2DBL(value);
246
253
 
247
254
  if (data->vector->header.type == GRN_UVECTOR) {
248
255
  grn_id id = RVAL2GRNID(key, data->context, data->range, data->self);
249
- grn_uvector_add_element(data->context, data->vector, id, weight);
256
+ grn_uvector_add_element_record(data->context, data->vector, id, weight);
250
257
  } else {
251
258
  GRN_BULK_REWIND(data->element_value);
252
259
  RVAL2GRNBULK(key, data->context, data->element_value);
253
260
 
254
- grn_vector_add_element(data->context, data->vector,
255
- GRN_BULK_HEAD(data->element_value),
256
- GRN_BULK_VSIZE(data->element_value),
257
- weight,
258
- data->element_value->header.domain);
261
+ grn_vector_add_element_float(data->context, data->vector,
262
+ GRN_BULK_HEAD(data->element_value),
263
+ GRN_BULK_VSIZE(data->element_value),
264
+ weight,
265
+ data->element_value->header.domain);
259
266
  }
260
267
 
261
268
  return ST_CONTINUE;
@@ -405,7 +412,7 @@ rb_grn_variable_size_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
405
412
  int i, n;
406
413
  n = RARRAY_LEN(rb_value);
407
414
  for (i = 0; i < n; i++) {
408
- unsigned int weight = 0;
415
+ float weight = 0;
409
416
  VALUE rb_element_value, rb_weight;
410
417
 
411
418
  rb_grn_scan_options(RARRAY_PTR(rb_value)[i],
@@ -414,23 +421,23 @@ rb_grn_variable_size_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value)
414
421
  NULL);
415
422
 
416
423
  if (!NIL_P(rb_weight)) {
417
- weight = NUM2UINT(rb_weight);
424
+ weight = (float)NUM2DBL(rb_weight);
418
425
  }
419
426
 
420
427
  if (value->header.type == GRN_UVECTOR) {
421
428
  grn_id id = RVAL2GRNID(rb_element_value, context, range, self);
422
- grn_uvector_add_element(context, value, id, weight);
429
+ grn_uvector_add_element_record(context, value, id, weight);
423
430
  } else {
424
431
  GRN_BULK_REWIND(element_value);
425
432
  if (!NIL_P(rb_element_value)) {
426
433
  RVAL2GRNBULK(rb_element_value, context, element_value);
427
434
  }
428
435
 
429
- grn_vector_add_element(context, value,
430
- GRN_BULK_HEAD(element_value),
431
- GRN_BULK_VSIZE(element_value),
432
- weight,
433
- element_value->header.domain);
436
+ grn_vector_add_element_float(context, value,
437
+ GRN_BULK_HEAD(element_value),
438
+ GRN_BULK_VSIZE(element_value),
439
+ weight,
440
+ element_value->header.domain);
434
441
  }
435
442
  }
436
443
  } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cHash))) {
data/ext/groonga/rb-grn.h CHANGED
@@ -93,7 +93,7 @@ RB_GRN_BEGIN_DECLS
93
93
 
94
94
  #define RB_GRN_MAJOR_VERSION 12
95
95
  #define RB_GRN_MINOR_VERSION 0
96
- #define RB_GRN_MICRO_VERSION 0
96
+ #define RB_GRN_MICRO_VERSION 8
97
97
 
98
98
  #define RB_GRN_OBJECT(object) ((RbGrnObject *)(object))
99
99
  #define RB_GRN_NAMED_OBJECT(object) ((RbGrnNamedObject *)(object))
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2009-2016 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2009-2022 Sutou Kouhei <kou@clear-code.com>
4
2
  # Copyright (C) 2014-2015 Masafumi Yokoyama <yokoyama@clear-code.com>
5
3
  #
6
4
  # This library is free software; you can redistribute it and/or
@@ -867,6 +865,36 @@ module Groonga
867
865
  # * `:lz4`: Compzressed by LZ4.
868
866
  # * `:zstd`: Compressed by Zstandard.
869
867
  # * `:zstandard`: Compressed by Zstandard.
868
+ # @option options [Boolean] :weight_float32 (false)
869
+ # It specifies whether the column uses 32 bit float for weight or not.
870
+ #
871
+ # You can't use this option for scalar column.
872
+ #
873
+ # @since 12.0.2
874
+ # @option options [:add, :ignore, :nil, nil] :missing_mode (nil)
875
+ # It specifies how to process missing value.
876
+ #
877
+ # * `:add`, `nil`: Correspond to `MISSING_ADD`
878
+ # * `:ignore`: Correspond to `MISSING_IGNORE`
879
+ # * `:nil`: Correspond to `MISSING_NIL`
880
+ #
881
+ # See
882
+ # https://groonga.org/docs/reference/commands/column_create.html#column-create-missing-mode
883
+ # for each `MISSING_*` values.
884
+ #
885
+ # @since 12.0.2
886
+ # @option options [:error, :warn, :ignore, nil] :invalid_mode (nil)
887
+ # It specifies how to process invalid value.
888
+ #
889
+ # * `:add`, `nil`: Correspond to `INVALID_ERROR`
890
+ # * `:warn`: Correspond to `INVALID_WARN`
891
+ # * `:ignore`: Correspond to `INVALID_IGNORE`
892
+ #
893
+ # See
894
+ # https://groonga.org/docs/reference/commands/column_create.html#column-create-invalid-mode
895
+ # for each `INVALID_*` values.
896
+ #
897
+ # @since 12.0.2
870
898
  def column(name, type, options={})
871
899
  definition = self[name, ColumnDefinition]
872
900
  if definition.nil?
@@ -1540,6 +1568,9 @@ module Groonga
1540
1568
  :type => @options[:type],
1541
1569
  :with_weight => @options[:with_weight],
1542
1570
  :compress => @options[:compress],
1571
+ :weight_float32 => @options[:weight_float32],
1572
+ :missing_mode => @options[:missing_mode],
1573
+ :invalid_mode => @options[:invalid_mode],
1543
1574
  }
1544
1575
  end
1545
1576
 
data/rroonga-build.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2021 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2009-2022 Sutou Kouhei <kou@clear-code.com>
2
2
  # Copyright (C) 2015-2017 Masafumi Yokoyama <yokoyama@clear-code.com>
3
3
  #
4
4
  # This library is free software; you can redistribute it and/or
@@ -16,12 +16,12 @@
16
16
 
17
17
  module RroongaBuild
18
18
  module RequiredGroongaVersion
19
- MAJOR = 11
19
+ MAJOR = 12
20
20
  MINOR = 0
21
- MICRO = 0
21
+ MICRO = 2
22
22
  VERSION = [MAJOR, MINOR, MICRO]
23
23
  STRING = VERSION.join(".")
24
- RELEASED_DATE = Time.utc(2021, 2, 9)
24
+ RELEASED_DATE = Time.utc(2022, 3, 29)
25
25
  end
26
26
 
27
27
  module_function
data/test/test-column.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2020 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright (C) 2009-2022 Sutou Kouhei <kou@clear-code.com>
2
2
  # Copyright (C) 2016 Masafumi Yokoyama <yokoyama@clear-code.com>
3
3
  #
4
4
  # This library is free software; you can redistribute it and/or
@@ -431,12 +431,19 @@ class ColumnTest < Test::Unit::TestCase
431
431
  def setup_schema
432
432
  Groonga::Schema.define do |schema|
433
433
  schema.create_table("Shops", :type => :hash) do |table|
434
- table.short_text("tags", :type => :vector)
434
+ table.short_text("tags",
435
+ type: :vector,
436
+ with_weight: true)
437
+ table.short_text("tags_float32",
438
+ type: :vector,
439
+ with_weight: true,
440
+ weight_float32: true)
435
441
  end
436
442
 
437
443
  schema.create_table("Tags",
438
444
  :type => :patricia_trie) do |table|
439
- table.index("Shops.tags", :with_weight => true)
445
+ table.index("Shops.tags",
446
+ with_weight: true)
440
447
  end
441
448
  end
442
449
 
@@ -453,6 +460,33 @@ class ColumnTest < Test::Unit::TestCase
453
460
  select_by_tag("curry"))
454
461
  end
455
462
 
463
+ def test_vector_weight_float32
464
+ @shops.add("Soul Food India",
465
+ :tags_float32 => [
466
+ {:value => "curry", :weight => 11.1},
467
+ {:value => "hot", :weight => 33.3},
468
+ ])
469
+ actual = @shops.collect do |shop|
470
+ attributes = shop.attributes
471
+ attributes["tags_float32"].each do |tag|
472
+ tag[:weight] = tag[:weight].round(1)
473
+ end
474
+ attributes
475
+ end
476
+ assert_equal([
477
+ {
478
+ "_id" => 1,
479
+ "_key" => "Soul Food India",
480
+ "tags" => [],
481
+ "tags_float32" => [
482
+ {:value => "curry", :weight => 11.1},
483
+ {:value => "hot", :weight => 33.3},
484
+ ]
485
+ },
486
+ ],
487
+ actual)
488
+ end
489
+
456
490
  def test_offline_index
457
491
  @shops.add("Soul Food India",
458
492
  :tags => [
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016-2017 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2016-2022 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -119,4 +119,198 @@ class DataColumnTest < Test::Unit::TestCase
119
119
  comments.collect {|comment| [comment.base, comment.plus1]})
120
120
  end
121
121
  end
122
+
123
+ sub_test_case "#missing_mode" do
124
+ def test_add
125
+ Groonga::Schema.define do |schema|
126
+ schema.create_table("Tags",
127
+ type: :hash,
128
+ key_type: :short_text) do |table|
129
+ end
130
+ schema.create_table("Memos") do |table|
131
+ table.reference("tags",
132
+ "Tags",
133
+ type: :vector,
134
+ missing_mode: :add)
135
+ end
136
+ end
137
+ memos = Groonga["Memos"]
138
+ memos_tags = Groonga["Memos.tags"]
139
+ tags = Groonga["Tags"]
140
+
141
+ record = memos.add(tags: ["nonexistent"])
142
+
143
+ assert_equal({
144
+ missing_mode: :add,
145
+ missing_add: true,
146
+ missing_ignore: false,
147
+ missing_nil: false,
148
+ values: [tags["nonexistent"]],
149
+ },
150
+ {
151
+ missing_mode: memos_tags.missing_mode,
152
+ missing_add: memos_tags.missing_add?,
153
+ missing_ignore: memos_tags.missing_ignore?,
154
+ missing_nil: memos_tags.missing_nil?,
155
+ values: record.tags,
156
+ })
157
+ end
158
+
159
+ def test_ignore
160
+ Groonga::Schema.define do |schema|
161
+ schema.create_table("Tags",
162
+ type: :hash,
163
+ key_type: :short_text) do |table|
164
+ end
165
+ schema.create_table("Memos") do |table|
166
+ table.reference("tags",
167
+ "Tags",
168
+ type: :vector,
169
+ missing_mode: :ignore)
170
+ end
171
+ end
172
+ memos = Groonga["Memos"]
173
+ memos_tags = Groonga["Memos.tags"]
174
+
175
+ record = memos.add(tags: ["nonexistent"])
176
+
177
+ assert_equal({
178
+ missing_mode: :ignore,
179
+ missing_add: false,
180
+ missing_ignore: true,
181
+ missing_nil: false,
182
+ values: [],
183
+ },
184
+ {
185
+ missing_mode: memos_tags.missing_mode,
186
+ missing_add: memos_tags.missing_add?,
187
+ missing_ignore: memos_tags.missing_ignore?,
188
+ missing_nil: memos_tags.missing_nil?,
189
+ values: record.tags,
190
+ })
191
+ end
192
+
193
+ def test_nil
194
+ Groonga::Schema.define do |schema|
195
+ schema.create_table("Tags",
196
+ type: :hash,
197
+ key_type: :short_text) do |table|
198
+ end
199
+ schema.create_table("Memos") do |table|
200
+ table.reference("tags",
201
+ "Tags",
202
+ type: :vector,
203
+ missing_mode: :nil,
204
+ invalid_mode: :ignore)
205
+ end
206
+ end
207
+ memos = Groonga["Memos"]
208
+ memos_tags = Groonga["Memos.tags"]
209
+
210
+ record = memos.add(tags: ["nonexistent"])
211
+
212
+ assert_equal({
213
+ missing_mode: :nil,
214
+ missing_add: false,
215
+ missing_ignore: false,
216
+ missing_nil: true,
217
+ values: [nil],
218
+ },
219
+ {
220
+ missing_mode: memos_tags.missing_mode,
221
+ missing_add: memos_tags.missing_add?,
222
+ missing_ignore: memos_tags.missing_ignore?,
223
+ missing_nil: memos_tags.missing_nil?,
224
+ values: record.tags,
225
+ })
226
+ end
227
+ end
228
+
229
+ sub_test_case "#invalid_mode" do
230
+ def test_error
231
+ Groonga::Schema.define do |schema|
232
+ schema.create_table("Memos") do |table|
233
+ table.uint32("count", invalid_mode: :error)
234
+ end
235
+ end
236
+ memos = Groonga["Memos"]
237
+ memos_count = Groonga["Memos.count"]
238
+
239
+ record = memos.add
240
+ assert_raise(Groonga::InvalidArgument) do
241
+ record.count = "invalid"
242
+ end
243
+
244
+ assert_equal({
245
+ invalid_mode: :error,
246
+ invalid_error: true,
247
+ invalid_warn: false,
248
+ invalid_ignore: false,
249
+ value: 0,
250
+ },
251
+ {
252
+ invalid_mode: memos_count.invalid_mode,
253
+ invalid_error: memos_count.invalid_error?,
254
+ invalid_warn: memos_count.invalid_warn?,
255
+ invalid_ignore: memos_count.invalid_ignore?,
256
+ value: record.count,
257
+ })
258
+ end
259
+
260
+ def test_warn
261
+ Groonga::Schema.define do |schema|
262
+ schema.create_table("Memos") do |table|
263
+ table.uint32("count", invalid_mode: :warn)
264
+ end
265
+ end
266
+ memos = Groonga["Memos"]
267
+ memos_count = Groonga["Memos.count"]
268
+
269
+ record = memos.add
270
+ record.count = "invalid"
271
+
272
+ assert_equal({
273
+ invalid_mode: :warn,
274
+ invalid_error: false,
275
+ invalid_warn: true,
276
+ invalid_ignore: false,
277
+ value: 0,
278
+ },
279
+ {
280
+ invalid_mode: memos_count.invalid_mode,
281
+ invalid_error: memos_count.invalid_error?,
282
+ invalid_warn: memos_count.invalid_warn?,
283
+ invalid_ignore: memos_count.invalid_ignore?,
284
+ value: record.count,
285
+ })
286
+ end
287
+
288
+ def test_ignore
289
+ Groonga::Schema.define do |schema|
290
+ schema.create_table("Memos") do |table|
291
+ table.uint32("count", invalid_mode: :ignore)
292
+ end
293
+ end
294
+ memos = Groonga["Memos"]
295
+ memos_count = Groonga["Memos.count"]
296
+
297
+ record = memos.add
298
+ record.count = "invalid"
299
+
300
+ assert_equal({
301
+ invalid_mode: :ignore,
302
+ invalid_error: false,
303
+ invalid_warn: false,
304
+ invalid_ignore: true,
305
+ value: 0,
306
+ },
307
+ {
308
+ invalid_mode: memos_count.invalid_mode,
309
+ invalid_error: memos_count.invalid_error?,
310
+ invalid_warn: memos_count.invalid_warn?,
311
+ invalid_ignore: memos_count.invalid_ignore?,
312
+ value: record.count,
313
+ })
314
+ end
315
+ end
122
316
  end