Susumu Yata
null+****@clear*****
Fri Jun 16 22:46:33 JST 2017
Susumu Yata 2017-06-16 22:46:33 +0900 (Fri, 16 Jun 2017) New Revision: 0f564f4f2a86c222abf1358b5eb95c4fba34d24c https://github.com/groonga/grnci/commit/0f564f4f2a86c222abf1358b5eb95c4fba34d24c Message: Support more commands in v2. Modified files: v2/command.go v2/db.go v2/db_test.go Modified: v2/command.go (+1 -1) =================================================================== --- v2/command.go 2017-06-16 15:37:24 +0900 (b5bfac0) +++ v2/command.go 2017-06-16 22:46:33 +0900 (2b5089b) @@ -293,7 +293,7 @@ var commandFormats = map[string]*commandFormat{ newParamFormat("name", nil, true), newParamFormat("flags", formatParamValueFlags, true), newParamFormat("type", nil, true), - newParamFormat("source", nil, false), + newParamFormat("source", formatParamValueCSV, false), ), "column_list": newCommandFormat( nil, Modified: v2/db.go (+717 -146) =================================================================== --- v2/db.go 2017-06-16 15:37:24 +0900 (442a49f) +++ v2/db.go 2017-06-16 22:46:33 +0900 (67be82c) @@ -21,173 +21,362 @@ func NewDB(h Handler) *DB { return &DB{Handler: h} } -// ColumnCreate executes column_create. -func (db *DB) ColumnCreate(tbl, name, typ string, flags []string) (bool, Response, error) { - cmd, err := NewCommand("column_create", map[string]interface{}{ - "table": tbl, - "name": name, - }) +// recvBool reads the bool result from resp. +func (db *DB) recvBool(resp Response) (bool, Response, error) { + defer resp.Close() + jsonData, err := ioutil.ReadAll(resp) + if err != nil { + return false, resp, err + } + var result bool + if err := json.Unmarshal(jsonData, &result); err != nil { + return false, resp, NewError(InvalidResponse, map[string]interface{}{ + "method": "json.Unmarshal", + "error": err.Error(), + }) + } + return result, resp, nil +} + +// recvInt reads the int result from resp. +func (db *DB) recvInt(resp Response) (int, Response, error) { + defer resp.Close() + jsonData, err := ioutil.ReadAll(resp) + if err != nil { + return 0, resp, err + } + var result int + if err := json.Unmarshal(jsonData, &result); err != nil { + return 0, resp, NewError(InvalidResponse, map[string]interface{}{ + "method": "json.Unmarshal", + "error": err.Error(), + }) + } + return result, resp, nil +} + +// recvInt reads the string result from resp. +func (db *DB) recvString(resp Response) (string, Response, error) { + defer resp.Close() + jsonData, err := ioutil.ReadAll(resp) + if err != nil { + return "", resp, err + } + var result string + if err := json.Unmarshal(jsonData, &result); err != nil { + return "", resp, NewError(InvalidResponse, map[string]interface{}{ + "method": "json.Unmarshal", + "error": err.Error(), + }) + } + return result, resp, nil +} + +// CacheLimit executes cache_limit. +// If max < 0, max is not passed to cache_limit. +func (db *DB) CacheLimit(max int) (int, Response, error) { + var params map[string]interface{} + if max >= 0 { + params = map[string]interface{}{ + "max": max, + } + } + resp, err := db.Invoke("cache_limit", params, nil) + if err != nil { + return 0, nil, err + } + return db.recvInt(resp) +} + +// ColumnCopy executes column_copy. +func (db *DB) ColumnCopy(from, to string) (bool, Response, error) { + i := strings.IndexByte(from, '.') + if i == -1 { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "from": from, + "error": "The from must contain a dot.", + }) + } + fromTable := from[:i] + fromName := from[i+1:] + if i = strings.IndexByte(to, '.'); i == -1 { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "to": to, + "error": "The to must contain a dot.", + }) + } + toTable := to[:i] + toName := to[i+1:] + resp, err := db.Invoke("column_copy", map[string]interface{}{ + "from_table": fromTable, + "from_name": fromName, + "to_table": toTable, + "to_name": toName, + }, nil) if err != nil { return false, nil, err } + return db.recvBool(resp) +} + +// ColumnCreate executes column_create. +func (db *DB) ColumnCreate(name, typ string, flags []string) (bool, Response, error) { + i := strings.IndexByte(name, '.') + if i == -1 { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "name": name, + "error": "The name must contain a dot.", + }) + } + params := map[string]interface{}{ + "table": name[:i], + "name": name[i+1:], + } typFlag := "COLUMN_SCALAR" - withSection := false - src := "" + var srcs []string if strings.HasPrefix(typ, "[]") { typFlag = "COLUMN_VECTOR" typ = typ[2:] } else if idx := strings.IndexByte(typ, '.'); idx != -1 { typFlag = "COLUMN_INDEX" - src = typ[idx+1:] + srcs = strings.Split(typ[idx+1:], ",") typ = typ[:idx] - if idx := strings.IndexByte(src, ','); idx != -1 { - withSection = true - } } flags = append(flags, typFlag) - if withSection { + if len(srcs) > 1 { flags = append(flags, "WITH_SECTION") } - if err := cmd.SetParam("flags", flags); err != nil { - return false, nil, err + params["flags"] = flags + params["type"] = typ + if srcs != nil { + params["source"] = srcs } - if err := cmd.SetParam("type", typ); err != nil { + resp, err := db.Invoke("column_create", params, nil) + if err != nil { return false, nil, err } - if src != "" { - if err := cmd.SetParam("source", src); err != nil { - return false, nil, err - } - } - resp, err := db.Query(cmd) + return db.recvBool(resp) +} + +// DBColumn is a result of column_list. +type DBColumn struct { + ID uint32 `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Type string `json:"type"` + Flags []string `json:"flags"` + Domain string `json:"domain"` + Range string `json:"range"` + Sources []string `json:"source"` +} + +// ColumnList executes column_list. +func (db *DB) ColumnList(tbl string) ([]DBColumn, Response, error) { + resp, err := db.Invoke("column_list", map[string]interface{}{ + "table": tbl, + }, nil) if err != nil { - return false, nil, err + return nil, nil, err } defer resp.Close() jsonData, err := ioutil.ReadAll(resp) if err != nil { - return false, resp, err + return nil, resp, err } - var result bool + var result [][]interface{} if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ + return nil, resp, NewError(InvalidResponse, map[string]interface{}{ "method": "json.Unmarshal", "error": err.Error(), }) } - return result, resp, nil + if len(result) == 0 { + return nil, resp, NewError(InvalidResponse, map[string]interface{}{ + "error": "The result is empty.", + }) + } + var fields []string + for _, meta := range result[0] { + if values, ok := meta.([]interface{}); ok { + if field, ok := values[0].(string); ok { + fields = append(fields, field) + } + } + } + var columns []DBColumn + for _, values := range result[1:] { + var column DBColumn + for i := 0; i < len(fields) && i < len(values); i++ { + switch fields[i] { + case "id": + if v, ok := values[i].(float64); ok { + column.ID = uint32(v) + } + case "name": + if v, ok := values[i].(string); ok { + column.Name = v + } + case "path": + if v, ok := values[i].(string); ok { + column.Path = v + } + case "type": + if v, ok := values[i].(string); ok { + column.Type = v + } + case "flags": + if v, ok := values[i].(string); ok { + column.Flags = strings.Split(v, "|") + } + case "domain": + if v, ok := values[i].(string); ok { + column.Domain = v + } + case "range": + if v, ok := values[i].(string); ok { + column.Range = v + } + case "source": + if vs, ok := values[i].([]interface{}); ok { + for _, v := range vs { + if v, ok := v.(string); ok { + column.Sources = append(column.Sources, v) + } + } + } + } + } + columns = append(columns, column) + } + return columns, resp, nil } // ColumnRemove executes column_remove. -func (db *DB) ColumnRemove(tbl, name string) (bool, Response, error) { - cmd, err := NewCommand("column_remove", map[string]interface{}{ - "table": tbl, - "name": name, - }) +func (db *DB) ColumnRemove(name string) (bool, Response, error) { + i := strings.IndexByte(name, '.') + if i == -1 { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "name": name, + "error": "The name must contain a dot.", + }) + } + resp, err := db.Invoke("column_remove", map[string]interface{}{ + "table": name[:i], + "name": name[i+1:], + }, nil) if err != nil { return false, nil, err } - resp, err := db.Query(cmd) + return db.recvBool(resp) +} + +// ColumnRename executes column_rename. +func (db *DB) ColumnRename(name, newName string) (bool, Response, error) { + i := strings.IndexByte(name, '.') + if i == -1 { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "name": name, + "error": "The name must contain a dot.", + }) + } + if j := strings.IndexByte(newName, '.'); j != -1 { + if i != j || name[:i] != newName[:i] { + return false, nil, NewError(InvalidCommand, map[string]interface{}{ + "name": name, + "newName": newName, + "error": "The names have different table names.", + }) + } + newName = newName[j+1:] + } + resp, err := db.Invoke("column_rename", map[string]interface{}{ + "table": name[:i], + "name": name[i+1:], + "new_name": newName, + }, nil) if err != nil { return false, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) + return db.recvBool(resp) +} + +// ConfigDelete executes config_delete. +func (db *DB) ConfigDelete(key, value string) (bool, Response, error) { + resp, err := db.Invoke("config_delete", map[string]interface{}{ + "key": key, + }, nil) if err != nil { - return false, resp, err + return false, nil, err } - var result bool - if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) + return db.recvBool(resp) +} + +// ConfigGet executes config_get. +func (db *DB) ConfigGet(key string) (string, Response, error) { + resp, err := db.Invoke("config_get", map[string]interface{}{ + "key": key, + }, nil) + if err != nil { + return "", nil, err } - return result, resp, nil + return db.recvString(resp) } -// DeleteByID executes delete. -func (db *DB) DeleteByID(tbl string, id int) (bool, Response, error) { - cmd, err := NewCommand("delete", map[string]interface{}{ - "table": tbl, - "id": id, - }) +// ConfigSet executes config_set. +func (db *DB) ConfigSet(key, value string) (bool, Response, error) { + resp, err := db.Invoke("config_set", map[string]interface{}{ + "key": key, + "value": value, + }, nil) if err != nil { return false, nil, err } - resp, err := db.Query(cmd) + return db.recvBool(resp) +} + +// DatabaseUnmap executes database_unmap. +func (db *DB) DatabaseUnmap() (bool, Response, error) { + resp, err := db.Invoke("delete", nil, nil) if err != nil { return false, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) + return db.recvBool(resp) +} + +// DeleteByID executes delete. +func (db *DB) DeleteByID(tbl string, id int) (bool, Response, error) { + resp, err := db.Invoke("delete", map[string]interface{}{ + "table": tbl, + "id": id, + }, nil) if err != nil { - return false, resp, err - } - var result bool - if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) + return false, nil, err } - return result, resp, nil + return db.recvBool(resp) } // DeleteByKey executes delete. func (db *DB) DeleteByKey(tbl string, key interface{}) (bool, Response, error) { - cmd, err := NewCommand("delete", map[string]interface{}{ + resp, err := db.Invoke("delete", map[string]interface{}{ "table": tbl, "key": key, - }) - if err != nil { - return false, nil, err - } - resp, err := db.Query(cmd) + }, nil) if err != nil { return false, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) - if err != nil { - return false, resp, err - } - var result bool - if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) - } - return result, resp, nil + return db.recvBool(resp) } // DeleteByFilter executes delete. func (db *DB) DeleteByFilter(tbl, filter string) (bool, Response, error) { - cmd, err := NewCommand("delete", map[string]interface{}{ + resp, err := db.Invoke("delete", map[string]interface{}{ "table": tbl, "filter": filter, - }) - if err != nil { - return false, nil, err - } - resp, err := db.Query(cmd) + }, nil) if err != nil { return false, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) - if err != nil { - return false, resp, err - } - var result bool - if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) - } - return result, resp, nil + return db.recvBool(resp) } // DBDumpOptions stores options for DB.Dump. @@ -253,28 +442,11 @@ func (db *DB) Load(tbl string, values io.Reader, options *DBLoadOptions) (int, R if options.IfExists != "" { params["ifexists"] = options.IfExists } - cmd, err := NewCommand("load", params) - if err != nil { - return 0, nil, err - } - cmd.SetBody(values) - resp, err := db.Query(cmd) + resp, err := db.Invoke("load", params, values) if err != nil { return 0, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) - if err != nil { - return 0, resp, err - } - var result int - if err := json.Unmarshal(jsonData, &result); err != nil { - return 0, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) - } - return result, resp, nil + return db.recvInt(resp) } // encodeRow encodes a row. @@ -337,6 +509,292 @@ func (db *DB) LoadRows(tbl string, rows interface{}, options *DBLoadOptions) (in return db.Load(tbl, bytes.NewReader(body), options) } +// LockAcquire executes lock_acquire. +func (db *DB) LockAcquire(target string) (bool, Response, error) { + var params map[string]interface{} + if target != "" { + params = map[string]interface{}{ + "target_name": target, + } + } + resp, err := db.Invoke("lock_acquire", params, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// LockClear executes lock_clear. +func (db *DB) LockClear(target string) (bool, Response, error) { + var params map[string]interface{} + if target != "" { + params = map[string]interface{}{ + "target_name": target, + } + } + resp, err := db.Invoke("lock_clear", params, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// LockRelease executes lock_release. +func (db *DB) LockRelease(target string) (bool, Response, error) { + var params map[string]interface{} + if target != "" { + params = map[string]interface{}{ + "target_name": target, + } + } + resp, err := db.Invoke("lock_release", params, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// LogLevel executes log_level. +func (db *DB) LogLevel(level string) (bool, Response, error) { + resp, err := db.Invoke("log_level", map[string]interface{}{ + "level": level, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// LogPut executes log_put. +func (db *DB) LogPut(level, msg string) (bool, Response, error) { + resp, err := db.Invoke("log_put", map[string]interface{}{ + "level": level, + "message": msg, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// LogReopen executes log_reopen. +func (db *DB) LogReopen() (bool, Response, error) { + resp, err := db.Invoke("log_reopen", nil, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// DBNormalizer is a result of tokenizer_list. +type DBNormalizer struct { + Name string `json:"name"` +} + +// NormalizerList executes normalizer_list. +func (db *DB) NormalizerList() ([]DBNormalizer, Response, error) { + resp, err := db.Invoke("normalizer_list", nil, 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 []DBNormalizer + 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 +} + +// ObjectExist executes object_exist. +func (db *DB) ObjectExist(name string) (bool, Response, error) { + resp, err := db.Invoke("object_exist", map[string]interface{}{ + "name": name, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// ObjectRemove executes object_remove. +func (db *DB) ObjectRemove(name string, force bool) (bool, Response, error) { + resp, err := db.Invoke("object_remove", map[string]interface{}{ + "name": name, + "force": force, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// PluginRegister executes plugin_register. +func (db *DB) PluginRegister(name string) (bool, Response, error) { + resp, err := db.Invoke("plugin_register", map[string]interface{}{ + "name": name, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// PluginUnregister executes plugin_unregister. +func (db *DB) PluginUnregister(name string) (bool, Response, error) { + resp, err := db.Invoke("plugin_unregister", map[string]interface{}{ + "name": name, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// Reindex executes reindex. +func (db *DB) Reindex(target string) (bool, Response, error) { + var params map[string]interface{} + if target != "" { + params = map[string]interface{}{ + "target_name": target, + } + } + resp, err := db.Invoke("reindex", params, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + +// DBSchemaPlugin is a part of DBSchema. +type DBSchemaPlugin struct { + Name string `json:"name"` +} + +// DBSchemaType is a part of DBSchema. +type DBSchemaType struct { + Name string `json:"name"` + Size int `json:"size"` + CanBeKeyType bool `json:"can_be_key_type"` + CanBeValueType bool `json:"can_be_value_type"` +} + +// DBSchemaTokenizer is a part of DBSchema. +type DBSchemaTokenizer struct { + Name string `json:"name"` +} + +// DBSchemaNormalizer is a part of DBSchema. +type DBSchemaNormalizer struct { + Name string `json:"name"` +} + +// DBSchemaTokenFilter is a part of DBSchema. +type DBSchemaTokenFilter struct { + Name string `json:"name"` +} + +// DBSchemaKeyType is a part of DBSchema. +type DBSchemaKeyType struct { + Name string `json:"name"` + Type string `json:"type"` +} + +// DBSchemaValueType is a part of DBSchema. +type DBSchemaValueType struct { + Name string `json:"name"` + Type string `json:"type"` +} + +// DBSchemaIndex is a part of DBSchema. +type DBSchemaIndex struct { + Table string `json:"table"` + Section int `json:"section"` + Name string `json:"name"` + FullName string `json:"full_name"` +} + +// DBSchemaCommand is a part of DBSchema. +type DBSchemaCommand struct { + Name string `json:"name"` + Arguments map[string]string `json:"arguments"` + CommandLine string `json:"command_line"` +} + +// DBSchemaSource is a part of DBSchema. +type DBSchemaSource struct { + Name string `json:"name"` + Table string `json:"table"` + FullName string `json:"full_name"` +} + +// DBSchemaColumn is a part of DBSchema. +type DBSchemaColumn struct { + Name string `json:"name"` + Table string `json:"table"` + FullName string `json:"full_name"` + Type string `json:"type"` + ValueType DBSchemaValueType `json:"value_type"` + Compress string `json:"compress"` + Section bool `json:"section"` + Weight bool `json:"weight"` + Position bool `json:"position"` + Sources []DBSchemaSource `json:"sources"` + Indexes []DBSchemaIndex `json:"indexes"` + Command DBSchemaCommand `json:"command"` +} + +// DBSchemaTable is a part of DBSchema. +type DBSchemaTable struct { + Name string `json:"name"` + Type string `json:"type"` + KeyType *DBSchemaKeyType `json:"key_type"` + ValueType *DBSchemaValueType `json:"value_type"` + Tokenizer *DBSchemaTokenizer `json:"tokenizer"` + Normalizer *DBSchemaNormalizer `json:"normalizer"` + TokenFilters []DBSchemaTokenFilter `json:"token_filters"` + Indexes []DBSchemaIndex `json:"indexes"` + Command DBSchemaCommand `json:"command"` + Columns map[string]DBSchemaColumn `json:"columns"` +} + +// DBSchema is a result of schema. +type DBSchema struct { + Plugins map[string]DBSchemaPlugin `json:"plugins"` + Types map[string]DBSchemaType `json:"types"` + Tokenizers map[string]DBSchemaTokenizer `json:"tokenizers"` + Normalizers map[string]DBSchemaNormalizer `json:"normalizers"` + TokenFilters map[string]DBSchemaTokenFilter `json:"token_filters"` + Tables map[string]DBSchemaTable `json:"tables"` +} + +// Schema executes schema. +func (db *DB) Schema() (*DBSchema, Response, error) { + resp, err := db.Invoke("schema", nil, 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 DBSchema + 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 +} + // DBSelectOptionsColumn stores --columns[NAME]. type DBSelectOptionsColumn struct { Stage string // --columns[NAME].stage @@ -505,8 +963,8 @@ func (db *DB) SelectRows(tbl string, rows interface{}, options *DBSelectOptions) return 0, nil, nil } -// DBStatusResult is a response of status. -type DBStatusResult struct { +// DBStatus is a response of status. +type DBStatus struct { AllocCount int `json:"alloc_count"` CacheHitRate float64 `json:"cache_hit_rate"` CommandVersion int `json:"command_version"` @@ -519,8 +977,8 @@ type DBStatusResult struct { } // Status executes status. -func (db *DB) Status() (*DBStatusResult, Response, error) { - resp, err := db.Exec("status", nil) +func (db *DB) Status() (*DBStatus, Response, error) { + resp, err := db.Invoke("status", nil, nil) if err != nil { return nil, nil, err } @@ -536,7 +994,7 @@ func (db *DB) Status() (*DBStatusResult, Response, error) { "error": err.Error(), }) } - var result DBStatusResult + var result DBStatus if v, ok := data["alloc_count"]; ok { if v, ok := v.(float64); ok { result.AllocCount = int(v) @@ -585,6 +1043,18 @@ func (db *DB) Status() (*DBStatusResult, Response, error) { return &result, resp, nil } +// TableCopy executes table_copy. +func (db *DB) TableCopy(from, to string) (bool, Response, error) { + resp, err := db.Invoke("table_copy", map[string]interface{}{ + "from": from, + "to": to, + }, nil) + if err != nil { + return false, nil, err + } + return db.recvBool(resp) +} + // DBTableCreateOptions stores options for DB.TableCreate. // http://groonga.org/docs/reference/commands/table_create.html type DBTableCreateOptions struct { @@ -677,42 +1147,155 @@ func (db *DB) TableCreate(name string, options *DBTableCreateOptions) (bool, Res if err != nil { return false, nil, err } + return db.recvBool(resp) +} + +// DBTable is a result of table_list. +type DBTable struct { + ID uint32 `json:"id"` + Name string `json:"name"` + Path string `json:"path"` + Flags []string `json:"flags"` + Domain string `json:"domain"` + Range string `json:"range"` + DefaultTokenizer string `json:"default_tokenizer"` + Normalizer string `json:"normalizer"` +} + +// TableList executes table_list. +func (db *DB) TableList() ([]DBTable, Response, error) { + resp, err := db.Invoke("table_list", nil, nil) + if err != nil { + return nil, nil, err + } defer resp.Close() jsonData, err := ioutil.ReadAll(resp) if err != nil { - return false, resp, err + return nil, resp, err } - var result bool + var result [][]interface{} if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ + return nil, resp, NewError(InvalidResponse, map[string]interface{}{ "method": "json.Unmarshal", "error": err.Error(), }) } - return result, resp, nil + if len(result) == 0 { + return nil, resp, NewError(InvalidResponse, map[string]interface{}{ + "error": "The result is empty.", + }) + } + var fields []string + for _, meta := range result[0] { + if values, ok := meta.([]interface{}); ok { + if field, ok := values[0].(string); ok { + fields = append(fields, field) + } + } + } + var tables []DBTable + for _, values := range result[1:] { + var table DBTable + for i := 0; i < len(fields) && i < len(values); i++ { + switch fields[i] { + case "id": + if v, ok := values[i].(float64); ok { + table.ID = uint32(v) + } + case "name": + if v, ok := values[i].(string); ok { + table.Name = v + } + case "path": + if v, ok := values[i].(string); ok { + table.Path = v + } + case "flags": + if v, ok := values[i].(string); ok { + table.Flags = strings.Split(v, "|") + } + case "domain": + if v, ok := values[i].(string); ok { + table.Domain = v + } + case "range": + if v, ok := values[i].(string); ok { + table.Range = v + } + case "default_tokenizer": + if v, ok := values[i].(string); ok { + table.DefaultTokenizer = v + } + case "normalizer": + if v, ok := values[i].(string); ok { + table.Normalizer = v + } + } + } + tables = append(tables, table) + } + return tables, resp, nil } // TableRemove executes table_remove. func (db *DB) TableRemove(name string, dependent bool) (bool, Response, error) { - cmd, err := NewCommand("table_remove", map[string]interface{}{ + resp, err := db.Invoke("table_remove", map[string]interface{}{ "name": name, "dependent": dependent, - }) + }, nil) if err != nil { return false, nil, err } - resp, err := db.Query(cmd) + return db.recvBool(resp) +} + +// TableRename executes table_rename. +func (db *DB) TableRename(name, newName string) (bool, Response, error) { + resp, err := db.Invoke("table_rename", map[string]interface{}{ + "name": name, + "new_name": newName, + }, nil) if err != nil { return false, nil, err } + return db.recvBool(resp) +} + +// ThreadLimit executes thread_limit. +// If max < 0, max is not passed to thread_limit. +func (db *DB) ThreadLimit(max int) (int, Response, error) { + var params map[string]interface{} + if max >= 0 { + params = map[string]interface{}{ + "max": max, + } + } + resp, err := db.Invoke("thread_limit", params, nil) + if err != nil { + return 0, nil, err + } + return db.recvInt(resp) +} + +// DBTokenizer is a result of tokenizer_list. +type DBTokenizer struct { + Name string `json:"name"` +} + +// TokenizerList executes tokenizer_list. +func (db *DB) TokenizerList() ([]DBTokenizer, Response, error) { + resp, err := db.Invoke("tokenizer_list", nil, nil) + if err != nil { + return nil, nil, err + } defer resp.Close() jsonData, err := ioutil.ReadAll(resp) if err != nil { - return false, resp, err + return nil, resp, err } - var result bool + var result []DBTokenizer if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ + return nil, resp, NewError(InvalidResponse, map[string]interface{}{ "method": "json.Unmarshal", "error": err.Error(), }) @@ -728,17 +1311,5 @@ func (db *DB) Truncate(target string) (bool, Response, error) { if err != nil { return false, nil, err } - defer resp.Close() - jsonData, err := ioutil.ReadAll(resp) - if err != nil { - return false, resp, err - } - var result bool - if err := json.Unmarshal(jsonData, &result); err != nil { - return false, resp, NewError(InvalidResponse, map[string]interface{}{ - "method": "json.Unmarshal", - "error": err.Error(), - }) - } - return result, resp, nil + return db.recvBool(resp) } Modified: v2/db_test.go (+134 -1) =================================================================== --- v2/db_test.go 2017-06-16 15:37:24 +0900 (9ac8a08) +++ v2/db_test.go 2017-06-16 22:46:33 +0900 (25fd77f) @@ -7,6 +7,63 @@ import ( "testing" ) +func TestDBColumnList(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.ColumnList("Tbl") + if err != nil { + t.Fatalf("db.ColumnList 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 TestDBColumnCopy(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.ColumnCopy("Tbl.col", "Tbl.col2") + if err != nil { + t.Fatalf("db.ColumnCopy 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 TestDBColumnCreate(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.ColumnCreate("Tbl.col", "ShortText", nil) + if err != nil { + t.Fatalf("db.ColumnCreate 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 TestDBColumnRemove(t *testing.T) { client, err := NewHTTPClient("", nil) if err != nil { @@ -15,7 +72,7 @@ func TestDBColumnRemove(t *testing.T) { db := NewDB(client) defer db.Close() - result, resp, err := db.ColumnRemove("no_such_table", "no_such_column") + result, resp, err := db.ColumnRemove("no_such_table.no_such_column") if err != nil { t.Fatalf("db.ColumnRemove failed: %v", err) } @@ -68,6 +125,44 @@ func TestDBLoad(t *testing.T) { } } +func TestDBNormalizerList(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.NormalizerList() + if err != nil { + t.Fatalf("db.NormalizerList 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 TestDBSchema(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.Schema() + if err != nil { + t.Fatalf("db.Schema 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 TestDBSelect(t *testing.T) { client, err := NewHTTPClient("", nil) if err != nil { @@ -110,6 +205,25 @@ func TestDBStatus(t *testing.T) { } } +func TestDBTableList(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.TableList() + if err != nil { + t.Fatalf("db.TableList 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 { @@ -147,3 +261,22 @@ func TestDBTableRemove(t *testing.T) { log.Printf("error = %#v", err) } } + +func TestDBTokenizerList(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.TokenizerList() + if err != nil { + t.Fatalf("db.TokenizerList failed: %v", err) + } + log.Printf("result = %#v", result) + log.Printf("resp = %#v", resp) + if err := resp.Err(); err != nil { + log.Printf("error = %#v", err) + } +} -------------- next part -------------- HTML����������������������������...Download