<commit_before>package drivers

import (
	"database/sql"
	"fmt"
	"net/url"
	"strings"

	_ "github.com/denisenkom/go-mssqldb"
	"github.com/pkg/errors"
	"github.com/vattle/sqlboiler/bdb"
)

// MSSQLDriver holds the database connection string and a handle
// to the database connection.
type MSSQLDriver struct {
	connStr string
	dbConn  *sql.DB
}

// NewMSSQLDriver takes the database connection details as parameters and
// returns a pointer to a MSSQLDriver object. Note that it is required to
// call MSSQLDriver.Open() and MSSQLDriver.Close() to open and close
// the database connection once an object has been obtained.
func NewMSSQLDriver(user, pass, dbname, host string, port int, sslmode string) *MSSQLDriver {
	driver := MSSQLDriver{
		connStr: MSSQLBuildQueryString(user, pass, dbname, host, port, sslmode),
	}

	return &driver
}

// MSSQLBuildQueryString builds a query string for MSSQL.
func MSSQLBuildQueryString(user, pass, dbname, host string, port int, sslmode string) string {

	query := url.Values{}
	query.Add("database", dbname)
	query.Add("encrypt", sslmode)

	u := &url.URL{
		Scheme: "sqlserver",
		User:   url.UserPassword(user, pass),
		Host:   fmt.Sprintf("%s:%d", host, port),
		// Path:  instance, // if connecting to an instance instead of a port
		RawQuery: query.Encode(),
	}

	return u.String()
}

// Open opens the database connection using the connection string
func (m *MSSQLDriver) Open() error {
	var err error
	m.dbConn, err = sql.Open("mssql", m.connStr)
	if err != nil {
		return err
	}

	return nil
}

// Close closes the database connection
func (m *MSSQLDriver) Close() {
	m.dbConn.Close()
}

// UseLastInsertID returns false for mssql
func (m *MSSQLDriver) UseLastInsertID() bool {
	return false
}

// UseTopClause returns true to indicate MS SQL supports SQL TOP clause
func (m *MSSQLDriver) UseTopClause() bool {
	return true
}

// TableNames connects to the postgres database and
// retrieves all table names from the information_schema where the
// table schema is public.
func (m *MSSQLDriver) TableNames(schema string, whitelist, blacklist []string) ([]string, error) {
	var names []string

	query := fmt.Sprintf(`select table_name from information_schema.tables where table_schema = ? and table_type = 'BASE TABLE'`)
	args := []interface{}{schema}
	if len(whitelist) > 0 {
		query += fmt.Sprintf(" and table_name in (%s);", strings.Repeat(",?", len(whitelist))[1:])
		for _, w := range whitelist {
			args = append(args, w)
		}
	} else if len(blacklist) > 0 {
		query += fmt.Sprintf(" and table_name not in (%s);", strings.Repeat(",?", len(blacklist))[1:])
		for _, b := range blacklist {
			args = append(args, b)
		}
	}

	rows, err := m.dbConn.Query(query, args...)

	if err != nil {
		return nil, err
	}

	defer rows.Close()
	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			return nil, err
		}
		names = append(names, name)
	}

	return names, nil
}

// Columns takes a table name and attempts to retrieve the table information
// from the database information_schema.columns. It retrieves the column names
// and column types and returns those as a []Column after TranslateColumnType()
// converts the SQL types to Go types, for example: "varchar" to "string"
func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
	var columns []bdb.Column

	rows, err := m.dbConn.Query(`
	SELECT column_name,
       CASE
         WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN data_type
         ELSE data_type + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
       END AS full_type,
       data_type,
	   column_default,
       CASE
         WHEN IS_NULLABLE = 'YES' THEN 1
         ELSE 0
       END AS is_nullable,
       CASE
         WHEN EXISTS (SELECT c.column_name
                      FROM information_schema.table_constraints tc
                        INNER JOIN information_schema.key_column_usage kcu
                                ON tc.constraint_name = kcu.constraint_name
                               AND tc.table_name = kcu.table_name
                               AND tc.table_schema = kcu.table_schema
                      WHERE c.column_name = kcu.column_name
                      AND   tc.table_name = c.table_name
                      AND   (tc.constraint_type = 'PRIMARY KEY' OR tc.constraint_type = 'UNIQUE')
                      AND   (SELECT COUNT(*)
                             FROM information_schema.key_column_usage
                             WHERE table_schema = kcu.table_schema
                             AND   table_name = tc.table_name
                             AND   constraint_name = tc.constraint_name) = 1) THEN 1
         ELSE 0
       END AS is_unique
	FROM INFORMATION_SCHEMA.columns c
	where table_name = ? and table_schema = ?;
	`, tableName, schema)

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var colName, colType, colFullType string
		var nullable, unique bool
		var defaultValue *string
		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique); err != nil {
			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
		}

		column := bdb.Column{
			Name:       colName,
			FullDBType: colFullType, // example: tinyint(1) instead of tinyint
			DBType:     colType,
			Nullable:   nullable,
			Unique:     unique,
		}

		if defaultValue != nil && *defaultValue != "NULL" {
			column.Default = *defaultValue
		}

		columns = append(columns, column)
	}

	return columns, nil
}

// PrimaryKeyInfo looks up the primary key for a table.
func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey, error) {
	pkey := &bdb.PrimaryKey{}
	var err error

	query := `
	select tc.constraint_name
	from information_schema.table_constraints as tc
	where tc.table_name = ? and tc.constraint_type = 'PRIMARY KEY' and tc.table_schema = ?;`

	row := m.dbConn.QueryRow(query, tableName, schema)
	if err = row.Scan(&pkey.Name); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	queryColumns := `
	select kcu.column_name
	from   information_schema.key_column_usage as kcu
	where  table_name = ? and constraint_name = ? and table_schema = ?;`

	var rows *sql.Rows
	if rows, err = m.dbConn.Query(queryColumns, tableName, pkey.Name, schema); err != nil {
		return nil, err
	}
	defer rows.Close()

	var columns []string
	for rows.Next() {
		var column string

		err = rows.Scan(&column)
		if err != nil {
			return nil, err
		}

		columns = append(columns, column)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	pkey.Columns = columns

	return pkey, nil
}

// ForeignKeyInfo retrieves the foreign keys for a given table name.
func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
	var fkeys []bdb.ForeignKey

	query := `
	SELECT
		ccu.constraint_name AS SourceConstraint
		,ccu.table_name AS SourceTable
		,ccu.column_name AS SourceColumn
		,kcu.table_name AS TargetTable
		,kcu.column_name AS TargetColumn
	FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
    INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
        ON ccu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
        ON kcu.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME
	where ccu.table_schema = ? and ccu.constraint_schema = ? and ccu.table_name = ?
	`

	var rows *sql.Rows
	var err error
	if rows, err = m.dbConn.Query(query, schema, schema, tableName); err != nil {
		return nil, err
	}

	for rows.Next() {
		var fkey bdb.ForeignKey
		var sourceTable string

		fkey.Table = tableName
		err = rows.Scan(&fkey.Name, &sourceTable, &fkey.Column, &fkey.ForeignTable, &fkey.ForeignColumn)
		if err != nil {
			return nil, err
		}

		fkeys = append(fkeys, fkey)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return fkeys, nil
}

// TranslateColumnType converts postgres database types to Go types, for example
// "varchar" to "string" and "bigint" to "int64". It returns this parsed data
// as a Column object.
func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
	if c.Nullable {
		switch c.DBType {
		case "bit":
			c.Type = "bool"
		case "tinyint":
			c.Type = "int8"
		case "smallint":
			c.Type = "null.Int16"
		case "mediumint":
			c.Type = "null.Int32"
		case "int", "integer":
			c.Type = "null.Int"
		case "bigint":
			c.Type = "null.Int64"
		case "float":
			c.Type = "null.Float32"
		case "double", "double precision", "real":
			c.Type = "null.Float64"
		case "boolean", "bool":
			c.Type = "null.Bool"
		case "date", "datetime", "timestamp", "time":
			c.Type = "null.Time"
		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
			c.Type = "null.Bytes"
		case "json":
			c.Type = "types.JSON"
		default:
			c.Type = "null.String"
		}
	} else {
		switch c.DBType {
		case "bit":
			c.Type = "bool"
		case "tinyint":
			c.Type = "int8"
		case "smallint":
			c.Type = "int16"
		case "mediumint":
			c.Type = "int32"
		case "int", "integer":
			c.Type = "int"
		case "bigint":
			c.Type = "int64"
		case "float":
			c.Type = "float32"
		case "double", "double precision", "real":
			c.Type = "float64"
		case "boolean", "bool":
			c.Type = "bool"
		case "date", "datetime", "timestamp", "time":
			c.Type = "time.Time"
		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
			c.Type = "[]byte"
		case "json":
			c.Type = "types.JSON"
		default:
			c.Type = "string"
		}
	}

	return c
}

// RightQuote is the quoting character for the right side of the identifier
func (m *MSSQLDriver) RightQuote() byte {
	return '"'
}

// LeftQuote is the quoting character for the left side of the identifier
func (m *MSSQLDriver) LeftQuote() byte {
	return '"'
}

// IndexPlaceholders returns true to indicate MS SQL supports indexed placeholders
func (m *MSSQLDriver) IndexPlaceholders() bool {
	return true
}
<commit_msg>Queries refactoring<commit_after>package drivers

import (
	"database/sql"
	"fmt"
	"net/url"
	"strings"

	_ "github.com/denisenkom/go-mssqldb"
	"github.com/pkg/errors"
	"github.com/vattle/sqlboiler/bdb"
)

// MSSQLDriver holds the database connection string and a handle
// to the database connection.
type MSSQLDriver struct {
	connStr string
	dbConn  *sql.DB
}

// NewMSSQLDriver takes the database connection details as parameters and
// returns a pointer to a MSSQLDriver object. Note that it is required to
// call MSSQLDriver.Open() and MSSQLDriver.Close() to open and close
// the database connection once an object has been obtained.
func NewMSSQLDriver(user, pass, dbname, host string, port int, sslmode string) *MSSQLDriver {
	driver := MSSQLDriver{
		connStr: MSSQLBuildQueryString(user, pass, dbname, host, port, sslmode),
	}

	return &driver
}

// MSSQLBuildQueryString builds a query string for MSSQL.
func MSSQLBuildQueryString(user, pass, dbname, host string, port int, sslmode string) string {

	query := url.Values{}
	query.Add("database", dbname)
	query.Add("encrypt", sslmode)

	u := &url.URL{
		Scheme: "sqlserver",
		User:   url.UserPassword(user, pass),
		Host:   fmt.Sprintf("%s:%d", host, port),
		// Path:  instance, // if connecting to an instance instead of a port
		RawQuery: query.Encode(),
	}

	return u.String()
}

// Open opens the database connection using the connection string
func (m *MSSQLDriver) Open() error {
	var err error
	m.dbConn, err = sql.Open("mssql", m.connStr)
	if err != nil {
		return err
	}

	return nil
}

// Close closes the database connection
func (m *MSSQLDriver) Close() {
	m.dbConn.Close()
}

// UseLastInsertID returns false for mssql
func (m *MSSQLDriver) UseLastInsertID() bool {
	return false
}

// UseTopClause returns true to indicate MS SQL supports SQL TOP clause
func (m *MSSQLDriver) UseTopClause() bool {
	return true
}

// TableNames connects to the postgres database and
// retrieves all table names from the information_schema where the
// table schema is public.
func (m *MSSQLDriver) TableNames(schema string, whitelist, blacklist []string) ([]string, error) {
	var names []string

	query := `
		SELECT table_name
		FROM   information_schema.tables
		WHERE  table_schema = ? AND table_type = 'BASE TABLE'`

	args := []interface{}{schema}
	if len(whitelist) > 0 {
		query += fmt.Sprintf(" AND table_name IN (%s);", strings.Repeat(",?", len(whitelist))[1:])
		for _, w := range whitelist {
			args = append(args, w)
		}
	} else if len(blacklist) > 0 {
		query += fmt.Sprintf(" AND table_name not IN (%s);", strings.Repeat(",?", len(blacklist))[1:])
		for _, b := range blacklist {
			args = append(args, b)
		}
	}

	rows, err := m.dbConn.Query(query, args...)

	if err != nil {
		return nil, err
	}

	defer rows.Close()
	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			return nil, err
		}
		names = append(names, name)
	}

	return names, nil
}

// Columns takes a table name and attempts to retrieve the table information
// from the database information_schema.columns. It retrieves the column names
// and column types and returns those as a []Column after TranslateColumnType()
// converts the SQL types to Go types, for example: "varchar" to "string"
func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
	var columns []bdb.Column

	rows, err := m.dbConn.Query(`
	SELECT column_name,
       CASE
         WHEN character_maximum_length IS NULL THEN data_type
         ELSE data_type + '(' + CAST(character_maximum_length AS VARCHAR) + ')'
       END AS full_type,
       data_type,
	   column_default,
       CASE
         WHEN is_nullable = 'YES' THEN 1
         ELSE 0
       END AS is_nullable,
       CASE
         WHEN EXISTS (SELECT c.column_name
                      FROM information_schema.table_constraints tc
                        INNER JOIN information_schema.key_column_usage kcu
                                ON tc.constraint_name = kcu.constraint_name
                               AND tc.table_name = kcu.table_name
                               AND tc.table_schema = kcu.table_schema
                      WHERE c.column_name = kcu.column_name
                      AND   tc.table_name = c.table_name
                      AND   (tc.constraint_type = 'PRIMARY KEY' OR tc.constraint_type = 'UNIQUE')
                      AND   (SELECT COUNT(*)
                             FROM information_schema.key_column_usage
                             WHERE table_schema = kcu.table_schema
                             AND   table_name = tc.table_name
                             AND   constraint_name = tc.constraint_name) = 1) THEN 1
         ELSE 0
       END AS is_unique
	FROM information_schema.columns c
	WHERE table_name = ? AND table_schema = ?;
	`, tableName, schema)

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var colName, colType, colFullType string
		var nullable, unique bool
		var defaultValue *string
		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique); err != nil {
			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
		}

		column := bdb.Column{
			Name:       colName,
			FullDBType: colFullType, // example: tinyint(1) instead of tinyint
			DBType:     colType,
			Nullable:   nullable,
			Unique:     unique,
		}

		if defaultValue != nil && *defaultValue != "NULL" {
			column.Default = *defaultValue
		}

		columns = append(columns, column)
	}

	return columns, nil
}

// PrimaryKeyInfo looks up the primary key for a table.
func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey, error) {
	pkey := &bdb.PrimaryKey{}
	var err error

	query := `
	SELECT constraint_name
	FROM   information_schema.table_constraints
	WHERE  table_name = ? AND constraint_type = 'PRIMARY KEY' AND table_schema = ?;`

	row := m.dbConn.QueryRow(query, tableName, schema)
	if err = row.Scan(&pkey.Name); err != nil {
		if err == sql.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}

	queryColumns := `
	SELECT column_name
	FROM   information_schema.key_column_usage
	WHERE  table_name = ? AND constraint_name = ? AND table_schema = ?;`

	var rows *sql.Rows
	if rows, err = m.dbConn.Query(queryColumns, tableName, pkey.Name, schema); err != nil {
		return nil, err
	}
	defer rows.Close()

	var columns []string
	for rows.Next() {
		var column string

		err = rows.Scan(&column)
		if err != nil {
			return nil, err
		}

		columns = append(columns, column)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	pkey.Columns = columns

	return pkey, nil
}

// ForeignKeyInfo retrieves the foreign keys for a given table name.
func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
	var fkeys []bdb.ForeignKey

	query := `
	SELECT
		ccu.constraint_name
		,ccu.table_name AS local_table
		,ccu.column_name AS local_column
		,kcu.table_name AS foreign_table
		,kcu.column_name AS foreign_column
	FROM information_schema.constraint_column_usage ccu
    INNER JOIN information_schema.referential_constraints rc
        ON ccu.constraint_name = rc.constraint_name
    INNER JOIN information_schema.key_column_usage kcu
        ON kcu.constraint_name = rc.unique_constraint_name
	WHERE ccu.table_schema = ? AND ccu.constraint_schema = ? AND ccu.table_name = ?
	`

	var rows *sql.Rows
	var err error
	if rows, err = m.dbConn.Query(query, schema, schema, tableName); err != nil {
		return nil, err
	}

	for rows.Next() {
		var fkey bdb.ForeignKey
		var sourceTable string

		fkey.Table = tableName
		err = rows.Scan(&fkey.Name, &sourceTable, &fkey.Column, &fkey.ForeignTable, &fkey.ForeignColumn)
		if err != nil {
			return nil, err
		}

		fkeys = append(fkeys, fkey)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return fkeys, nil
}

// TranslateColumnType converts postgres database types to Go types, for example
// "varchar" to "string" and "bigint" to "int64". It returns this parsed data
// as a Column object.
func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
	if c.Nullable {
		switch c.DBType {
		case "bit":
			c.Type = "bool"
		case "tinyint":
			c.Type = "int8"
		case "smallint":
			c.Type = "null.Int16"
		case "mediumint":
			c.Type = "null.Int32"
		case "int", "integer":
			c.Type = "null.Int"
		case "bigint":
			c.Type = "null.Int64"
		case "float":
			c.Type = "null.Float32"
		case "double", "double precision", "real":
			c.Type = "null.Float64"
		case "boolean", "bool":
			c.Type = "null.Bool"
		case "date", "datetime", "timestamp", "time":
			c.Type = "null.Time"
		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
			c.Type = "null.Bytes"
		case "json":
			c.Type = "types.JSON"
		default:
			c.Type = "null.String"
		}
	} else {
		switch c.DBType {
		case "bit":
			c.Type = "bool"
		case "tinyint":
			c.Type = "int8"
		case "smallint":
			c.Type = "int16"
		case "mediumint":
			c.Type = "int32"
		case "int", "integer":
			c.Type = "int"
		case "bigint":
			c.Type = "int64"
		case "float":
			c.Type = "float32"
		case "double", "double precision", "real":
			c.Type = "float64"
		case "boolean", "bool":
			c.Type = "bool"
		case "date", "datetime", "timestamp", "time":
			c.Type = "time.Time"
		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
			c.Type = "[]byte"
		case "json":
			c.Type = "types.JSON"
		default:
			c.Type = "string"
		}
	}

	return c
}

// RightQuote is the quoting character for the right side of the identifier
func (m *MSSQLDriver) RightQuote() byte {
	return '"'
}

// LeftQuote is the quoting character for the left side of the identifier
func (m *MSSQLDriver) LeftQuote() byte {
	return '"'
}

// IndexPlaceholders returns true to indicate MS SQL supports indexed placeholders
func (m *MSSQLDriver) IndexPlaceholders() bool {
	return true
}
<|endoftext|>


<commit_before>// Method implements the ability to override HTTP methods
// This package was created from github.com/codegangsta/martini-contrib/method
// and modified to work with the echo framework
package method

import (
	"errors"
	"fmt"

	"github.com/labstack/echo"
)

// HeaderHTTPMethodOVerride is a common HTTP header used to override the HTTP
// method
const HeaderHTTPMethodOverride = "X-HTTP-Method-Override"

// ParamHTTPMethodOverride is a common used HTTML form parameter used to
// override the HTTP method
const ParamHTTPMethodOverride = "_method"

// HTTP methods overridden by this package
var httpMethods = []string{"PUT", "PATCH", "DELETE"}

// ErrInvalidOverrideMethod is returned when
// an invalid http method was given to OverrideRequestMethod.
var ErrInvalidOverrideMethod = errors.New("invalid override method")

// isValidOverrideMethod determines if the method is a valid override method
func isValidOverrideMethod(method string) bool {
	for _, m := range httpMethods {
		if m == method {
			return true
		}
	}
	return false
}

// Override checks for the X-HTTP-Method-Override header
// or the HTML for parameter, `_method`
// and uses (if valid) the http method instead of
// Request.Method.
// This is especially useful for http clients
// that don't support many http verbs.
// It isn't secure to override e.g a GET to a POST,
// so only Request.Method which are POSTs are considered.
func Override() echo.HandlerFunc {
	return func(c *echo.Context) error {
		fmt.Println(c.Request().Method)

		if c.Request().Method == "POST" {
			m := c.Form(ParamHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				OverrideRequestMethod(c, m)
			}
			m = c.Request().Header.Get(HeaderHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				c.Request().Method = m
			}
		}
		return nil
	}
}

// OverrideRequestMethod overrides the http
// request's method with the specified method.
func OverrideRequestMethod(c *echo.Context, method string) error {
	if !isValidOverrideMethod(method) {
		return ErrInvalidOverrideMethod
	}
	c.Request().Header.Set(HeaderHTTPMethodOverride, method)
	return nil
}
<commit_msg>removing fmt.Println<commit_after>// Method implements the ability to override HTTP methods
// This package was created from github.com/codegangsta/martini-contrib/method
// and modified to work with the echo framework
package method

import (
	"errors"

	"github.com/labstack/echo"
)

// HeaderHTTPMethodOVerride is a common HTTP header used to override the HTTP
// method
const HeaderHTTPMethodOverride = "X-HTTP-Method-Override"

// ParamHTTPMethodOverride is a common used HTTML form parameter used to
// override the HTTP method
const ParamHTTPMethodOverride = "_method"

// HTTP methods overridden by this package
var httpMethods = []string{"PUT", "PATCH", "DELETE"}

// ErrInvalidOverrideMethod is returned when
// an invalid http method was given to OverrideRequestMethod.
var ErrInvalidOverrideMethod = errors.New("invalid override method")

// isValidOverrideMethod determines if the method is a valid override method
func isValidOverrideMethod(method string) bool {
	for _, m := range httpMethods {
		if m == method {
			return true
		}
	}
	return false
}

// Override checks for the X-HTTP-Method-Override header
// or the HTML for parameter, `_method`
// and uses (if valid) the http method instead of
// Request.Method.
// This is especially useful for http clients
// that don't support many http verbs.
// It isn't secure to override e.g a GET to a POST,
// so only Request.Method which are POSTs are considered.
func Override() echo.HandlerFunc {
	return func(c *echo.Context) error {
		if c.Request().Method == "POST" {
			m := c.Form(ParamHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				OverrideRequestMethod(c, m)
			}
			m = c.Request().Header.Get(HeaderHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				c.Request().Method = m
			}
		}
		return nil
	}
}

// OverrideRequestMethod overrides the http
// request's method with the specified method.
func OverrideRequestMethod(c *echo.Context, method string) error {
	if !isValidOverrideMethod(method) {
		return ErrInvalidOverrideMethod
	}
	c.Request().Header.Set(HeaderHTTPMethodOverride, method)
	return nil
}
<|endoftext|>


<commit_before>package runtime

import (
	"testing"
)

func TestLen(t *testing.T) {
	cases := []struct {
		src Val
		exp int64
	}{
		0: {
			src: Nil,
			exp: 0,
		},
		1: {
			src: Number(3.14),
			exp: 4,
		},
		2: {
			src: String("hi, there"),
			exp: 9,
		},
		3: {
			src: Bool(true),
			exp: 4,
		},
		4: {
			src: String(`this
has
new
lines`),
			exp: 18,
		},
		5: {
			src: &object{
				map[Val]Val{
					Number(1):      String("val1"),
					String("name"): Bool(false),
					String("subobj"): &object{
						map[Val]Val{
							String("key"): Number(10),
						},
					},
				},
			},
			exp: 3,
		},
		6: {
			src: &object{},
			exp: 0,
		},
		7: {
			src: String(""),
			exp: 0,
		},
	}

	bi := new(builtinMod)
	ctx := NewCtx(nil, nil)
	bi.SetCtx(ctx)
	for i, c := range cases {
		ret := bi._len(c.src)
		if c.exp != ret.Int() {
			t.Errorf("[%d] - expected %d, got %d", i, c.exp, ret.Int())
		}
	}
}
<commit_msg>add tests for _panic<commit_after>package runtime

import (
	"testing"
)

func TestLen(t *testing.T) {
	cases := []struct {
		src Val
		exp int64
	}{
		0: {
			src: Nil,
			exp: 0,
		},
		1: {
			src: Number(3.14),
			exp: 4,
		},
		2: {
			src: String("hi, there"),
			exp: 9,
		},
		3: {
			src: Bool(true),
			exp: 4,
		},
		4: {
			src: String(`this
has
new
lines`),
			exp: 18,
		},
		5: {
			src: &object{
				map[Val]Val{
					Number(1):      String("val1"),
					String("name"): Bool(false),
					String("subobj"): &object{
						map[Val]Val{
							String("key"): Number(10),
						},
					},
				},
			},
			exp: 3,
		},
		6: {
			src: &object{},
			exp: 0,
		},
		7: {
			src: String(""),
			exp: 0,
		},
	}

	bi := new(builtinMod)
	ctx := NewCtx(nil, nil)
	bi.SetCtx(ctx)
	for i, c := range cases {
		ret := bi._len(c.src)
		if c.exp != ret.Int() {
			t.Errorf("[%d] - expected %d, got %d", i, c.exp, ret.Int())
		}
	}
}

func TestPanic(t *testing.T) {
	ctx := NewCtx(nil, nil)

	cases := []struct {
		src Val
		err bool
	}{
		0: {
			src: Nil,
			err: false,
		},
		1: {
			src: Bool(false),
			err: false,
		},
		2: {
			src: String(""),
			err: false,
		},
		3: {
			src: Number(0),
			err: false,
		},
		4: {
			src: Number(0.0),
			err: false,
		},
		5: {
			src: &object{
				map[Val]Val{
					String("__toBool"): NewNativeFunc(ctx, "", func(args ...Val) Val {
						return Bool(false)
					}),
				},
			},
			err: false,
		},
		6: {
			src: Number(0.1),
			err: true,
		},
		7: {
			src: Bool(true),
			err: true,
		},
		8: {
			src: String("error"),
			err: true,
		},
		9: {
			src: NewNativeFunc(ctx, "", func(args ...Val) Val { return Nil }),
			err: true,
		},
		10: {
			src: Number(-1),
			err: true,
		},
		11: {
			src: &object{},
			err: true,
		},
		12: {
			src: &object{
				map[Val]Val{
					String("__toBool"): NewNativeFunc(ctx, "", func(args ...Val) Val {
						return Bool(true)
					}),
				},
			},
			err: true,
		},
	}

	bi := new(builtinMod)
	bi.SetCtx(ctx)
	for i, c := range cases {
		func() {
			defer func() {
				if e := recover(); (e != nil) != c.err {
					if c.err {
						t.Errorf("[%d] - expected a panic, got none", i)
					} else {
						t.Errorf("[%d] - expected no panic, got %v", i, e)
					}
				}
			}()
			bi._panic(c.src)
		}()
	}
}
<|endoftext|>


<commit_before>package instances

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/echo"
)

type apiInstance struct {
	*instance.Instance
}

func (i *apiInstance) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.Instance)
}

// Links is used to generate a JSON-API link for the instance
func (i *apiInstance) Links() *jsonapi.LinksList {
	return &jsonapi.LinksList{Self: "/instances/" + i.Instance.DocID}
}

// Relationships is used to generate the content relationship in JSON-API format
func (i *apiInstance) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (i *apiInstance) Included() []jsonapi.Object {
	return nil
}

func createHandler(c echo.Context) error {
	var diskQuota int64
	if c.QueryParam("DiskQuota") != "" {
		var err error
		diskQuota, err = strconv.ParseInt(c.QueryParam("DiskQuota"), 10, 64)
		if err != nil {
			return wrapError(err)
		}
	}
	var settings couchdb.JSONDoc
	settings.M = make(map[string]interface{})
	for _, setting := range strings.Split(c.QueryParam("Settings"), ",") {
		if parts := strings.SplitN(setting, ":", 2); len(parts) == 2 {
			settings.M[parts[0]] = parts[1]
		}
	}
	if tz := c.QueryParam("Timezone"); tz != "" {
		settings.M["tz"] = tz
	}
	if email := c.QueryParam("Email"); email != "" {
		settings.M["email"] = email
	}
	if name := c.QueryParam("PublicName"); name != "" {
		settings.M["public_name"] = name
	}
	in, err := instance.Create(&instance.Options{
		Domain:    c.QueryParam("Domain"),
		Locale:    c.QueryParam("Locale"),
		DiskQuota: diskQuota,
		Settings:  settings,
		Apps:      utils.SplitTrimString(c.QueryParam("Apps"), ","),
		Dev:       (c.QueryParam("Dev") == "true"),
	})
	if err != nil {
		return wrapError(err)
	}
	in.OAuthSecret = nil
	in.SessionSecret = nil
	in.PassphraseHash = nil
	pass := c.QueryParam("Passphrase")
	if pass != "" {
		if err = in.RegisterPassphrase([]byte(pass), in.RegisterToken); err != nil {
			return err
		}
	}
	return jsonapi.Data(c, http.StatusCreated, &apiInstance{in}, nil)
}

func showHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func modifyHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	var shouldUpdate bool
	if quota := c.QueryParam("DiskQuota"); quota != "" {
		var diskQuota int64
		diskQuota, err = strconv.ParseInt(quota, 10, 64)
		if err != nil {
			return wrapError(err)
		}
		i.BytesDiskQuota = diskQuota
		shouldUpdate = true
	}
	if locale := c.QueryParam("Locale"); locale != "" {
		i.Locale = locale
		shouldUpdate = true
	}
	if shouldUpdate {
		if err = instance.Update(i); err != nil {
			return wrapError(err)
		}
	}
	if debug, err := strconv.ParseBool(c.QueryParam("Debug")); err == nil {
		if debug {
			err = logger.AddDebugDomain(domain)
		} else {
			err = logger.RemoveDebugDomain(domain)
		}
		if err != nil {
			return wrapError(err)
		}
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func listHandler(c echo.Context) error {
	is, err := instance.List()
	if err != nil {
		return wrapError(err)
	}

	objs := make([]jsonapi.Object, len(is))
	for i, in := range is {
		in.OAuthSecret = nil
		in.SessionSecret = nil
		in.RegisterToken = nil
		in.PassphraseHash = nil
		objs[i] = &apiInstance{in}
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

func deleteHandler(c echo.Context) error {
	domain := c.Param("domain")
	err := instance.Destroy(domain)
	if err != nil {
		return wrapError(err)
	}
	return c.NoContent(http.StatusNoContent)
}

func createToken(c echo.Context) error {
	domain := c.QueryParam("Domain")
	audience := c.QueryParam("Audience")
	scope := c.QueryParam("Scope")
	subject := c.QueryParam("Subject")
	expire := c.QueryParam("Expire")
	in, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	switch audience {
	case "app":
		audience = permissions.AppAudience
	case "konn", "konnector":
		audience = permissions.KonnectorAudience
	case "access-token":
		audience = permissions.AccessTokenAudience
	case "cli":
		audience = permissions.CLIAudience
	default:
		return echo.NewHTTPError(http.StatusBadRequest, "Unknown audience %s", audience)
	}
	issuedAt := time.Now()
	if expire != "" && expire != "0s" {
		var duration time.Duration
		if duration, err = time.ParseDuration(expire); err == nil {
			issuedAt = issuedAt.Add(duration - permissions.TokenValidityDuration)
		}
	}
	token, err := in.MakeJWT(audience, subject, scope, issuedAt)
	if err != nil {
		return err
	}
	return c.String(http.StatusOK, token)
}

func registerClient(c echo.Context) error {
	in, err := instance.Get(c.QueryParam("Domain"))
	if err != nil {
		return wrapError(err)
	}
	client := oauth.Client{
		RedirectURIs: []string{c.QueryParam("RedirectURI")},
		ClientName:   c.QueryParam("ClientName"),
		SoftwareID:   c.QueryParam("SoftwareID"),
	}
	if regErr := client.Create(in); regErr != nil {
		return c.String(http.StatusBadRequest, regErr.Description)
	}
	return c.String(http.StatusOK, client.ClientID)
}

func wrapError(err error) error {
	switch err {
	case instance.ErrNotFound:
		return jsonapi.NotFound(err)
	case instance.ErrExists:
		return jsonapi.Conflict(err)
	case instance.ErrIllegalDomain:
		return jsonapi.InvalidParameter("domain", err)
	case instance.ErrMissingToken:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidToken:
		return jsonapi.BadRequest(err)
	case instance.ErrMissingPassphrase:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidPassphrase:
		return jsonapi.BadRequest(err)
	}
	return err
}

// Routes sets the routing for the instances service
func Routes(router *echo.Group) {
	router.GET("", listHandler)
	router.POST("", createHandler)
	router.GET("/:domain", showHandler)
	router.PATCH("/:domain", modifyHandler)
	router.DELETE("/:domain", deleteHandler)
	router.POST("/token", createToken)
	router.POST("/oauth_client", registerClient)
}
<commit_msg>Fix cozy-stack instance ls on a fresh couchdb<commit_after>package instances

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/utils"
	"github.com/cozy/cozy-stack/web/jsonapi"
	"github.com/cozy/echo"
)

type apiInstance struct {
	*instance.Instance
}

func (i *apiInstance) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.Instance)
}

// Links is used to generate a JSON-API link for the instance
func (i *apiInstance) Links() *jsonapi.LinksList {
	return &jsonapi.LinksList{Self: "/instances/" + i.Instance.DocID}
}

// Relationships is used to generate the content relationship in JSON-API format
func (i *apiInstance) Relationships() jsonapi.RelationshipMap {
	return jsonapi.RelationshipMap{}
}

// Included is part of the jsonapi.Object interface
func (i *apiInstance) Included() []jsonapi.Object {
	return nil
}

func createHandler(c echo.Context) error {
	var diskQuota int64
	if c.QueryParam("DiskQuota") != "" {
		var err error
		diskQuota, err = strconv.ParseInt(c.QueryParam("DiskQuota"), 10, 64)
		if err != nil {
			return wrapError(err)
		}
	}
	var settings couchdb.JSONDoc
	settings.M = make(map[string]interface{})
	for _, setting := range strings.Split(c.QueryParam("Settings"), ",") {
		if parts := strings.SplitN(setting, ":", 2); len(parts) == 2 {
			settings.M[parts[0]] = parts[1]
		}
	}
	if tz := c.QueryParam("Timezone"); tz != "" {
		settings.M["tz"] = tz
	}
	if email := c.QueryParam("Email"); email != "" {
		settings.M["email"] = email
	}
	if name := c.QueryParam("PublicName"); name != "" {
		settings.M["public_name"] = name
	}
	in, err := instance.Create(&instance.Options{
		Domain:    c.QueryParam("Domain"),
		Locale:    c.QueryParam("Locale"),
		DiskQuota: diskQuota,
		Settings:  settings,
		Apps:      utils.SplitTrimString(c.QueryParam("Apps"), ","),
		Dev:       (c.QueryParam("Dev") == "true"),
	})
	if err != nil {
		return wrapError(err)
	}
	in.OAuthSecret = nil
	in.SessionSecret = nil
	in.PassphraseHash = nil
	pass := c.QueryParam("Passphrase")
	if pass != "" {
		if err = in.RegisterPassphrase([]byte(pass), in.RegisterToken); err != nil {
			return err
		}
	}
	return jsonapi.Data(c, http.StatusCreated, &apiInstance{in}, nil)
}

func showHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func modifyHandler(c echo.Context) error {
	domain := c.Param("domain")
	i, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	var shouldUpdate bool
	if quota := c.QueryParam("DiskQuota"); quota != "" {
		var diskQuota int64
		diskQuota, err = strconv.ParseInt(quota, 10, 64)
		if err != nil {
			return wrapError(err)
		}
		i.BytesDiskQuota = diskQuota
		shouldUpdate = true
	}
	if locale := c.QueryParam("Locale"); locale != "" {
		i.Locale = locale
		shouldUpdate = true
	}
	if shouldUpdate {
		if err = instance.Update(i); err != nil {
			return wrapError(err)
		}
	}
	if debug, err := strconv.ParseBool(c.QueryParam("Debug")); err == nil {
		if debug {
			err = logger.AddDebugDomain(domain)
		} else {
			err = logger.RemoveDebugDomain(domain)
		}
		if err != nil {
			return wrapError(err)
		}
	}
	return jsonapi.Data(c, http.StatusOK, &apiInstance{i}, nil)
}

func listHandler(c echo.Context) error {
	is, err := instance.List()
	if err != nil {
		if couchdb.IsNoDatabaseError(err) {
			return jsonapi.DataList(c, http.StatusOK, nil, nil)
		}
		return wrapError(err)
	}

	objs := make([]jsonapi.Object, len(is))
	for i, in := range is {
		in.OAuthSecret = nil
		in.SessionSecret = nil
		in.RegisterToken = nil
		in.PassphraseHash = nil
		objs[i] = &apiInstance{in}
	}

	return jsonapi.DataList(c, http.StatusOK, objs, nil)
}

func deleteHandler(c echo.Context) error {
	domain := c.Param("domain")
	err := instance.Destroy(domain)
	if err != nil {
		return wrapError(err)
	}
	return c.NoContent(http.StatusNoContent)
}

func createToken(c echo.Context) error {
	domain := c.QueryParam("Domain")
	audience := c.QueryParam("Audience")
	scope := c.QueryParam("Scope")
	subject := c.QueryParam("Subject")
	expire := c.QueryParam("Expire")
	in, err := instance.Get(domain)
	if err != nil {
		return wrapError(err)
	}
	switch audience {
	case "app":
		audience = permissions.AppAudience
	case "konn", "konnector":
		audience = permissions.KonnectorAudience
	case "access-token":
		audience = permissions.AccessTokenAudience
	case "cli":
		audience = permissions.CLIAudience
	default:
		return echo.NewHTTPError(http.StatusBadRequest, "Unknown audience %s", audience)
	}
	issuedAt := time.Now()
	if expire != "" && expire != "0s" {
		var duration time.Duration
		if duration, err = time.ParseDuration(expire); err == nil {
			issuedAt = issuedAt.Add(duration - permissions.TokenValidityDuration)
		}
	}
	token, err := in.MakeJWT(audience, subject, scope, issuedAt)
	if err != nil {
		return err
	}
	return c.String(http.StatusOK, token)
}

func registerClient(c echo.Context) error {
	in, err := instance.Get(c.QueryParam("Domain"))
	if err != nil {
		return wrapError(err)
	}
	client := oauth.Client{
		RedirectURIs: []string{c.QueryParam("RedirectURI")},
		ClientName:   c.QueryParam("ClientName"),
		SoftwareID:   c.QueryParam("SoftwareID"),
	}
	if regErr := client.Create(in); regErr != nil {
		return c.String(http.StatusBadRequest, regErr.Description)
	}
	return c.String(http.StatusOK, client.ClientID)
}

func wrapError(err error) error {
	switch err {
	case instance.ErrNotFound:
		return jsonapi.NotFound(err)
	case instance.ErrExists:
		return jsonapi.Conflict(err)
	case instance.ErrIllegalDomain:
		return jsonapi.InvalidParameter("domain", err)
	case instance.ErrMissingToken:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidToken:
		return jsonapi.BadRequest(err)
	case instance.ErrMissingPassphrase:
		return jsonapi.BadRequest(err)
	case instance.ErrInvalidPassphrase:
		return jsonapi.BadRequest(err)
	}
	return err
}

// Routes sets the routing for the instances service
func Routes(router *echo.Group) {
	router.GET("", listHandler)
	router.POST("", createHandler)
	router.GET("/:domain", showHandler)
	router.PATCH("/:domain", modifyHandler)
	router.DELETE("/:domain", deleteHandler)
	router.POST("/token", createToken)
	router.POST("/oauth_client", registerClient)
}
<|endoftext|>


<commit_before>package sharings

import (
	"net/http"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/sharing"
	"github.com/cozy/cozy-stack/web/middlewares"
	perm "github.com/cozy/cozy-stack/web/permissions"
	"github.com/cozy/echo"
)

// RevsDiff is part of the replicator
func RevsDiff(c echo.Context) error {
	inst := middlewares.GetInstance(c)
	sharingID := c.Param("sharing-id")
	s, err := sharing.FindSharing(inst, sharingID)
	if err != nil {
		return wrapErrors(err)
	}
	var changes sharing.Changes
	if err = c.Bind(&changes); err != nil {
		return wrapErrors(err)
	}
	if changes == nil {
		return echo.NewHTTPError(http.StatusBadRequest)
	}
	missings, err := s.ComputeRevsDiff(inst, changes)
	if err != nil {
		return wrapErrors(err)
	}
	return c.JSON(http.StatusOK, missings)
}

// BulkDocs is part of the replicator
func BulkDocs(c echo.Context) error {
	inst := middlewares.GetInstance(c)
	sharingID := c.Param("sharing-id")
	s, err := sharing.FindSharing(inst, sharingID)
	if err != nil {
		return wrapErrors(err)
	}
	var docs sharing.DocsByDoctype
	if err = c.Bind(&docs); err != nil {
		return wrapErrors(err)
	}
	if docs == nil {
		return echo.NewHTTPError(http.StatusBadRequest)
	}
	err = s.ApplyBulkDocs(inst, docs)
	if err != nil {
		return wrapErrors(err)
	}
	return c.JSON(http.StatusOK, []interface{}{})
}

// replicatorRoutes sets the routing for the replicator
func replicatorRoutes(router *echo.Group) {
	group := router.Group("", checkSharingPermissions)
	group.POST("/:sharing-id/_revs_diff", RevsDiff, checkSharingPermissions)
	group.POST("/:sharing-id/_bulk_docs", BulkDocs, checkSharingPermissions)
}

func checkSharingPermissions(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		sharingID := c.Param("sharing-id")
		requestPerm, err := perm.GetPermission(c)
		if err != nil {
			return err
		}
		if !requestPerm.Permissions.AllowID("GET", consts.Sharings, sharingID) {
			return echo.NewHTTPError(http.StatusForbidden)
		}
		return next(c)
	}
}
<commit_msg>Add some debug logs in web/sharings<commit_after>package sharings

import (
	"net/http"

	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/sharing"
	"github.com/cozy/cozy-stack/web/middlewares"
	perm "github.com/cozy/cozy-stack/web/permissions"
	"github.com/cozy/echo"
)

// RevsDiff is part of the replicator
func RevsDiff(c echo.Context) error {
	inst := middlewares.GetInstance(c)
	sharingID := c.Param("sharing-id")
	s, err := sharing.FindSharing(inst, sharingID)
	if err != nil {
		inst.Logger().Debugf("[revs_diff] Sharing was not found: %s", err)
		return wrapErrors(err)
	}
	var changes sharing.Changes
	if err = c.Bind(&changes); err != nil {
		inst.Logger().Debugf("[revs_diff] Changes cannot be bound: %s", err)
		return wrapErrors(err)
	}
	if changes == nil {
		inst.Logger().Debugf("[revs_diff] No changes")
		return echo.NewHTTPError(http.StatusBadRequest)
	}
	missings, err := s.ComputeRevsDiff(inst, changes)
	if err != nil {
		inst.Logger().Debugf("[revs_diff] Error on compute: %s", err)
		return wrapErrors(err)
	}
	return c.JSON(http.StatusOK, missings)
}

// BulkDocs is part of the replicator
func BulkDocs(c echo.Context) error {
	inst := middlewares.GetInstance(c)
	sharingID := c.Param("sharing-id")
	s, err := sharing.FindSharing(inst, sharingID)
	if err != nil {
		inst.Logger().Debugf("[bulk_docs] Sharing was not found: %s", err)
		return wrapErrors(err)
	}
	var docs sharing.DocsByDoctype
	if err = c.Bind(&docs); err != nil {
		inst.Logger().Debugf("[bulk_docs] Docs cannot be bound: %s", err)
		return wrapErrors(err)
	}
	if docs == nil {
		inst.Logger().Debugf("[bulk_docs] No docs")
		return echo.NewHTTPError(http.StatusBadRequest)
	}
	err = s.ApplyBulkDocs(inst, docs)
	if err != nil {
		inst.Logger().Debugf("[bulk_docs] Error on apply: %s", err)
		return wrapErrors(err)
	}
	return c.JSON(http.StatusOK, []interface{}{})
}

// replicatorRoutes sets the routing for the replicator
func replicatorRoutes(router *echo.Group) {
	group := router.Group("", checkSharingPermissions)
	group.POST("/:sharing-id/_revs_diff", RevsDiff, checkSharingPermissions)
	group.POST("/:sharing-id/_bulk_docs", BulkDocs, checkSharingPermissions)
}

func checkSharingPermissions(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		sharingID := c.Param("sharing-id")
		requestPerm, err := perm.GetPermission(c)
		if err != nil {
			middlewares.GetInstance(c).Logger().Debugf("[sharing] Invalid permission: %s", err)
			return err
		}
		if !requestPerm.Permissions.AllowID("GET", consts.Sharings, sharingID) {
			middlewares.GetInstance(c).Logger().Debugf("[sharing] Not allowed (%s)", sharingID)
			return echo.NewHTTPError(http.StatusForbidden)
		}
		return next(c)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package datastore

import (
	"errors"
	//	"fmt"
	"reflect"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/mpl/scancabimport/third_party/code.google.com/p/goprotobuf/proto"
	pb "github.com/mpl/scancabimport/third_party/google.golang.org/cloud/internal/datastore"
)

const (
	tagKeyDatastore = "datastore"
)

var (
	reCCtoUnderscore = regexp.MustCompile("([A-Z][a-z|0-9]*)")
)

var operatorToProto = map[operator]*pb.PropertyFilter_Operator{
	lessThan:    pb.PropertyFilter_LESS_THAN.Enum(),
	lessEq:      pb.PropertyFilter_LESS_THAN_OR_EQUAL.Enum(),
	equal:       pb.PropertyFilter_EQUAL.Enum(),
	greaterEq:   pb.PropertyFilter_GREATER_THAN_OR_EQUAL.Enum(),
	greaterThan: pb.PropertyFilter_GREATER_THAN.Enum(),
}

var sortDirectionToProto = map[sortDirection]*pb.PropertyOrder_Direction{
	ascending:  pb.PropertyOrder_ASCENDING.Enum(),
	descending: pb.PropertyOrder_ASCENDING.Enum(),
}

var (
	typeOfByteSlice   = reflect.TypeOf([]byte{})
	typeOfTime        = reflect.TypeOf(time.Time{})
	typeOfKeyPtr      = reflect.TypeOf(&Key{})
	typeOfKeyPtrSlice = reflect.SliceOf(typeOfKeyPtr)
)

type fieldMeta struct {
	field   *reflect.StructField
	name    string
	indexed bool
}

var (
	mu         sync.Mutex
	entityMeta map[reflect.Type](map[string]*fieldMeta) = make(map[reflect.Type](map[string]*fieldMeta))
)

func camelCaseToUnderscore(name string) string {
	v := reCCtoUnderscore.ReplaceAllString(name, "${1}_")
	return strings.Trim(strings.ToLower(v), "_")
}

func registerEntityMeta(typ reflect.Type) map[string]*fieldMeta {
	mu.Lock()
	defer mu.Unlock()

	metadata, ok := entityMeta[typ]
	if ok {
		return metadata
	}
	entityMeta[typ] = make(map[string]*fieldMeta)
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		tag := field.Tag.Get(tagKeyDatastore)
		name := ""
		indexed := true // by default TODO(jbd): If list, don't set.

		// name_of_the_field
		// name_of_the_field,noindex
		if strings.Contains(tag, "noindex") {
			indexed = false
			name = strings.Replace(tag, ",noindex", "", -1)
		} else {
			name = tag
		}
		if name == "" {
			name = camelCaseToUnderscore(field.Name)
		}

		entityMeta[typ][name] = &fieldMeta{
			field: &field, name: name, indexed: indexed,
		}
	}
	return entityMeta[typ]
}

func keyToProto(k *Key) *pb.Key {
	// TODO(jbd): Eliminate unrequired allocations.
	path := []*pb.Key_PathElement(nil)
	for {
		el := &pb.Key_PathElement{
			Kind: proto.String(k.kind),
		}
		if k.id != 0 {
			el.Id = proto.Int64(k.id)
		}
		if k.name != "" {
			el.Name = proto.String(k.name)
		}
		path = append([]*pb.Key_PathElement{el}, path...)
		if k.parent == nil {
			break
		}
		k = k.parent
	}
	key := &pb.Key{
		PathElement: path,
	}
	if k.namespace != "" {
		key.PartitionId = &pb.PartitionId{
			Namespace: proto.String(k.namespace),
		}
	}
	return key
}

func protoToKey(p *pb.Key) *Key {
	pe := p.GetPathElement()
	if len(pe) == 0 {
		return nil
	}
	keys := make([]*Key, len(pe))
	for i, el := range pe {
		keys[i] = &Key{
			namespace: p.GetPartitionId().GetNamespace(),
			kind:      el.GetKind(),
			id:        el.GetId(),
			name:      el.GetName(),
		}
	}
	for i := 0; i < len(keys)-1; i++ {
		keys[i+1].parent = keys[i]
	}
	return keys[len(keys)-1]
}

func queryToProto(q *Query) *pb.Query {
	// TODO(jbd): Support ancestry queries.
	p := &pb.Query{}
	p.Kind = make([]*pb.KindExpression, len(q.kinds))
	for i, kind := range q.kinds {
		p.Kind[i] = &pb.KindExpression{Name: proto.String(kind)}
	}
	if len(q.projection) > 0 {
		p.Projection = make([]*pb.PropertyExpression, len(q.projection))
		for i, fieldName := range q.projection {
			p.Projection[i] = &pb.PropertyExpression{
				Property: &pb.PropertyReference{Name: proto.String(fieldName)},
			}
		}
	}
	// filters
	if len(q.filter) > 0 {
		p.Filter = &pb.Filter{
			CompositeFilter: &pb.CompositeFilter{},
		}
		filters := make([]*pb.Filter, len(q.filter))
		for i, f := range q.filter {
			filters[i] = &pb.Filter{
				PropertyFilter: &pb.PropertyFilter{
					Property: &pb.PropertyReference{Name: &f.FieldName},
					Operator: operatorToProto[f.Op],
					Value:    objToValue(f.Value),
				},
			}
		}
		p.Filter.CompositeFilter.Filter = filters
		p.Filter.CompositeFilter.Operator = pb.CompositeFilter_AND.Enum()
	}
	// group-by
	if len(q.groupBy) > 0 {
		p.GroupBy = make([]*pb.PropertyReference, len(q.groupBy))
		for i, fieldName := range q.groupBy {
			p.GroupBy[i] = &pb.PropertyReference{Name: &fieldName}
		}
	}
	// pagination
	if len(q.start) > 0 {
		p.StartCursor = q.start
	}
	if len(q.end) > 0 {
		p.EndCursor = q.end
	}
	if q.limit > 0 {
		p.Limit = &q.limit

	}
	if q.offset > 0 {
		p.Offset = &q.offset
	}
	return p
}

func entityToProto(key *Key, val reflect.Value) *pb.Entity {
	typ := val.Type()
	metadata := registerEntityMeta(typ)
	entityProto := &pb.Entity{
		Key:      keyToProto(key),
		Property: make([]*pb.Property, 0),
	}

	for name, f := range metadata {
		p := &pb.Property{}
		v := val.FieldByName(f.field.Name)
		p.Name = proto.String(name)
		p.Value = objToValue(v.Interface())
		entityProto.Property = append(entityProto.GetProperty(), p)
	}
	return entityProto
}

func protoToEntity(src *pb.Entity, dest interface{}) {
	typ := reflect.TypeOf(dest).Elem()
	val := reflect.ValueOf(dest).Elem()
	metadata := registerEntityMeta(typ)
	for _, p := range src.GetProperty() {
		f, ok := metadata[p.GetName()]
		if !ok {
			// skip if not presented in the struct
			continue
		}
		fv := val.FieldByName(f.field.Name)
		pv := p.GetValue()
		switch f.field.Type.Kind() {
		case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
			fv.SetInt(pv.GetIntegerValue())
		case reflect.Bool:
			fv.SetBool(pv.GetBooleanValue())
		case reflect.Float32, reflect.Float64:
			fv.SetFloat(pv.GetDoubleValue())
		case reflect.String:
			fv.SetString(pv.GetStringValue())
//		case typeOfKeyPtrSlice.Kind():
//			if strings.ToLower(f.field.Name) == "tags" {
//				println("BINGO")
//			}
//			var keys []*Key
//			for _, lv := range pv.GetListValue() {
//				keys = append(keys, protoToKey(lv.GetKeyValue()))
//			}
//			fv.Set(reflect.ValueOf(keys))
		case typeOfByteSlice.Kind():
			// slice types can not be differentiated with Kind(), so whichever
			// case is the first in the switch would be the one used, regardless
			// of whether the type is a slice of bytes or a slice of key pointers
			// for example. Therefore, we use the string representation to detect
			// when we get a slice of key pointers.
			if f.field.Type.String() == "[]*datastore.Key" {
				lv := pv.GetListValue()
				keys := make([]*Key, 0, len(lv))
				for _, lv := range lv {
					keys = append(keys, protoToKey(lv.GetKeyValue()))
				}
				fv.Set(reflect.ValueOf(keys))
			} else if f.field.Type.String() == "[]string" {
				lv := pv.GetListValue()
				ss := make([]string, 0, len(lv))
				for _, lv := range lv {
					ss = append(ss, lv.GetStringValue())
				}
				fv.Set(reflect.ValueOf(ss))
			} else {
				fv.SetBytes(pv.GetBlobValue())
			}
		case typeOfKeyPtr.Kind():
			key := protoToKey(pv.GetKeyValue())
			fv.Set(reflect.ValueOf(key))
		case typeOfTime.Kind():
			sec := pv.GetTimestampMicrosecondsValue() / (1000 * 1000)
			us := pv.GetTimestampMicrosecondsValue() % (1000 * 1000)
			t := time.Unix(sec, us*1000)
			fv.Set(reflect.ValueOf(t))
			// TODO(jbd): Handle lists and composites
		case reflect.Slice:
			panic("not yet implemented")
		case reflect.Struct:
			panic("not yet implemented")
		}
	}
}

func objToValue(src interface{}) *pb.Value {
	switch src.(type) {
	case bool:
		return &pb.Value{BooleanValue: proto.Bool(src.(bool))}
	case int16, int32, int64, int:
		return &pb.Value{IntegerValue: proto.Int64(src.(int64))}
	case float32, float64:
		return &pb.Value{DoubleValue: proto.Float64(src.(float64))}
	case time.Time:
		t := src.(time.Time)
		us := t.UnixNano() / 1000
		return &pb.Value{TimestampMicrosecondsValue: proto.Int64(us)}
	case *Key:
		return &pb.Value{KeyValue: keyToProto(src.(*Key))}
	case string:
		return &pb.Value{StringValue: proto.String(src.(string))}
	case []byte:
		return &pb.Value{BlobValue: src.([]byte)}
	}
	// TODO(jbd): Support Composite types and lists.
	return nil
}

type multiConverter struct {
	dest interface{}
	size int

	sliceTyp reflect.Type
	elemType reflect.Type
	sliceVal reflect.Value
}

func newMultiConverter(size int, dest interface{}) (*multiConverter, error) {
	if reflect.TypeOf(dest).Kind() != reflect.Slice {
		return nil, errors.New("datastore: dest should be a slice")
	}
	c := &multiConverter{
		dest:     dest,
		size:     size,
		sliceTyp: reflect.TypeOf(dest).Elem(),
		sliceVal: reflect.ValueOf(dest),
	}
	if c.sliceVal.Len() < size {
		return nil, errors.New("datastore: dest length is smaller than the number of the results")
	}
	// pre-init the item values if nil
	for i := 0; i < size; i++ {
		v := c.sliceVal.Index(i)
		if v.IsNil() && c.sliceTyp.Kind() == reflect.Interface {
			return nil, errors.New("datastore: interface{} slice with nil items are not allowed")
		}
		if v.IsNil() {
			v.Set(reflect.New(c.typeOfElem(i)))
		}
	}
	return c, nil
}

func (c *multiConverter) set(i int, proto *pb.Entity) {
	if i < 0 || i >= c.size {
		return
	}
	protoToEntity(proto, c.sliceVal.Index(i).Interface())
}

func (c *multiConverter) typeOfElem(i int) reflect.Type {
	if c.sliceTyp.Kind() == reflect.Interface {
		return c.sliceVal.Index(i).Elem().Type().Elem()
	}
	return c.sliceVal.Index(i).Type().Elem()
}
<commit_msg>[]string tested with tags<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package datastore

import (
	"errors"
	//	"fmt"
	"reflect"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/mpl/scancabimport/third_party/code.google.com/p/goprotobuf/proto"
	pb "github.com/mpl/scancabimport/third_party/google.golang.org/cloud/internal/datastore"
)

const (
	tagKeyDatastore = "datastore"
)

var (
	reCCtoUnderscore = regexp.MustCompile("([A-Z][a-z|0-9]*)")
)

var operatorToProto = map[operator]*pb.PropertyFilter_Operator{
	lessThan:    pb.PropertyFilter_LESS_THAN.Enum(),
	lessEq:      pb.PropertyFilter_LESS_THAN_OR_EQUAL.Enum(),
	equal:       pb.PropertyFilter_EQUAL.Enum(),
	greaterEq:   pb.PropertyFilter_GREATER_THAN_OR_EQUAL.Enum(),
	greaterThan: pb.PropertyFilter_GREATER_THAN.Enum(),
}

var sortDirectionToProto = map[sortDirection]*pb.PropertyOrder_Direction{
	ascending:  pb.PropertyOrder_ASCENDING.Enum(),
	descending: pb.PropertyOrder_ASCENDING.Enum(),
}

var (
	typeOfByteSlice   = reflect.TypeOf([]byte{})
	typeOfTime        = reflect.TypeOf(time.Time{})
	typeOfKeyPtr      = reflect.TypeOf(&Key{})
)

type fieldMeta struct {
	field   *reflect.StructField
	name    string
	indexed bool
}

var (
	mu         sync.Mutex
	entityMeta map[reflect.Type](map[string]*fieldMeta) = make(map[reflect.Type](map[string]*fieldMeta))
)

func camelCaseToUnderscore(name string) string {
	v := reCCtoUnderscore.ReplaceAllString(name, "${1}_")
	return strings.Trim(strings.ToLower(v), "_")
}

func registerEntityMeta(typ reflect.Type) map[string]*fieldMeta {
	mu.Lock()
	defer mu.Unlock()

	metadata, ok := entityMeta[typ]
	if ok {
		return metadata
	}
	entityMeta[typ] = make(map[string]*fieldMeta)
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)
		tag := field.Tag.Get(tagKeyDatastore)
		name := ""
		indexed := true // by default TODO(jbd): If list, don't set.

		// name_of_the_field
		// name_of_the_field,noindex
		if strings.Contains(tag, "noindex") {
			indexed = false
			name = strings.Replace(tag, ",noindex", "", -1)
		} else {
			name = tag
		}
		if name == "" {
			name = camelCaseToUnderscore(field.Name)
		}

		entityMeta[typ][name] = &fieldMeta{
			field: &field, name: name, indexed: indexed,
		}
	}
	return entityMeta[typ]
}

func keyToProto(k *Key) *pb.Key {
	// TODO(jbd): Eliminate unrequired allocations.
	path := []*pb.Key_PathElement(nil)
	for {
		el := &pb.Key_PathElement{
			Kind: proto.String(k.kind),
		}
		if k.id != 0 {
			el.Id = proto.Int64(k.id)
		}
		if k.name != "" {
			el.Name = proto.String(k.name)
		}
		path = append([]*pb.Key_PathElement{el}, path...)
		if k.parent == nil {
			break
		}
		k = k.parent
	}
	key := &pb.Key{
		PathElement: path,
	}
	if k.namespace != "" {
		key.PartitionId = &pb.PartitionId{
			Namespace: proto.String(k.namespace),
		}
	}
	return key
}

func protoToKey(p *pb.Key) *Key {
	pe := p.GetPathElement()
	if len(pe) == 0 {
		return nil
	}
	keys := make([]*Key, len(pe))
	for i, el := range pe {
		keys[i] = &Key{
			namespace: p.GetPartitionId().GetNamespace(),
			kind:      el.GetKind(),
			id:        el.GetId(),
			name:      el.GetName(),
		}
	}
	for i := 0; i < len(keys)-1; i++ {
		keys[i+1].parent = keys[i]
	}
	return keys[len(keys)-1]
}

func queryToProto(q *Query) *pb.Query {
	// TODO(jbd): Support ancestry queries.
	p := &pb.Query{}
	p.Kind = make([]*pb.KindExpression, len(q.kinds))
	for i, kind := range q.kinds {
		p.Kind[i] = &pb.KindExpression{Name: proto.String(kind)}
	}
	if len(q.projection) > 0 {
		p.Projection = make([]*pb.PropertyExpression, len(q.projection))
		for i, fieldName := range q.projection {
			p.Projection[i] = &pb.PropertyExpression{
				Property: &pb.PropertyReference{Name: proto.String(fieldName)},
			}
		}
	}
	// filters
	if len(q.filter) > 0 {
		p.Filter = &pb.Filter{
			CompositeFilter: &pb.CompositeFilter{},
		}
		filters := make([]*pb.Filter, len(q.filter))
		for i, f := range q.filter {
			filters[i] = &pb.Filter{
				PropertyFilter: &pb.PropertyFilter{
					Property: &pb.PropertyReference{Name: &f.FieldName},
					Operator: operatorToProto[f.Op],
					Value:    objToValue(f.Value),
				},
			}
		}
		p.Filter.CompositeFilter.Filter = filters
		p.Filter.CompositeFilter.Operator = pb.CompositeFilter_AND.Enum()
	}
	// group-by
	if len(q.groupBy) > 0 {
		p.GroupBy = make([]*pb.PropertyReference, len(q.groupBy))
		for i, fieldName := range q.groupBy {
			p.GroupBy[i] = &pb.PropertyReference{Name: &fieldName}
		}
	}
	// pagination
	if len(q.start) > 0 {
		p.StartCursor = q.start
	}
	if len(q.end) > 0 {
		p.EndCursor = q.end
	}
	if q.limit > 0 {
		p.Limit = &q.limit

	}
	if q.offset > 0 {
		p.Offset = &q.offset
	}
	return p
}

func entityToProto(key *Key, val reflect.Value) *pb.Entity {
	typ := val.Type()
	metadata := registerEntityMeta(typ)
	entityProto := &pb.Entity{
		Key:      keyToProto(key),
		Property: make([]*pb.Property, 0),
	}

	for name, f := range metadata {
		p := &pb.Property{}
		v := val.FieldByName(f.field.Name)
		p.Name = proto.String(name)
		p.Value = objToValue(v.Interface())
		entityProto.Property = append(entityProto.GetProperty(), p)
	}
	return entityProto
}

func protoToEntity(src *pb.Entity, dest interface{}) {
	typ := reflect.TypeOf(dest).Elem()
	val := reflect.ValueOf(dest).Elem()
	metadata := registerEntityMeta(typ)
	for _, p := range src.GetProperty() {
		f, ok := metadata[p.GetName()]
		if !ok {
			// skip if not presented in the struct
			continue
		}
		fv := val.FieldByName(f.field.Name)
		pv := p.GetValue()
		switch f.field.Type.Kind() {
		case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
			fv.SetInt(pv.GetIntegerValue())
		case reflect.Bool:
			fv.SetBool(pv.GetBooleanValue())
		case reflect.Float32, reflect.Float64:
			fv.SetFloat(pv.GetDoubleValue())
		case reflect.String:
			fv.SetString(pv.GetStringValue())
		case typeOfByteSlice.Kind():
			// slice types can not be differentiated with Kind(), so whichever
			// case is the first in the switch would be the one used, regardless
			// of whether the type is a slice of bytes or a slice of key pointers
			// for example. Therefore, we use the string representation to detect
			// when we get a slice of key pointers.
			if f.field.Type.String() == "[]*datastore.Key" {
				lv := pv.GetListValue()
				keys := make([]*Key, 0, len(lv))
				for _, lv := range lv {
					keys = append(keys, protoToKey(lv.GetKeyValue()))
				}
				fv.Set(reflect.ValueOf(keys))
			} else if f.field.Type.String() == "[]string" {
				lv := pv.GetListValue()
				ss := make([]string, 0, len(lv))
				for _, lv := range lv {
					ss = append(ss, lv.GetStringValue())
				}
				fv.Set(reflect.ValueOf(ss))
			} else {
				fv.SetBytes(pv.GetBlobValue())
			}
		case typeOfKeyPtr.Kind():
			key := protoToKey(pv.GetKeyValue())
			fv.Set(reflect.ValueOf(key))
		case typeOfTime.Kind():
			sec := pv.GetTimestampMicrosecondsValue() / (1000 * 1000)
			us := pv.GetTimestampMicrosecondsValue() % (1000 * 1000)
			t := time.Unix(sec, us*1000)
			fv.Set(reflect.ValueOf(t))
			// TODO(jbd): Handle lists and composites
		case reflect.Slice:
			panic("not yet implemented")
		case reflect.Struct:
			panic("not yet implemented")
		}
	}
}

func objToValue(src interface{}) *pb.Value {
	switch src.(type) {
	case bool:
		return &pb.Value{BooleanValue: proto.Bool(src.(bool))}
	case int16, int32, int64, int:
		return &pb.Value{IntegerValue: proto.Int64(src.(int64))}
	case float32, float64:
		return &pb.Value{DoubleValue: proto.Float64(src.(float64))}
	case time.Time:
		t := src.(time.Time)
		us := t.UnixNano() / 1000
		return &pb.Value{TimestampMicrosecondsValue: proto.Int64(us)}
	case *Key:
		return &pb.Value{KeyValue: keyToProto(src.(*Key))}
	case string:
		return &pb.Value{StringValue: proto.String(src.(string))}
	case []byte:
		return &pb.Value{BlobValue: src.([]byte)}
	}
	// TODO(jbd): Support Composite types and lists.
	return nil
}

type multiConverter struct {
	dest interface{}
	size int

	sliceTyp reflect.Type
	elemType reflect.Type
	sliceVal reflect.Value
}

func newMultiConverter(size int, dest interface{}) (*multiConverter, error) {
	if reflect.TypeOf(dest).Kind() != reflect.Slice {
		return nil, errors.New("datastore: dest should be a slice")
	}
	c := &multiConverter{
		dest:     dest,
		size:     size,
		sliceTyp: reflect.TypeOf(dest).Elem(),
		sliceVal: reflect.ValueOf(dest),
	}
	if c.sliceVal.Len() < size {
		return nil, errors.New("datastore: dest length is smaller than the number of the results")
	}
	// pre-init the item values if nil
	for i := 0; i < size; i++ {
		v := c.sliceVal.Index(i)
		if v.IsNil() && c.sliceTyp.Kind() == reflect.Interface {
			return nil, errors.New("datastore: interface{} slice with nil items are not allowed")
		}
		if v.IsNil() {
			v.Set(reflect.New(c.typeOfElem(i)))
		}
	}
	return c, nil
}

func (c *multiConverter) set(i int, proto *pb.Entity) {
	if i < 0 || i >= c.size {
		return
	}
	protoToEntity(proto, c.sliceVal.Index(i).Interface())
}

func (c *multiConverter) typeOfElem(i int) reflect.Type {
	if c.sliceTyp.Kind() == reflect.Interface {
		return c.sliceVal.Index(i).Elem().Type().Elem()
	}
	return c.sliceVal.Index(i).Type().Elem()
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16 notation with two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	For numeric values, the width and precision flags control
	formatting; width sets the width of the field, precision the
	number of places after the decimal, if appropriate.  The
	format %6.2f prints 123.45. The width of a field is the number
	of Unicode code points in the string. This differs from C's printf where
	the field width is the number of bytes.  Either or both of the
	flags may be replaced with the character '*', causing their values
	to be obtained from the next operand, which must be of type int.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating
		point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<commit_msg>fmt: fix documentation format glitch.  no content to change. Fixes issue 1313.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
	Floating-point and complex constituents:
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16 notation with two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	For numeric values, the width and precision flags control
	formatting; width sets the width of the field, precision the
	number of places after the decimal, if appropriate.  The
	format %6.2f prints 123.45. The width of a field is the number
	of Unicode code points in the string. This differs from C's printf where
	the field width is the number of bytes.  Either or both of the
	flags may be replaced with the character '*', causing their values
	to be obtained from the next operand, which must be of type int.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Sscanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the
	input they return, which means that a loop calling a scan
	routine may skip some of the input.  This is usually a
	problem only when there is no space between input values.
	However, if the reader provided to Fscan implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach an UnreadRune method
	to a reader without that capability, use bufio.NewReader.
*/
package fmt
<|endoftext|>


<commit_before>package runtimestats

import (
	"context"
	"fmt"
	"runtime"
	"sync"
	"time"

	"github.com/keybase/client/go/chat/globals"
	"github.com/keybase/client/go/chat/utils"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/sync/errgroup"
)

type Runner struct {
	globals.Contextified
	sync.Mutex

	started bool
	stopCh  chan struct{}
	eg      errgroup.Group
	sfsCli  keybase1.SimpleFSInterface
}

func NewRunner(g *globals.Context) *Runner {
	r := &Runner{
		Contextified: globals.NewContextified(g),
	}
	r.G().PushShutdownHook(func() error {
		<-r.Stop(context.Background())
		return nil
	})
	return r
}

func (r *Runner) debug(ctx context.Context, msg string, args ...interface{}) {
	r.G().Log.CDebugf(ctx, "RuntimeStats.Runner: %s", fmt.Sprintf(msg, args...))
}

func (r *Runner) Start(ctx context.Context) {
	defer r.G().CTrace(ctx, "Runner.Start", func() error { return nil })()
	r.Lock()
	defer r.Unlock()
	if !r.G().Env.GetRuntimeStatsEnabled() {
		r.debug(ctx, "not starting, not enabled in env")
		return
	}
	if r.started {
		return
	}
	r.stopCh = make(chan struct{})
	r.started = true

	r.eg.Go(func() error { return r.statsLoop(r.stopCh) })
}

func (r *Runner) Stop(ctx context.Context) chan struct{} {
	defer r.G().CTrace(ctx, "Runner.Stop", func() error { return nil })()
	r.Lock()
	defer r.Unlock()
	ch := make(chan struct{})
	if r.started {
		close(r.stopCh)
		r.started = false
		go func() {
			r.eg.Wait()
			close(ch)
		}()
	} else {
		close(ch)
	}
	return ch
}

func (r *Runner) statsLoop(stopCh chan struct{}) error {
	ctx := context.Background()
	r.updateStats(ctx)
	for {
		select {
		case <-time.After(4 * time.Second):
			r.updateStats(ctx)
		case <-stopCh:
			r.G().NotifyRouter.HandleRuntimeStatsUpdate(ctx, nil)
			return nil
		}
	}
}

func (r *Runner) addDbStats(
	ctx context.Context, dbType keybase1.DbType, db *libkb.JSONLocalDb,
	stats *keybase1.RuntimeStats) {
	var s keybase1.DbStats
	s.Type = dbType
	var err error
	s.MemCompActive, s.TableCompActive, err = db.CompactionStats()
	if err != nil {
		r.debug(ctx, "Couldn't get compaction stats for %s: %+v", dbType, err)
		return
	}
	stats.DbStats = append(stats.DbStats, s)
}

// GetProcessStats gets CPU and memory stats for the running process.
func GetProcessStats(t keybase1.ProcessType) keybase1.ProcessRuntimeStats {
	stats := getStats().Export()
	stats.Type = t
	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	stats.Goheap = utils.PresentBytes(int64(memstats.HeapAlloc))
	stats.Goheapsys = utils.PresentBytes(int64(memstats.HeapSys))
	stats.Goreleased = utils.PresentBytes(int64(memstats.HeapReleased))
	return stats
}

func (r *Runner) updateStats(ctx context.Context) {
	serviceStats := GetProcessStats(keybase1.ProcessType_MAIN)

	var stats keybase1.RuntimeStats
	stats.ProcessStats = append(stats.ProcessStats, serviceStats)

	stats.DbStats = make([]keybase1.DbStats, 0, 2)
	r.addDbStats(ctx, keybase1.DbType_MAIN, r.G().LocalDb, &stats)
	r.addDbStats(ctx, keybase1.DbType_CHAT, r.G().LocalChatDb, &stats)

	stats.ConvLoaderActive = r.G().ConvLoader.IsBackgroundActive()
	stats.SelectiveSyncActive = r.G().Indexer.IsBackgroundActive()

	xp := r.G().ConnectionManager.LookupByClientType(keybase1.ClientType_KBFS)
	if xp != nil {
		sfsCli := &keybase1.SimpleFSClient{
			Cli: rpc.NewClient(xp, libkb.NewContextifiedErrorUnwrapper(
				r.G().ExternalG()), nil),
		}

		sfsStats, err := sfsCli.SimpleFSGetStats(ctx)
		if err != nil {
			r.debug(ctx, "KBFS stats error: %+v", err)
		} else {
			stats.ProcessStats = append(
				stats.ProcessStats, sfsStats.ProcessStats)
			for _, s := range sfsStats.RuntimeDbStats {
				stats.DbStats = append(stats.DbStats, s)
			}
		}
	}

	r.G().NotifyRouter.HandleRuntimeStatsUpdate(ctx, &stats)
	r.debug(ctx, "update: %+v", stats)
}

type statsResult struct {
	TotalCPU      int
	TotalResident int64
	TotalVirtual  int64
	TotalFree     int64
}

func (r statsResult) Export() keybase1.ProcessRuntimeStats {
	return keybase1.ProcessRuntimeStats{
		Cpu:              fmt.Sprintf("%.2f%%", float64(r.TotalCPU)/100.0),
		Resident:         utils.PresentBytes(r.TotalResident),
		Virt:             utils.PresentBytes(r.TotalVirtual),
		Free:             utils.PresentBytes(r.TotalFree),
		CpuSeverity:      r.cpuSeverity(),
		ResidentSeverity: r.residentSeverity(),
	}
}

func (r statsResult) cpuSeverity() keybase1.StatsSeverityLevel {
	if r.TotalCPU >= 10000 {
		return keybase1.StatsSeverityLevel_SEVERE
	} else if r.TotalCPU >= 6000 {
		return keybase1.StatsSeverityLevel_WARNING
	} else {
		return keybase1.StatsSeverityLevel_NORMAL
	}
}

func (r statsResult) residentSeverity() keybase1.StatsSeverityLevel {
	val := r.TotalResident / 1e6
	if val >= 900 {
		return keybase1.StatsSeverityLevel_SEVERE
	} else if val >= 700 {
		return keybase1.StatsSeverityLevel_WARNING
	} else {
		return keybase1.StatsSeverityLevel_NORMAL
	}
}
<commit_msg>runtimestats: de-linting<commit_after>package runtimestats

import (
	"context"
	"fmt"
	"runtime"
	"sync"
	"time"

	"github.com/keybase/client/go/chat/globals"
	"github.com/keybase/client/go/chat/utils"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"golang.org/x/sync/errgroup"
)

type Runner struct {
	globals.Contextified
	sync.Mutex

	started bool
	stopCh  chan struct{}
	eg      errgroup.Group
}

func NewRunner(g *globals.Context) *Runner {
	r := &Runner{
		Contextified: globals.NewContextified(g),
	}
	r.G().PushShutdownHook(func() error {
		<-r.Stop(context.Background())
		return nil
	})
	return r
}

func (r *Runner) debug(ctx context.Context, msg string, args ...interface{}) {
	r.G().Log.CDebugf(ctx, "RuntimeStats.Runner: %s", fmt.Sprintf(msg, args...))
}

func (r *Runner) Start(ctx context.Context) {
	defer r.G().CTrace(ctx, "Runner.Start", func() error { return nil })()
	r.Lock()
	defer r.Unlock()
	if !r.G().Env.GetRuntimeStatsEnabled() {
		r.debug(ctx, "not starting, not enabled in env")
		return
	}
	if r.started {
		return
	}
	r.stopCh = make(chan struct{})
	r.started = true

	r.eg.Go(func() error { return r.statsLoop(r.stopCh) })
}

func (r *Runner) Stop(ctx context.Context) chan struct{} {
	defer r.G().CTrace(ctx, "Runner.Stop", func() error { return nil })()
	r.Lock()
	defer r.Unlock()
	ch := make(chan struct{})
	if r.started {
		close(r.stopCh)
		r.started = false
		go func() {
			_ = r.eg.Wait()
			close(ch)
		}()
	} else {
		close(ch)
	}
	return ch
}

func (r *Runner) statsLoop(stopCh chan struct{}) error {
	ctx := context.Background()
	r.updateStats(ctx)
	for {
		select {
		case <-time.After(4 * time.Second):
			r.updateStats(ctx)
		case <-stopCh:
			r.G().NotifyRouter.HandleRuntimeStatsUpdate(ctx, nil)
			return nil
		}
	}
}

func (r *Runner) addDbStats(
	ctx context.Context, dbType keybase1.DbType, db *libkb.JSONLocalDb,
	stats *keybase1.RuntimeStats) {
	var s keybase1.DbStats
	s.Type = dbType
	var err error
	s.MemCompActive, s.TableCompActive, err = db.CompactionStats()
	if err != nil {
		r.debug(ctx, "Couldn't get compaction stats for %s: %+v", dbType, err)
		return
	}
	stats.DbStats = append(stats.DbStats, s)
}

// GetProcessStats gets CPU and memory stats for the running process.
func GetProcessStats(t keybase1.ProcessType) keybase1.ProcessRuntimeStats {
	stats := getStats().Export()
	stats.Type = t
	var memstats runtime.MemStats
	runtime.ReadMemStats(&memstats)
	stats.Goheap = utils.PresentBytes(int64(memstats.HeapAlloc))
	stats.Goheapsys = utils.PresentBytes(int64(memstats.HeapSys))
	stats.Goreleased = utils.PresentBytes(int64(memstats.HeapReleased))
	return stats
}

func (r *Runner) updateStats(ctx context.Context) {
	serviceStats := GetProcessStats(keybase1.ProcessType_MAIN)

	var stats keybase1.RuntimeStats
	stats.ProcessStats = append(stats.ProcessStats, serviceStats)

	stats.DbStats = make([]keybase1.DbStats, 0, 2)
	r.addDbStats(ctx, keybase1.DbType_MAIN, r.G().LocalDb, &stats)
	r.addDbStats(ctx, keybase1.DbType_CHAT, r.G().LocalChatDb, &stats)

	stats.ConvLoaderActive = r.G().ConvLoader.IsBackgroundActive()
	stats.SelectiveSyncActive = r.G().Indexer.IsBackgroundActive()

	xp := r.G().ConnectionManager.LookupByClientType(keybase1.ClientType_KBFS)
	if xp != nil {
		sfsCli := &keybase1.SimpleFSClient{
			Cli: rpc.NewClient(xp, libkb.NewContextifiedErrorUnwrapper(
				r.G().ExternalG()), nil),
		}

		sfsStats, err := sfsCli.SimpleFSGetStats(ctx)
		if err != nil {
			r.debug(ctx, "KBFS stats error: %+v", err)
		} else {
			stats.ProcessStats = append(
				stats.ProcessStats, sfsStats.ProcessStats)
			stats.DbStats = append(stats.DbStats, sfsStats.RuntimeDbStats...)
		}
	}

	r.G().NotifyRouter.HandleRuntimeStatsUpdate(ctx, &stats)
	r.debug(ctx, "update: %+v", stats)
}

type statsResult struct {
	TotalCPU      int
	TotalResident int64
	TotalVirtual  int64
	TotalFree     int64
}

func (r statsResult) Export() keybase1.ProcessRuntimeStats {
	return keybase1.ProcessRuntimeStats{
		Cpu:              fmt.Sprintf("%.2f%%", float64(r.TotalCPU)/100.0),
		Resident:         utils.PresentBytes(r.TotalResident),
		Virt:             utils.PresentBytes(r.TotalVirtual),
		Free:             utils.PresentBytes(r.TotalFree),
		CpuSeverity:      r.cpuSeverity(),
		ResidentSeverity: r.residentSeverity(),
	}
}

func (r statsResult) cpuSeverity() keybase1.StatsSeverityLevel {
	switch {
	case r.TotalCPU >= 10000:
		return keybase1.StatsSeverityLevel_SEVERE
	case r.TotalCPU >= 6000:
		return keybase1.StatsSeverityLevel_WARNING
	default:
		return keybase1.StatsSeverityLevel_NORMAL
	}
}

func (r statsResult) residentSeverity() keybase1.StatsSeverityLevel {
	val := r.TotalResident / 1e6
	switch {
	case val >= 900:
		return keybase1.StatsSeverityLevel_SEVERE
	case val >= 700:
		return keybase1.StatsSeverityLevel_WARNING
	default:
		return keybase1.StatsSeverityLevel_NORMAL
	}
}
<|endoftext|>


<commit_before>package summa

import (
	"database/sql"
	"fmt"
	_ "go-sqlite3"
)

type snippets []snippet

func snippetsFetch(db *sql.DB, start, limit float64, orderBy, username string) (*snippets, error) {
	var snips snippets

	whereClause := ""
	if username != "" {
		whereClause = "WHERE snippet.username=?"
	}
	query := fmt.Sprintf(
		"SELECT snippet.snippet_id,snippet.username,display_name,description,snippet.created,snippet.updated,"+
			"COUNT(snippet_file.snippet_id) files,COUNT(snippet_comment.snippet_id) comments "+
			"FROM snippet JOIN user USING (username) JOIN snippet_file USING (snippet_id) "+
			"LEFT JOIN snippet_comment USING (snippet_id) %s GROUP BY snippet.snippet_id "+
			"ORDER BY %s LIMIT %d OFFSET %d",
		whereClause,
		orderBy,
		int(limit),
		int(start-1),
	)

	var rows *sql.Rows
	var err error
	if whereClause == "" {
		rows, err = db.Query(
			query,
		)
	} else {
		rows, err = db.Query(
			query,
			username,
		)
	}

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var snip snippet

		rows.Scan(
			&snip.ID,
			&snip.Username,
			&snip.DisplayName,
			&snip.Description,
			&snip.Created,
			&snip.Updated,
			&snip.NumFiles,
			&snip.NumComments,
		)

		snips = append(snips, snip)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return &snips, nil
}

// snippetsUnread will return unread snippets for a specific user
func snippetsUnread(db *sql.DB, username string) (*snippets, error) {
	var snips snippets

	rows, err := db.Query(
		"SELECT snippet.snippet_id,snippet.username,display_name,description,snippet.created,snippet.updated,"+
			"COUNT(snippet_file.snippet_id) files,COUNT(snippet_comment.snippet_id) comments "+
			"FROM snippet JOIN user USING (username) JOIN snippet_file USING (snippet_id) "+
			"LEFT JOIN snippet_comment USING (snippet_id) WHERE snippet.snippet_id NOT IN "+
			"(SELECT snippet_id FROM snippet_view sv WHERE sv.username=?)",
		username,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var snip snippet

		rows.Scan(
			&snip.ID,
			&snip.Username,
			&snip.DisplayName,
			&snip.Description,
			&snip.Created,
			&snip.Updated,
			&snip.NumFiles,
			&snip.NumComments,
		)

		snips = append(snips, snip)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return &snips, nil
}
<commit_msg>Fix SQL query in API to grab unread snippets for a user<commit_after>package summa

import (
	"database/sql"
	"fmt"
	_ "go-sqlite3"
)

type snippets []snippet

func snippetsFetch(db *sql.DB, start, limit float64, orderBy, username string) (*snippets, error) {
	var snips snippets

	whereClause := ""
	if username != "" {
		whereClause = "WHERE snippet.username=?"
	}
	query := fmt.Sprintf(
		"SELECT snippet.snippet_id,snippet.username,display_name,description,snippet.created,snippet.updated,"+
			"COUNT(snippet_file.snippet_id) files,COUNT(snippet_comment.snippet_id) comments "+
			"FROM snippet JOIN user USING (username) JOIN snippet_file USING (snippet_id) "+
			"LEFT JOIN snippet_comment USING (snippet_id) %s GROUP BY snippet.snippet_id "+
			"ORDER BY %s LIMIT %d OFFSET %d",
		whereClause,
		orderBy,
		int(limit),
		int(start-1),
	)

	var rows *sql.Rows
	var err error
	if whereClause == "" {
		rows, err = db.Query(
			query,
		)
	} else {
		rows, err = db.Query(
			query,
			username,
		)
	}

	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var snip snippet

		rows.Scan(
			&snip.ID,
			&snip.Username,
			&snip.DisplayName,
			&snip.Description,
			&snip.Created,
			&snip.Updated,
			&snip.NumFiles,
			&snip.NumComments,
		)

		snips = append(snips, snip)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return &snips, nil
}

// snippetsUnread will return unread snippets for a specific user
func snippetsUnread(db *sql.DB, username string) (*snippets, error) {
	var snips snippets

	rows, err := db.Query(
		"SELECT s.snippet_id,s.username,u.display_name,s.description,s.created,s.updated,"+
			"COUNT(sf.snippet_id) files,COUNT(sc.snippet_id) comments FROM snippet s JOIN "+
			"user u ON u.username=s.username JOIN snippet_file sf ON s.snippet_id=sf.snippet_id "+
			"LEFT JOIN snippet_comment sc ON s.snippet_id=sc.snippet_id LEFT JOIN snippet_view sv "+
			"ON s.snippet_id=sv.snippet_id AND sv.username=? WHERE sv.snippet_id IS NULL "+
			"GROUP BY s.snippet_id",
		username,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	for rows.Next() {
		var snip snippet

		rows.Scan(
			&snip.ID,
			&snip.Username,
			&snip.DisplayName,
			&snip.Description,
			&snip.Created,
			&snip.Updated,
			&snip.NumFiles,
			&snip.NumComments,
		)

		snips = append(snips, snip)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return &snips, nil
}
<|endoftext|>


<commit_before>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package client2

import (
	"strconv"
)

// These numbers should exactly match values defined in dist/vt-mysql-5.1.52/include/mysql/mysql_com.h
const (
	VT_DECIMAL     = 0
	VT_TINY        = 1
	VT_SHORT       = 2
	VT_LONG        = 3
	VT_FLOAT       = 4
	VT_DOUBLE      = 5
	VT_NULL        = 6
	VT_TIMESTAMP   = 7
	VT_LONGLONG    = 8
	VT_INT24       = 9
	VT_DATE        = 10
	VT_TIME        = 11
	VT_DATETIME    = 12
	VT_YEAR        = 13
	VT_NEWDATE     = 14
	VT_VARCHAR     = 15
	VT_BIT         = 16
	VT_NEWDECIMAL  = 246
	VT_ENUM        = 247
	VT_SET         = 248
	VT_TINY_BLOB   = 249
	VT_MEDIUM_BLOB = 250
	VT_LONG_BLOB   = 251
	VT_BLOB        = 252
	VT_VAR_STRING  = 253
	VT_STRING      = 254
	VT_GEOMETRY    = 255
)

func convert(mysqlType int, val string) interface{} {
	switch mysqlType {
	case VT_TINY, VT_SHORT, VT_LONG, VT_LONGLONG, VT_INT24:
		return tonumber(val)
	case VT_FLOAT, VT_DOUBLE:
		fval, err := strconv.ParseFloat(val, 64)
		if err != nil { // Not expected
			panic(err)
		}
		return fval
	}
	return []byte(val)
}

func tonumber(val string) (number interface{}) {
	var err error
	if val[0] == '-' {
		number, err = strconv.ParseInt(val, 0, 64)
	} else {
		number, err = strconv.ParseUint(val, 0, 64)
	}
	if err != nil { // Not expected
		panic(err)
	}
	return number
}
<commit_msg>remove legacy convert code<commit_after><|endoftext|>