[Groonga-commit] groonga/grnci at 41e2503 [master] Support more commands in v2.

Back to archive index

Susumu Yata null+****@clear*****
Mon Jun 19 11:40:35 JST 2017


Susumu Yata	2017-06-19 11:40:35 +0900 (Mon, 19 Jun 2017)

  New Revision: 41e250309336a9d2eb630965c49fb2b320122959
  https://github.com/groonga/grnci/commit/41e250309336a9d2eb630965c49fb2b320122959

  Message:
    Support more commands in v2.

  Modified files:
    v2/command.go
    v2/db.go
    v2/db_test.go
    v2/info.go

  Modified: v2/command.go (+2 -0)
===================================================================
--- v2/command.go    2017-06-16 22:46:33 +0900 (2b5089b)
+++ v2/command.go    2017-06-19 11:40:35 +0900 (ad68a19)
@@ -42,6 +42,8 @@ var formatParamValueDefault = func(value interface{}) (string, error) {
 		return strconv.FormatFloat(v, 'f', -1, 64), nil
 	case string:
 		return v, nil
+	// TODO: case time.Time:
+	// TODO: case Geo:
 	default:
 		return "", NewError(InvalidCommand, map[string]interface{}{
 			"value": value,

  Modified: v2/db.go (+594 -23)
===================================================================
--- v2/db.go    2017-06-16 22:46:33 +0900 (67be82c)
+++ v2/db.go    2017-06-19 11:40:35 +0900 (0709b5b)
@@ -7,6 +7,7 @@ import (
 	"io"
 	"io/ioutil"
 	"reflect"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -449,31 +450,95 @@ func (db *DB) Load(tbl string, values io.Reader, options *DBLoadOptions) (int, R
 	return db.recvInt(resp)
 }
 
+// encodeValue encodes a value.
+func (db *DB) encodeValue(body []byte, v reflect.Value) []byte {
+	for v.Kind() == reflect.Ptr {
+		if v.IsNil() {
+			return append(body, "null"...)
+		}
+		v = v.Elem()
+	}
+	switch v := v.Interface().(type) {
+	case bool:
+		return strconv.AppendBool(body, v)
+	case int:
+		return strconv.AppendInt(body, int64(v), 10)
+	case int8:
+		return strconv.AppendInt(body, int64(v), 10)
+	case int16:
+		return strconv.AppendInt(body, int64(v), 10)
+	case int32:
+		return strconv.AppendInt(body, int64(v), 10)
+	case int64:
+		return strconv.AppendInt(body, v, 10)
+	case uint:
+		return strconv.AppendUint(body, uint64(v), 10)
+	case uint8:
+		return strconv.AppendUint(body, uint64(v), 10)
+	case uint16:
+		return strconv.AppendUint(body, uint64(v), 10)
+	case uint32:
+		return strconv.AppendUint(body, uint64(v), 10)
+	case uint64:
+		return strconv.AppendUint(body, v, 10)
+	case float32:
+		return strconv.AppendFloat(body, float64(v), 'e', -1, 32)
+	case float64:
+		return strconv.AppendFloat(body, v, 'e', -1, 64)
+	case string:
+		b, _ := json.Marshal(v)
+		return append(body, b...)
+	case time.Time:
+		return strconv.AppendFloat(body, float64(v.UnixNano())/1000000000.0, 'f', -1, 64)
+	default:
+		return body
+	}
+}
+
 // encodeRow encodes a row.
 func (db *DB) encodeRow(body []byte, row reflect.Value, fis []*StructFieldInfo) []byte {
-	// TODO
+	body = append(body, '[')
+	for i, fi := range fis {
+		if i != 0 {
+			body = append(body, ',')
+		}
+		v := row.Field(fi.Index)
+		if v.Kind() == reflect.Ptr {
+			if v.IsNil() {
+				body = append(body, "null"...)
+				continue
+			}
+			v = v.Elem()
+		}
+		switch v.Kind() {
+		case reflect.Array, reflect.Slice:
+			body = append(body, '[')
+			for i := 0; i < v.Len(); i++ {
+				if i != 0 {
+					body = append(body, ',')
+				}
+				body = db.encodeValue(body, v.Index(i))
+			}
+			body = append(body, ']')
+		default:
+			body = db.encodeValue(body, v)
+		}
+	}
+	body = append(body, ']')
 	return body
 }
 
 // encodeRows encodes rows.
-func (db *DB) encodeRows(rows reflect.Value, fis []*StructFieldInfo) ([]byte, error) {
-	body := []byte("[")
-	for rows.Kind() == reflect.Ptr {
-		rows = rows.Elem()
-	}
-	switch rows.Kind() {
-	case reflect.Array, reflect.Slice:
-		for i := 0; i < rows.Len(); i++ {
-			row := rows.Index(i)
-			for row.Kind() == reflect.Ptr {
-				row = row.Elem()
-			}
-			body = db.encodeRow(body, row, fis)
+func (db *DB) encodeRows(body []byte, rows reflect.Value, fis []*StructFieldInfo) []byte {
+	n := rows.Len()
+	for i := 0; i < n; i++ {
+		if i != 0 {
+			body = append(body, ',')
 		}
-	case reflect.Struct:
+		row := rows.Index(i)
+		body = db.encodeRow(body, row, fis)
 	}
-	body = append(body, ']')
-	return body, nil
+	return body
 }
 
 // LoadRows executes load.
@@ -496,16 +561,43 @@ func (db *DB) LoadRows(tbl string, rows interface{}, options *DBLoadOptions) (in
 			fi, ok := si.FieldsByColumnName[col]
 			if !ok {
 				return 0, nil, NewError(InvalidCommand, map[string]interface{}{
-					"error": "",
+					"column": col,
+					"error":  "The column has no assciated field.",
 				})
 			}
 			fis = append(fis, fi)
 		}
 	}
-	body, err := db.encodeRows(reflect.ValueOf(rows), fis)
-	if err != nil {
-		return 0, nil, err
+
+	body := []byte("[")
+	v := reflect.ValueOf(rows)
+	switch v.Kind() {
+	case reflect.Ptr:
+		if v.IsNil() {
+			return 0, nil, NewError(InvalidCommand, map[string]interface{}{
+				"rows":  nil,
+				"error": "The rows must not be nil.",
+			})
+		}
+		v = v.Elem()
+		if v.Kind() != reflect.Struct {
+			return 0, nil, NewError(InvalidCommand, map[string]interface{}{
+				"type":  reflect.TypeOf(rows).Name(),
+				"error": "The type is not supported.",
+			})
+		}
+		body = db.encodeRow(body, v, fis)
+	case reflect.Array, reflect.Slice:
+		body = db.encodeRows(body, v, fis)
+	case reflect.Struct:
+		body = db.encodeRow(body, v, fis)
+	default:
+		return 0, nil, NewError(InvalidCommand, map[string]interface{}{
+			"type":  reflect.TypeOf(rows).Name(),
+			"error": "The type is not supported.",
+		})
 	}
+	body = append(body, ']')
 	return db.Load(tbl, bytes.NewReader(body), options)
 }
 
@@ -586,6 +678,41 @@ func (db *DB) LogReopen() (bool, Response, error) {
 	return db.recvBool(resp)
 }
 
+// DBNormalizedText is a result of normalize.
+type DBNormalizedText struct {
+	Normalized string   `json:"normalized"`
+	Types      []string `json:"types"`
+	Checks     []int    `json:"checks"`
+}
+
+// Normalize executes normalize.
+func (db *DB) Normalize(normalizer, str string, flags []string) (*DBNormalizedText, Response, error) {
+	params := map[string]interface{}{
+		"normalizer": normalizer,
+		"string":     str,
+	}
+	if flags != nil {
+		params["flags"] = flags
+	}
+	resp, err := db.Invoke("normalize", params, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer resp.Close()
+	jsonData, err := ioutil.ReadAll(resp)
+	if err != nil {
+		return nil, resp, err
+	}
+	var result DBNormalizedText
+	if err := json.Unmarshal(jsonData, &result); err != nil {
+		return nil, resp, NewError(InvalidResponse, map[string]interface{}{
+			"method": "json.Unmarshal",
+			"error":  err.Error(),
+		})
+	}
+	return &result, resp, nil
+}
+
 // DBNormalizer is a result of tokenizer_list.
 type DBNormalizer struct {
 	Name string `json:"name"`
@@ -904,6 +1031,9 @@ func (db *DB) Select(tbl string, options *DBSelectOptions) (Response, error) {
 		params["sort_keys"] = options.SortKeys
 	}
 	if options.OutputColumns != nil {
+		params["output_columns"] = options.OutputColumns
+	}
+	if options.OutputColumns != nil {
 		params["query"] = options.Query
 	}
 	if options.Offset != 0 {
@@ -957,10 +1087,342 @@ func (db *DB) Select(tbl string, options *DBSelectOptions) (Response, error) {
 	return db.Invoke("select", params, nil)
 }
 
+// parseRows parses rows.
+func (db *DB) parseRows(rows interface{}, data []byte, fis []*StructFieldInfo) (int, error) {
+	var raw [][][]json.RawMessage
+	if err := json.Unmarshal(data, &raw); err != nil {
+		return 0, NewError(InvalidResponse, map[string]interface{}{
+			"method": "json.Unmarshal",
+			"error":  err.Error(),
+		})
+	}
+
+	var nHits int
+	if err := json.Unmarshal(raw[0][0][0], &nHits); err != nil {
+		return 0, err
+	}
+
+	rawCols := raw[0][1]
+	nCols := len(rawCols)
+	if nCols != len(fis) {
+		// Remove _score from fields if _score does not exist in the response.
+		for i, field := range fis {
+			if field.ColumnName == "_score" {
+				hasScore := false
+				for _, rawCol := range rawCols {
+					var nameType []string
+					if err := json.Unmarshal(rawCol, &nameType); err != nil {
+						return 0, NewError(InvalidResponse, map[string]interface{}{
+							"method": "json.Unmarshal",
+							"error":  err.Error(),
+						})
+					}
+					if nameType[0] == "_score" {
+						hasScore = true
+						break
+					}
+				}
+				if !hasScore {
+					for j := i + 1; j < len(fis); j++ {
+						fis[j-1] = fis[j]
+					}
+					fis = fis[:len(fis)-1]
+				}
+				break
+			}
+		}
+		if nCols != len(fis) {
+			return 0, NewError(InvalidResponse, map[string]interface{}{
+				"nFields": len(fis),
+				"nCols":   nCols,
+				"error":   "nFields and nColumns must be same.",
+			})
+		}
+	}
+	// FIXME: the following check disallows functions.
+	//	for i, rawCol := range rawCols {
+	//		var nameType []string
+	//		if err := json.Unmarshal(rawCol, &nameType); err != nil {
+	//			return 0, err
+	//		}
+	//		if nameType[0] != fields[i].ColumnName() {
+	//			return 0, fmt.Errorf("column %#v expected but column %#v actual",
+	//				fields[i].ColumnName(), nameType[0])
+	//		}
+	//	}
+
+	rawRecs := raw[0][2:]
+	nRecs := len(rawRecs)
+
+	recs := reflect.ValueOf(rows).Elem()
+	recs.Set(reflect.MakeSlice(recs.Type(), nRecs, nRecs))
+	for i := 0; i < nRecs; i++ {
+		rec := recs.Index(i)
+		for j, field := range fis {
+			ptr := rec.Field(field.Index).Addr()
+			switch v := ptr.Interface().(type) {
+			case *bool:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *int:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *int8:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *int16:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *int32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *int64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *uint:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *uint8:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *uint16:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *uint32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *uint64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *float32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *float64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *string:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *time.Time:
+				var f float64
+				if err := json.Unmarshal(rawRecs[i][j], &f); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+				*v = time.Unix(int64(f), int64(f*1000000)%1000000)
+			case *[]bool:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]int:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]int8:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]int16:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]int32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]int64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]uint:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]uint8:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]uint16:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]uint32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]uint64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]float32:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]float64:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]string:
+				if err := json.Unmarshal(rawRecs[i][j], v); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+			case *[]time.Time:
+				var f []float64
+				if err := json.Unmarshal(rawRecs[i][j], &f); err != nil {
+					return 0, NewError(InvalidResponse, map[string]interface{}{
+						"method": "json.Unmarshal",
+						"error":  err.Error(),
+					})
+				}
+				*v = make([]time.Time, len(f))
+				for i := range f {
+					(*v)[i] = time.Unix(int64(f[i]), int64(f[i]*1000000)%1000000)
+				}
+			}
+		}
+	}
+	return nHits, nil
+
+}
+
 // SelectRows executes select.
 func (db *DB) SelectRows(tbl string, rows interface{}, options *DBSelectOptions) (int, Response, error) {
-	// TODO
-	return 0, nil, nil
+	if options == nil {
+		options = NewDBSelectOptions()
+	}
+	si, err := GetStructInfo(rows)
+	if err != nil {
+		return 0, nil, err
+	}
+	var fis []*StructFieldInfo
+	if options.OutputColumns == nil {
+		fis = si.Fields
+		for _, fi := range fis {
+			options.OutputColumns = append(options.OutputColumns, fi.ColumnName)
+		}
+	} else {
+		for _, col := range options.OutputColumns {
+			fi, ok := si.FieldsByColumnName[col]
+			if !ok {
+				return 0, nil, NewError(InvalidCommand, map[string]interface{}{
+					"column": col,
+					"error":  "The column has no assciated field.",
+				})
+			}
+			fis = append(fis, fi)
+		}
+	}
+	resp, err := db.Select(tbl, options)
+	if err != nil {
+		return 0, nil, err
+	}
+	defer resp.Close()
+	data, err := ioutil.ReadAll(resp)
+	if err != nil {
+		return 0, nil, err
+	}
+	n, err := db.parseRows(rows, data, fis)
+	return n, resp, err
 }
 
 // DBStatus is a response of status.
@@ -1261,6 +1723,62 @@ func (db *DB) TableRename(name, newName string) (bool, Response, error) {
 	return db.recvBool(resp)
 }
 
+// DBTableTokenizeOptions is options of DB.TableTokenize.
+type DBTableTokenizeOptions struct {
+	Flags       []string
+	Mode        string
+	IndexColumn string
+}
+
+// NewDBTableTokenizeOptions returns the default DBTableTokenizeOptions.
+func NewDBTableTokenizeOptions() *DBTableTokenizeOptions {
+	return &DBTableTokenizeOptions{}
+}
+
+// DBToken is a result of table_tokenize and tokenize.
+type DBToken struct {
+	Position    int    `json:"position"`
+	ForcePrefix bool   `json:"force_prefix"`
+	Value       string `json:"value"`
+}
+
+// TableTokenize executes tokenize.
+func (db *DB) TableTokenize(tbl, str string, options *DBTableTokenizeOptions) ([]DBToken, Response, error) {
+	if options == nil {
+		options = NewDBTableTokenizeOptions()
+	}
+	params := map[string]interface{}{
+		"table":  tbl,
+		"string": str,
+	}
+	if options.Flags != nil {
+		params["flags"] = options.Flags
+	}
+	if options.Mode != "" {
+		params["mode"] = options.Mode
+	}
+	if options.IndexColumn != "" {
+		params["index_column"] = options.IndexColumn
+	}
+	resp, err := db.Invoke("table_tokenize", params, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer resp.Close()
+	jsonData, err := ioutil.ReadAll(resp)
+	if err != nil {
+		return nil, resp, err
+	}
+	var result []DBToken
+	if err := json.Unmarshal(jsonData, &result); err != nil {
+		return nil, resp, NewError(InvalidResponse, map[string]interface{}{
+			"method": "json.Unmarshal",
+			"error":  err.Error(),
+		})
+	}
+	return result, resp, nil
+}
+
 // ThreadLimit executes thread_limit.
 // If max < 0, max is not passed to thread_limit.
 func (db *DB) ThreadLimit(max int) (int, Response, error) {
@@ -1277,6 +1795,59 @@ func (db *DB) ThreadLimit(max int) (int, Response, error) {
 	return db.recvInt(resp)
 }
 
+// DBTokenizeOptions is options of DB.Tokenize.
+type DBTokenizeOptions struct {
+	Normalizer   string
+	Flags        []string
+	Mode         string
+	TokenFilters []string
+}
+
+// NewDBTokenizeOptions returns the default DBTokenizeOptions.
+func NewDBTokenizeOptions() *DBTokenizeOptions {
+	return &DBTokenizeOptions{}
+}
+
+// Tokenize executes tokenize.
+func (db *DB) Tokenize(tokenizer, str string, options *DBTokenizeOptions) ([]DBToken, Response, error) {
+	if options == nil {
+		options = NewDBTokenizeOptions()
+	}
+	params := map[string]interface{}{
+		"tokenizer": tokenizer,
+		"string":    str,
+	}
+	if options.Normalizer != "" {
+		params["normalizer"] = options.Normalizer
+	}
+	if options.Flags != nil {
+		params["flags"] = options.Flags
+	}
+	if options.Mode != "" {
+		params["mode"] = options.Mode
+	}
+	if options.TokenFilters != nil {
+		params["token_filters"] = options.TokenFilters
+	}
+	resp, err := db.Invoke("tokenize", params, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+	defer resp.Close()
+	jsonData, err := ioutil.ReadAll(resp)
+	if err != nil {
+		return nil, resp, err
+	}
+	var result []DBToken
+	if err := json.Unmarshal(jsonData, &result); err != nil {
+		return nil, resp, NewError(InvalidResponse, map[string]interface{}{
+			"method": "json.Unmarshal",
+			"error":  err.Error(),
+		})
+	}
+	return result, resp, nil
+}
+
 // DBTokenizer is a result of tokenizer_list.
 type DBTokenizer struct {
 	Name string `json:"name"`

  Modified: v2/db_test.go (+165 -1)
===================================================================
--- v2/db_test.go    2017-06-16 22:46:33 +0900 (25fd77f)
+++ v2/db_test.go    2017-06-19 11:40:35 +0900 (7033029)
@@ -5,6 +5,7 @@ import (
 	"log"
 	"strings"
 	"testing"
+	"time"
 )
 
 func TestDBColumnList(t *testing.T) {
@@ -116,7 +117,71 @@ func TestDBLoad(t *testing.T) {
 
 	result, resp, err := db.Load("Tbl", strings.NewReader("[]"), nil)
 	if err != nil {
-		t.Fatalf("db.Dump failed: %v", err)
+		t.Fatalf("db.Load failed: %v", err)
+	}
+	log.Printf("result = %d", result)
+	log.Printf("resp = %#v", resp)
+	if err := resp.Err(); err != nil {
+		log.Printf("error = %#v", err)
+	}
+}
+
+func TestDBLoadRows(t *testing.T) {
+	client, err := NewHTTPClient("", nil)
+	if err != nil {
+		t.Skipf("NewHTTPClient failed: %v", err)
+	}
+	db := NewDB(client)
+	defer db.Close()
+
+	type Row struct {
+		Key          string      `grnci:"_key"`
+		Bool         bool        `grnci:"bool"`
+		Int          int         `grnci:"int"`
+		Int8         int8        `grnci:"int8"`
+		Int16        int16       `grnci:"int16"`
+		Int32        int32       `grnci:"int32"`
+		Int64        int64       `grnci:"int64"`
+		UInt         uint        `grnci:"uint"`
+		UInt8        uint8       `grnci:"uint8"`
+		UInt16       uint16      `grnci:"uint16"`
+		UInt32       uint32      `grnci:"uint32"`
+		UInt64       uint64      `grnci:"uint64"`
+		Float32      float32     `grnci:"float32"`
+		Float64      float64     `grnci:"float64"`
+		String       string      `grnci:"string"`
+		Time         time.Time   `grnci:"time"`
+		BoolSlice    []bool      `grnci:"bool_slice"`
+		IntSlice     []int       `grnci:"int_slice"`
+		Int8Slice    []int8      `grnci:"int8_slice"`
+		Int16Slice   []int16     `grnci:"int16_slice"`
+		Int32Slice   []int32     `grnci:"int32_slice"`
+		Int64Slice   []int64     `grnci:"int64_slice"`
+		UIntSlice    []uint      `grnci:"uint_slice"`
+		UInt8Slice   []uint8     `grnci:"uint8_slice"`
+		UInt16Slice  []uint16    `grnci:"uint16_slice"`
+		UInt32Slice  []uint32    `grnci:"uint32_slice"`
+		UInt64Slice  []uint64    `grnci:"uint64_slice"`
+		Float32Slice []float32   `grnci:"float32_slice"`
+		Float64Slice []float64   `grnci:"float64_slice"`
+		StringSlice  []string    `grnci:"string_slice"`
+		TimeSlice    []time.Time `grnci:"time_slice"`
+	}
+	rows := []Row{
+		Row{
+			Key:         "Appke",
+			Time:        time.Now(),
+			StringSlice: []string{"iOS", "Safari"},
+		},
+		Row{
+			Key:         "Microsoft",
+			Time:        time.Now(),
+			StringSlice: []string{"Windows", "Edge"},
+		},
+	}
+	result, resp, err := db.LoadRows("Tbl", rows, nil)
+	if err != nil {
+		t.Fatalf("db.LoadRows failed: %v", err)
 	}
 	log.Printf("result = %d", result)
 	log.Printf("resp = %#v", resp)
@@ -125,6 +190,27 @@ func TestDBLoad(t *testing.T) {
 	}
 }
 
+func TestDBNormalize(t *testing.T) {
+	client, err := NewHTTPClient("", nil)
+	if err != nil {
+		t.Skipf("NewHTTPClient failed: %v", err)
+	}
+	db := NewDB(client)
+	defer db.Close()
+
+	result, resp, err := db.Normalize("NormalizerAuto", "LaTeX", []string{
+		"WITH_TYPES", "WITH_CHECKS",
+	})
+	if err != nil {
+		t.Fatalf("db.Normalize failed: %v", err)
+	}
+	log.Printf("result = %#v", result)
+	log.Printf("resp = %#v", resp)
+	if err := resp.Err(); err != nil {
+		log.Printf("error = %#v", err)
+	}
+}
+
 func TestDBNormalizerList(t *testing.T) {
 	client, err := NewHTTPClient("", nil)
 	if err != nil {
@@ -186,6 +272,44 @@ func TestDBSelect(t *testing.T) {
 	}
 }
 
+func TestDBSelectRows(t *testing.T) {
+	client, err := NewHTTPClient("", nil)
+	if err != nil {
+		t.Skipf("NewHTTPClient failed: %v", err)
+	}
+	db := NewDB(client)
+	defer db.Close()
+
+	type Row struct {
+		Key       string      `grnci:"_key"`
+		Bool      bool        `grnci:"bool"`
+		Int8      int8        `grnci:"int8"`
+		Int16     int16       `grnci:"int16"`
+		Int32     int32       `grnci:"int32"`
+		Int64     int64       `grnci:"int64"`
+		UInt8     int8        `grnci:"uint8"`
+		UInt16    int16       `grnci:"uint16"`
+		UInt32    int32       `grnci:"uint32"`
+		UInt64    int64       `grnci:"uint64"`
+		Float     float64     `grnci:"float"`
+		String    string      `grnci:"string"`
+		Time      time.Time   `grnci:"time"`
+		TimeSlice []time.Time `grnci:"time_slice"`
+	}
+	var rows []Row
+	n, resp, err := db.SelectRows("Tbl", &rows, nil)
+	if err != nil {
+		t.Fatalf("db.SelectRows failed: %v", err)
+	}
+	log.Printf("n = %d", n)
+	log.Printf("rows = %#v", rows)
+	log.Printf("time = %s", rows[0].Time)
+	log.Printf("resp = %#v", resp)
+	if err := resp.Err(); err != nil {
+		log.Printf("error = %#v", err)
+	}
+}
+
 func TestDBStatus(t *testing.T) {
 	client, err := NewHTTPClient("", nil)
 	if err != nil {
@@ -224,6 +348,46 @@ func TestDBTableList(t *testing.T) {
 	}
 }
 
+func TestDBTableTokenize(t *testing.T) {
+	client, err := NewHTTPClient("", nil)
+	if err != nil {
+		t.Skipf("NewHTTPClient failed: %v", err)
+	}
+	db := NewDB(client)
+	defer db.Close()
+
+	options := NewDBTableTokenizeOptions()
+	options.Mode = "ADD"
+	result, resp, err := db.TableTokenize("Tbl", "あいうえお", options)
+	if err != nil {
+		t.Fatalf("db.TableTokenize failed: %v", err)
+	}
+	log.Printf("result = %#v", result)
+	log.Printf("resp = %#v", resp)
+	if err := resp.Err(); err != nil {
+		log.Printf("error = %#v", err)
+	}
+}
+
+func TestDBTokenize(t *testing.T) {
+	client, err := NewHTTPClient("", nil)
+	if err != nil {
+		t.Skipf("NewHTTPClient failed: %v", err)
+	}
+	db := NewDB(client)
+	defer db.Close()
+
+	result, resp, err := db.Tokenize("TokenBigram", "あいうえお", nil)
+	if err != nil {
+		t.Fatalf("db.Tokenize failed: %v", err)
+	}
+	log.Printf("result = %#v", result)
+	log.Printf("resp = %#v", resp)
+	if err := resp.Err(); err != nil {
+		log.Printf("error = %#v", err)
+	}
+}
+
 func TestDBTruncate(t *testing.T) {
 	client, err := NewHTTPClient("", nil)
 	if err != nil {

  Modified: v2/info.go (+6 -8)
===================================================================
--- v2/info.go    2017-06-16 22:46:33 +0900 (8b8434f)
+++ v2/info.go    2017-06-19 11:40:35 +0900 (8efeff8)
@@ -11,7 +11,6 @@ import (
 const (
 	// tagKey is the tag key for struct fields associated with Groonga columns.
 	tagKey = "grnci"
-
 	// tagSep is the separator in a struct field tag value.
 	tagSep = ';'
 )
@@ -62,20 +61,19 @@ func newStructFieldInfo(index int, field *reflect.StructField) (*StructFieldInfo
 	case float32, float64:
 	case string:
 	case time.Time:
-	case Geo:
 	default:
 		return nil, NewError(InvalidType, map[string]interface{}{
 			"type":  typ.Name(),
 			"error": "The type is not supported.",
 		})
 	}
-
 	return &StructFieldInfo{
-		Index:     index,
-		Field:     field,
-		Tags:      tags,
-		Type:      field.Type,
-		Dimension: dim,
+		Index:      index,
+		Field:      field,
+		Tags:       tags,
+		Type:       field.Type,
+		ColumnName: tags[0],
+		Dimension:  dim,
 	}, nil
 }
 
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index