[Groonga-commit] groonga/grngo at 39eaac2 [master] Add Load() that is experimental.

Back to archive index

Susumu Yata null+****@clear*****
Tue Dec 22 14:07:35 JST 2015


Susumu Yata	2015-12-22 14:07:35 +0900 (Tue, 22 Dec 2015)

  New Revision: 39eaac215d7fac8a49074a4e262069e6cde8b30c
  https://github.com/groonga/grngo/commit/39eaac215d7fac8a49074a4e262069e6cde8b30c

  Message:
    Add Load() that is experimental.

  Modified files:
    grngo.go
    grngo_test.go

  Modified: grngo.go (+199 -0)
===================================================================
--- grngo.go    2015-12-05 14:17:19 +0900 (43a390c)
+++ grngo.go    2015-12-22 14:07:35 +0900 (a99e9c3)
@@ -6,6 +6,7 @@ package grngo
 import "C"
 
 import (
+	"bytes"
 	"fmt"
 	"reflect"
 	"strings"
@@ -682,6 +683,25 @@ func (db *DB) FindTable(name string) (*Table, error) {
 	return table, nil
 }
 
+type LoadOptions struct {
+	IfExists string
+}
+
+// NewLoadOptions returns a new LoadOptions with the default settings.
+func NewLoadOptions() *LoadOptions {
+	options := new(LoadOptions)
+	return options
+}
+
+// (Experimental) Load loads values.
+func (db *DB) Load(tableName string, values interface{}, options *LoadOptions) ([]byte, error) {
+	table, err := db.FindTable(tableName)
+	if err != nil {
+		return nil, err
+	}
+	return table.Load(values, options)
+}
+
 // InsertRow finds or inserts a row.
 func (db *DB) InsertRow(tableName string, key interface{}) (inserted bool, id uint32, err error) {
 	table, err := db.FindTable(tableName)
@@ -760,6 +780,185 @@ func newTable(db *DB, c *C.grngo_table, name string) *Table {
 	return &table
 }
 
+// genLoadHead generates the head line of a load command.
+func (table *Table) genLoadHead(options *LoadOptions) (string, error) {
+	line := fmt.Sprintf("load --table %s", table.name)
+	if options.IfExists != "" {
+		value := strings.Replace(options.IfExists, "\\", "\\\\", -1)
+		value = strings.Replace(value, "\"", "\\\"", -1)
+		line += fmt.Sprintf(" --ifexists '%s'", value)
+	}
+	return line, nil
+}
+
+// writeLoadColumns writes columns of a load command.
+func (table *Table) writeLoadColumns(buf *bytes.Buffer, valueType reflect.Type) error {
+	if err := buf.WriteByte('['); err != nil {
+		return err
+	}
+	needsDelimiter := false
+	for i := 0; i < valueType.NumField(); i++ {
+		field := valueType.Field(i)
+		columnName := field.Tag.Get("grngo")
+		if columnName == "" {
+			continue
+		}
+		if needsDelimiter {
+			if err := buf.WriteByte(','); err != nil {
+				return err
+			}
+		} else {
+			needsDelimiter = true
+		}
+		if _, err := fmt.Fprintf(buf, "\"%s\"", columnName); err != nil {
+			return err
+		}
+	}
+	if err := buf.WriteByte(']'); err != nil {
+		return err
+	}
+	return nil
+}
+
+// writeLoadValue writes a value of a load command.
+func (table *Table) writeLoadValue(buf *bytes.Buffer, value *reflect.Value) error {
+	if err := buf.WriteByte('['); err != nil {
+		return err
+	}
+	valueType := value.Type()
+	needsDelimiter := false
+	for i := 0; i < valueType.NumField(); i++ {
+		field := valueType.Field(i)
+		tag := field.Tag.Get("grngo")
+		if tag == "" {
+			continue
+		}
+		if needsDelimiter {
+			if err := buf.WriteByte(','); err != nil {
+				return err
+			}
+		} else {
+			needsDelimiter = true
+		}
+		fieldValue := value.Field(i)
+		switch fieldValue.Kind() {
+		case reflect.Bool:
+			if _, err := fmt.Fprint(buf, fieldValue.Bool()); err != nil {
+				return err
+			}
+		case reflect.Int64:
+			if _, err := fmt.Fprint(buf, fieldValue.Int()); err != nil {
+				return err
+			}
+		case reflect.Float64:
+			if _, err := fmt.Fprint(buf, fieldValue.Float()); err != nil {
+				return err
+			}
+		case reflect.String:
+			str := fieldValue.String()
+			str = strings.Replace(str, "\\", "\\\\", -1)
+			str = strings.Replace(str, "\"", "\\\"", -1)
+			if _, err := fmt.Fprintf(buf, "\"%s\"", str); err != nil {
+				return err
+			}
+		case reflect.Slice:
+			switch field.Type.Elem().Kind() {
+			case reflect.Uint8:
+				str := string(fieldValue.Bytes())
+				str = strings.Replace(str, "\\", "\\\\", -1)
+				str = strings.Replace(str, "\"", "\\\"", -1)
+				if _, err := fmt.Fprintf(buf, "\"%s\"", str); err != nil {
+					return err
+				}
+			default:
+				// TODO: Support other types!
+				return fmt.Errorf("unsupported data kind")
+			}
+		default:
+			// TODO: Support other types!
+			return fmt.Errorf("unsupported data kind")
+		}
+	}
+	if err := buf.WriteByte(']'); err != nil {
+		return err
+	}
+	return nil
+}
+
+// genLoadBody generates the body line of a load command.
+func (table *Table) genLoadBody(values interface{}) (string, error) {
+	buf := new(bytes.Buffer)
+	if err := buf.WriteByte('['); err != nil {
+		return "", err
+	}
+	value := reflect.ValueOf(values)
+	switch value.Kind() {
+	case reflect.Struct:
+	case reflect.Ptr:
+		value := value.Elem()
+		if value.Kind() != reflect.Struct {
+			return "", fmt.Errorf("invalid values")
+		}
+		if err := table.writeLoadColumns(buf, value.Type()); err != nil {
+			return "", err
+		}
+		if err := table.writeLoadValue(buf, &value); err != nil {
+			return "", err
+		}
+	case reflect.Slice:
+		if value.Len() == 0 {
+			return "", fmt.Errorf("invalid values")
+		}
+		valueType := value.Type().Elem()
+		if valueType.Kind() != reflect.Struct {
+			return "", fmt.Errorf("invalid values")
+		}
+		if err := table.writeLoadColumns(buf, valueType); err != nil {
+			return "", err
+		}
+		for i := 0; i < value.Len(); i++ {
+			if err := buf.WriteByte(','); err != nil {
+				return "", err
+			}
+			v := value.Index(i)
+			if err := table.writeLoadValue(buf, &v); err != nil {
+				return "", err
+			}
+		}
+	}
+	if err := buf.WriteByte(']'); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+}
+
+// (Experimental) Load loads values.
+//
+// Implicit conversion for Time is not supported.
+// GeoPoint is not supported.
+// Vector types are not supported.
+func (table *Table) Load(values interface{}, options *LoadOptions) ([]byte, error) {
+	if options == nil {
+		options = NewLoadOptions()
+	}
+	headLine, err := table.genLoadHead(options)
+	if err != nil {
+		return nil, err
+	}
+	bodyLine, err := table.genLoadBody(values)
+	if err != nil {
+		return nil, err
+	}
+	lines := []string{ headLine, bodyLine }
+	for _, line := range lines {
+		if err := table.db.Send(line); err != nil {
+			result, _ := table.db.Recv()
+			return result, err
+		}
+	}
+	return table.db.Recv()
+}
+
 // InsertRow finds or inserts a row.
 func (table *Table) InsertRow(key interface{}) (inserted bool, id uint32, err error) {
 	var rc C.grn_rc

  Modified: grngo_test.go (+37 -0)
===================================================================
--- grngo_test.go    2015-12-05 14:17:19 +0900 (6866100)
+++ grngo_test.go    2015-12-22 14:07:35 +0900 (f5645d1)
@@ -255,6 +255,43 @@ func removeTempDB(tb testing.TB, dirPath string, db *DB) {
 
 // Tests.
 
+type Rec struct {
+	A bool `grngo:"A"`
+	B int64 `grngo:"B"`
+	C float64 `grngo:"C"`
+	D string `grngo:"D"`
+	E []byte `grngo:"E"`
+}
+
+func TestLoad(t *testing.T) {
+	dirPath, _, db, _ := createTempTable(t, "Table", nil)
+	defer removeTempDB(t, dirPath, db)
+	if _, err := db.CreateColumn("Table", "A", "Bool", nil); err != nil {
+		t.Fatal("DB.CreateColumn() failed:", err)
+	}
+	if _, err := db.CreateColumn("Table", "B", "Int64", nil); err != nil {
+		t.Fatal("DB.CreateColumn() failed:", err)
+	}
+	if _, err := db.CreateColumn("Table", "C", "Float", nil); err != nil {
+		t.Fatal("DB.CreateColumn() failed:", err)
+	}
+	if _, err := db.CreateColumn("Table", "D", "Text", nil); err != nil {
+		t.Fatal("DB.CreateColumn() failed:", err)
+	}
+	if _, err := db.CreateColumn("Table", "E", "Text", nil); err != nil {
+		t.Fatal("DB.CreateColumn() failed:", err)
+	}
+	var recs []Rec
+	recs = append(recs, Rec{false, 100, 1.23, "ABC", []byte("123")})
+	recs = append(recs, Rec{true, 200, 2.34, "BCD", []byte("456")})
+	recs = append(recs, Rec{false, 300, 3.45, "C\"DE", []byte("789")})
+	_, err := db.Load("Table", recs, nil)
+	if err != nil {
+		t.Fatalf("DB.Load() failed: %v", err)
+	}
+//	bytes, _ := db.Query("select Table")
+}
+
 func TestDB(t *testing.T) {
 	dirPath, dbPath, db := createTempDB(t)
 	defer os.RemoveAll(dirPath)
-------------- next part --------------
HTML����������������������������...
Download 



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