Skip to content

Commit b1683f9

Browse files
committed
Add unit tests
1 parent f41f65a commit b1683f9

File tree

3 files changed

+277
-19
lines changed

3 files changed

+277
-19
lines changed

src/main/java/com/nordstrom/common/jdbc/DatabaseUtils.java

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,16 @@
194194
* /** args: [ coffee_name, max_percent, new_price ] */
195195
* RAISE_PRICE("RAISE_PRICE(>, >, =)", Types.VARCHAR, Types.REAL, Types.NUMERIC),
196196
* /** args: [ str, val... ] */
197-
* IN_VARARGS("IN_VARARGS(<, >...)", Types.VARCHAR, Types.INTEGER),
197+
* IN_VARARGS("IN_VARARGS(<, >:)", Types.VARCHAR, Types.INTEGER),
198198
* /** args: [ val, str... ] *&#47;
199-
* OUT_VARARGS("OUT_VARARGS(>, <...)", Types.INTEGER, Types.VARCHAR);
199+
* OUT_VARARGS("OUT_VARARGS(>, <:)", Types.INTEGER, Types.VARCHAR);
200200
*
201201
* private int[] argTypes;
202202
* private String signature;
203203
*
204204
* SProcValues(String signature, int... argTypes) {
205205
* this.signature = signature;
206+
*
206207
* this.argTypes = argTypes;
207208
* }
208209
*
@@ -232,7 +233,7 @@
232233
public class DatabaseUtils {
233234

234235
private static Pattern SPROC_PATTERN =
235-
Pattern.compile("([\\p{Alpha}_][\\p{Alpha}\\p{Digit}@$#_]*)(?:\\(([<>=](?:,\\s*[<>=])*)?([.]{3})?\\))?");
236+
Pattern.compile("([\\p{Alpha}_][\\p{Alpha}\\p{Digit}@$#_]*)(?:\\(([<>=](?:,\\s*[<>=])*)?(:)?\\))?");
236237

237238
private DatabaseUtils() {
238239
throw new AssertionError("DatabaseUtils is a static utility class that cannot be instantiated");
@@ -361,6 +362,40 @@ public static Object executeQuery(Class<?> resultType, String connectionStr, Str
361362
}
362363
}
363364

365+
/**
366+
* Execute the specified stored procedure object with supplied parameters
367+
*
368+
* @param sproc stored procedure object to execute
369+
* @param params an array of objects containing the input parameter values
370+
* @return row 1 / column 1 as integer; -1 if no rows were returned
371+
*/
372+
public static int getInt(SProcAPI sproc, Object... params) {
373+
Integer result = (Integer) executeStoredProcedure(Integer.class, sproc, params);
374+
return (result != null) ? result.intValue() : -1;
375+
}
376+
377+
/**
378+
* Execute the specified stored procedure object with supplied parameters
379+
*
380+
* @param sproc stored procedure object to execute
381+
* @param params an array of objects containing the input parameter values
382+
* @return row 1 / column 1 as string; {@code null} if no rows were returned
383+
*/
384+
public static String getString(SProcAPI sproc, Object... params) {
385+
return (String) executeStoredProcedure(String.class, sproc, params);
386+
}
387+
388+
/**
389+
* Execute the specified stored procedure object with supplied parameters
390+
*
391+
* @param sproc stored procedure object to execute
392+
* @param params an array of objects containing the input parameter values
393+
* @return {@link ResultPackage} object
394+
*/
395+
public static ResultPackage getResultPackage(SProcAPI sproc, Object... params) {
396+
return (ResultPackage) executeStoredProcedure(ResultPackage.class, sproc, params);
397+
}
398+
364399
/**
365400
* Execute the specified stored procedure with the specified arguments, returning a result of the indicated type.
366401
* <p>
@@ -377,7 +412,7 @@ public static Object executeQuery(Class<?> resultType, String connectionStr, Str
377412
* <b>NOTE</b>: If you specify {@link ResultPackage} as the result type, it's recommended that you close this object
378413
* when you're done with it to free up database and JDBC resources that were allocated for it.
379414
*/
380-
public static Object executeStoredProcedure(Class<?> resultType, SProcAPI sproc, Object... parms) {
415+
public static Object executeStoredProcedure(Class<?> resultType, SProcAPI sproc, Object... params) {
381416
Objects.requireNonNull(resultType, "[resultType] argument must be non-null");
382417

383418
String[] args = {};
@@ -410,7 +445,7 @@ public static Object executeStoredProcedure(Class<?> resultType, SProcAPI sproc,
410445

411446
int argsCount = args.length;
412447
int typesCount = argTypes.length;
413-
int parmsCount = parms.length;
448+
int parmsCount = params.length;
414449

415450
int minCount = typesCount;
416451

@@ -448,13 +483,13 @@ public static Object executeStoredProcedure(Class<?> resultType, SProcAPI sproc,
448483
// process declared parameters
449484
for (i = 0; i < minCount; i++) {
450485
Mode mode = Mode.fromChar(args[i].charAt(0));
451-
parmArray[i] = Param.create(mode, argTypes[i], parms[i]);
486+
parmArray[i] = Param.create(mode, argTypes[i], params[i]);
452487
}
453488

454489
// handle varargs parameters
455490
for (int j = i; j < parmsCount; j++) {
456491
Mode mode = Mode.fromChar(args[i].charAt(0));
457-
parmArray[j] = Param.create(mode, argTypes[i], parms[j]);
492+
parmArray[j] = Param.create(mode, argTypes[i], params[j]);
458493
}
459494

460495
return executeStoredProcedure(resultType, sproc.getConnection(), sprocName, parmArray);
@@ -495,7 +530,7 @@ public static Object executeStoredProcedure(Class<?> resultType, String connecti
495530
CallableStatement statement = connection.prepareCall(sprocStr.toString());
496531

497532
for (int i = 0; i < params.length; i++) {
498-
params[i].set(statement, i);
533+
params[i].set(statement, i + 1);
499534
}
500535

501536
return executeStatement(resultType, connection, statement);
@@ -534,16 +569,32 @@ private static Object executeStatement(Class<?> resultType, Connection connectio
534569
if (resultType == null) {
535570
result = Integer.valueOf(statement.executeUpdate());
536571
} else {
537-
resultSet = statement.executeQuery(); //NOSONAR
538-
539-
if (resultType == ResultPackage.class) {
540-
result = new ResultPackage(connection, statement, resultSet); //NOSONAR
541-
} else if (resultType == Integer.class) {
542-
result = Integer.valueOf((resultSet.next()) ? resultSet.getInt(1) : -1);
543-
} else if (resultType == String.class) {
544-
result = (resultSet.next()) ? resultSet.getString(1) : null;
572+
if (statement instanceof CallableStatement) {
573+
if (statement.execute()) {
574+
resultSet = statement.getResultSet(); //NOSONAR
575+
}
576+
577+
if (resultType == ResultPackage.class) {
578+
result = new ResultPackage(connection, statement, resultSet); //NOSONAR
579+
} else if (resultType == Integer.class) {
580+
result = ((CallableStatement) statement).getInt(1);
581+
} else if (resultType == String.class) {
582+
result = ((CallableStatement) statement).getString(1);
583+
} else {
584+
result = ((CallableStatement) statement).getObject(1);
585+
}
545586
} else {
546-
result = (resultSet.next()) ? resultSet.getObject(1, resultType) : null;
587+
resultSet = statement.executeQuery(); //NOSONAR
588+
589+
if (resultType == ResultPackage.class) {
590+
result = new ResultPackage(connection, statement, resultSet); //NOSONAR
591+
} else if (resultType == Integer.class) {
592+
result = Integer.valueOf((resultSet.next()) ? resultSet.getInt(1) : -1);
593+
} else if (resultType == String.class) {
594+
result = (resultSet.next()) ? resultSet.getString(1) : null;
595+
} else {
596+
result = (resultSet.next()) ? resultSet.getObject(1, resultType) : null;
597+
}
547598
}
548599
}
549600

@@ -702,6 +753,14 @@ private ResultPackage(Connection connection, PreparedStatement statement, Result
702753
this.resultSet = resultSet;
703754
}
704755

756+
public Connection getConnection() {
757+
return connection;
758+
}
759+
760+
public PreparedStatement getStatement() {
761+
return statement;
762+
}
763+
705764
/**
706765
* Get the result set object of this package.
707766
*

src/test/java/com/nordstrom/common/jdbc/DatabaseUtilsTest.java

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package com.nordstrom.common.jdbc;
22

3+
import static org.testng.Assert.assertEquals;
4+
5+
import java.sql.CallableStatement;
36
import java.sql.Connection;
47
import java.sql.DriverManager;
58
import java.sql.SQLException;
9+
import java.sql.Types;
610
import org.testng.annotations.AfterClass;
711
import org.testng.annotations.BeforeClass;
812
import org.testng.annotations.Test;
913

1014
import com.nordstrom.common.jdbc.DatabaseUtils.QueryAPI;
1115
import com.nordstrom.common.jdbc.DatabaseUtils.ResultPackage;
16+
import com.nordstrom.common.jdbc.DatabaseUtils.SProcAPI;
1217

1318
public class DatabaseUtilsTest {
1419

@@ -75,7 +80,32 @@ public void updateRows() {
7580
DatabaseUtils.update(TestQuery.UPDATE, 300, "Lakeshore Ave.", 180);
7681
}
7782

78-
@Test(dependsOnMethods={"updateRows"})
83+
@Test(dependsOnMethods= {"updateRows"})
84+
public void showAddresses() {
85+
try {
86+
DatabaseUtils.update(TestQuery.SHOW_ADDRESSES);
87+
} catch (Exception e) {
88+
}
89+
90+
ResultPackage pkg = DatabaseUtils.getResultPackage(TestSProc.SHOW_ADDRESSES);
91+
92+
int rowCount = 0;
93+
try {
94+
while (pkg.getResultSet().next()) {
95+
rowCount++;
96+
int num = pkg.getResultSet().getInt("num");
97+
String addr = pkg.getResultSet().getString("addr");
98+
System.out.println("addr" + rowCount + ": " + num + " " + addr);
99+
}
100+
} catch (SQLException e) {
101+
}
102+
pkg.close();
103+
104+
DatabaseUtils.update(TestQuery.DROP_PROC_SHOW);
105+
assertEquals(rowCount, 2);
106+
}
107+
108+
@Test(dependsOnMethods={"showAddresses"})
79109
public void getInt() {
80110
DatabaseUtils.getInt(TestQuery.GET_NUM);
81111
}
@@ -96,14 +126,84 @@ public void dropTable() {
96126
DatabaseUtils.update(TestQuery.DROP);
97127
}
98128

129+
@Test
130+
public void testInVarargs() {
131+
try {
132+
DatabaseUtils.update(TestQuery.IN_VARARGS);
133+
} catch (Exception e) {
134+
}
135+
136+
String result = DatabaseUtils.getString(TestSProc.IN_VARARGS, "", 5, 4, 3);
137+
DatabaseUtils.update(TestQuery.DROP_PROC_IN);
138+
assertEquals(result, "RESULT: 5 4 3");
139+
}
140+
141+
@Test()
142+
public void testOutVarargs() throws SQLException {
143+
try {
144+
DatabaseUtils.update(TestQuery.OUT_VARARGS);
145+
} catch (Exception e) {
146+
}
147+
148+
ResultPackage pkg = DatabaseUtils.getResultPackage(TestSProc.OUT_VARARGS, 5, 0, 0, 0);
149+
int[] out = new int[3];
150+
out[0] = ((CallableStatement) pkg.getStatement()).getInt(2);
151+
out[1] = ((CallableStatement) pkg.getStatement()).getInt(3);
152+
out[2] = ((CallableStatement) pkg.getStatement()).getInt(4);
153+
pkg.close();
154+
155+
DatabaseUtils.update(TestQuery.DROP_PROC_OUT);
156+
157+
assertEquals(out[0], 5);
158+
assertEquals(out[1], 6);
159+
assertEquals(out[2], 7);
160+
}
161+
162+
@Test
163+
public void testInOutVarargs() throws SQLException {
164+
try {
165+
DatabaseUtils.update(TestQuery.INOUT_VARARGS);
166+
} catch (Exception e) {
167+
}
168+
169+
ResultPackage pkg = DatabaseUtils.getResultPackage(TestSProc.INOUT_VARARGS, 5, 3, 10, 100);
170+
int[] out = new int[3];
171+
out[0] = ((CallableStatement) pkg.getStatement()).getInt(2);
172+
out[1] = ((CallableStatement) pkg.getStatement()).getInt(3);
173+
out[2] = ((CallableStatement) pkg.getStatement()).getInt(4);
174+
pkg.close();
175+
176+
DatabaseUtils.update(TestQuery.DROP_PROC_INOUT);
177+
178+
assertEquals(out[0], 8);
179+
assertEquals(out[1], 15);
180+
assertEquals(out[2], 105);
181+
}
182+
99183
enum TestQuery implements QueryAPI {
100184
CREATE("create table location(num int, addr varchar(40))"),
101185
INSERT("insert into location values (?, ?)", "num", "addr"),
102186
UPDATE("update location set num=?, addr=? where num=?", "num", "addr", "whereNum"),
187+
SHOW_ADDRESSES("create procedure SHOW_ADDRESSES() parameter style java "
188+
+ "language java dynamic result sets 1 "
189+
+ "external name 'com.nordstrom.common.jdbc.StoredProcedure.showAddresses'"),
190+
DROP_PROC_SHOW("drop procedure SHOW_ADDRESSES"),
103191
GET_NUM("select num from location where addr='Union St.'"),
104192
GET_STR("select addr from location where num=1910"),
105193
GET_RESULT_PACKAGE("select * from location"),
106-
DROP("drop table location");
194+
DROP("drop table location"),
195+
IN_VARARGS("create procedure IN_VARARGS(out result varchar( 32672 ), b int ...) "
196+
+ "language java parameter style derby no sql deterministic "
197+
+ "external name 'com.nordstrom.common.jdbc.StoredProcedure.inVarargs'"),
198+
DROP_PROC_IN("drop procedure IN_VARARGS"),
199+
OUT_VARARGS("create procedure OUT_VARARGS(seed int, out b int ...) "
200+
+ "language java parameter style derby no sql deterministic "
201+
+ "external name 'com.nordstrom.common.jdbc.StoredProcedure.outVarargs'"),
202+
DROP_PROC_OUT("drop procedure OUT_VARARGS"),
203+
INOUT_VARARGS("create procedure INOUT_VARARGS(seed int, inout b int ...) "
204+
+ "language java parameter style derby no sql deterministic "
205+
+ "external name 'com.nordstrom.common.jdbc.StoredProcedure.inoutVarargs'"),
206+
DROP_PROC_INOUT("drop procedure INOUT_VARARGS");
107207

108208
private String query;
109209
private String[] args;
@@ -137,6 +237,41 @@ public static String connection() {
137237
return "jdbc:derby:@TestDB";
138238
}
139239
}
240+
241+
enum TestSProc implements SProcAPI {
242+
SHOW_ADDRESSES("SHOW_ADDRESSES()"),
243+
IN_VARARGS("IN_VARARGS(<, >:)", Types.VARCHAR, Types.INTEGER),
244+
OUT_VARARGS("OUT_VARARGS(>, <:)", Types.INTEGER, Types.INTEGER),
245+
INOUT_VARARGS("INOUT_VARARGS(>, =:)", Types.INTEGER, Types.INTEGER);
246+
247+
private int[] argTypes;
248+
private String signature;
249+
250+
TestSProc(String signature, int... argTypes) {
251+
this.signature = signature;
252+
this.argTypes = argTypes;
253+
}
254+
255+
@Override
256+
public String getSignature() {
257+
return signature;
258+
}
259+
260+
@Override
261+
public int[] getArgTypes() {
262+
return argTypes;
263+
}
264+
265+
@Override
266+
public String getConnection() {
267+
return TestQuery.connection();
268+
}
269+
270+
@Override
271+
public Enum<? extends SProcAPI> getEnum() {
272+
return this;
273+
}
274+
}
140275

141276
/**
142277
* Prints details of an SQLException chain to <code>System.err</code>.

0 commit comments

Comments
 (0)