rroonga 12.0.0 → 12.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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