1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2014-2015 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 
19 #include "../grn_ctx_impl.h"
20 
21 #ifdef GRN_WITH_MRUBY
22 #include <mruby.h>
23 #include <mruby/class.h>
24 #include <mruby/data.h>
25 #include <mruby/string.h>
26 #include <mruby/hash.h>
27 #include <mruby/variable.h>
28 
29 #include "mrb_ctx.h"
30 #include "mrb_bulk.h"
31 #include "mrb_table_cursor.h"
32 
33 #include "mrb_converter.h"
34 #include "mrb_options.h"
35 
36 static struct mrb_data_type mrb_grn_table_cursor_type = {
37   "Groonga::TableCursor",
38   NULL
39 };
40 
41 static mrb_value
mrb_grn_table_cursor_class_open_raw(mrb_state * mrb,mrb_value klass)42 mrb_grn_table_cursor_class_open_raw(mrb_state *mrb, mrb_value klass)
43 {
44   grn_ctx *ctx = (grn_ctx *)mrb->ud;
45   mrb_value mrb_table;
46   mrb_value mrb_options = mrb_nil_value();
47   grn_table_cursor *table_cursor;
48   grn_obj *table;
49   void *min = NULL;
50   unsigned int min_size = 0;
51   grn_mrb_value_to_raw_data_buffer min_buffer;
52   void *max = NULL;
53   unsigned int max_size = 0;
54   grn_mrb_value_to_raw_data_buffer max_buffer;
55   int offset = 0;
56   int limit = -1;
57   int flags = 0;
58 
59   mrb_get_args(mrb, "o|H", &mrb_table, &mrb_options);
60 
61   table = DATA_PTR(mrb_table);
62   grn_mrb_value_to_raw_data_buffer_init(mrb, &min_buffer);
63   grn_mrb_value_to_raw_data_buffer_init(mrb, &max_buffer);
64   if (!mrb_nil_p(mrb_options)) {
65     grn_id key_domain_id;
66     mrb_value mrb_min;
67     mrb_value mrb_max;
68     mrb_value mrb_flags;
69 
70     if (table->header.type == GRN_DB) {
71       key_domain_id = GRN_DB_SHORT_TEXT;
72     } else {
73       key_domain_id = table->header.domain;
74     }
75 
76     mrb_min = grn_mrb_options_get_lit(mrb, mrb_options, "min");
77     grn_mrb_value_to_raw_data(mrb, "min", mrb_min,
78                               key_domain_id, &min_buffer, &min, &min_size);
79 
80     mrb_max = grn_mrb_options_get_lit(mrb, mrb_options, "max");
81     grn_mrb_value_to_raw_data(mrb, "max", mrb_max,
82                               key_domain_id, &max_buffer, &max, &max_size);
83 
84     mrb_flags = grn_mrb_options_get_lit(mrb, mrb_options, "flags");
85     if (!mrb_nil_p(mrb_flags)) {
86       flags = mrb_fixnum(mrb_flags);
87     }
88   }
89   table_cursor = grn_table_cursor_open(ctx, table,
90                                        min, min_size,
91                                        max, max_size,
92                                        offset, limit, flags);
93   grn_mrb_value_to_raw_data_buffer_fin(mrb, &min_buffer);
94   grn_mrb_value_to_raw_data_buffer_fin(mrb, &max_buffer);
95   grn_mrb_ctx_check(mrb);
96 
97   {
98     mrb_value mrb_table_cursor;
99     mrb_table_cursor = mrb_funcall(mrb, klass,
100                                    "new", 1, mrb_cptr_value(mrb, table_cursor));
101     mrb_iv_set(mrb, mrb_table_cursor, mrb_intern_lit(mrb, "@table"), mrb_table);
102     return mrb_table_cursor;
103   }
104 }
105 
106 static mrb_value
mrb_grn_table_cursor_initialize(mrb_state * mrb,mrb_value self)107 mrb_grn_table_cursor_initialize(mrb_state *mrb, mrb_value self)
108 {
109   mrb_value mrb_table_cursor_ptr;
110 
111   mrb_get_args(mrb, "o", &mrb_table_cursor_ptr);
112   DATA_TYPE(self) = &mrb_grn_table_cursor_type;
113   DATA_PTR(self) = mrb_cptr(mrb_table_cursor_ptr);
114 
115   return self;
116 }
117 
118 static mrb_value
mrb_grn_table_cursor_close(mrb_state * mrb,mrb_value self)119 mrb_grn_table_cursor_close(mrb_state *mrb, mrb_value self)
120 {
121   grn_ctx *ctx = (grn_ctx *)mrb->ud;
122   grn_table_cursor *table_cursor;
123 
124   table_cursor = DATA_PTR(self);
125   if (table_cursor) {
126     DATA_PTR(self) = NULL;
127     grn_table_cursor_close(ctx, table_cursor);
128     grn_mrb_ctx_check(mrb);
129   }
130 
131   return mrb_nil_value();
132 }
133 
134 static mrb_value
mrb_grn_table_cursor_next(mrb_state * mrb,mrb_value self)135 mrb_grn_table_cursor_next(mrb_state *mrb, mrb_value self)
136 {
137   grn_ctx *ctx = (grn_ctx *)mrb->ud;
138   grn_id id;
139 
140   id = grn_table_cursor_next(ctx, DATA_PTR(self));
141   grn_mrb_ctx_check(mrb);
142 
143   return mrb_fixnum_value(id);
144 }
145 
146 static mrb_value
mrb_grn_table_cursor_count(mrb_state * mrb,mrb_value self)147 mrb_grn_table_cursor_count(mrb_state *mrb, mrb_value self)
148 {
149   grn_ctx *ctx = (grn_ctx *)mrb->ud;
150   int n_records = 0;
151 
152   while (grn_table_cursor_next(ctx, DATA_PTR(self)) != GRN_ID_NIL) {
153     n_records++;
154   }
155 
156   return mrb_fixnum_value(n_records);
157 }
158 
159 static mrb_value
mrb_grn_table_cursor_get_key(mrb_state * mrb,mrb_value self)160 mrb_grn_table_cursor_get_key(mrb_state *mrb, mrb_value self)
161 {
162   grn_ctx *ctx = (grn_ctx *)mrb->ud;
163   mrb_value mrb_table;
164   grn_obj *table;
165   grn_id domain;
166   void *key;
167   int key_size;
168 
169   mrb_table = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@table"));
170   table = DATA_PTR(mrb_table);
171   if (table->header.type == GRN_DB) {
172     domain = GRN_DB_SHORT_TEXT;
173   } else {
174     domain = table->header.domain;
175   }
176   key_size = grn_table_cursor_get_key(ctx, DATA_PTR(self), &key);
177 
178   return grn_mrb_value_from_raw_data(mrb, domain, key, key_size);
179 }
180 
181 void
grn_mrb_table_cursor_init(grn_ctx * ctx)182 grn_mrb_table_cursor_init(grn_ctx *ctx)
183 {
184   grn_mrb_data *data = &(ctx->impl->mrb);
185   mrb_state *mrb = data->state;
186   struct RClass *module = data->module;
187   struct RClass *klass;
188 
189   klass = mrb_define_class_under(mrb, module, "TableCursor", mrb->object_class);
190   MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
191 
192   mrb_define_class_method(mrb, klass, "open_raw",
193                           mrb_grn_table_cursor_class_open_raw,
194                           MRB_ARGS_ARG(1, 1));
195 
196   mrb_define_method(mrb, klass, "initialize",
197                     mrb_grn_table_cursor_initialize, MRB_ARGS_REQ(1));
198   mrb_define_method(mrb, klass, "close",
199                     mrb_grn_table_cursor_close, MRB_ARGS_NONE());
200   mrb_define_method(mrb, klass, "next",
201                     mrb_grn_table_cursor_next, MRB_ARGS_NONE());
202   mrb_define_method(mrb, klass, "count",
203                     mrb_grn_table_cursor_count, MRB_ARGS_NONE());
204 
205   mrb_define_method(mrb, klass, "key",
206                     mrb_grn_table_cursor_get_key, MRB_ARGS_NONE());
207 }
208 #endif
209