Skip to content

Commit 11acaf4

Browse files
committed
Making sure column order is preserved, fixes mauricio#61
1 parent facb7e3 commit 11acaf4

File tree

8 files changed

+121
-40
lines changed

8 files changed

+121
-40
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
out/*
12
generate_bundles.rb
23
.cache
34
target/*
@@ -15,3 +16,4 @@ mysql-async/target/*
1516
.ruby-version
1617
.ruby-gemset
1718
*.jar
19+
*.iml

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
scalaVersion := "2.10.2"
1+
scalaVersion := "2.10.3"

db-async-common/src/main/scala/com/github/mauricio/async/db/general/MutableResultSet.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
package com.github.mauricio.async.db.general
1818

1919
import collection.mutable.ArrayBuffer
20-
import com.github.mauricio.async.db.column.ColumnDecoderRegistry
21-
import com.github.mauricio.async.db.util.Log
2220
import com.github.mauricio.async.db.{RowData, ResultSet}
23-
import java.nio.charset.Charset
21+
import com.github.mauricio.async.db.util.Log
2422

2523
object MutableResultSet {
26-
val log = Log.get[MutableResultSet[ColumnData]]
24+
val log = Log.get[MutableResultSet[Nothing]]
2725
}
2826

2927
class MutableResultSet[T <: ColumnData](
@@ -35,7 +33,7 @@ class MutableResultSet[T <: ColumnData](
3533
( this.columnTypes(index).name, index ) ).toMap
3634

3735

38-
val columnNames : IndexedSeq[String] = this.columnMapping.keys.toIndexedSeq
36+
val columnNames : IndexedSeq[String] = this.columnTypes.map(c => c.name)
3937

4038
override def length: Int = this.rows.length
4139

mysql-async/src/main/scala/com/github/mauricio/async/db/mysql/codec/MySQLConnectionHandler.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class MySQLConnectionHandler(
4949
)
5050
extends SimpleChannelInboundHandler[Object] {
5151

52+
//import MySQLConnectionHandler.log
53+
5254
private implicit val internalPool = executionContext
5355

5456
private final val bootstrap = new Bootstrap().group(this.group)
@@ -248,9 +250,14 @@ class MySQLConnectionHandler(
248250
}
249251

250252
def onColumnDefinitionFinished() {
251-
this.currentQuery = new MutableResultSet[ColumnDefinitionMessage](
253+
254+
val columns = if ( this.currentPreparedStatementHolder != null ) {
255+
this.currentPreparedStatementHolder.columns
256+
} else {
252257
this.currentColumns
253-
)
258+
}
259+
260+
this.currentQuery = new MutableResultSet[ColumnDefinitionMessage](columns)
254261

255262
if ( this.currentPreparedStatementHolder != null ) {
256263
this.parsedStatements.put( this.currentPreparedStatementHolder.statement, this.currentPreparedStatementHolder )

mysql-async/src/test/scala/com/github/mauricio/async/db/mysql/QuerySpec.scala

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import scala.concurrent.duration.Duration
2323
import java.util.concurrent.TimeUnit
2424
import io.netty.util.CharsetUtil
2525
import com.github.mauricio.async.db.exceptions.InsufficientParametersException
26+
import org.specs2.matcher.MatchResult
27+
import com.github.mauricio.async.db.{QueryResult, ResultSet}
2628

2729
class QuerySpec extends Specification with ConnectionHelper {
2830

@@ -147,18 +149,38 @@ class QuerySpec extends Specification with ConnectionHelper {
147149
| some_bytes BLOB not null,
148150
| primary key (id) )""".stripMargin
149151

150-
val columns = List("id", "some_bytes")
152+
val createIdeas = """CREATE TEMPORARY TABLE ideas (
153+
| id INT NOT NULL AUTO_INCREMENT,
154+
| some_idea VARCHAR(255) NOT NULL,
155+
| primary key (id) )""".stripMargin
156+
151157
val select = "SELECT * FROM posts"
158+
val selectIdeas = "SELECT * FROM ideas"
159+
160+
val matcher : QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
161+
val columns = result.rows.get.columnNames
162+
List(columns must contain(allOf("id", "some_bytes")).inOrder, columns must have size(2))
163+
}
164+
165+
val ideasMatcher : QueryResult => List[MatchResult[IndexedSeq[String]]] = { result =>
166+
val columns = result.rows.get.columnNames
167+
List(columns must contain(allOf("id", "some_idea")).inOrder, columns must have size(2))
168+
}
152169

153170
withConnection {
154171
connection =>
155172
executeQuery(connection, create)
173+
executeQuery(connection, createIdeas)
174+
175+
matcher(executePreparedStatement(connection, select))
176+
ideasMatcher(executePreparedStatement(connection, selectIdeas))
177+
178+
matcher(executePreparedStatement(connection, select))
179+
ideasMatcher(executePreparedStatement(connection, selectIdeas))
156180

157-
val preparedResult = executePreparedStatement(connection, select).rows.get
158-
preparedResult.columnNames === columns
181+
matcher(executeQuery(connection, select))
182+
ideasMatcher(executeQuery(connection, selectIdeas))
159183

160-
val result = executeQuery(connection, select).rows.get
161-
result.columnNames === columns
162184
}
163185

164186
}

postgresql-async/src/test/scala/com/github/mauricio/async/db/general/MutableResultSetSpec.scala

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,30 @@ class MutableResultSetSpec extends Specification {
2727
val charset = CharsetUtil.UTF_8
2828
val decoder = new PostgreSQLColumnDecoderRegistry
2929

30+
def create(name: String, dataType: Int, columnNumber: Int = 0, dataTypeSize: Int = -1) = new PostgreSQLColumnData(
31+
name = name,
32+
tableObjectId = 0,
33+
columnNumber = columnNumber,
34+
dataType = dataType,
35+
dataTypeSize = dataTypeSize,
36+
dataTypeModifier = 0,
37+
fieldFormat = 0
38+
)
39+
3040
"result set" should {
3141

3242
"correctly map column data to fields" in {
3343

3444
val columns = Array(
35-
new PostgreSQLColumnData(
45+
create(
3646
name = "id",
37-
tableObjectId = 0,
38-
columnNumber = 0,
3947
dataType = ColumnTypes.Integer,
40-
dataTypeSize = 4,
41-
dataTypeModifier = 0,
42-
fieldFormat = 0
48+
dataTypeSize = 4
4349
),
44-
new PostgreSQLColumnData(
50+
create(
4551
name = "name",
46-
tableObjectId = 0,
4752
columnNumber = 5,
48-
dataType = ColumnTypes.Varchar,
49-
dataTypeSize = -1,
50-
dataTypeModifier = 0,
51-
fieldFormat = 0
53+
dataType = ColumnTypes.Varchar
5254
)
5355
)
5456

@@ -57,8 +59,8 @@ class MutableResultSetSpec extends Specification {
5759

5860
val resultSet = new MutableResultSet(columns)
5961

60-
resultSet.addRow( Array( 1, text ) )
61-
resultSet.addRow( Array( 2, otherText ) )
62+
resultSet.addRow(Array(1, text))
63+
resultSet.addRow(Array(2, otherText))
6264

6365
resultSet(0)(0) === 1
6466
resultSet(0)("id") === 1
@@ -74,18 +76,20 @@ class MutableResultSetSpec extends Specification {
7476

7577
}
7678

77-
}
79+
"should return the same order as the one given by columns" in {
7880

79-
def toBuffer( content : String ) : ByteBuf = {
80-
val buffer = Unpooled.buffer()
81-
buffer.writeBytes( content.getBytes(charset) )
82-
buffer
83-
}
81+
val columns = Array(
82+
create("id", ColumnTypes.Integer),
83+
create("name", ColumnTypes.Varchar),
84+
create("birthday", ColumnTypes.Date),
85+
create("created_at", ColumnTypes.Timestamp),
86+
create("updated_at", ColumnTypes.Timestamp)
87+
)
88+
val resultSet = new MutableResultSet(columns)
89+
90+
resultSet.columnNames must contain(allOf("id", "name", "birthday", "created_at", "updated_at")).inOrder
91+
}
8492

85-
def toBuffer( value : Int ) : ByteBuf = {
86-
val buffer = Unpooled.buffer()
87-
buffer.writeBytes(value.toString.getBytes(charset))
88-
buffer
8993
}
9094

9195
}

postgresql-async/src/test/scala/com/github/mauricio/async/db/postgresql/PreparedStatementSpec.scala

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,53 @@ class PreparedStatementSpec extends Specification with DatabaseTestHelper {
9292

9393
}
9494

95+
"run two different prepared statements in sequence and get the right values" in {
96+
97+
val create = """CREATE TEMP TABLE other_messages
98+
(
99+
id bigserial NOT NULL,
100+
other_moment date NULL,
101+
other_content character varying(255) NOT NULL,
102+
CONSTRAINT other_messages_bigserial_column_pkey PRIMARY KEY (id )
103+
)"""
104+
105+
val select = "SELECT * FROM other_messages"
106+
val insert = "INSERT INTO other_messages (other_moment, other_content) VALUES (?, ?)"
107+
108+
val moment = LocalDate.now()
109+
val otherMoment = LocalDate.now().minusDays(10)
110+
111+
val message = "this is some message"
112+
val otherMessage = "this is some other message"
113+
114+
withHandler {
115+
handler =>
116+
executeDdl(handler, this.messagesCreate)
117+
executeDdl(handler, create)
118+
119+
1.until(4).map {
120+
x =>
121+
executePreparedStatement(handler, this.messagesInsert, Array(message, moment))
122+
executePreparedStatement(handler, insert, Array(otherMoment, otherMessage))
123+
124+
val result = executePreparedStatement(handler, this.messagesSelectAll).rows.get
125+
result.size === x
126+
result.columnNames must contain(allOf("id", "content", "moment")).inOrder
127+
result(x - 1)("moment") === moment
128+
result(x - 1)("content") === message
129+
130+
val otherResult = executePreparedStatement(handler, select).rows.get
131+
otherResult.size === x
132+
otherResult.columnNames must contain(allOf( "id", "other_moment", "other_content")).inOrder
133+
otherResult(x - 1)("other_moment") === otherMoment
134+
otherResult(x - 1)("other_content") === otherMessage
135+
136+
}
137+
138+
}
139+
140+
}
141+
95142
"support prepared statement with Option parameters (Some/None)" in {
96143
withHandler {
97144
handler =>

project/Build.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ object ProjectBuild extends Build {
4646
object Configuration {
4747

4848
val commonVersion = "0.2.9-SNAPSHOT"
49+
val projectScalaVersion = "2.10.3"
4950

5051
val specs2Dependency = "org.specs2" %% "specs2" % "2.0" % "test"
5152
val logbackDependency = "ch.qos.logback" % "logback-classic" % "1.0.13" % "test"
@@ -55,8 +56,8 @@ object Configuration {
5556
"org.slf4j" % "slf4j-api" % "1.7.5",
5657
"joda-time" % "joda-time" % "2.2",
5758
"org.joda" % "joda-convert" % "1.3.1",
58-
"org.scala-lang" % "scala-library" % "2.10.3",
59-
"io.netty" % "netty-all" % "4.0.11.Final",
59+
"org.scala-lang" % "scala-library" % projectScalaVersion,
60+
"io.netty" % "netty-all" % "4.0.12.Final",
6061
"org.javassist" % "javassist" % "3.18.1-GA",
6162
specs2Dependency,
6263
logbackDependency
@@ -75,7 +76,7 @@ object Configuration {
7576
:+ "-feature"
7677
,
7778
scalacOptions in doc := Seq("-doc-external-doc:scala=http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/"),
78-
scalaVersion := "2.10.3",
79+
scalaVersion := projectScalaVersion,
7980
javacOptions := Seq("-source", "1.5", "-target", "1.5", "-encoding", "UTF8"),
8081
organization := "com.github.mauricio",
8182
version := commonVersion,

0 commit comments

Comments
 (0)