package orm_test import ( "database/sql/driver" "errors" "fmt" "math" "testing" "github.com/go-pg/pg/orm" "github.com/go-pg/pg/types" ) type ValuerError string func (e ValuerError) Value() (driver.Value, error) { return nil, errors.New(string(e)) } type StructFormatter struct { tableName struct{} `sql:"my_name,alias:my_alias"` String string NotNull string `sql:",notnull"` Iface interface{} } func (StructFormatter) Method() string { return "method_value" } func (StructFormatter) MethodParam() types.Q { return types.Q("?string") } func (StructFormatter) MethodWithArgs(string) string { return "method_value" } func (StructFormatter) MethodWithCompositeReturn() (string, string) { return "method_value1", "method_value2" } type EmbeddedStructFormatter struct { *StructFormatter } func (EmbeddedStructFormatter) Method2() string { return "method_value2" } type params []interface{} type paramsMap map[string]interface{} type formatTest struct { q string params params paramsMap paramsMap wanted string } var ( structv = &StructFormatter{ String: "string_value", Iface: "iface_value", } embeddedStructv = &EmbeddedStructFormatter{structv} ) var formatTests = []formatTest{ {q: "?", params: params{ValuerError("error")}, wanted: "?!(error)"}, {q: "?", wanted: "?"}, {q: "?_?", params: params{"foo", "bar"}, wanted: "'foo'_'bar'"}, {q: "?0_?0", params: params{"foo", "bar"}, wanted: "'foo'_'foo'"}, {q: "? ? ?", params: params{"foo", "bar"}, wanted: "'foo' 'bar' ?"}, {q: "?0 ?1", params: params{"foo", "bar"}, wanted: "'foo' 'bar'"}, {q: "?0 ?1 ?2", params: params{"foo", "bar"}, wanted: "'foo' 'bar' ?2"}, {q: "?0 ?1 ?0", params: params{"foo", "bar"}, wanted: "'foo' 'bar' 'foo'"}, {q: "one ?foo two", wanted: "one ?foo two"}, {q: "one ?foo two", params: params{structv}, wanted: "one ?foo two"}, {q: "one ?MethodWithArgs two", params: params{structv}, wanted: "one ?MethodWithArgs two"}, {q: "one ?MethodWithCompositeReturn two", params: params{structv}, wanted: "one ?MethodWithCompositeReturn two"}, {q: "?", params: params{uint64(math.MaxUint64)}, wanted: "18446744073709551615"}, {q: "?", params: params{orm.Q("query")}, wanted: "query"}, {q: "?", params: params{types.F("field")}, wanted: `"field"`}, {q: "?", params: params{structv}, wanted: `'{"String":"string_value","NotNull":"","Iface":"iface_value"}'`}, {q: `\? ?`, params: params{1}, wanted: "? 1"}, {q: `?`, params: params{types.Q(`\?`)}, wanted: `\?`}, {q: `?`, params: params{types.Q(`\\?`)}, wanted: `\\?`}, {q: `?`, params: params{types.Q(`\?param`)}, wanted: `\?param`}, {q: "?string", params: params{structv}, wanted: `'string_value'`}, {q: "?iface", params: params{structv}, wanted: `'iface_value'`}, {q: "?string", params: params{&StructFormatter{}}, wanted: `NULL`}, { q: "? ?string ?", params: params{"one", "two", structv}, wanted: "'one' 'string_value' 'two'", }, { q: "?string ?Method", params: params{structv}, wanted: "'string_value' 'method_value'", }, { q: "?string ?Method ?Method2", params: params{embeddedStructv}, wanted: "'string_value' 'method_value' 'method_value2'", }, { q: "?string", params: params{structv}, paramsMap: paramsMap{"string": "my_value"}, wanted: "'my_value'", }, { q: "?", params: params{types.Q("?string")}, paramsMap: paramsMap{"string": "my_value"}, wanted: "?string", }, { q: "?", params: params{types.F("?string")}, paramsMap: paramsMap{"string": types.Q("my_value")}, wanted: `"?string"`, }, { q: "?", params: params{orm.Q("?string")}, paramsMap: paramsMap{"string": "my_value"}, wanted: "'my_value'", }, { q: "?MethodParam", params: params{structv}, paramsMap: paramsMap{"string": "my_value"}, wanted: "?string", }, } func TestFormatQuery(t *testing.T) { for _, test := range formatTests { var f orm.Formatter for k, v := range test.paramsMap { f.SetParam(k, v) } got := f.Append(nil, test.q, test.params...) if string(got) != test.wanted { t.Fatalf( "got %q, wanted %q (q=%q params=%v paramsMap=%v)", got, test.wanted, test.q, test.params, test.paramsMap, ) } } } func BenchmarkFormatQueryWithoutParams(b *testing.B) { for i := 0; i < b.N; i++ { _ = orm.Q("SELECT * FROM my_table WHERE id = 1") } } func BenchmarkFormatQuery1Param(b *testing.B) { for i := 0; i < b.N; i++ { _ = orm.Q("SELECT * FROM my_table WHERE id = ?", 1) } } func BenchmarkFormatQuery10Params(b *testing.B) { for i := 0; i < b.N; i++ { _ = orm.Q( "SELECT * FROM my_table WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ) } } func BenchmarkFormatQuerySprintf(b *testing.B) { for i := 0; i < b.N; i++ { _ = fmt.Sprintf("SELECT * FROM my_table WHERE id = %d", 1) } } func BenchmarkFormatQueryStructParam(b *testing.B) { param := StructFormatter{ String: "1", } for i := 0; i < b.N; i++ { _ = orm.Q("SELECT * FROM my_table WHERE id = ?string", param) } } func BenchmarkFormatQueryStructMethod(b *testing.B) { param := StructFormatter{} for i := 0; i < b.N; i++ { _ = orm.Q("SELECT * FROM my_table WHERE id = ?Method", ¶m) } }