All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.ext.asyncsql.impl.AsyncSQLConnectionImpl Maven / Gradle / Ivy

/*
 *  Copyright 2015 Red Hat, Inc.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *  The Eclipse Public License is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */

package io.vertx.ext.asyncsql.impl;

import com.github.mauricio.async.db.Connection;
import com.github.mauricio.async.db.QueryResult;
import com.github.mauricio.async.db.RowData;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.ext.asyncsql.impl.pool.AsyncConnectionPool;
import io.vertx.ext.sql.ResultSet;
import io.vertx.ext.sql.SQLConnection;
import io.vertx.ext.sql.UpdateResult;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import scala.Option;
import scala.concurrent.ExecutionContext;
import scala.runtime.AbstractFunction1;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * Implementation of {@link SQLConnection} using the {@link AsyncConnectionPool}.
 *
 * @author Clement Escoffier
 */
public class AsyncSQLConnectionImpl implements SQLConnection {

  private final ExecutionContext executionContext;
  private volatile boolean inTransaction = false;
  private boolean inAutoCommit = true;

  private final Connection connection;
  private final AsyncConnectionPool pool;

  public AsyncSQLConnectionImpl(Connection connection, AsyncConnectionPool pool, ExecutionContext executionContext) {
    this.connection = connection;
    this.pool = pool;
    this.executionContext = executionContext;
  }

  @Override
  public SQLConnection call(String sql, Handler> resultHandler) {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public SQLConnection callWithParams(String sql, JsonArray params, JsonArray outputs, Handler> resultHandler) {
    throw new UnsupportedOperationException("Not implemented");
  }

  @Override
  public SQLConnection setAutoCommit(boolean autoCommit, Handler> handler) {
    Future fut;

    synchronized (this) {
      if (inTransaction && autoCommit) {
        inTransaction = false;
        fut = ScalaUtils.scalaToVertxVoid(connection.sendQuery("COMMIT"), executionContext);
      } else {
        fut = Future.succeededFuture();
      }
      inAutoCommit = autoCommit;
    }

    fut.setHandler(handler);
    return this;

  }

  @Override
  public SQLConnection execute(String sql, Handler> handler) {
    beginTransactionIfNeeded(v -> {
      final scala.concurrent.Future future = connection.sendQuery(sql);
      future.onComplete(ScalaUtils.toFunction1(ar -> {
        if (ar.failed()) {
          handler.handle(Future.failedFuture(ar.cause()));
        } else {
          handler.handle(Future.succeededFuture());
        }
      }), executionContext);
    });

    return this;
  }

  @Override
  public SQLConnection query(String sql, Handler> handler) {
    beginTransactionIfNeeded(v -> {
      final Future future = ScalaUtils.scalaToVertx(connection.sendQuery(sql), executionContext);
      future.setHandler(ar -> {
        if (ar.succeeded()) {
          handler.handle(Future.succeededFuture(queryResultToResultSet(ar.result())));
        } else {
          handler.handle(Future.failedFuture(ar.cause()));
        }

      });
    });

    return this;
  }

  @Override
  public SQLConnection queryWithParams(String sql, JsonArray params, Handler> handler) {
    beginTransactionIfNeeded(v -> {
      final scala.concurrent.Future future = connection.sendPreparedStatement(sql,
          ScalaUtils.toScalaList(params.getList()));
      future.onComplete(ScalaUtils.toFunction1(ar -> {
        if (ar.succeeded()) {
          handler.handle(Future.succeededFuture(queryResultToResultSet(ar.result())));
        } else {
          handler.handle(Future.failedFuture(ar.cause()));
        }

      }), executionContext);
    });

    return this;
  }

  @Override
  public SQLConnection update(String sql, Handler> handler) {
    beginTransactionIfNeeded(v -> {
      final scala.concurrent.Future future = connection.sendQuery(sql);
      future.onComplete(ScalaUtils.toFunction1(ar -> {
        if (ar.failed()) {
          handler.handle(Future.failedFuture(ar.cause()));
        } else {
          handler.handle(Future.succeededFuture(queryResultToUpdateResult(ar.result())));
        }
      }), executionContext);
    });

    return this;
  }

  @Override
  public SQLConnection updateWithParams(String sql, JsonArray params, Handler> handler) {
    beginTransactionIfNeeded(v -> {
      final scala.concurrent.Future future = connection.sendPreparedStatement(sql,
          ScalaUtils.toScalaList(params.getList()));
      future.onComplete(ScalaUtils.toFunction1(ar -> {
        if (ar.failed()) {
          handler.handle(Future.failedFuture(ar.cause()));
        } else {
          handler.handle(Future.succeededFuture(queryResultToUpdateResult(ar.result())));
        }
      }), executionContext);
    });

    return this;
  }

  @Override
  public synchronized void close(Handler> handler) {
    inAutoCommit = true;
    if (inTransaction) {
      inTransaction = false;
      Future future = ScalaUtils.scalaToVertx(connection.sendQuery("COMMIT"), executionContext);
      future.setHandler((v) -> {
        pool.giveBack(connection);
        handler.handle(Future.succeededFuture());
      });
    } else {
      pool.giveBack(connection);
      handler.handle(Future.succeededFuture());
    }
  }

  @Override
  public void close() {
    close((ar) -> {
      // Do nothing by default.
    });
  }

  @Override
  public SQLConnection commit(Handler> handler) {
    return endAndStartTransaction("COMMIT", handler);
  }

  @Override
  public SQLConnection rollback(Handler> handler) {
    return endAndStartTransaction("ROLLBACK", handler);
  }

  private SQLConnection endAndStartTransaction(String command, Handler> handler) {
    if (inTransaction) {
      inTransaction = false;
      ScalaUtils.scalaToVertx(connection.sendQuery(command), executionContext).setHandler(
          ar -> {
            if (ar.failed()) {
              handler.handle(Future.failedFuture(ar.cause()));
            } else {
              ScalaUtils.scalaToVertx(connection.sendQuery("BEGIN"), executionContext).setHandler(
                  ar2 -> {
                    if (ar2.failed()) {
                      handler.handle(Future.failedFuture(ar.cause()));
                    } else {
                      inTransaction = true;
                      handler.handle(Future.succeededFuture());
                    }
                  }
              );
            }
          });
    } else {
      handler.handle(Future.failedFuture(
          new IllegalStateException("Not in transaction currently")));
    }
    return this;
  }

  private synchronized void beginTransactionIfNeeded(Handler> action) {
    if (!inAutoCommit && !inTransaction) {
      inTransaction = true;
      ScalaUtils.scalaToVertxVoid(connection.sendQuery("BEGIN"), executionContext)
          .setHandler(action);
    } else {
      action.handle(Future.succeededFuture());
    }
  }

  private ResultSet queryResultToResultSet(QueryResult qr) {
    final Option rows = qr.rows();
    if (!rows.isDefined()) {
      return new ResultSet(Collections.emptyList(), Collections.emptyList());
    } else {
      final List names = ScalaUtils.toJavaList(rows.get().columnNames().toList());
      final List arrays = rowDataSeqToJsonArray(rows.get());
      return new ResultSet(names, arrays);
    }
  }

  protected UpdateResult queryResultToUpdateResult(QueryResult qr) {
    int affected = (int) qr.rowsAffected();
    return new UpdateResult(affected, new JsonArray());
  }

  private List rowDataSeqToJsonArray(com.github.mauricio.async.db.ResultSet set) {
    List list = new ArrayList<>();
    set.foreach(new AbstractFunction1() {
      @Override
      public Void apply(RowData row) {
        list.add(rowToJsonArray(row));
        return null;
      }
    });
    return list;
  }

  private JsonArray rowToJsonArray(RowData data) {
    JsonArray array = new JsonArray();
    data.foreach(new AbstractFunction1() {
      @Override
      public Void apply(Object value) {
        if (value == null) {
          array.addNull();
        } else if (value instanceof LocalDateTime) {
          array.add(value.toString());
        } else if (value instanceof LocalDate) {
          array.add(value.toString());
        } else if (value instanceof UUID) {
          array.add(value.toString());
        } else {
          array.add(value);
        }
        return null;
      }
    });
    return array;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy