Beispiel #1
0
func (s *Shard) Transact(txFun TxFunc) errs.Err {
	conn, stdErr := s.db.Begin()
	if stdErr != nil {
		return errs.Wrap(stdErr, errs.Info{"Description": "Could not open transaction"})
	}
	defer func() {
		if panicErr := recover(); panicErr != nil {
			rbErr := conn.Rollback()
			panic(errs.New(errs.Info{
				"Description": "Panic during sql transcation",
				"PanicErr":    panicErr,
				"RollbackErr": rbErr,
			}))
		}
	}()

	err := txFun(&Shard{s.DBName, nil, conn})
	if err != nil {
		rbErr := conn.Rollback()
		if rbErr != nil {
			return errs.Wrap(rbErr, errs.Info{"Description": "Transact rollback error", "TransactionError": err})
		}

	} else {
		stdErr = conn.Commit()
		if stdErr != nil {
			return errs.Wrap(stdErr, errs.Info{"Description": "Could not commit transaction"})
		}
	}

	return nil
}
Beispiel #2
0
func do(method, url, contentType string, bodyReader io.Reader) (statusCode int, responseBody string, err errs.Err) {
	req, stdErr := http.NewRequest(method, url, bodyReader)
	if stdErr != nil {
		err = errs.Wrap(stdErr, errs.Info{"URL": url})
		return
	}
	if contentType != "" {
		req.Header.Set("Content-Type", contentType)
	}
	req.Close = true
	req.Header.Set("Connection", "close")

	res, stdErr := http.DefaultClient.Do(req)
	if stdErr != nil {
		err = errs.Wrap(stdErr, errs.Info{"URL": url})
		return
	}
	defer res.Body.Close()

	statusCode = res.StatusCode
	bodyBytes, stdErr := ioutil.ReadAll(res.Body)
	if stdErr != nil {
		err = errs.Wrap(stdErr, errs.Info{"URL": url})
		return
	}
	responseBody = string(bodyBytes)
	return
}
Beispiel #3
0
func (s *Shard) queryOne(query string, args []interface{}, out interface{}) (found bool, err errs.Err) {
	rows, err := s.Query(query, args...)
	if err != nil {
		return
	}
	defer rows.Close()

	if rows.Next() {
		stdErr := rows.Scan(out)
		if stdErr != nil {
			err = errs.Wrap(stdErr, errInfo("queryOne rows.Scan error", query, args))
			return
		}
		if rows.Next() {
			err = errs.New(errInfo("queryOne query returned too many rows", query, args))
			return
		}
		found = true
	}

	stdErr := rows.Err()
	if stdErr != nil {
		err = errs.Wrap(stdErr, errInfo("queryOne rows.Err", query, args))
		return
	}

	return
}
Beispiel #4
0
func (s *Shard) scanOne(output interface{}, query string, required bool, args ...interface{}) (found bool, err errs.Err) {
	// Check types
	var outputReflectionPtr = reflect.ValueOf(output)
	if !outputReflectionPtr.IsValid() {
		panic(scanOneTypeError)
	}
	if outputReflectionPtr.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}
	var outputReflection = outputReflectionPtr.Elem()
	if outputReflection.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}

	// Query DB
	rows, err := s.Query(query, args...)
	if err != nil {
		return
	}
	defer rows.Close()

	// Reflect onto struct
	columns, stdErr := rows.Columns()
	if stdErr != nil {
		err = errs.Wrap(stdErr, errInfo("rows.Columns() error", query, args))
		return
	}
	if !rows.Next() {
		return
	}

	var vStruct reflect.Value
	if outputReflection.IsNil() {
		structPtrVal := reflect.New(outputReflection.Type().Elem())
		outputReflection.Set(structPtrVal)
		vStruct = structPtrVal.Elem()
	} else {
		vStruct = outputReflection.Elem()
	}

	err = structFromRow(vStruct, columns, rows, query, args)
	if err != nil {
		return
	}

	if rows.Next() {
		err = errs.New(errInfo("scanOne got multiple rows", query, args))
		return
	}

	stdErr = rows.Err()
	if stdErr != nil {
		err = errs.Wrap(stdErr, errInfo("scanOne rows.Err() error", query, args))
		return
	}

	found = true
	return
}
Beispiel #5
0
func JSONBytesIndent(v interface{}, prefix, indent string) ([]byte, errs.Err) {
	jsonBytes, stdErr := json.MarshalIndent(v, prefix, indent)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errs.Info{})
	}
	return jsonBytes, nil
}
Beispiel #6
0
func mymysqlDriverOpener(username, password, dbName, host string, port int, connVars funGoSql.ConnVariables) (*sql.DB, errs.Err) {
	db, stdErr := sql.Open("sqlite3", dbName)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errs.Info{})
	}
	return db, nil
}
Beispiel #7
0
func DecodeJSON(reader io.Reader, v interface{}) errs.Err {
	stdErr := json.NewDecoder(reader).Decode(v)
	if stdErr != nil {
		return errs.Wrap(stdErr, errs.Info{})
	}
	return nil
}
Beispiel #8
0
func ParseJSONBytes(jsonBytes []byte, v interface{}) errs.Err {
	stdErr := json.Unmarshal(jsonBytes, v)
	if stdErr != nil {
		return errs.Wrap(stdErr, errs.Info{"JSON": string(jsonBytes)}, "Could not parse JSON")
	}
	return nil
}
Beispiel #9
0
func JSONBytes(v interface{}) ([]byte, errs.Err) {
	bytes, stdErr := json.Marshal(v)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errs.Info{}, "Could not convert to JSON")
	}
	return bytes, nil
}
Beispiel #10
0
// Execute with fixed args
func (s *Shard) Exec(query string, args ...interface{}) (sql.Result, errs.Err) {
	fixArgs(args)
	res, stdErr := s.sqlConn.Exec(query, args...)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errInfo("Exec sqlConn.Exec() error", query, args))
	}
	return res, nil
}
Beispiel #11
0
func Open(path string) (file *os.File, err errs.Err) {
	file, stdErr := os.Open(path)
	if stdErr != nil {
		err = errs.Wrap(stdErr, errs.Info{"Path": path})
		return
	}
	return
}
Beispiel #12
0
// Query with fixed args
func (s *Shard) Query(query string, args ...interface{}) (*sql.Rows, errs.Err) {
	fixArgs(args)
	rows, stdErr := s.sqlConn.Query(query, args...)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errInfo("Query sqlConn.Query() error", query, args))
	}
	return rows, nil
}
func goSqlDriverOpener(username, password, dbName, host string, port int, connVars funGoSql.ConnVariables) (*sql.DB, errs.Err) {
	sourceString := fmt.Sprintf(
		"%s:%s@tcp(%s:%d)/%s?%s",
		username, password, host, port, dbName, connVars.Join("&"))
	db, stdErr := sql.Open("mysql", sourceString)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errs.Info{})
	}
	return db, nil
}
Beispiel #14
0
func mymysqlDriverOpener(username, password, dbName, host string, port int, connVars funGoSql.ConnVariables) (*sql.DB, error) {
	sourceString := fmt.Sprintf(
		"tcp:%s:%d,%s*%s/%s/%s",
		host, port, connVars.Join(","), dbName, username, password)
	db, stdErr := sql.Open("mymysql", sourceString)
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, errs.Info{})
	}
	return db, nil
}
Beispiel #15
0
func (s *Shard) Insert(query string, args ...interface{}) (id int64, err errs.Err) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}
	id, stdErr := res.LastInsertId()
	if stdErr != nil {
		err = errs.Wrap(stdErr, errInfo("Insert LastInsertIderror", query, args))
		return
	}
	return
}
Beispiel #16
0
func (s *Shard) Update(query string, args ...interface{}) (rowsAffected int64, err errs.Err) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}

	rowsAffected, stdErr := res.RowsAffected()
	if stdErr != nil {
		err = errs.Wrap(stdErr, errInfo("Update RowsAffected error", query, args))
		return
	}
	return
}
Beispiel #17
0
func Uid(numChars int) (uid string, err errs.Err) {
	if numChars%4 != 0 {
		err = errs.New(nil, "uid length must be a multiple of 4")
		return
	}
	buf := make([]byte, numChars)
	_, stdErr := io.ReadFull(rand.Reader, buf)
	if stdErr != nil {
		err = errs.Wrap(stdErr, nil)
		return
	}

	uid = base64.URLEncoding.EncodeToString(buf)
	return
}
Beispiel #18
0
func scanColumnValue(column string, reflectVal reflect.Value, value *sql.RawBytes, query string, args []interface{}) errs.Err {
	bytes := []byte(*value)
	if bytes == nil {
		return nil // Leave struct field empty
	}
	switch reflectVal.Kind() {
	case reflect.String:
		reflectVal.SetString(string(bytes))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		uintVal, stdErr := strconv.ParseUint(string(bytes), 10, 64)
		if stdErr != nil {
			return errs.Wrap(stdErr, errInfo("strconv.ParseUint error", query, args, errs.Info{"Bytes": bytes}))
		}
		reflectVal.SetUint(reflect.ValueOf(uintVal).Uint())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		intVal, stdErr := strconv.ParseInt(string(bytes), 10, 64)
		if stdErr != nil {
			return errs.Wrap(stdErr, errInfo("strconv.ParseInt error", query, args, errs.Info{"Bytes": bytes}))
		}
		reflectVal.SetInt(reflect.ValueOf(intVal).Int())
	case reflect.Bool:
		boolVal, stdErr := strconv.ParseBool(string(bytes))
		if stdErr != nil {
			return errs.Wrap(stdErr, errInfo("strconv.ParseBool error", query, args, errs.Info{"Bytes": bytes}))
		}
		reflectVal.SetBool(reflect.ValueOf(boolVal).Bool())
	default:
		if reflectVal.Kind() == reflect.Slice { // && reflectVal. == reflect.Uint8 {
			// byte slice
			reflectVal.SetBytes(bytes)
		} else {
			return errs.New(errInfo("Bad row value for column "+column+": "+reflectVal.Kind().String(), query, args))
		}
	}
	return nil
}
Beispiel #19
0
func newShard(s *ShardSet, dbName string, autoIncrementOffset int) (*Shard, errs.Err) {
	connVars := ConnVariables{
		"autocommit":               "true",
		"clientFoundRows":          "true",
		"charset":                  "utf8mb4",
		"collation":                "utf8_unicode_ci",
		"auto_increment_increment": strconv.Itoa(s.maxShards),
		"auto_increment_offset":    strconv.Itoa(autoIncrementOffset),
		"sql_mode":                 "STRICT_ALL_TABLES",
	}

	db, err := dbOpener(s.username, s.password, dbName, s.host, s.port, connVars)
	if err != nil {
		return nil, err
	}

	db.SetMaxOpenConns(s.maxConns)
	// db.SetMaxIdleConns(n)
	stdErr := db.Ping()
	if stdErr != nil {
		return nil, errs.Wrap(stdErr, nil)
	}
	return &Shard{dbName, db, db}, nil
}
Beispiel #20
0
func structFromRow(outputItemStructVal reflect.Value, columns []string, rows *sql.Rows, query string, args []interface{}) errs.Err {
	vals := make([]interface{}, len(columns))
	for i, _ := range columns {
		vals[i] = &sql.RawBytes{}
	}
	stdErr := rows.Scan(vals...)
	if stdErr != nil {
		return errs.Wrap(stdErr, errInfo("structFromRow error", query, args))
	}

	for i, column := range columns {
		structFieldValue := outputItemStructVal.FieldByName(column)
		if !structFieldValue.IsValid() {
			fmt.Println("Warning: no corresponding struct field found for column: " + column)
			continue
		}
		err := scanColumnValue(column, structFieldValue, vals[i].(*sql.RawBytes), query, args)
		if err != nil {
			return err
		}
	}

	return nil
}
Beispiel #21
0
func (s *Shard) Select(output interface{}, query string, args ...interface{}) errs.Err {
	// Check types
	var outputPtr = reflect.ValueOf(output)
	if outputPtr.Kind() != reflect.Ptr {
		return errs.New(errInfo("Select expects a pointer to a slice of items", query, args))
	}
	var outputReflection = reflect.Indirect(outputPtr)
	if outputReflection.Kind() != reflect.Slice {
		return errs.New(errInfo("Select expects items to be a slice", query, args))
	}
	if outputReflection.Len() != 0 {
		return errs.New(errInfo("Select expects items to be empty", query, args))
	}
	outputReflection.Set(reflect.MakeSlice(outputReflection.Type(), 0, 0))

	// Query DB
	var rows, err = s.Query(query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()
	columns, stdErr := rows.Columns()
	if stdErr != nil {
		return errs.Wrap(stdErr, errInfo("Select rows.Columns error", query, args))
	}

	valType := outputReflection.Type().Elem()
	isStruct := (valType.Kind() == reflect.Ptr && valType.Elem().Kind() == reflect.Struct)
	if isStruct {
		// Reflect onto structs
		for rows.Next() {
			structPtrVal := reflect.New(valType.Elem())
			outputItemStructVal := structPtrVal.Elem()
			err = structFromRow(outputItemStructVal, columns, rows, query, args)
			if err != nil {
				return err
			}
			outputReflection.Set(reflect.Append(outputReflection, structPtrVal))
		}
	} else {
		if len(columns) != 1 {
			return errs.New(errInfo("Select expected single column in select statement for slice of non-struct values", query, args))
		}
		for rows.Next() {
			rawBytes := &sql.RawBytes{}
			stdErr = rows.Scan(rawBytes)
			if stdErr != nil {
				return errs.Wrap(stdErr, errInfo("Select rows.Scan error", query, args))
			}
			outputValue := reflect.New(valType).Elem()
			err = scanColumnValue(columns[0], outputValue, rawBytes, query, args)
			if err != nil {
				return err
			}
			outputReflection.Set(reflect.Append(outputReflection, outputValue))
		}
	}

	stdErr = rows.Err()
	if err != nil {
		return errs.Wrap(stdErr, errInfo("Select rows.Err() error", query, args))
	}
	return nil
}