Skip to content

Commit c5fd513

Browse files
aclindsanelsam
authored andcommitted
postgres: Allow for lowercasing quoted fields (#360)
* postgres: Allow for lowercasing quoted fields This allows for conditionally reverting the behavior changed 418d928 at runtime, while maintaining the current behavior by default. * Add ginkgo unit tests for Postgres
1 parent d62836b commit c5fd513

2 files changed

Lines changed: 198 additions & 1 deletion

File tree

dialect_postgres.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import (
1919
)
2020

2121
type PostgresDialect struct {
22-
suffix string
22+
suffix string
23+
LowercaseFields bool
2324
}
2425

2526
func (d PostgresDialect) QuerySuffix() string { return ";" }
@@ -128,6 +129,9 @@ func (d PostgresDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql stri
128129
}
129130

130131
func (d PostgresDialect) QuoteField(f string) string {
132+
if d.LowercaseFields {
133+
return `"` + strings.ToLower(f) + `"`
134+
}
131135
return `"` + f + `"`
132136
}
133137

dialect_postgres_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
// Copyright 2012 James Cooper. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package gorp provides a simple way to marshal Go structs to and from
6+
// SQL databases. It uses the database/sql package, and should work with any
7+
// compliant database/sql driver.
8+
//
9+
// Source code and project home:
10+
// https://github.com/go-gorp/gorp
11+
12+
package gorp_test
13+
14+
import (
15+
"database/sql"
16+
"reflect"
17+
"time"
18+
19+
// ginkgo/gomega functions read better as dot-imports.
20+
. "github.com/onsi/ginkgo"
21+
. "github.com/onsi/ginkgo/extensions/table"
22+
. "github.com/onsi/gomega"
23+
24+
"github.com/go-gorp/gorp"
25+
)
26+
27+
var _ = Describe("PostgresDialect", func() {
28+
var (
29+
lowercasefields bool
30+
dialect gorp.PostgresDialect
31+
)
32+
33+
JustBeforeEach(func() {
34+
dialect = gorp.PostgresDialect{
35+
LowercaseFields: lowercasefields,
36+
}
37+
})
38+
39+
DescribeTable("ToSqlType",
40+
func(value interface{}, maxsize int, autoIncr bool, expected string) {
41+
typ := reflect.TypeOf(value)
42+
sqlType := dialect.ToSqlType(typ, maxsize, autoIncr)
43+
Expect(sqlType).To(Equal(expected))
44+
},
45+
Entry("bool", true, 0, false, "boolean"),
46+
Entry("int8", int8(1), 0, false, "integer"),
47+
Entry("uint8", uint8(1), 0, false, "integer"),
48+
Entry("int16", int16(1), 0, false, "integer"),
49+
Entry("uint16", uint16(1), 0, false, "integer"),
50+
Entry("int32", int32(1), 0, false, "integer"),
51+
Entry("int (treated as int32)", int(1), 0, false, "integer"),
52+
Entry("uint32", uint32(1), 0, false, "integer"),
53+
Entry("uint (treated as uint32)", uint(1), 0, false, "integer"),
54+
Entry("int64", int64(1), 0, false, "bigint"),
55+
Entry("uint64", uint64(1), 0, false, "bigint"),
56+
Entry("float32", float32(1), 0, false, "real"),
57+
Entry("float64", float64(1), 0, false, "double precision"),
58+
Entry("[]uint8", []uint8{1}, 0, false, "bytea"),
59+
Entry("NullInt64", sql.NullInt64{}, 0, false, "bigint"),
60+
Entry("NullFloat64", sql.NullFloat64{}, 0, false, "double precision"),
61+
Entry("NullBool", sql.NullBool{}, 0, false, "boolean"),
62+
Entry("Time", time.Time{}, 0, false, "timestamp with time zone"),
63+
Entry("default-size string", "", 0, false, "text"),
64+
Entry("sized string", "", 50, false, "varchar(50)"),
65+
Entry("large string", "", 1024, false, "varchar(1024)"),
66+
)
67+
68+
Describe("AutoIncrStr", func() {
69+
It("returns the auto increment string", func() {
70+
Expect(dialect.AutoIncrStr()).To(Equal(""))
71+
})
72+
})
73+
74+
Describe("AutoIncrBindValue", func() {
75+
It("returns the value used to bind the auto-increment value", func() {
76+
Expect(dialect.AutoIncrBindValue()).To(Equal("default"))
77+
})
78+
})
79+
80+
Describe("AutoIncrInsertSuffix", func() {
81+
It("returns the suffix needed for auto-incrementing", func() {
82+
cm := gorp.ColumnMap{
83+
ColumnName: "foo",
84+
}
85+
Expect(dialect.AutoIncrInsertSuffix(&cm)).To(Equal(` returning "foo"`))
86+
})
87+
})
88+
89+
Describe("CreateTableSuffix", func() {
90+
It("returns an empty suffix", func() {
91+
Expect(dialect.CreateTableSuffix()).To(Equal(""))
92+
})
93+
})
94+
95+
Describe("CreateIndexSuffix", func() {
96+
It("returns the suffix for creating indexes", func() {
97+
Expect(dialect.CreateIndexSuffix()).To(Equal("using"))
98+
})
99+
})
100+
101+
Describe("DropIndexSuffix", func() {
102+
It("returns the suffix for deleting indexes", func() {
103+
Expect(dialect.DropIndexSuffix()).To(Equal(""))
104+
})
105+
})
106+
107+
Describe("TruncateClause", func() {
108+
It("returns the clause for truncating a table", func() {
109+
Expect(dialect.TruncateClause()).To(Equal("truncate"))
110+
})
111+
})
112+
113+
Describe("SleepClause", func() {
114+
It("returns the clause for sleeping", func() {
115+
Expect(dialect.SleepClause(1 * time.Second)).To(Equal("pg_sleep(1.000000)"))
116+
Expect(dialect.SleepClause(100 * time.Millisecond)).To(Equal("pg_sleep(0.100000)"))
117+
})
118+
})
119+
120+
Describe("BindVar", func() {
121+
It("returns the variable binding sequence", func() {
122+
Expect(dialect.BindVar(0)).To(Equal("$1"))
123+
Expect(dialect.BindVar(4)).To(Equal("$5"))
124+
})
125+
})
126+
127+
PDescribe("InsertAutoIncr", func() {})
128+
129+
Describe("QuoteField", func() {
130+
It("returns the argument quoted as a field (mixed case by default)", func() {
131+
Expect(dialect.QuoteField("Foo")).To(Equal(`"Foo"`))
132+
Expect(dialect.QuoteField("bar")).To(Equal(`"bar"`))
133+
})
134+
Context("with lowercase fields", func() {
135+
BeforeEach(func() {
136+
lowercasefields = true
137+
})
138+
It("returns the argument quoted as a field", func() {
139+
Expect(dialect.QuoteField("Foo")).To(Equal(`"foo"`))
140+
})
141+
})
142+
})
143+
144+
Describe("QuotedTableForQuery", func() {
145+
var (
146+
schema, table string
147+
148+
quotedTable string
149+
)
150+
151+
JustBeforeEach(func() {
152+
quotedTable = dialect.QuotedTableForQuery(schema, table)
153+
})
154+
155+
Context("using the default schema", func() {
156+
BeforeEach(func() {
157+
schema = ""
158+
table = "foo"
159+
})
160+
It("returns just the table", func() {
161+
Expect(quotedTable).To(Equal(`"foo"`))
162+
})
163+
})
164+
165+
Context("with a supplied schema", func() {
166+
BeforeEach(func() {
167+
schema = "foo"
168+
table = "bar"
169+
})
170+
It("returns the schema and table", func() {
171+
Expect(quotedTable).To(Equal(`foo."bar"`))
172+
})
173+
})
174+
})
175+
176+
Describe("IfSchemaNotExists", func() {
177+
It("appends 'if not exists' to the command", func() {
178+
Expect(dialect.IfSchemaNotExists("foo", "bar")).To(Equal("foo if not exists"))
179+
})
180+
})
181+
182+
Describe("IfTableExists", func() {
183+
It("appends 'if exists' to the command", func() {
184+
Expect(dialect.IfTableExists("foo", "bar", "baz")).To(Equal("foo if exists"))
185+
})
186+
})
187+
188+
Describe("IfTableNotExists", func() {
189+
It("appends 'if not exists' to the command", func() {
190+
Expect(dialect.IfTableNotExists("foo", "bar", "baz")).To(Equal("foo if not exists"))
191+
})
192+
})
193+
})

0 commit comments

Comments
 (0)