Ejemplo n.º 1
0
/*
 * _constant_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。
 *
 * @overload append_constant(constant, operation=Groonga::Operator::PUSH, n_arguments=1)
 *   @param [Object] constant 追加する _constant_
 *   @param [Groonga::Operator::XXX] operation 追加する _operation_
 *   @param [Integer] n_arguments _operation_ の取る引数
 * @return [Self] self
 */
static VALUE
rb_grn_expression_append_constant (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_constant, rb_operator, rb_n_arguments;
    VALUE exception;
    grn_ctx *context = NULL;
    grn_obj *expression, *constant = NULL;
    grn_operator operator = GRN_OP_PUSH;
    int n_arguments = 1;

    rb_scan_args(argc, argv, "12", &rb_constant, &rb_operator, &rb_n_arguments);
    if (!NIL_P(rb_operator))
        operator = RVAL2GRNOPERATOR(rb_operator);
    if (!NIL_P(rb_n_arguments))
        n_arguments = NUM2INT(rb_n_arguments);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL, NULL,
                                  NULL, NULL);

    RVAL2GRNOBJ(rb_constant, context, &constant);
    grn_expr_append_const(context, expression, constant, operator, n_arguments);

    exception = rb_grn_context_to_exception(context, self);
    grn_obj_unlink(context, constant);
    if (!NIL_P(exception))
        rb_exc_raise(exception);

    return self;
}
Ejemplo n.º 2
0
/*
 * _object_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。
 *
 * @overload append_object(object, operation=Groonga::Operator::PUSH, n_arguments=1)
 *   @param [Object] object 追加するオブジェクト
 *   @param [Groonga::Operator::XXX] operation 追加する _operation_
 *   @param [Integer] n_arguments _operation_ の取る引数
 * @return [Self] self
 *
 */
static VALUE
rb_grn_expression_append_object (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_object, rb_operation, rb_n_arguments;
    grn_ctx *context = NULL;
    grn_obj *expression, *object;
    grn_operator operation = GRN_OP_PUSH;
    int n_arguments = 1;

    rb_scan_args(argc, argv, "12", &rb_object, &rb_operation, &rb_n_arguments);
    if (!NIL_P(rb_operation))
        operation = RVAL2GRNOPERATOR(rb_operation);
    if (!NIL_P(rb_n_arguments))
        n_arguments = NUM2INT(rb_n_arguments);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    object = RVAL2GRNOBJECT(rb_object, &context);
    grn_expr_append_obj(context, expression, object,
                        operation, n_arguments);
    rb_grn_context_check(context, self);
    rb_ary_push(rb_iv_get(self, "@objects"), rb_object);

    return self;
}
Ejemplo n.º 3
0
/*
 * Document-method: search
 *
 * call-seq:
 *   column.search(query, options={}) -> Groonga::Hash
 *
 * _object_から_query_に対応するオブジェクトを検索し、見つかっ
 * たオブジェクトのIDがキーになっているGroonga::Hashを返す。
 *
 * 利用可能なオプションは以下の通り。
 *
 * [_:result_]
 *   結果を格納するGroonga::Hash。指定しない場合は新しく
 *   Groonga::Hashを生成し、それに結果を格納して返す。
 * [_:operator_]
 *   以下のどれかの値を指定する。+nil+, <tt>"or"</tt>, <tt>"||"</tt>,
 *   <tt>"and"</tt>, <tt>"+"</tt>, <tt>"&&"</tt>, <tt>"but"</tt>,
 *   <tt>"not"</tt>, <tt>"-"</tt>, <tt>"adjust"</tt>, <tt>">"</tt>。
 *   それぞれ以下のようになる。(FIXME: 「以下」)
 * [_:exact_]
 *   +true+を指定すると完全一致で検索する
 * [_:longest_common_prefix_]
 *   +true+を指定すると_query_と同じ接頭辞をもつエントリのう
 *   ち、もっとも長いエントリを検索する
 * [_:suffix_]
 *   +true+を指定すると_query_が後方一致するエントリを検索す
 *   る
 * [_:prefix_]
 *   +true+を指定すると_query_が前方一致するレコードを検索す
 *   る
 * [_:near_]
 *   +true+を指定すると_query_に指定した複数の語が近傍に含ま
 *   れるレコードを検索する
 * [...]
 *   ...
 */
static VALUE
rb_grn_index_column_search (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *column;
    grn_obj *range;
    grn_obj *query = NULL, *id_query = NULL, *string_query = NULL;
    grn_obj *result;
    grn_operator operator;
    grn_rc rc;
    VALUE rb_query, options, rb_result, rb_operator;

    rb_grn_index_column_deconstruct(SELF(self), &column, &context,
				    NULL, NULL,
				    NULL, NULL, NULL, &range,
				    &id_query, &string_query);

    rb_scan_args(argc, argv, "11", &rb_query, &options);

    if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cGrnQuery))) {
	grn_query *_query;
	_query = RVAL2GRNQUERY(rb_query);
	query = (grn_obj *)_query;
    } else if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cInteger))) {
	grn_id id;
	id = NUM2UINT(rb_query);
	GRN_TEXT_SET(context, id_query, &id, sizeof(grn_id));
	query = id_query;
    } else {
	const char *_query;
	_query = StringValuePtr(rb_query);
	GRN_TEXT_SET(context, string_query, _query, RSTRING_LEN(rb_query));
	query = string_query;
    }

    rb_grn_scan_options(options,
			"result", &rb_result,
			"operator", &rb_operator,
			NULL);

    if (NIL_P(rb_result)) {
	result = grn_table_create(context, NULL, 0, NULL,
				  GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
				  range, 0);
	rb_grn_context_check(context, self);
	rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE);
    } else {
	result = RVAL2GRNOBJECT(rb_result, &context);
    }

    operator = RVAL2GRNOPERATOR(rb_operator);

    rc = grn_obj_search(context, column, query, result, operator, NULL);
    rb_grn_rc_check(rc, self);

    return rb_result;
}
Ejemplo n.º 4
0
/*
 * _key_ にマッチするレコードのIDがキーに入っている
 * {Groonga::Hash} を返す。マッチするレコードがない場合は空の
 * {fGroonga::Hash} が返る。
 * _options_ で +:result+ を指定することにより、そのテーブルにマッ
 * チしたレコードIDがキーのレコードを追加することができる。
 * +:result+ にテーブルを指定した場合は、そのテーブルが返る。
 *
 * @example 複数のキーで検索し、結果を1つのテーブルに集める。
 *   result = nil
 *   keys = ["morita", "gunyara-kun", "yu"]
 *   keys.each do |key|
 *     result = users.search(key, :result => result)
 *   end
 *   result.each do |record|
 *     user = record.key
 *     p user.key # -> "morita"または"gunyara-kun"または"yu"
 *   end
 *
 * @overload search(key, options=nil)
 *   @return [Groonga::Hash]
 *   @param key [String] レコードにマッチさせる値
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :result The result
 *     結果を格納するテーブル。
 *   @option options :operator (Groonga::Operator::OR)
 *     マッチしたレコードをどのように扱うか。指定可能な値は以
 *     下の通り。
 *
 *     - Groonga::Operator::OR :=
 *       マッチしたレコードを追加。すでにレコードが追加され
 *       ている場合は何もしない。 =:
 *     - Groonga::Operator::AND :=
 *       マッチしたレコードのスコアを増加。マッチしなかった
 *       レコードを削除。 =:
 *     - Groonga::Operator::AND_NOT :=
 *       マッチしたレコードを削除。 =:
 *     - Groonga::Operator::ADJUST :=
 *       マッチしたレコードのスコアを増加。 =:
 *     - +:type+ :=
 *       ????? =:
 *
 */
static VALUE
rb_grn_double_array_trie_search (int argc, VALUE *argv, VALUE self)
{
    grn_rc rc;
    grn_ctx *context;
    grn_obj *table;
    grn_id domain_id;
    grn_obj *key, *domain, *result;
    grn_operator operator;
    grn_search_optarg search_options;
    grn_bool search_options_is_set = GRN_FALSE;
    VALUE rb_key, options, rb_result, rb_operator, rb_type;

    rb_grn_double_array_trie_deconstruct(SELF(self), &table, &context,
                                         &key, NULL, &domain_id, &domain,
                                         NULL, NULL, NULL,
                                         NULL);

    rb_scan_args(argc, argv, "11", &rb_key, &options);

    RVAL2GRNKEY(rb_key, context, key, domain_id, domain, self);

    rb_grn_scan_options(options,
                        "result", &rb_result,
                        "operator", &rb_operator,
                        "type", &rb_type,
                        NULL);

    if (NIL_P(rb_result)) {
        result = grn_table_create(context, NULL, 0, NULL,
                                  GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
                                  table, 0);
        rb_grn_context_check(context, self);
        rb_result = GRNOBJECT2RVAL(Qnil, context, result, GRN_TRUE);
    } else {
        result = RVAL2GRNOBJECT(rb_result, &context);
    }

    operator = RVAL2GRNOPERATOR(rb_operator);

    rc = grn_obj_search(context, table, key,
                        result, operator,
                        search_options_is_set ? &search_options : NULL);
    rb_grn_rc_check(rc, self);

    return rb_result;
}
Ejemplo n.º 5
0
/*
 * _object_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。
 *
 * @overload append_object(object, operation=Groonga::Operator::PUSH, n_arguments=1)
 *   @param [Object] object 追加するオブジェクト
 *   @param [Groonga::Operator::XXX] operation 追加する _operation_
 *   @param [Integer] n_arguments _operation_ の取る引数
 * @return [Self] self
 *
 */
static VALUE
rb_grn_expression_append_object (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_object, rb_operation, rb_n_arguments;
    grn_ctx *context = NULL;
    grn_obj *expression, *object;
    grn_operator operation = GRN_OP_PUSH;
    int n_arguments = 1;

    rb_scan_args(argc, argv, "12", &rb_object, &rb_operation, &rb_n_arguments);
    if (!NIL_P(rb_operation))
        operation = RVAL2GRNOPERATOR(rb_operation);
    if (!NIL_P(rb_n_arguments))
        n_arguments = NUM2INT(rb_n_arguments);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    if (RB_TYPE_P(rb_object, RUBY_T_HASH)) {
        RbGrnHashFromRubyHashData data;
        data.context = context;
        data.hash = grn_hash_create(context, NULL,
                                    GRN_TABLE_MAX_KEY_SIZE,
                                    sizeof(grn_obj),
                                    GRN_OBJ_KEY_VAR_SIZE |
                                    GRN_OBJ_TEMPORARY |
                                    GRN_HASH_TINY);
        grn_expr_take_obj(context, expression, (grn_obj *)(data.hash));
        data.rb_hash = rb_object;
        rb_hash_foreach(rb_object,
                        rb_grn_hash_from_ruby_hash_body,
                        (VALUE)&data);
        grn_expr_append_obj(context, expression, (grn_obj *)(data.hash),
                            operation, n_arguments);
    } else {
        object = RVAL2GRNOBJECT(rb_object, &context);
        grn_expr_append_obj(context, expression, object,
                            operation, n_arguments);
    }
    rb_grn_context_check(context, self);
    rb_ary_push(rb_iv_get(self, "@objects"), rb_object);

    return self;
}
Ejemplo n.º 6
0
/*
 * _n_arguments_ 個の引数を取る _operation_ を追加する。
 *
 * @overload append_operation(operation, n_arguments)
 */
static VALUE
rb_grn_expression_append_operation (VALUE self, VALUE rb_operation,
                                    VALUE rb_n_arguments)
{
    grn_ctx *context = NULL;
    grn_obj *expression;
    grn_operator operation;
    int n_arguments = 0;

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    operation = RVAL2GRNOPERATOR(rb_operation);
    n_arguments = NUM2INT(rb_n_arguments);
    grn_expr_append_op(context, expression, operation, n_arguments);
    rb_grn_context_check(context, self);
    return Qnil;
}
Ejemplo n.º 7
0
/*
 * Document-method: indexes
 *
 * call-seq:
 *   column.indexes(operator=Groonga::Operator::MATCH) -> [index_column, ...]
 *
 * _operation_ を実行できる _column_ のインデックスを返す。
 *
 * @since 1.0.9
 */
static VALUE
rb_grn_column_get_indexes (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *column;
    grn_obj **indexes = NULL;
    int i, n_indexes;
    grn_operator operator = GRN_OP_MATCH;
    VALUE rb_operator, rb_indexes;

    rb_scan_args(argc, argv, "01", &rb_operator);

    rb_grn_column_deconstruct(SELF(self), &column, &context,
			     NULL, NULL,
			     NULL, NULL, NULL);

    if (!NIL_P(rb_operator)) {
	operator = RVAL2GRNOPERATOR(rb_operator);
    }

    rb_indexes = rb_ary_new();
    n_indexes = grn_column_index(context, column, operator,
				 NULL, 0, NULL);
    if (n_indexes == 0)
	return rb_indexes;

    indexes = xmalloc(sizeof(grn_obj *) * n_indexes);
    n_indexes = grn_column_index(context, column, operator,
				 indexes, n_indexes, NULL);
    for (i = 0; i < n_indexes; i++) {
	VALUE rb_index;
	rb_index = GRNOBJECT2RVAL(Qnil, context, indexes[i], GRN_FALSE);
	rb_ary_push(rb_indexes, rb_index);
	grn_obj_unlink(context, indexes[i]);
    }
    xfree(indexes);
    return rb_indexes;
}
Ejemplo n.º 8
0
/*
 * 文字列 _query_ をパースする。
 * @overload parse(query, options={})
 *   @param [String] query パースする文字列
 *   @param [::Hash] options The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :default_column
 *     "column_name:hoge"ではなく"hoge"のようにcolumn_nameが指
 *     定されない条件の検索対象となるカラムを指定する。
 *   @option options :default_operator (Groonga::Operator::AND)
 *     "+"や"OR"で繋がれず、ただ列挙された複数の条件があった時、
 *     _expression_ 全体として各レコードをヒットとみなすかの論理
 *     条件を指定する。省略した場合はGroonga::Operator::AND。
 *
 *     - Groonga::Operator::OR :=
 *       レコードはいずれかの条件にマッチすればいい。 =:
 *     - Groonga::Operator::AND :=
 *       レコードは全ての条件にマッチしなければならない。 =:
 *     - Groonga::Operator::AND_NOT :=
 *       最初の条件にレコードはマッチし、残りの条件にレコードは
 *       マッチしてはならない。 =:
 *
 *   @option options :default_mode (Groonga::Operator::MATCH)
 *     検索時のモードを指定する。省略した場合はGroonga::Operator::MATCH。
 *     (FIXME: モードによってどういう動作になるかを書く。)
 *   @option options :syntax (:query)
 *     _query_ の構文を指定する。指定可能な値は以下の通り。省略
 *     した場合は +:query+ 。
 *
 *     - +:query+ :=
 *       「文字列1 OR 文字列2」で「"文字列1"あるいは"文字列2"
 *       にマッチという検索エンジンで利用できるような構文を使
 *       う。
 *       参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html =:
 *     - +nil+ :=
 *       +:query+と同様 =:
 *     - +:script+ :=
 *       「[カラム名] == [値]」というようにECMAScript風の構文を使う。
 *       参考: "Groongaのscript構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html =:
 *   @option options :allow_pragma
 *     _query_ の構文に query を用いているとき( +:syntax+
 *     オプション参照)、「*E-1」というようにクエリの先頭で
 *     pragmaを利用できるようにする。script構文を用いている
 *     ときはこのオプションを利用できない。
 *
 *     デフォルトではプラグマを利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_column
 *     _query_ の構文にqueryを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名:値」というようにカラム名を指定した
 *     条件式を利用できるようにする。script構文を用いていると
 *     きはこのオプションを利用できない。
 *
 *     デフォルトではカラム名を指定した条件式を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_update
 *     _query_ の構文にscriptを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名 = 値」というように更新操作を利用で
 *     きるようにする。query構文を用いているときはこのオプショ
 *     ンを利用できない。
 *
 *     デフォルトでは更新操作を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 */
static VALUE
rb_grn_expression_parse (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *expression, *default_column;
    grn_bool default_column_is_created = GRN_FALSE;
    grn_operator default_operator = GRN_OP_AND;
    grn_operator default_mode = GRN_OP_MATCH;
    grn_rc rc;
    char *query = NULL;
    unsigned query_size = 0;
    grn_expr_flags flags = 0;
    VALUE options, rb_query, rb_default_column, rb_default_operator;
    VALUE rb_default_mode, rb_syntax;
    VALUE rb_allow_pragma, rb_allow_column, rb_allow_update, rb_allow_leading_not;
    VALUE exception = Qnil;

    rb_scan_args(argc, argv, "11", &rb_query, &options);
    rb_grn_scan_options(options,
                        "default_column", &rb_default_column,
                        "default_operator", &rb_default_operator,
                        "default_mode", &rb_default_mode,
                        "syntax", &rb_syntax,
                        "allow_pragma", &rb_allow_pragma,
                        "allow_column", &rb_allow_column,
                        "allow_update", &rb_allow_update,
                        "allow_leading_not", &rb_allow_leading_not,
                        NULL);

    query = StringValuePtr(rb_query);
    query_size = RSTRING_LEN(rb_query);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    if (NIL_P(rb_default_column)) {
        default_column = NULL;
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_default_column, rb_cGrnObject))) {
        default_column = RVAL2GRNOBJECT(rb_default_column, &context);
    } else {
        default_column = RVAL2GRNBULK(rb_default_column, context, NULL);
        default_column_is_created = GRN_TRUE;
    }

    if (!NIL_P(rb_default_mode))
        default_mode = RVAL2GRNOPERATOR(rb_default_mode);
    if (!NIL_P(rb_default_operator))
        default_operator = RVAL2GRNSETOPERATOR(rb_default_operator);

    if (NIL_P(rb_syntax) ||
        rb_grn_equal_option(rb_syntax, "query")) {
        flags = GRN_EXPR_SYNTAX_QUERY;
    } else if (rb_grn_equal_option(rb_syntax, "script")) {
        flags = GRN_EXPR_SYNTAX_SCRIPT;
    } else {
        rb_raise(rb_eArgError,
                 "syntax should be one of "
                 "[nil, :query, :script]: %s",
                 rb_grn_inspect(rb_syntax));
    }

    if (NIL_P(rb_allow_pragma)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_pragma isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_pragma))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    }

    if (NIL_P(rb_allow_column)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_column isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_column))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    }

    if (NIL_P(rb_allow_update)) {
        flags |= GRN_EXPR_ALLOW_UPDATE;
    } else {
        if (RVAL2CBOOL(rb_allow_update))
            flags |= GRN_EXPR_ALLOW_UPDATE;
    }

    if (!NIL_P(rb_allow_leading_not)) {
        if (RVAL2CBOOL(rb_allow_leading_not))
            flags |= GRN_EXPR_ALLOW_LEADING_NOT;
    }

    rc = grn_expr_parse(context, expression, query, query_size,
                        default_column, default_mode, default_operator,
                        flags);
    if (rc != GRN_SUCCESS) {
        VALUE related_object;

        related_object =
            rb_ary_new_from_args(2,
                                 self,
                                 rb_ary_new_from_values(argc, argv));
        exception = rb_grn_context_to_exception(context, related_object);
    }
    if (default_column_is_created)
        grn_obj_unlink(context, default_column);

    if (!NIL_P(exception))
        rb_exc_raise(exception);

    return Qnil;
}