JDBC wrapper in a functional manner

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












I implemented a simple Java JDBC wrapper in Kotlin with Arrow functional library.



/**
* Executes simple SQL statement that takes no arguments.
* E.g. "CREATE TABLE" statement.
*
* @return IO with either an exception or boolean result
*/
fun String.executeStatement(dataSource: DataSource): IO<Either<Throwable, Boolean>>
val connection = dataSource.connection
return IO connection.createStatement().execute(this) .attemptAndCloseConnection(connection)


/**
* Executes prepared SQL statement (a statement that takes arguments).
* E.g. "INSERT, UPDATE, DELETE..." statements.
*
* @return IO with either an exception or with result of execution as an integer
*/
fun String.executePreparedStatement(dataSource: DataSource, vararg args: Any): IO<Either<Throwable, Int>>
val connection = dataSource.connection
return IO
val preparedStatement = connection.prepareStatement(this)
args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
preparedStatement.executeUpdate()
.attemptAndCloseConnection(connection)


/**
* Executes SQL query
*/
fun <E> String.executeQuery(dataSource: DataSource, resultSetMapper: (ResultSet) -> E, vararg args: Any): IO<Either<Throwable, List<E>>>
val connection = dataSource.connection
return IO
val list = mutableListOf<E>()
val preparedStatement = connection.prepareStatement(this)
args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
val resultSet = preparedStatement.executeQuery()
while (resultSet.next())
list.add(resultSetMapper(resultSet))

list.toList()
.attemptAndCloseConnection(connection)


private fun <A> IO<A>.attemptAndCloseConnection(connection: Connection?) =
this.attempt().map connection?.close(); it


Every result of execution is wrapped in an instance of IO to represent side-effects.



Functions are invoked directly on strings which produces an instance of Either<Throwable, T> when run:



val dataSource = HikariDataSource()
// add config for data source...

"""CREATE TABLE cities (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL);""".executeStatement(dataSource)
.unsafeRunSync()

"INSERT INTO cities (name) VALUES (?)".executePreparedStatement(dataSource, "New York").unsafeRunSync()


My major concerns are:



  • Passing an instance of DataSource upon invocation of every function. E.g. with Scala, I could pass data source implicitly which would declutter invocations.

  • Mutable list in executeQuery function. Is it even ok?

  • Closing connection (attemptAndCloseConnection function) - is there some better way to do this?

  • Other proposals?






share|improve this question

























    up vote
    0
    down vote

    favorite












    I implemented a simple Java JDBC wrapper in Kotlin with Arrow functional library.



    /**
    * Executes simple SQL statement that takes no arguments.
    * E.g. "CREATE TABLE" statement.
    *
    * @return IO with either an exception or boolean result
    */
    fun String.executeStatement(dataSource: DataSource): IO<Either<Throwable, Boolean>>
    val connection = dataSource.connection
    return IO connection.createStatement().execute(this) .attemptAndCloseConnection(connection)


    /**
    * Executes prepared SQL statement (a statement that takes arguments).
    * E.g. "INSERT, UPDATE, DELETE..." statements.
    *
    * @return IO with either an exception or with result of execution as an integer
    */
    fun String.executePreparedStatement(dataSource: DataSource, vararg args: Any): IO<Either<Throwable, Int>>
    val connection = dataSource.connection
    return IO
    val preparedStatement = connection.prepareStatement(this)
    args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
    preparedStatement.executeUpdate()
    .attemptAndCloseConnection(connection)


    /**
    * Executes SQL query
    */
    fun <E> String.executeQuery(dataSource: DataSource, resultSetMapper: (ResultSet) -> E, vararg args: Any): IO<Either<Throwable, List<E>>>
    val connection = dataSource.connection
    return IO
    val list = mutableListOf<E>()
    val preparedStatement = connection.prepareStatement(this)
    args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
    val resultSet = preparedStatement.executeQuery()
    while (resultSet.next())
    list.add(resultSetMapper(resultSet))

    list.toList()
    .attemptAndCloseConnection(connection)


    private fun <A> IO<A>.attemptAndCloseConnection(connection: Connection?) =
    this.attempt().map connection?.close(); it


    Every result of execution is wrapped in an instance of IO to represent side-effects.



    Functions are invoked directly on strings which produces an instance of Either<Throwable, T> when run:



    val dataSource = HikariDataSource()
    // add config for data source...

    """CREATE TABLE cities (
    id INTEGER PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL);""".executeStatement(dataSource)
    .unsafeRunSync()

    "INSERT INTO cities (name) VALUES (?)".executePreparedStatement(dataSource, "New York").unsafeRunSync()


    My major concerns are:



    • Passing an instance of DataSource upon invocation of every function. E.g. with Scala, I could pass data source implicitly which would declutter invocations.

    • Mutable list in executeQuery function. Is it even ok?

    • Closing connection (attemptAndCloseConnection function) - is there some better way to do this?

    • Other proposals?






    share|improve this question





















      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I implemented a simple Java JDBC wrapper in Kotlin with Arrow functional library.



      /**
      * Executes simple SQL statement that takes no arguments.
      * E.g. "CREATE TABLE" statement.
      *
      * @return IO with either an exception or boolean result
      */
      fun String.executeStatement(dataSource: DataSource): IO<Either<Throwable, Boolean>>
      val connection = dataSource.connection
      return IO connection.createStatement().execute(this) .attemptAndCloseConnection(connection)


      /**
      * Executes prepared SQL statement (a statement that takes arguments).
      * E.g. "INSERT, UPDATE, DELETE..." statements.
      *
      * @return IO with either an exception or with result of execution as an integer
      */
      fun String.executePreparedStatement(dataSource: DataSource, vararg args: Any): IO<Either<Throwable, Int>>
      val connection = dataSource.connection
      return IO
      val preparedStatement = connection.prepareStatement(this)
      args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
      preparedStatement.executeUpdate()
      .attemptAndCloseConnection(connection)


      /**
      * Executes SQL query
      */
      fun <E> String.executeQuery(dataSource: DataSource, resultSetMapper: (ResultSet) -> E, vararg args: Any): IO<Either<Throwable, List<E>>>
      val connection = dataSource.connection
      return IO
      val list = mutableListOf<E>()
      val preparedStatement = connection.prepareStatement(this)
      args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
      val resultSet = preparedStatement.executeQuery()
      while (resultSet.next())
      list.add(resultSetMapper(resultSet))

      list.toList()
      .attemptAndCloseConnection(connection)


      private fun <A> IO<A>.attemptAndCloseConnection(connection: Connection?) =
      this.attempt().map connection?.close(); it


      Every result of execution is wrapped in an instance of IO to represent side-effects.



      Functions are invoked directly on strings which produces an instance of Either<Throwable, T> when run:



      val dataSource = HikariDataSource()
      // add config for data source...

      """CREATE TABLE cities (
      id INTEGER PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(255) NOT NULL);""".executeStatement(dataSource)
      .unsafeRunSync()

      "INSERT INTO cities (name) VALUES (?)".executePreparedStatement(dataSource, "New York").unsafeRunSync()


      My major concerns are:



      • Passing an instance of DataSource upon invocation of every function. E.g. with Scala, I could pass data source implicitly which would declutter invocations.

      • Mutable list in executeQuery function. Is it even ok?

      • Closing connection (attemptAndCloseConnection function) - is there some better way to do this?

      • Other proposals?






      share|improve this question











      I implemented a simple Java JDBC wrapper in Kotlin with Arrow functional library.



      /**
      * Executes simple SQL statement that takes no arguments.
      * E.g. "CREATE TABLE" statement.
      *
      * @return IO with either an exception or boolean result
      */
      fun String.executeStatement(dataSource: DataSource): IO<Either<Throwable, Boolean>>
      val connection = dataSource.connection
      return IO connection.createStatement().execute(this) .attemptAndCloseConnection(connection)


      /**
      * Executes prepared SQL statement (a statement that takes arguments).
      * E.g. "INSERT, UPDATE, DELETE..." statements.
      *
      * @return IO with either an exception or with result of execution as an integer
      */
      fun String.executePreparedStatement(dataSource: DataSource, vararg args: Any): IO<Either<Throwable, Int>>
      val connection = dataSource.connection
      return IO
      val preparedStatement = connection.prepareStatement(this)
      args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
      preparedStatement.executeUpdate()
      .attemptAndCloseConnection(connection)


      /**
      * Executes SQL query
      */
      fun <E> String.executeQuery(dataSource: DataSource, resultSetMapper: (ResultSet) -> E, vararg args: Any): IO<Either<Throwable, List<E>>>
      val connection = dataSource.connection
      return IO
      val list = mutableListOf<E>()
      val preparedStatement = connection.prepareStatement(this)
      args.forEachIndexed() idx, arg -> preparedStatement.setObject(idx + 1, arg)
      val resultSet = preparedStatement.executeQuery()
      while (resultSet.next())
      list.add(resultSetMapper(resultSet))

      list.toList()
      .attemptAndCloseConnection(connection)


      private fun <A> IO<A>.attemptAndCloseConnection(connection: Connection?) =
      this.attempt().map connection?.close(); it


      Every result of execution is wrapped in an instance of IO to represent side-effects.



      Functions are invoked directly on strings which produces an instance of Either<Throwable, T> when run:



      val dataSource = HikariDataSource()
      // add config for data source...

      """CREATE TABLE cities (
      id INTEGER PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(255) NOT NULL);""".executeStatement(dataSource)
      .unsafeRunSync()

      "INSERT INTO cities (name) VALUES (?)".executePreparedStatement(dataSource, "New York").unsafeRunSync()


      My major concerns are:



      • Passing an instance of DataSource upon invocation of every function. E.g. with Scala, I could pass data source implicitly which would declutter invocations.

      • Mutable list in executeQuery function. Is it even ok?

      • Closing connection (attemptAndCloseConnection function) - is there some better way to do this?

      • Other proposals?








      share|improve this question










      share|improve this question




      share|improve this question









      asked Jul 12 at 11:35









      Branislav Lazic

      1689




      1689

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198358%2fjdbc-wrapper-in-a-functional-manner%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198358%2fjdbc-wrapper-in-a-functional-manner%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Chat program with C++ and SFML

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          Will my employers contract hold up in court?