Skip to content

Commit 2cd3bb8

Browse files
committed
kotlin: rewrite numbered params to positional params
1 parent 0f5afd3 commit 2cd3bb8

File tree

8 files changed

+171
-69
lines changed

8 files changed

+171
-69
lines changed

examples/kotlin/src/main/kotlin/com/example/booktest/postgresql/QueriesImpl.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ WHERE book_id = ?
109109
data class UpdateBookISBNParams (
110110
val title: String,
111111
val tags: List<String>,
112-
val bookId: Int,
113-
val isbn: String
112+
val isbn: String,
113+
val bookId: Int
114114
)
115115

116116
class QueriesImpl(private val conn: Connection) {
@@ -282,8 +282,8 @@ class QueriesImpl(private val conn: Connection) {
282282
val stmt = conn.prepareStatement(updateBookISBN)
283283
stmt.setString(1, arg.title)
284284
stmt.setArray(2, conn.createArrayOf("pg_catalog.varchar", arg.tags.toTypedArray()))
285-
stmt.setInt(3, arg.bookId)
286-
stmt.setString(4, arg.isbn)
285+
stmt.setString(3, arg.isbn)
286+
stmt.setInt(4, arg.bookId)
287287

288288
stmt.execute()
289289
stmt.close()

examples/kotlin/src/main/kotlin/com/example/ondeck/QueriesImpl.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ WHERE slug = ?
9696
"""
9797

9898
data class UpdateCityNameParams (
99-
val slug: String,
100-
val name: String
99+
val name: String,
100+
val slug: String
101101
)
102102

103103
const val updateVenueName = """-- name: updateVenueName :one
@@ -108,8 +108,8 @@ RETURNING id
108108
"""
109109

110110
data class UpdateVenueNameParams (
111-
val slug: String,
112-
val name: String
111+
val name: String,
112+
val slug: String
113113
)
114114

115115
const val venueCountByCity = """-- name: venueCountByCity :many
@@ -180,6 +180,7 @@ class QueriesImpl(private val conn: Connection) : Queries {
180180
override fun deleteVenue(slug: String) {
181181
val stmt = conn.prepareStatement(deleteVenue)
182182
stmt.setString(1, slug)
183+
stmt.setString(2, slug)
183184

184185
stmt.execute()
185186
stmt.close()
@@ -278,8 +279,8 @@ class QueriesImpl(private val conn: Connection) : Queries {
278279
@Throws(SQLException::class)
279280
override fun updateCityName(arg: UpdateCityNameParams) {
280281
val stmt = conn.prepareStatement(updateCityName)
281-
stmt.setString(1, arg.slug)
282-
stmt.setString(2, arg.name)
282+
stmt.setString(1, arg.name)
283+
stmt.setString(2, arg.slug)
283284

284285
stmt.execute()
285286
stmt.close()
@@ -288,8 +289,8 @@ class QueriesImpl(private val conn: Connection) : Queries {
288289
@Throws(SQLException::class)
289290
override fun updateVenueName(arg: UpdateVenueNameParams): Int {
290291
val stmt = conn.prepareStatement(updateVenueName)
291-
stmt.setString(1, arg.slug)
292-
stmt.setString(2, arg.name)
292+
stmt.setString(1, arg.name)
293+
stmt.setString(2, arg.slug)
293294

294295
return stmt.executeQuery().use { results ->
295296
if (!results.next()) {

examples/kotlin/src/test/kotlin/com/example/booktest/postgresql/QueriesImplTest.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ class QueriesImplTest {
8181

8282
// ISBN update fails because parameters are not in sequential order. After changing $N to ?, ordering is lost,
8383
// and the parameters are filled into the wrong slots.
84-
// db.updateBookISBN(
85-
// UpdateBookISBNParams(
86-
// bookId = b3.bookId,
87-
// isbn = "NEW ISBN",
88-
// title = "never ever gonna finish, a quatrain",
89-
// tags = listOf("someother")
90-
// )
91-
// )
84+
db.updateBookISBN(
85+
UpdateBookISBNParams(
86+
bookId = b3.bookId,
87+
isbn = "NEW ISBN",
88+
title = "never ever gonna finish, a quatrain",
89+
tags = listOf("someother")
90+
)
91+
)
9292

9393
val books0 = db.booksByTitleYear(BooksByTitleYearParams("my book title", 2016))
9494

examples/kotlin/src/test/kotlin/com/example/ondeck/QueriesImplTest.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ class QueriesImplTest {
4343
assertEquals(listOf(city), q.listCities())
4444
assertEquals(listOf(venue), q.listVenues(city.slug))
4545

46-
// These updates fail because parameters are not in sequential order. After changing $N to ?, ordering is lost,
47-
// and the parameters are filled into the wrong slots.
48-
// q.updateCityName(UpdateCityNameParams(slug = city.slug, name = "SF"))
49-
// q.updateVenueName(UpdateVenueNameParams(slug = venue.slug, name = "Fillmore"))
46+
q.updateCityName(UpdateCityNameParams(slug = city.slug, name = "SF"))
47+
val id = q.updateVenueName(UpdateVenueNameParams(slug = venue.slug, name = "Fillmore"))
48+
assertEquals(venue.id, id)
49+
50+
q.deleteVenue(venue.slug)
5051
}
5152
}

internal/dinosql/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ func ParseConfig(rd io.Reader) (GenerateSettings, error) {
208208
}
209209
if config.Packages[j].Language == "" {
210210
config.Packages[j].Language = LanguageGo
211+
} else if config.Packages[j].Language == "kotlin" {
212+
config.Packages[j].rewriteParams = true
211213
}
212214
}
213215
return config, nil

internal/dinosql/gen.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -719,28 +719,43 @@ func (r Result) goInnerType(col core.Column, settings CombinedSettings) string {
719719
}
720720
}
721721

722+
type goColumn struct {
723+
id int
724+
core.Column
725+
}
726+
722727
// It's possible that this method will generate duplicate JSON tag values
723728
//
724729
// Columns: count, count, count_2
725730
// Fields: Count, Count_2, Count2
726731
// JSON tags: count, count_2, count_2
727732
//
728733
// This is unlikely to happen, so don't fix it yet
729-
func (r Result) columnsToStruct(name string, columns []core.Column, settings CombinedSettings) *GoStruct {
734+
func (r Result) columnsToStruct(name string, columns []goColumn, settings CombinedSettings) *GoStruct {
730735
gs := GoStruct{
731736
Name: name,
732737
}
733738
seen := map[string]int{}
739+
suffixes := map[int]int{}
734740
for i, c := range columns {
735741
tagName := c.Name
736-
fieldName := StructName(columnName(c, i), settings)
737-
if v := seen[c.Name]; v > 0 {
738-
tagName = fmt.Sprintf("%s_%d", tagName, v+1)
739-
fieldName = fmt.Sprintf("%s_%d", fieldName, v+1)
742+
fieldName := StructName(columnName(c.Column, i), settings)
743+
// Track suffixes by the ID of the column, so that columns referring to the same numbered parameter can be
744+
// reused.
745+
suffix := 0
746+
if o, ok := suffixes[c.id]; ok {
747+
suffix = o
748+
} else if v := seen[c.Name]; v > 0 {
749+
suffix = v+1
750+
}
751+
suffixes[c.id] = suffix
752+
if suffix > 0 {
753+
tagName = fmt.Sprintf("%s_%d", tagName, suffix)
754+
fieldName = fmt.Sprintf("%s_%d", fieldName, suffix)
740755
}
741756
gs.Fields = append(gs.Fields, GoField{
742757
Name: fieldName,
743-
Type: r.goType(c, settings),
758+
Type: r.goType(c.Column, settings),
744759
Tags: map[string]string{"json:": tagName},
745760
})
746761
seen[c.Name]++
@@ -815,9 +830,12 @@ func (r Result) GoQueries(settings CombinedSettings) []GoQuery {
815830
Typ: r.goType(p.Column, settings),
816831
}
817832
} else if len(query.Params) > 1 {
818-
var cols []core.Column
833+
var cols []goColumn
819834
for _, p := range query.Params {
820-
cols = append(cols, p.Column)
835+
cols = append(cols, goColumn{
836+
id: p.Number,
837+
Column: p.Column,
838+
})
821839
}
822840
gq.Arg = GoQueryValue{
823841
Emit: true,
@@ -858,7 +876,14 @@ func (r Result) GoQueries(settings CombinedSettings) []GoQuery {
858876
}
859877

860878
if gs == nil {
861-
gs = r.columnsToStruct(gq.MethodName+"Row", query.Columns, settings)
879+
var columns []goColumn
880+
for i, c := range query.Columns {
881+
columns = append(columns, goColumn{
882+
id: i,
883+
Column: c,
884+
})
885+
}
886+
gs = r.columnsToStruct(gq.MethodName+"Row", columns, settings)
862887
emit = true
863888
}
864889
gq.Ret = GoQueryValue{

internal/dinosql/kotlin/gen.go

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,19 @@ type KtField struct {
3737
}
3838

3939
type KtStruct struct {
40-
Table core.FQN
41-
Name string
42-
Fields []KtField
43-
Comment string
40+
Table core.FQN
41+
Name string
42+
Fields []KtField
43+
JDBCParamBindings []KtField
44+
Comment string
4445
}
4546

4647
type KtQueryValue struct {
47-
Emit bool
48-
Name string
49-
Struct *KtStruct
50-
Typ ktType
48+
Emit bool
49+
Name string
50+
Struct *KtStruct
51+
Typ ktType
52+
JDBCParamBindCount int
5153
}
5254

5355
func (v KtQueryValue) EmitStruct() bool {
@@ -101,9 +103,15 @@ func (v KtQueryValue) Params() string {
101103
}
102104
var out []string
103105
if v.Struct == nil {
104-
out = append(out, jdbcSet(v.Typ, 1, v.Name))
106+
repeat := 1
107+
if v.JDBCParamBindCount > 0 {
108+
repeat = v.JDBCParamBindCount
109+
}
110+
for i := 1; i <= repeat; i++ {
111+
out = append(out, jdbcSet(v.Typ, i, v.Name))
112+
}
105113
} else {
106-
for i, f := range v.Struct.Fields {
114+
for i, f := range v.Struct.JDBCParamBindings {
107115
out = append(out, jdbcSet(f.Type, i+1, v.Name+"."+f.Name))
108116
}
109117
}
@@ -595,21 +603,34 @@ func (r Result) ktInnerType(col core.Column, settings dinosql.CombinedSettings)
595603
}
596604
}
597605

598-
func (r Result) ktColumnsToStruct(name string, columns []core.Column, settings dinosql.CombinedSettings) *KtStruct {
606+
type goColumn struct {
607+
id int
608+
core.Column
609+
}
610+
611+
func (r Result) ktColumnsToStruct(name string, columns []goColumn, settings dinosql.CombinedSettings) *KtStruct {
599612
gs := KtStruct{
600613
Name: name,
601614
}
602-
seen := map[string]int{}
615+
idSeen := map[int]KtField{}
616+
nameSeen := map[string]int{}
603617
for i, c := range columns {
604-
fieldName := KtMemberName(ktColumnName(c, i), settings)
605-
if v := seen[c.Name]; v > 0 {
618+
if binding, ok := idSeen[c.id]; ok {
619+
gs.JDBCParamBindings = append(gs.JDBCParamBindings, binding)
620+
continue
621+
}
622+
fieldName := KtMemberName(ktColumnName(c.Column, i), settings)
623+
if v := nameSeen[c.Name]; v > 0 {
606624
fieldName = fmt.Sprintf("%s_%d", fieldName, v+1)
607625
}
608-
gs.Fields = append(gs.Fields, KtField{
626+
field := KtField{
609627
Name: fieldName,
610-
Type: r.ktType(c, settings),
611-
})
612-
seen[c.Name]++
628+
Type: r.ktType(c.Column, settings),
629+
}
630+
gs.Fields = append(gs.Fields, field)
631+
gs.JDBCParamBindings = append(gs.JDBCParamBindings, field)
632+
nameSeen[c.Name]++
633+
idSeen[c.id] = field
613634
}
614635
return &gs
615636
}
@@ -672,21 +693,26 @@ func (r Result) KtQueries(settings dinosql.CombinedSettings) []KtQuery {
672693
Comments: query.Comments,
673694
}
674695

675-
if len(query.Params) == 1 {
696+
var cols []goColumn
697+
for _, p := range query.Params {
698+
cols = append(cols, goColumn{
699+
id: p.Number,
700+
Column: p.Column,
701+
})
702+
}
703+
params := r.ktColumnsToStruct(gq.ClassName+"Params", cols, settings)
704+
if len(params.Fields) == 1 {
676705
p := query.Params[0]
677706
gq.Arg = KtQueryValue{
678-
Name: ktParamName(p),
679-
Typ: r.ktType(p.Column, settings),
680-
}
681-
} else if len(query.Params) > 1 {
682-
var cols []core.Column
683-
for _, p := range query.Params {
684-
cols = append(cols, p.Column)
707+
Name: ktParamName(p),
708+
Typ: r.ktType(p.Column, settings),
709+
JDBCParamBindCount: len(params.JDBCParamBindings),
685710
}
711+
} else if len(params.Fields) > 1 {
686712
gq.Arg = KtQueryValue{
687713
Emit: true,
688714
Name: "arg",
689-
Struct: r.ktColumnsToStruct(gq.ClassName+"Params", cols, settings),
715+
Struct: params,
690716
}
691717
}
692718

@@ -722,7 +748,14 @@ func (r Result) KtQueries(settings dinosql.CombinedSettings) []KtQuery {
722748
}
723749

724750
if gs == nil {
725-
gs = r.ktColumnsToStruct(gq.ClassName+"Row", query.Columns, settings)
751+
var columns []goColumn
752+
for i, c := range query.Columns {
753+
columns = append(columns, goColumn{
754+
id: i,
755+
Column: c,
756+
})
757+
}
758+
gs = r.ktColumnsToStruct(gq.ClassName+"Row", columns, settings)
726759
emit = true
727760
}
728761
gq.Ret = KtQueryValue{

0 commit comments

Comments
 (0)