Repository: nuveo/prest
Pull request #166 (2017-06-08 18:17:00)

remove data wrapper from body and Standardize functions
related issue #145 and #142 


Patch:
diff --git a/README.md b/README.md
index f30c06c..2aebaeb 100644
--- a/README.md
+++ b/README.md
@@ -214,10 +214,8 @@ http://127.0.0.1:8000/DATABASE/SCHEMA/TABLE
 JSON DATA:
 ```
 {
-    "data": {
-        "FIELD1": "string value",
-        "FIELD2": 1234567890
-    }
+    "FIELD1": "string value",
+    "FIELD2": 1234567890
 }
 ```
 
@@ -232,11 +230,9 @@ http://127.0.0.1:8000/DATABASE/SCHEMA/TABLE?FIELD1=xyz
 JSON DATA:
 ```
 {
-    "data": {
-        "FIELD1": "string value",
-        "FIELD2": 1234567890,
-        "ARRAYFIELD": ["value 1","value 2"]
-    }
+    "FIELD1": "string value",
+    "FIELD2": 1234567890,
+    "ARRAYFIELD": ["value 1","value 2"]
 }
 ```
 
diff --git a/adapters/postgres/postgres.go b/adapters/postgres/postgres.go
index 5273fe5..d8533ea 100644
--- a/adapters/postgres/postgres.go
+++ b/adapters/postgres/postgres.go
@@ -1,21 +1,18 @@
 package postgres
 
 import (
+	"database/sql"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"log"
 	"net/http"
+	"regexp"
 	"strconv"
 	"strings"
 	"unicode"
 
-	"database/sql"
-
-	"regexp"
-
 	"github.com/nuveo/prest/adapters/postgres/connection"
-	"github.com/nuveo/prest/api"
 	"github.com/nuveo/prest/config"
 	"github.com/nuveo/prest/statements"
 )
@@ -27,9 +24,14 @@ const (
 )
 
 var removeOperatorRegex *regexp.Regexp
+var insertTableNameRegex *regexp.Regexp
+
+// ErrBodyEmpty err throw when body is empty
+var ErrBodyEmpty = errors.New("body is empty")
 
 func init() {
 	removeOperatorRegex = regexp.MustCompile(`\$[a-z]+.`)
+	insertTableNameRegex = regexp.MustCompile(`(?i)INTO\s+([\w|\.]*\.)*(\w+)\s*\(`)
 }
 
 // chkInvalidIdentifier return true if identifier is invalid
@@ -133,6 +135,79 @@ func WhereByRequest(r *http.Request, initialPlaceholderID int) (whereSyntax stri
 	return
 }
 
+// SetByRequest create a set clause for SQL
+func SetByRequest(r *http.Request, initialPlaceholderID int) (setSyntax string, values []interface{}, err error) {
+	body := make(map[string]interface{})
+	if err = json.NewDecoder(r.Body).Decode(&body); err != nil {
+		return
+	}
+	defer r.Body.Close()
+
+	if len(body) == 0 {
+		err = ErrBodyEmpty
+		return
+	}
+
+	fields := make([]string, 0)
+	for key, value := range body {
+		if chkInvalidIdentifier(key) {
+			err = errors.New("Set: Invalid identifier")
+			return
+		}
+		fields = append(fields, fmt.Sprintf("%s=$%d", key, initialPlaceholderID))
+
+		switch value.(type) {
+		case []interface{}:
+			values = append(values, parseArray(value))
+		default:
+			values = append(values, value)
+		}
+
+		initialPlaceholderID++
+	}
+	setSyntax = strings.Join(fields, ", ")
+	return
+}
+
+// ParseInsertRequest create insert SQL
+func ParseInsertRequest(r *http.Request) (colsName string, colsValue string, values []interface{}, err error) {
+	body := make(map[string]interface{})
+	if err = json.NewDecoder(r.Body).Decode(&body); err != nil {
+		return
+	}
+	defer r.Body.Close()
+
+	if len(body) == 0 {
+		err = ErrBodyEmpty
+		return
+	}
+
+	fields := make([]string, 0)
+	for key, value := range body {
+		if chkInvalidIdentifier(key) {
+			err = errors.New("Insert: Invalid identifier")
+			return
+		}
+		fields = append(fields, key)
+
+		switch value.(type) {
+		case []interface{}:
+			values = append(values, parseArray(value))
+		default:
+			values = append(values, value)
+		}
+	}
+
+	colsName = strings.Join(fields, ", ")
+	for i := 1; i < len(values)+1; i++ {
+		if colsValue != "" {
+			colsValue += ","
+		}
+		colsValue += fmt.Sprintf("$%d", i)
+	}
+	return
+}
+
 // DatabaseClause return a SELECT `query`
 func DatabaseClause(req *http.Request) (query string, hasCount bool) {
 	queries := req.URL.Query()
@@ -353,37 +428,7 @@ func parseArray(value interface{}) string {
 }
 
 // Insert execute insert sql into a table
-func Insert(database, schema, table string, body api.Request) (jsonData []byte, err error) {
-	if chkInvalidIdentifier(database, schema, table) {
-		err = errors.New("Insert: Invalid identifier")
-		return
-	}
-
-	fields := make([]string, 0)
-	values := make([]interface{}, 0)
-	for key, value := range body.Data {
-		if chkInvalidIdentifier(key) {
-			err = errors.New("Insert: Invalid identifier")
-			return
-		}
-		fields = append(fields, key)
-
-		switch value.(type) {
-		case []interface{}:
-			values = append(values, parseArray(value))
-		default:
-			values = append(values, value)
-		}
-	}
-
-	colsName := strings.Join(fields, ", ")
-	colPlaceholder := ""
-	for i := 1; i < len(values)+1; i++ {
-		if colPlaceholder != "" {
-			colPlaceholder += ","
-		}
-		colPlaceholder += fmt.Sprintf("$%d", i)
-	}
+func Insert(SQL string, params ...interface{}) (jsonData []byte, err error) {
 	db, err := connection.Get()
 	if err != nil {
 		log.Println(err)
@@ -395,31 +440,6 @@ func Insert(database, schema, table string, body api.Request) (jsonData []byte,
 		log.Printf("could not begin transaction: %v\n", err)
 		return
 	}
-	stmtPK, err := tx.Prepare(statements.SelectPKTableName)
-	if err != nil {
-		log.Printf("could not prepare sql: %s\n Error: %v\n", statements.SelectPKTableName, err)
-		return
-	}
-	var pkName string
-	pkRow, err := stmtPK.Query(table)
-	if err != nil {
-		return
-	}
-	for pkRow.Next() {
-		err = pkRow.Scan(&pkName)
-		if err != nil {
-			return
-		}
-	}
-	err = pkRow.Close()
-	if err != nil {
-		return
-	}
-
-	sql := fmt.Sprintf("INSERT INTO %s.%s.%s (%s) VALUES (%s)", database, schema, table, colsName, colPlaceholder)
-	if pkName != "" {
-		sql = fmt.Sprintf("%s RETURNING %s", sql, pkName)
-	}
 
 	defer func() {
 		switch err {
@@ -430,61 +450,28 @@ func Insert(database, schema, table string, body api.Request) (jsonData []byte,
 		}
 	}()
 
-	stmt, err := tx.Prepare(sql)
-	if err != nil {
-		log.Printf("could not prepare sql: %s\n Error: %v\n", sql, err)
+	tableName := insertTableNameRegex.FindStringSubmatch(SQL)
+	if len(tableName) < 2 {
+		err = errors.New("unable to find table name")
 		return
 	}
+	SQL = fmt.Sprintf("%s RETURNING row_to_json(%s)", SQL, tableName[2])
 
-	valuesAux := make([]interface{}, 0, len(values))
-
-	for i := 0; i < len(values); i++ {
-		valuesAux = append(valuesAux, values[i])
-	}
-
-	var lastID interface{}
-	if pkName != "" {
-		result := stmt.QueryRow(valuesAux...)
-		err = result.Scan(&lastID)
-		if err != nil {
-			return
-		}
-	} else {
-		_, err = stmt.Exec(valuesAux...)
-		if err != nil {
-			return
-		}
+	stmt, err := tx.Prepare(SQL)
+	if err != nil {
+		log.Printf("could not prepare sql: %s\n Error: %v\n", SQL, err)
+		return
 	}
 
-	data := make(map[string]interface{})
-	for i := range fields {
-		data[fields[i]] = values[i]
-	}
-	if pkName != "" {
-		data[pkName] = lastID
-	}
-	jsonData, err = json.Marshal(data)
+	err = stmt.QueryRow(params...).Scan(&jsonData)
 	return
 }
 
 // Delete execute delete sql into a table
-func Delete(database, schema, table, where string, whereValues []interface{}) (jsonData []byte, err error) {
+func Delete(SQL string, params ...interface{}) (jsonData []byte, err error) {
 	var result sql.Result
 	var rowsAffected int64
 
-	if chkInvalidIdentifier(database, schema, table) {
-		err = errors.New("Delete: Invalid identifier")
-		return
-	}
-
-	sql := fmt.Sprintf("DELETE FROM %s.%s.%s", database, schema, table)
-	if where != "" {
-		sql = fmt.Sprint(
-			sql,
-			" WHERE ",
-			where)
-	}
-
 	db, err := connection.Get()
 	if err != nil {
 		log.Println(err)
@@ -506,7 +493,7 @@ func Delete(database, schema, table, where string, whereValues []interface{}) (j
 		}
 	}()
 
-	result, err = tx.Exec(sql, whereValues...)
+	result, err = tx.Exec(SQL, params...)
 	if err != nil {
 		return
 	}
@@ -523,42 +510,10 @@ func Delete(database, schema, table, where string, whereValues []interface{}) (j
 }
 
 // Update execute update sql into a table
-func Update(database, schema, table, where string, whereValues []interface{}, body api.Request) (jsonData []byte, err error) {
-	if chkInvalidIdentifier(database, schema, table) {
-		err = errors.New("Update: Invalid identifier")
-		return
-	}
-
+func Update(SQL string, params ...interface{}) (jsonData []byte, err error) {
 	var result sql.Result
 	var rowsAffected int64
 
-	fields := []string{}
-	values := make([]interface{}, 0)
-	pid := len(whereValues) + 1 // placeholder id
-	for key, value := range body.Data {
-		fields = append(fields, fmt.Sprintf("%s=$%d", key, pid))
-
-		switch value.(type) {
-		case []interface{}:
-			values = append(values, parseArray(value))
-		default:
-			values = append(values, value)
-		}
-
-		pid++
-	}
-	setSyntax := strings.Join(fields, ", ")
-
-	sql := fmt.Sprintf("UPDATE %s.%s.%s SET %s", database, schema, table, setSyntax)
-
-	if where != "" {
-		sql = fmt.Sprint(
-			sql,
-			" WHERE ",
-			where)
-		values = append(whereValues, values...)
-	}
-
 	db, err := connection.Get()
 	if err != nil {
 		log.Println(err)
@@ -580,19 +535,13 @@ func Update(database, schema, table, where string, whereValues []interface{}, bo
 		}
 	}()
 
-	stmt, err := tx.Prepare(sql)
+	stmt, err := tx.Prepare(SQL)
 	if err != nil {
-		log.Printf("could not prepare sql: %s\n Error: %v\n", sql, err)
+		log.Printf("could not prepare sql: %s\n Error: %v\n", SQL, err)
 		return
 	}
 
-	valuesAux := make([]interface{}, 0, len(values))
-
-	for i := 0; i < len(values); i++ {
-		valuesAux = append(valuesAux, values[i])
-	}
-
-	result, err = stmt.Exec(valuesAux...)
+	result, err = stmt.Exec(params...)
 	if err != nil {
 		return
 	}
diff --git a/api/request.go b/api/request.go
deleted file mode 100644
index 40e8f4d..0000000
--- a/api/request.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package api
-
-// Request body representation
-type Request struct {
-	Data map[string]interface{} `json:"data"`
-}
diff --git a/controllers/tables.go b/controllers/tables.go
index 7db141a..619bf0e 100644
--- a/controllers/tables.go
+++ b/controllers/tables.go
@@ -4,11 +4,8 @@ import (
 	"fmt"
 	"net/http"
 
-	"encoding/json"
-
 	"github.com/gorilla/mux"
 	"github.com/nuveo/prest/adapters/postgres"
-	"github.com/nuveo/prest/api"
 	"github.com/nuveo/prest/statements"
 )
 
@@ -207,15 +204,16 @@ func InsertInTables(w http.ResponseWriter, r *http.Request) {
 	schema := vars["schema"]
 	table := vars["table"]
 
-	req := api.Request{}
-	defer r.Body.Close()
-	err := json.NewDecoder(r.Body).Decode(&req)
+	names, placeholders, values, err := postgres.ParseInsertRequest(r)
 	if err != nil {
-		err = fmt.Errorf("could not decode body: %v", err)
+		err = fmt.Errorf("could not perform InsertInTables: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
-	object, err := postgres.Insert(database, schema, table, req)
+
+	sql := fmt.Sprintf(statements.InsertQuery, database, schema, table, names, placeholders)
+
+	object, err := postgres.Insert(sql, values...)
 	if err != nil {
 		err = fmt.Errorf("could not perform InsertInTables: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
@@ -239,7 +237,12 @@ func DeleteFromTable(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	object, err := postgres.Delete(database, schema, table, where, values)
+	sql := fmt.Sprintf(statements.DeleteQuery, database, schema, table)
+	if where != "" {
+		sql = fmt.Sprint(sql, " WHERE ", where)
+	}
+
+	object, err := postgres.Delete(sql, values...)
 	if err != nil {
 		err = fmt.Errorf("could not perform DELETE: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
@@ -256,23 +259,32 @@ func UpdateTable(w http.ResponseWriter, r *http.Request) {
 	schema := vars["schema"]
 	table := vars["table"]
 
-	req := api.Request{}
-	defer r.Body.Close()
-	err := json.NewDecoder(r.Body).Decode(&req)
+	where, whereValues, err := postgres.WhereByRequest(r, 1)
 	if err != nil {
-		err = fmt.Errorf("could not decode body: %v", err)
+		err = fmt.Errorf("could not perform WhereByRequest: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
 
-	where, values, err := postgres.WhereByRequest(r, 1)
+	pid := len(whereValues) + 1 // placeholder id
+
+	setSyntax, values, err := postgres.SetByRequest(r, pid)
 	if err != nil {
-		err = fmt.Errorf("could not perform WhereByRequest: %v", err)
+		err = fmt.Errorf("could not perform UPDATE: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
+	sql := fmt.Sprintf(statements.UpdateQuery, database, schema, table, setSyntax)
+
+	if where != "" {
+		sql = fmt.Sprint(
+			sql,
+			" WHERE ",
+			where)
+		values = append(whereValues, values...)
+	}
 
-	object, err := postgres.Update(database, schema, table, where, values, req)
+	object, err := postgres.Update(sql, values...)
 	if err != nil {
 		err = fmt.Errorf("could not perform UPDATE: %v", err)
 		http.Error(w, err.Error(), http.StatusBadRequest)
diff --git a/statements/queries.go b/statements/queries.go
index d5465aa..b03d752 100644
--- a/statements/queries.go
+++ b/statements/queries.go
@@ -109,16 +109,17 @@ SELECT
 	*
 FROM`
 
-	// SelectPKTableName query
-	SelectPKTableName = `
-SELECT a.attname AS chave_pk
-FROM pg_class c
-  INNER JOIN pg_attribute a ON (c.oid = a.attrelid)
-  INNER JOIN pg_index i ON (c.oid = i.indrelid)
-WHERE
-  i.indkey[0] = a.attnum AND
-  i.indisprimary = 't' AND
-  c.relname = $1`
+	// InsertQuery query
+	InsertQuery = `
+INSERT INTO %s.%s.%s(%s) VALUES(%s)`
+
+	// DeleteQuery query
+	DeleteQuery = `
+DELETE FROM %s.%s.%s`
+
+	// UpdateQuery query
+	UpdateQuery = `
+UPDATE %s.%s.%s SET %s`
 )
 
 var (


Test patch:
diff --git a/adapters/postgres/postgres_test.go b/adapters/postgres/postgres_test.go
index da710ee..ebe9868 100644
--- a/adapters/postgres/postgres_test.go
+++ b/adapters/postgres/postgres_test.go
@@ -7,11 +7,112 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/nuveo/prest/api"
+	"bytes"
+
 	"github.com/nuveo/prest/config"
 	"github.com/nuveo/prest/statements"
 )
 
+func TestParseInsertRequest(t *testing.T) {
+	m := make(map[string]interface{})
+	m["name"] = "prest"
+	mc := make(map[string]interface{})
+	mc["test"] = "prest"
+	mc["dbname"] = "prest"
+
+	var testCases = []struct {
+		description      string
+		body             map[string]interface{}
+		expectedColNames []string
+		expectedValues   []string
+		err              error
+	}{
+		{"insert by request more than one field", mc, []string{"dbname", "test"}, []string{"prest", "prest"}, nil},
+		{"insert by request one field", m, []string{"name"}, []string{"prest"}, nil},
+		{"insert by request empty body", nil, nil, nil, ErrBodyEmpty},
+	}
+
+	for _, tc := range testCases {
+		t.Log(tc.description)
+		body, err := json.Marshal(tc.body)
+		if err != nil {
+			t.Errorf("expected no errors in http request, got %v", err)
+		}
+		req, err := http.NewRequest("POST", "/", bytes.NewReader(body))
+		if err != nil {
+			t.Errorf("expected no errors in http request, got %v", err)
+		}
+
+		colsNames, _, values, err := ParseInsertRequest(req)
+		if err != tc.err {
+			t.Errorf("expected errors %v in where by request, got %v", tc.err, err)
+		}
+
+		for _, sql := range tc.expectedColNames {
+			if !strings.Contains(colsNames, sql) {
+				t.Errorf("expected %s in %s, but not was!", sql, colsNames)
+			}
+		}
+
+		expectedValuesSTR := strings.Join(tc.expectedValues, " ")
+		for _, value := range values {
+			if !strings.Contains(expectedValuesSTR, value.(string)) {
+				t.Errorf("expected %s in %s", value, expectedValuesSTR)
+			}
+		}
+	}
+}
+
+func TestSetByRequest(t *testing.T) {
+	m := make(map[string]interface{})
+	m["name"] = "prest"
+	mc := make(map[string]interface{})
+	mc["test"] = "prest"
+	mc["dbname"] = "prest"
+
+	var testCases = []struct {
+		description    string
+		body           map[string]interface{}
+		expectedSQL    []string
+		expectedValues []string
+		err            error
+	}{
+		{"set by request more than one field", mc, []string{"dbname=$", "test=$", ", "}, []string{"prest", "prest"}, nil},
+		{"set by request one field", m, []string{"name=$"}, []string{"prest"}, nil},
+		{"set by request empty body", nil, nil, nil, ErrBodyEmpty},
+	}
+
+	for _, tc := range testCases {
+		t.Log(tc.description)
+		body, err := json.Marshal(tc.body)
+		if err != nil {
+			t.Errorf("expected no errors in http request, got %v", err)
+		}
+		req, err := http.NewRequest("PUT", "/", bytes.NewReader(body))
+		if err != nil {
+			t.Errorf("expected no errors in http request, got %v", err)
+		}
+
+		setSyntax, values, err := SetByRequest(req, 1)
+		if err != tc.err {
+			t.Errorf("expected errors %v in where by request, got %v", tc.err, err)
+		}
+
+		for _, sql := range tc.expectedSQL {
+			if !strings.Contains(setSyntax, sql) {
+				t.Errorf("expected %s in %s, but not was!", sql, setSyntax)
+			}
+		}
+
+		expectedValuesSTR := strings.Join(tc.expectedValues, " ")
+		for _, value := range values {
+			if !strings.Contains(expectedValuesSTR, value.(string)) {
+				t.Errorf("expected %s in %s", value, expectedValuesSTR)
+			}
+		}
+	}
+}
+
 func TestWhereByRequest(t *testing.T) {
 	var testCases = []struct {
 		description    string
@@ -201,95 +302,45 @@ func TestInvalidPaginateIfPossible(t *testing.T) {
 func TestInsert(t *testing.T) {
 	var testCases = []struct {
 		description string
-		key         string
-		value       string
-		db          string
-		schema      string
-		table       string
-		result      interface{}
-		primaryKey  string
+		sql         string
+		values      []interface{}
 	}{
-		{"Insert data into a table with primary key", "name", "prest-test-insert", "prest", "public", "test4", 1.0, "id"},
-		{"Insert data into a table with primary key named nuveo", "name", "prest-test-insert", "prest", "public", "test6", 1.0, "nuveo"},
-		{"Insert data into a table without primary key", "name", "prest-test-insert", "prest", "public", "test6", nil, ""},
-	}
-
-	t.Log("Insert data with more columns in table")
-	m := make(map[string]interface{}, 0)
-	m["name"] = "prest-test-insert"
-	m["celphone"] = "88888888888"
-	r := api.Request{
-		Data: m,
-	}
-
-	jsonByte, err := Insert("prest", "public", "test5", r)
-	if err != nil {
-		t.Errorf("expected no errors, but got %s", err)
-	}
-	if len(jsonByte) < 1 {
-		t.Errorf("expected valid response body, but got %s", string(jsonByte))
+		{"Insert data into a table with one field", "INSERT INTO prest.public.test4(name) VALUES($1)", []interface{}{"prest-test-insert"}},
+		{"Insert data into a table with more than one field", "INSERT INTO prest.public.test5(name, celphone) VALUES($1, $2)", []interface{}{"prest-test-insert", "88888888"}},
 	}
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		m := make(map[string]interface{}, 0)
-		m[tc.key] = tc.value
-		r := api.Request{
-			Data: m,
-		}
-
-		jsonByte, err := Insert(tc.db, tc.schema, tc.table, r)
+		jsonByte, err := Insert(tc.sql, tc.values...)
 		if err != nil {
 			t.Errorf("expected no errors, but got %s", err)
 		}
 		if len(jsonByte) < 1 {
 			t.Errorf("expected valid response body, but got %s", string(jsonByte))
 		}
-
-		var toJSON map[string]interface{}
-		err = json.Unmarshal(jsonByte, &toJSON)
-		if err != nil {
-			t.Errorf("expected no errors, but got %s", err)
-		}
-
-		if tc.primaryKey != "" && toJSON[tc.primaryKey] != tc.result {
-			t.Errorf("expected %v in result, got %v", toJSON[tc.primaryKey], tc.result)
-		}
 	}
 }
 
-func TestInvalidInsert(t *testing.T) {
+func TestInsertInvalid(t *testing.T) {
 	var testCases = []struct {
 		description string
-		key         string
-		value       string
-		db          string
-		schema      string
-		table       string
+		sql         string
+		values      []interface{}
 	}{
-		{"Insert invalid data into a table with primary key", "prest", "prest-test-insert", "prest", "public", "test6"},
-		{"Insert data into a table with contraints", "name", "prest", "prest", "public", "test3"},
-		{"Insert data into a database invalid", "name", "prest", "0prest", "public", "test3"},
-		{"Insert data into a schema invalid", "name", "prest", "prest", "0public", "test3"},
-		{"Insert data into a table invalid", "name", "prest", "prest", "public", "0test3"},
-		{"Insert data into a request invalid", "0name", "prest", "prest", "public", "test3"},
+		{"Insert data into a table invalid database", "INSERT INTO 0prest.public.test4(name) VALUES($1)", []interface{}{"prest-test-insert"}},
+		{"Insert data into a table invalid schema", "INSERT INTO prest.0public.test4(name) VALUES($1)", []interface{}{"prest-test-insert"}},
+		{"Insert data into a table invalid table", "INSERT INTO prest.public.0test4(name) VALUES($1)", []interface{}{"prest-test-insert"}},
+		{"Insert data into a table with empty name", "INSERT INTO (name) VALUES($1)", []interface{}{"prest-test-insert"}},
 	}
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		m := make(map[string]interface{}, 0)
-		m[tc.key] = tc.value
-		r := api.Request{
-			Data: m,
-		}
-
-		jsonByte, err := Insert(tc.db, tc.schema, tc.table, r)
+		jsonByte, err := Insert(tc.sql, tc.values...)
 		if err == nil {
-			t.Errorf("expected no errors, but got %s", err)
+			t.Errorf("expected  errors, but no has")
 		}
-
 		if len(jsonByte) > 0 {
-			t.Errorf("expected invalid response body, but got %s", string(jsonByte))
+			t.Errorf("expected valid response body, but got %s", string(jsonByte))
 		}
 	}
 }
@@ -297,20 +348,17 @@ func TestInvalidInsert(t *testing.T) {
 func TestDelete(t *testing.T) {
 	var testCases = []struct {
 		description string
-		db          string
-		schema      string
-		table       string
-		partialSQL  string
+		sql         string
 		values      []interface{}
 	}{
-		{"Try Delete data from invalid database", "0prest", "public", "test", "name=$1", []interface{}{"nuveo"}},
-		{"Try Delete data from invalid schema", "prest", "0public", "test", "name=$1", []interface{}{"nuveo"}},
-		{"Try Delete data from invalid table", "prest", "public", "0test", "name=$1", []interface{}{"nuveo"}},
+		{"Try Delete data from invalid database", "DELETE FROM 0prest.public.test WHERE name=$1", []interface{}{"nuveo"}},
+		{"Try Delete data from invalid schema", "DELETE FROM prest.0public.test WHERE name=$1", []interface{}{"nuveo"}},
+		{"Try Delete data from invalid table", "DELETE FROM prest.public.0test WHERE name=$1", []interface{}{"nuveo"}},
 	}
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		response, err := Delete(tc.db, tc.schema, tc.table, tc.partialSQL, tc.values)
+		response, err := Delete(tc.sql, tc.values)
 		if err == nil {
 			t.Errorf("expected error, but got: %s", err)
 		}
@@ -321,7 +369,7 @@ func TestDelete(t *testing.T) {
 	}
 
 	t.Log("Delete data from table")
-	response, err := Delete("prest", "public", "test", "name=$1", []interface{}{"nuveo"})
+	response, err := Delete("DELETE FROM prest.public.test WHERE name=$1", "nuveo")
 	if err != nil {
 		t.Errorf("expected no error, but got: %s", err)
 	}
@@ -334,25 +382,16 @@ func TestDelete(t *testing.T) {
 func TestUpdate(t *testing.T) {
 	var testCases = []struct {
 		description string
-		db          string
-		schema      string
-		table       string
-		partialSQL  string
+		sql         string
 		values      []interface{}
 	}{
-		{"Update data into an invalid database", "0prest", "public", "test3", "name=$1", []interface{}{"prest tester"}},
-		{"Update data into an invalid schema", "prest", "0public", "test3", "name=$1", []interface{}{"prest tester"}},
-		{"Update data into an invalid table", "prest", "public", "0test3", "name=$1", []interface{}{"prest tester"}},
-	}
-	m := make(map[string]interface{}, 0)
-	m["name"] = "prest"
-
-	r := api.Request{
-		Data: m,
+		{"Update data into an invalid database", "UPDATE 0prest.publc.test3 SET name=$1", []interface{}{"prest tester"}},
+		{"Update data into an invalid schema", "UPDATE prest.0publc.test3 SET name=$1", []interface{}{"prest tester"}},
+		{"Update data into an invalid table", "UPDATE prest.publc.0test3 SET name=$1", []interface{}{"prest tester"}},
 	}
 
 	t.Log("Update data into a table")
-	response, err := Update("prest", "public", "test", "name=$1", []interface{}{"prest"}, r)
+	response, err := Update("UPDATE prest.public.test SET name=$2 WHERE name=$1", "prest tester", "prest")
 	if err != nil {
 		t.Errorf("expected no errors, but got: %s", err)
 	}
@@ -363,7 +402,7 @@ func TestUpdate(t *testing.T) {
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		response, err := Update(tc.db, tc.schema, tc.table, tc.partialSQL, tc.values, r)
+		response, err := Update(tc.sql, tc.values...)
 		if err == nil {
 			t.Errorf("expected error, but got: %s", err)
 		}
diff --git a/controllers/databases_test.go b/controllers/databases_test.go
index 8d2afbe..c93d0ab 100644
--- a/controllers/databases_test.go
+++ b/controllers/databases_test.go
@@ -7,7 +7,6 @@ import (
 	"net/http/httptest"
 
 	"github.com/gorilla/mux"
-	"github.com/nuveo/prest/api"
 )
 
 func TestGetDatabases(t *testing.T) {
@@ -27,7 +26,6 @@ func TestGetDatabases(t *testing.T) {
 		{"Get databases with noexistent column", "/databases?datatata=$eq.test", "GET", http.StatusBadRequest},
 	}
 
-	r := api.Request{}
 	router := mux.NewRouter()
 	router.HandleFunc("/databases", GetDatabases).Methods("GET")
 	server := httptest.NewServer(router)
@@ -35,6 +33,6 @@ func TestGetDatabases(t *testing.T) {
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "GetDatabases")
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetDatabases")
 	}
 }
diff --git a/controllers/schemas_test.go b/controllers/schemas_test.go
index a17a23f..985d195 100644
--- a/controllers/schemas_test.go
+++ b/controllers/schemas_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 
 	"github.com/gorilla/mux"
-	"github.com/nuveo/prest/api"
 )
 
 func TestGetSchemas(t *testing.T) {
@@ -32,10 +31,9 @@ func TestGetSchemas(t *testing.T) {
 	server := httptest.NewServer(router)
 	defer server.Close()
 
-	r := api.Request{}
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "GetSchemas", tc.body)
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body)
 	}
 }
 
@@ -64,10 +62,9 @@ func TestVersionDependentGetSchemas(t *testing.T) {
 	server := httptest.NewServer(router)
 	defer server.Close()
 
-	r := api.Request{}
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "GetSchemas", tc.body...)
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body...)
 	}
 
 }
diff --git a/controllers/sql_test.go b/controllers/sql_test.go
index 936ecfa..a485a88 100644
--- a/controllers/sql_test.go
+++ b/controllers/sql_test.go
@@ -7,7 +7,6 @@ import (
 	"testing"
 
 	"github.com/gorilla/mux"
-	"github.com/nuveo/prest/api"
 	"github.com/nuveo/prest/config"
 	"github.com/nuveo/prest/config/middlewares"
 	"github.com/nuveo/prest/config/router"
@@ -57,10 +56,9 @@ func TestExecuteScriptQuery(t *testing.T) {
 		{"Execute script POST method", "/testing/script-post/?field1=gopherzin&field2=pereira", "POST", http.StatusOK},
 	}
 
-	apiReq := api.Request{}
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, ts.URL+tc.url, apiReq, tc.method, tc.status, "ExecuteScriptQuery")
+		doRequest(t, ts.URL+tc.url, nil, tc.method, tc.status, "ExecuteScriptQuery")
 	}
 }
 
@@ -70,8 +68,6 @@ func TestExecuteFromScripts(t *testing.T) {
 	server := httptest.NewServer(router)
 	defer server.Close()
 
-	r := api.Request{}
-
 	var testCases = []struct {
 		description string
 		url         string
@@ -92,7 +88,7 @@ func TestExecuteFromScripts(t *testing.T) {
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "ExecuteFromScripts")
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "ExecuteFromScripts")
 	}
 }
 
@@ -116,10 +112,9 @@ func TestRenderWithXML(t *testing.T) {
 	server := httptest.NewServer(n)
 	defer server.Close()
 
-	req := api.Request{}
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, req, tc.method, tc.status, "GetSchemas", tc.body)
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetSchemas", tc.body)
 
 	}
 }
diff --git a/controllers/tables_test.go b/controllers/tables_test.go
index bd224d6..d524732 100644
--- a/controllers/tables_test.go
+++ b/controllers/tables_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 
 	"github.com/gorilla/mux"
-	"github.com/nuveo/prest/api"
 )
 
 func TestGetTables(t *testing.T) {
@@ -31,10 +30,9 @@ func TestGetTables(t *testing.T) {
 	server := httptest.NewServer(router)
 	defer server.Close()
 
-	r := api.Request{}
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "GetTables")
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTables")
 	}
 }
 
@@ -56,7 +54,6 @@ func TestGetTablesByDatabaseAndSchema(t *testing.T) {
 		{"Get tables by databases with noexistent column", "/prest/public?t.taababa=$eq.test", "GET", http.StatusBadRequest},
 	}
 
-	r := api.Request{}
 	router := mux.NewRouter()
 	router.HandleFunc("/{database}/{schema}", GetTablesByDatabaseAndSchema).Methods("GET")
 	server := httptest.NewServer(router)
@@ -64,12 +61,11 @@ func TestGetTablesByDatabaseAndSchema(t *testing.T) {
 
 	for _, tc := range testCases {
 		t.Log(tc.description)
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "GetTablesByDatabaseAndSchema")
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "GetTablesByDatabaseAndSchema")
 	}
 }
 
 func TestSelectFromTables(t *testing.T) {
-	r := api.Request{}
 	router := mux.NewRouter()
 	router.HandleFunc("/{database}/{schema}/{table}", SelectFromTables).Methods("GET")
 	server := httptest.NewServer(router)
@@ -121,31 +117,23 @@ func TestSelectFromTables(t *testing.T) {
 	for _, tc := range testCases {
 		t.Log(tc.description)
 		if tc.body != "" {
-			doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "SelectFromTables", tc.body)
+			doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables", tc.body)
 			continue
 		}
-		doRequest(t, server.URL+tc.url, r, tc.method, tc.status, "SelectFromTables")
+		doRequest(t, server.URL+tc.url, nil, tc.method, tc.status, "SelectFromTables")
 	}
 }
 
 func TestInsertInTables(t *testing.T) {
 	m := make(map[string]interface{})
 	m["name"] = "prest"
-	r := api.Request{
-		Data: m,
-	}
+
 	mJSON := make(map[string]interface{})
 	mJSON["name"] = "prest"
 	mJSON["data"] = `{"term": "name", "subterm": ["names", "of", "subterms"], "obj": {"emp": "nuveo"}}`
-	rJSON := api.Request{
-		Data: mJSON,
-	}
 
 	mARRAY := make(map[string]interface{})
 	mARRAY["data"] = []string{"value 1", "value 2", "value 3"}
-	rARRAY := api.Request{
-		Data: mARRAY,
-	}
 
 	router := mux.NewRouter()
 	router.HandleFunc("/{database}/{schema}/{table}", InsertInTables).Methods("POST")
@@ -155,16 +143,16 @@ func TestInsertInTables(t *testing.T) {
 	var testCases = []struct {
 		description string
 		url         string
-		request     api.Request
+		request     map[string]interface{}
 		status      int
 	}{
-		{"execute insert in a table with array field", "/prest/public/testarray", rARRAY, http.StatusOK},
-		{"execute insert in a table with jsonb field", "/prest/public/testjson", rJSON, http.StatusOK},
-		{"execute insert in a table without custom where clause", "/prest/public/test", r, http.StatusOK},
-		{"execute insert in a table with invalid database", "/0prest/public/test", r, http.StatusBadRequest},
-		{"execute insert in a table with invalid schema", "/prest/0public/test", r, http.StatusBadRequest},
-		{"execute insert in a table with invalid table", "/prest/public/0test", r, http.StatusBadRequest},
-		{"execute insert in a table with invalid body", "/prest/public/test", api.Request{}, http.StatusBadRequest},
+		{"execute insert in a table with array field", "/prest/public/testarray", mARRAY, http.StatusOK},
+		{"execute insert in a table with jsonb field", "/prest/public/testjson", mJSON, http.StatusOK},
+		{"execute insert in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
+		{"execute insert in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
+		{"execute insert in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
+		{"execute insert in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
+		{"execute insert in a table with invalid body", "/prest/public/test", nil, http.StatusBadRequest},
 	}
 
 	for _, tc := range testCases {
@@ -182,15 +170,15 @@ func TestDeleteFromTable(t *testing.T) {
 	var testCases = []struct {
 		description string
 		url         string
-		request     api.Request
+		request     map[string]interface{}
 		status      int
 	}{
-		{"execute delete in a table without custom where clause", "/prest/public/test", api.Request{}, http.StatusOK},
-		{"excute delete in a table with where clause", "/prest/public/test?name=$eq.nuveo", api.Request{}, http.StatusOK},
-		{"execute delete in a table with invalid database", "/0prest/public/test", api.Request{}, http.StatusBadRequest},
-		{"execute delete in a table with invalid schema", "/prest/0public/test", api.Request{}, http.StatusBadRequest},
-		{"execute delete in a table with invalid table", "/prest/public/0test", api.Request{}, http.StatusBadRequest},
-		{"execute delete in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", api.Request{}, http.StatusBadRequest},
+		{"execute delete in a table without custom where clause", "/prest/public/test", nil, http.StatusOK},
+		{"excute delete in a table with where clause", "/prest/public/test?name=$eq.nuveo", nil, http.StatusOK},
+		{"execute delete in a table with invalid database", "/0prest/public/test", nil, http.StatusBadRequest},
+		{"execute delete in a table with invalid schema", "/prest/0public/test", nil, http.StatusBadRequest},
+		{"execute delete in a table with invalid table", "/prest/public/0test", nil, http.StatusBadRequest},
+		{"execute delete in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", nil, http.StatusBadRequest},
 	}
 
 	for _, tc := range testCases {
@@ -208,23 +196,19 @@ func TestUpdateFromTable(t *testing.T) {
 	m := make(map[string]interface{}, 0)
 	m["name"] = "prest"
 
-	r := api.Request{
-		Data: m,
-	}
-
 	var testCases = []struct {
 		description string
 		url         string
-		request     api.Request
+		request     map[string]interface{}
 		status      int
 	}{
-		{"execute update in a table without custom where clause", "/prest/public/test", r, http.StatusOK},
-		{"excute update in a table with where clause", "/prest/public/test?name=$eq.nuveo", r, http.StatusOK},
-		{"execute update in a table with invalid database", "/0prest/public/test", r, http.StatusBadRequest},
-		{"execute update in a table with invalid schema", "/prest/0public/test", r, http.StatusBadRequest},
-		{"execute update in a table with invalid table", "/prest/public/0test", r, http.StatusBadRequest},
-		{"execute update in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", r, http.StatusBadRequest},
-		{"execute update in a table with invalid body", "/prest/public/test?name=$eq.nuveo", api.Request{}, http.StatusBadRequest},
+		{"execute update in a table without custom where clause", "/prest/public/test", m, http.StatusOK},
+		{"excute update in a table with where clause", "/prest/public/test?name=$eq.nuveo", m, http.StatusOK},
+		{"execute update in a table with invalid database", "/0prest/public/test", m, http.StatusBadRequest},
+		{"execute update in a table with invalid schema", "/prest/0public/test", m, http.StatusBadRequest},
+		{"execute update in a table with invalid table", "/prest/public/0test", m, http.StatusBadRequest},
+		{"execute update in a table with invalid where clause", "/prest/public/test?0name=$eq.nuveo", m, http.StatusBadRequest},
+		{"execute update in a table with invalid body", "/prest/public/test?name=$eq.nuveo", nil, http.StatusBadRequest},
 	}
 
 	for _, tc := range testCases {
diff --git a/controllers/utils_test.go b/controllers/utils_test.go
index ce85559..534a1a8 100644
--- a/controllers/utils_test.go
+++ b/controllers/utils_test.go
@@ -12,8 +12,6 @@ import (
 
 	"bytes"
 	"encoding/json"
-
-	"github.com/nuveo/prest/api"
 )
 
 func validate(t *testing.T, w *httptest.ResponseRecorder, r *http.Request, h http.HandlerFunc, where string) {
@@ -47,7 +45,7 @@ func doValidGetRequest(t *testing.T, url string, where string) {
 	}
 }
 
-func doValidPostRequest(t *testing.T, url string, r api.Request, where string) {
+func doValidPostRequest(t *testing.T, url string, r map[string]interface{}, where string) {
 	fmt.Println("Test:", where)
 	byt, err := json.Marshal(r)
 	if err != nil {
@@ -92,7 +90,7 @@ func doValidDeleteRequest(t *testing.T, url string, where string) {
 	}
 }
 
-func doValidPutRequest(t *testing.T, url string, r api.Request, where string) {
+func doValidPutRequest(t *testing.T, url string, r map[string]interface{}, where string) {
 	fmt.Println("Test:", where)
 	byt, err := json.Marshal(r)
 	if err != nil {
@@ -120,7 +118,7 @@ func doValidPutRequest(t *testing.T, url string, r api.Request, where string) {
 	}
 }
 
-func doValidPatchRequest(t *testing.T, url string, r api.Request, where string) {
+func doValidPatchRequest(t *testing.T, url string, r map[string]interface{}, where string) {
 	fmt.Println("Test:", where)
 	byt, err := json.Marshal(r)
 	if err != nil {
@@ -148,12 +146,12 @@ func doValidPatchRequest(t *testing.T, url string, r api.Request, where string)
 	}
 }
 
-func doRequest(t *testing.T, url string, r api.Request, method string, expectedStatus int, where string, expectedBody ...string) {
+func doRequest(t *testing.T, url string, r map[string]interface{}, method string, expectedStatus int, where string, expectedBody ...string) {
 	fmt.Println("Test:", where)
 	var byt []byte
 	var err error
 
-	if r.Data != nil {
+	if r != nil {
 		byt, err = json.Marshal(r)
 		if err != nil {
 			t.Error("error on json marshal", err)