When I query a database and receive a (forward-only, read-only) ResultSet back, the ResultSet acts like a list of database rows.
I am trying to find some way to treat this ResultSet like a Scala Stream
. This will allow such operations as filter
, map
, etc., while not consuming large amounts of RAM.
I implemented a tail-recursive method to extract the individual items, but this requires that all items be in memory at the same time, a problem if the ResultSet is very large:
// Iterate through the result set and gather all of the String values into a list
// then return that list
@tailrec
def loop(resultSet: ResultSet,
accumulator: List[String] = List()): List[String] = {
if (!resultSet.next) accumulator.reverse
else {
val value = resultSet.getString(1)
loop(resultSet, value +: accumulator)
}
}
i needed something similar. Building on elbowich's very cool answer, I wrapped it a bit, and instead of the string, I return the result (so you can get any column)
I needed to access table metadata, but this will work for table rows (could do a stmt.executeQuery(sql) instead of md.getColumns):
Utility function for @elbowich's answer:
Allows you to use type inference. E.g.:
I didn't test it, but why wouldn't it work?
This implementation, although longer and clumsier it is in better correspondence with the ResultSet contract. The side-effect has been removed from hasNext(...) and moved into next().
Because ResultSet is just a mutable object being navigated by next, we need to define our own concept of a next row. We can do so with an input function as follows:
EDIT: Translate to stream or something else as per above.
This sounds like a great opportunity for an implicit class. First define the implicit class somewhere:
Next, simply import this implicit class wherever you have executed your query and defined the ResultSet object:
Finally get the data out using the toStream method. For example, get all the ids as shown below: