Groonga Cライブラリ grn_objの操作

## grn_obj とは・・・

Groonga における汎用オブジェクトです。
型を指定してあげることで、その型に応じたデータを持たせることができます。
v4.0.5 時点で数値型、文字列型、時間型、地理情報型が用意されており、
主にデータベースに値を渡す際の仲介バッファとして用います。

## 操作関数の概要

型ごとに使う関数は異なりますが、似通ったインタフェイスを持ちます。

#### 初期化

grn_obj オブジェクトを使うには、初期化が必要になります。

> GRN_*_INIT(obj,flags)

obj パラメータに、初期化したい grn_obj オブジェクトを指定します。
flags パラメータは、基本的には指定不要ですので、 0 を指定しましょう。

#### 値のセット

> GRN_*_SET(ctx,obj,val)

ctx パラメータに、`grn_ctx_open()`などで取得したコンテキストオブジェクトを指定します。
obj パラメータに、値をセットしたい grn_obj オブジェクトを指定します。
val パラメータに、セットしたい値を指定します。

#### 値の参照

> GRN_*_VALUE(obj)

obj パラメータに、値を参照したい grn_obj オブジェクトを指定します。

#### 解放処理

grn_objオブジェクトを使い終わったら、解放してあげましょう。

> void grn_obj_unlink(grn_ctx *ctx, grn_obj *obj);

ctx パラメータに、`grn_ctx_open()`などで取得したコンテキストオブジェクトを指定します。
obj パラメータに、解放したい grn_obj オブジェクトを指定します。

## 数値型、真偽値型

- INT8
- UINT8
- INT16
- UINT16
- INT32
- UINT32
- INT64
- UINT64
- BOOL

それでは grn_obj を使ってみましょう！
数値型は最もシンプルです。
数値型は v4.0.5 時点で9種類ありますが、 UINT32 型を使って、
初期化、値のセット、値の参照、解放までを行います。

```c
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <groonga/groonga.h>

int main (int argc, char **argv) {
  // ライブラリを初期化
  assert(grn_init() == GRN_SUCCESS);

  // コンテキストを取得
  grn_ctx *ctx;
  ctx = grn_ctx_open(0);
  assert(ctx != NULL);

  // 数値型を操作
  grn_obj intobj;
  GRN_UINT32_INIT(&intobj, 0);
  GRN_UINT32_SET(ctx, &intobj, 100);
  assert(GRN_UINT32_VALUE(&intobj) == 100);
  grn_obj_unlink(ctx, &intobj);

```
 
## 文字列型

- SHORT_TEXT
- TEXT
- LONG_TEXT

最も使う機会の多いであろう文字列型です。
文字列型は v4.0.5 時点で3種類ありますが、ここでは SHORT_TEXT 型を使います。
数値型との違いですが、SET 系の関数を使うことで文字列をセットできます。

- GRN_TEXT_SET(ctx,obj,str,len)
- GRN_TEXT_SETS(ctx,obj,str)

``GRN_TEXT_VALUE(obj)``で文字列の参照、``GRN_TEXT_LEN(obj)``で文字列長を取得できます。

```c
  // 文字列型を操作
  grn_obj textobj;
  GRN_SHORT_TEXT_INIT(&textobj, 0);
  GRN_TEXT_SETS(ctx, &textobj, "qiita");
  assert(strncmp(GRN_TEXT_VALUE(&textobj), "qiita", GRN_TEXT_LEN(&textobj)) == 0);

```

PUT系の関数を使うことで、文字列を逐次的に足していくことも可能です。

- GRN_TEXT_PUT(ctx,obj,str,len)
- GRN_TEXT_PUTC(ctx,obj,c)
- GRN_TEXT_PUTS(ctx,obj,str)

追加されたサイズに応じて内部バッファは伸長されるので、ストリームのように文字長を意識せずに使うことができます。

```c
  GRN_BULK_REWIND(&textobj);
  for (int i = 0; i < 5; ++i) {
    GRN_TEXT_PUTC(ctx, &textobj, 'a');
  }
  assert(strncmp(GRN_TEXT_VALUE(&textobj), "aaaaa", GRN_TEXT_LEN(&textobj)) == 0);
  grn_obj_unlink(ctx, &textobj);

```

さらに、参照渡しも可能です。

- GRN_TEXT_SET_REF(obj,str,len)

但し GRN_OBJ_DO_SHALLOW_COPY フラグを指定して、grn_objオブジェクトを初期化する必要があります。

```c
  GRN_SHORT_TEXT_INIT(&textobj, GRN_OBJ_DO_SHALLOW_COPY);
  static const char title[] = "qiita";
  GRN_TEXT_SET_REF(&textobj, title, strlen(title));
  assert(strncmp(GRN_TEXT_VALUE(&textobj), "qiita", GRN_TEXT_LEN(&textobj)) == 0);
  grn_obj_unlink(ctx, &textobj);

```

## 時間型

- TIME

時間型は、内部的には数値型の INT64 と同じですが、
パッキング用のユーティリティ関数が用意されています。

- GRN_TIME_PACK(sec, usec)
- GRN_TIME_UNPACK(time_value, sec, usec)

```c
  // 時間型を操作
  grn_obj timeobj;
  GRN_TIME_INIT(&timeobj, 0);
  GRN_TIME_SET(ctx, &timeobj, GRN_TIME_PACK(30, 5000));
  int sec, usec;
  GRN_TIME_UNPACK(GRN_TIME_VALUE(&timeobj), sec, usec);
  assert(sec == 30);
  assert(usec == 5000);
  grn_obj_unlink(ctx, &timeobj);

```

## 地理情報型

- TOKYO_GEO_POINT
- WGS84_GEO_POINT

最後に地理情報型です。
地理情報検索の操作に用います。

```c
  // 地理情報型を操作
  grn_obj geoobj;
  GRN_TOKYO_GEO_POINT_INIT(&geoobj, 0);
  GRN_GEO_POINT_SET(ctx, &geoobj, 128487316, 502920929);
  int latitude;
  int longitude;
  GRN_GEO_POINT_VALUE(geoobj, latitude, longitude);
  assert(latitude == 128487316);
  assert(longitude == 502920929);
  grn_obj_unlink(ctx, &geoobj);

  // コンテキストを破棄
  assert(grn_ctx_close(ctx) == GRN_SUCCESS);

  // ライブラリの終了処理
  assert(grn_fin() == GRN_SUCCESS);
}
```