Skip to content

Commit

Permalink
Reactive MS SQL client support (#249)
Browse files Browse the repository at this point in the history
* +Removed unneeded parameters

* ~Test moved to integration tests

* +Coverage for MS SQL; support for not using database in SQL requests

* +Support of new API

* +Full coverage of MS SQL

* ~Refactoring

* +Temporary fix

* ~Format
  • Loading branch information
fedinskiy authored Sep 13, 2021
1 parent 564d327 commit c208728
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
package io.quarkus.ts.sqldb.sqlapp;

import io.quarkus.test.bootstrap.DefaultService;
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.bootstrap.SqlServerService;
import io.quarkus.test.scenarios.OpenShiftScenario;
import io.quarkus.test.services.Container;
import io.quarkus.test.services.QuarkusApplication;

@OpenShiftScenario
public class OpenShiftMssqlDatabaseIT extends AbstractSqlDatabaseIT {
private static final String MSSQL_PASSWORD = "QuArKuS_tEsT";
private static final String DATABASE = "msdb";

static final int MSSQL_PORT = 1433;

@Container(image = "${mssql.image}", port = MSSQL_PORT, expectedLog = "Service Broker manager has started")
static SqlServerService mssql = new SqlServerService();
//fixme Replace with SqlServerService when https://github.com/quarkus-qe/quarkus-test-framework/issues/251 will be solved
static DefaultService mssql = new DefaultService()
.withProperty("ACCEPT_EULA", "Y")
.withProperty("SA_PASSWORD", MSSQL_PASSWORD);

@QuarkusApplication
static RestService app = new RestService()
static final RestService app = new RestService()
.withProperties("mssql.properties")
.withProperty("quarkus.datasource.username", mssql.getUser())
.withProperty("quarkus.datasource.password", mssql.getPassword())
.withProperty("quarkus.datasource.jdbc.url", mssql::getJdbcUrl);
.withProperty("quarkus.datasource.username", "sa")
.withProperty("quarkus.datasource.password", MSSQL_PASSWORD)
.withProperty("quarkus.datasource.jdbc.url",
() -> mssql.getHost().replace("http", "jdbc:sqlserver") + ":" +
mssql.getPort() + ";databaseName=" + DATABASE);
}
8 changes: 8 additions & 0 deletions sql-db/vertx-sql/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-db2</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-mssql-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-mssql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-flyway</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.jackson.DatabindCodec;
import io.vertx.mutiny.db2client.DB2Pool;
import io.vertx.mutiny.mssqlclient.MSSQLPool;
import io.vertx.mutiny.mysqlclient.MySQLPool;
import io.vertx.mutiny.pgclient.PgPool;

/** Application is used as a main class in order to setup some global configuration */
/**
* Application is used as a main class in order to setup some global configuration
*/
@ApplicationScoped
public class Application {

Expand Down Expand Up @@ -55,6 +58,11 @@ public class Application {
@IfBuildProfile("db2")
DB2Pool db2;

@Inject
@Named("mssql")
@IfBuildProfile("mssql")
MSSQLPool mssql;

void onStart(@Observes StartupEvent ev) {
LOGGER.info("The application is starting with profile " + ProfileManager.getActiveProfile());

Expand All @@ -71,6 +79,8 @@ synchronized DbPoolService pool() {
return new DbPoolService(mysql, mysqlDbName, selectedDB);
case "db2":
return new DbPoolService(db2, "\"" + db2DbName + "\"", selectedDB);
case "mssql":
return new DbPoolService(mssql, null, selectedDB);
default:
return new DbPoolService(postgresql, postgresqlDbName, selectedDB);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected static Multi<Airline> fromSet(RowSet<Row> rows) {
}

public static Multi<Airline> findAll(DbPoolService client) {
return client.query("SELECT * FROM " + client.getDatabaseName() + ".airlines").execute().onItem()
return client.query("SELECT * FROM " + client.getTableName("airlines")).execute().onItem()
.transformToMulti(Airline::fromSet);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected static Multi<Airport> fromSet(RowSet<Row> rows) {
}

public static Multi<Airport> findAll(DbPoolService client) {
return client.query("SELECT * FROM " + client.getDatabaseName() + ".airports").execute().onItem()
return client.query("SELECT * FROM " + client.getTableName("airports")).execute().onItem()
.transformToMulti(Airport::fromSet);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ protected static Multi<Flight> fromSet(RowSet<Row> rows) {
}

public static Multi<Flight> findAll(DbPoolService client) {
return client.query("SELECT * FROM " + client.getDatabaseName() + ".flights").execute().onItem()
return client.query("SELECT * FROM " + client.getTableName("flights")).execute().onItem()
.transformToMulti(Flight::fromSet);
}

Expand All @@ -64,7 +64,7 @@ public static Uni<List<Flight>> findAllAsList(DbPoolService client) {
}

public static Multi<Flight> findByOriginDestination(DbPoolService client, String origin, String destination) {
String query = String.format("SELECT * FROM " + client.getDatabaseName() + ".flights where %s = '%s' and %s = '%s'",
String query = String.format("SELECT * FROM " + client.getTableName("flights") + " where %s = '%s' and %s = '%s'",
QUALIFIED_ORIGIN_NAME, origin, QUALIFIED_DESTINATION_NAME, destination);
return client.query(query).execute().onItem().transformToMulti(Flight::fromSet);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ protected static Multi<PricingRules> fromSet(RowSet<Row> rows) {
}

public static Multi<PricingRules> findAll(DbPoolService client) {
return client.query("SELECT * FROM " + client.getDatabaseName() + ".pricingRules").execute().onItem()
return client.query("SELECT * FROM " + client.getTableName("pricingRules")).execute().onItem()
.transformToMulti(PricingRules::fromSet);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.db2client.DB2Exception;
import io.vertx.mssqlclient.MSSQLException;
import io.vertx.mysqlclient.MySQLException;
import io.vertx.pgclient.PgException;

Expand All @@ -31,6 +32,11 @@ void databaseDb2ConstraintFailure(DB2Exception e, HttpServerResponse response) {
response.setStatusCode(400).end(Json.encode(new JsonObject().put("msg", e.getMessage())));
}

@Route(path = "/*", type = Route.HandlerType.FAILURE, produces = "application/json")
void databaseDb2ConstraintFailure(MSSQLException e, HttpServerResponse response) {
response.setStatusCode(400).end(Json.encode(new JsonObject().put("msg", e.getMessage())));
}

@Route(path = "/*", type = Route.HandlerType.FAILURE, produces = "application/json")
public void exceptions(ConstraintViolationException e, HttpServerResponse res) {
res.setStatusCode(400).end(handler -> e.getConstraintViolations().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public DbPoolService(Pool delegate, String dbName, String selectedDb) {
this.selectedDb = selectedDb;
}

public String getDatabaseName() {
return databaseName;
public String getTableName(String table) {
return null == databaseName
? table
: databaseName + "." + table;
}

public Uni<Long> save(String tableName, List<String> fieldsNames, List<Object> fieldsValues) {
Expand All @@ -30,18 +32,34 @@ public Uni<Long> save(String tableName, List<String> fieldsNames, List<Object> f
return saveMysql(tableName, fieldsNames, fieldsValues);
case "db2":
return saveDb2(tableName, fieldsNames, fieldsValues);
case "mssql":
return saveMS(tableName, fieldsNames, fieldsValues);
default:
return savePg(tableName, fieldsNames, fieldsValues);
}
}

private Uni<Long> saveMS(String tableName, List<String> fieldsNames, List<Object> fieldsValues) {
return SqlClientHelper.inTransactionUni(this, tx -> {
String fields = tableFieldsToString(fieldsNames);
String values = tableFieldsValuesToString(fieldsValues);

return tx
.preparedQuery(
"INSERT INTO " + getTableName(tableName) + " (" + fields + ") VALUES (" + values
+ "); SELECT SCOPE_IDENTITY() as id;")
.execute()
.map(r -> r.iterator().next().getLong("id"));
});
}

protected Uni<Long> savePg(String tableName, List<String> fieldsNames, List<Object> fieldsValues) {
return SqlClientHelper.inTransactionUni(this, tx -> {
String fields = tableFieldsToString(fieldsNames);
String values = tableFieldsValuesToString(fieldsValues);

return tx
.preparedQuery("INSERT INTO " + getDatabaseName() + "." + tableName + " (" + fields + ") VALUES (" + values
.preparedQuery("INSERT INTO " + getTableName(tableName) + " (" + fields + ") VALUES (" + values
+ ") RETURNING id")
.execute().onItem().transform(id -> id.iterator().next().getLong("id"));
});
Expand All @@ -54,7 +72,7 @@ protected Uni<Long> saveMysql(String tableName, List<String> fieldsNames, List<O

return tx
.preparedQuery(
"INSERT INTO " + getDatabaseName() + "." + tableName + " (" + fields + ") VALUES (" + values + ")")
"INSERT INTO " + getTableName(tableName) + " (" + fields + ") VALUES (" + values + ")")
.execute()
.onItem().invoke(r -> this.query("SELECT LAST_INSERT_ID();"))
.onItem().transform(id -> (Long) id.getDelegate().property(LAST_INSERTED_ID));
Expand All @@ -67,7 +85,7 @@ protected Uni<Long> saveDb2(String tableName, List<String> fieldsNames, List<Obj
String values = tableFieldsValuesToString(fieldsValues);

return tx
.preparedQuery("select id from NEW TABLE (INSERT INTO " + getDatabaseName() + "." + tableName + " ("
.preparedQuery("select id from NEW TABLE (INSERT INTO " + getTableName(tableName) + " ("
+ fields + ") VALUES (" + values + "))")
.execute().onItem().transform(id -> id.iterator().next().getLong("id"));
});
Expand All @@ -88,5 +106,4 @@ private String tableFieldsValuesToString(List<Object> fieldsValues) {
return content;
}).collect(Collectors.joining(",", "", ""));
}

}
20 changes: 16 additions & 4 deletions sql-db/vertx-sql/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ quarkus.datasource.reactive.reconnect-attempts=3
quarkus.datasource.reactive.reconnect-interval=3

## Flyway
quarkus.flyway.migrate-at-start=true
quarkus.flyway.migrate-at-start=false
quarkus.flyway.schemas=amadeus
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/amadeus
quarkus.flyway.locations=db/migration/postgresql,db/migration/common
Expand All @@ -33,7 +33,6 @@ quarkus.datasource.mysql.password=test
quarkus.datasource.mysql.reactive.url=mysql://localhost:3306/amadeus

# Flyway
quarkus.flyway.mysql.migrate-at-start=true
quarkus.flyway.mysql.schemas=amadeus
quarkus.datasource.mysql.jdbc.url=jdbc:mysql://localhost:3306/amadeus?useSSL=false
quarkus.flyway.mysql.locations=db/migration/mysql,db/migration/common
Expand All @@ -49,7 +48,20 @@ quarkus.datasource.db2.password=test
quarkus.datasource.db2.reactive.url=vertx-reactive:db2://localhost:50000/amadeus

# Flyway
quarkus.flyway.db2.migrate-at-start=true
quarkus.flyway.db2.schemas=amadeus
quarkus.datasource.db2.jdbc.url=jdbc:db2://localhost:50000/amadeus
quarkus.flyway.db2.locations=db/migration/db2,db/migration/common
quarkus.flyway.db2.locations=db/migration/db2,db/migration/common

## MS SQL
## Database
%mssql.app.selected.db=mssql
quarkus.datasource.mssql.reactive=true
quarkus.datasource.mssql.db-kind=mssql
quarkus.datasource.mssql.username=sa
quarkus.datasource.mssql.password=QuArKuS_tEsT
quarkus.datasource.mssql.reactive.url=vertx-reactive:sqlserver://localhost:1433/msdb

# Flyway
quarkus.flyway.mssql.schemas=msdb
quarkus.datasource.mssql.jdbc.url=jdbc:sqlserver://localhost:1433;databaseName=msdb
quarkus.flyway.mssql.locations=db/migration/mssql,db/migration/common
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
CREATE TABLE airports (
id INT NOT NULL IDENTITY(1,1),
iata_code VARCHAR(100) NOT NULL,
city VARCHAR(100) NOT NULL,
PRIMARY KEY(id)
);

CREATE TABLE airlines (
id INT NOT NULL IDENTITY(1,1),
iata_code VARCHAR(100) NOT NULL,
name VARCHAR(100) NOT NULL,
infant_price FLOAT(3),
PRIMARY KEY(id)
);

CREATE TABLE flights (
id INT NOT NULL IDENTITY(1,1),
origin VARCHAR(100) NOT NULL,
destination VARCHAR(100) NOT NULL,
flight_code VARCHAR(100) NOT NULL,
base_price INTEGER NOT NULL,
PRIMARY KEY(id)
);

CREATE TABLE pricingRules (
id INT NOT NULL IDENTITY(1,1),
days_to_departure INTEGER NOT NULL,
until INTEGER NOT NULL,
percentage INTEGER NOT NULL,
PRIMARY KEY(id)
);

CREATE TABLE address (
id INT NOT NULL IDENTITY(1,1),
street VARCHAR(300) NOT NULL,
block_number VARCHAR(20) NOT NULL,
zip_code VARCHAR(20) NOT NULL,
city VARCHAR(150) NOT NULL,
country VARCHAR(200) NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT,
PRIMARY KEY(id)
);

CREATE TABLE passenger (
id INT NOT NULL IDENTITY(1,1),
nif VARCHAR(10) NOT NULL,
name VARCHAR(25) NOT NULL,
last_name VARCHAR(55) NOT NULL,
contact_number VARCHAR(20) NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT,
address_id INT,
PRIMARY KEY(id),
FOREIGN KEY (address_id) REFERENCES address(id) ON DELETE SET NULL
);

CREATE TABLE basket (
id INT NOT NULL IDENTITY(1,1),
flight VARCHAR(10) NOT NULL,
price NUMERIC NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT,
passenger_id INT,
PRIMARY KEY(id),
FOREIGN KEY (passenger_id) REFERENCES passenger(id) ON DELETE SET NULL
);
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ public class Db2HandlerIT extends CommonTestCases {
private static final String DATABASE = "amadeus";

@Container(image = "${db2.image}", port = 50000, expectedLog = "Setup has completed")
static Db2Service db2 = new Db2Service()
.with("test", "test", DATABASE);
static Db2Service db2 = new Db2Service().with("test", "test", DATABASE);

@QuarkusApplication
static final RestService app = new RestService()
.withProperty("quarkus.datasource.db2.jdbc.url", db2::getJdbcUrl)
.withProperty("quarkus.datasource.db2.reactive.url", db2::getReactiveUrl)
.withProperty("quarkus.datasource.db2.jdbc.url",
() -> db2.getHost().replace("http", "jdbc:db2") + ":" +
db2.getPort() + "/" + DATABASE)
.withProperty("quarkus.datasource.db2.reactive.url",
() -> db2.getHost().replace("http", "db2") + ":" +
db2.getPort() + "/" + DATABASE)
.withProperty("app.selected.db", "db2")
// Enable Flyway for DB2
.withProperty("quarkus.flyway.db2.migrate-at-start", "true")
// Disable Flyway for MySQL
.withProperty("quarkus.flyway.mysql.migrate-at-start", "false")
// Disable Flyway for Postgresql
.withProperty("quarkus.flyway.migrate-at-start", "false");
.withProperty("quarkus.flyway.db2.migrate-at-start", "true");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.quarkus.qe.vertx.sql.handlers;

import io.quarkus.test.bootstrap.DefaultService;
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.Container;
import io.quarkus.test.services.QuarkusApplication;

@QuarkusScenario
public class MSsqlHandlerIT extends CommonTestCases {
private static final String MSSQL_PASSWORD = "QuArKuS_tEsT";
private static final String DATABASE = "msdb";
private static final int MSSQL_PORT = 1433;

//fixme Replace with SqlServerService when https://github.com/quarkus-qe/quarkus-test-framework/issues/251 will be solved
@Container(image = "${mssql.image}", port = MSSQL_PORT, expectedLog = "Service Broker manager has started")
static DefaultService mssql = new DefaultService()
.withProperty("ACCEPT_EULA", "Y")
.withProperty("SA_PASSWORD", MSSQL_PASSWORD);

@QuarkusApplication
static final RestService app = new RestService()
.withProperty("quarkus.datasource.mssql.jdbc.url",
() -> mssql.getHost().replace("http", "jdbc:sqlserver") + ":" +
mssql.getPort() + ";databaseName=" + DATABASE)
.withProperty("quarkus.datasource.mssql.reactive.url",
() -> mssql.getHost().replace("http", "sqlserver") + ":" +
mssql.getPort() + "/" + DATABASE)
.withProperty("app.selected.db", "mssql")
// Enable Flyway for MySQL
.withProperty("quarkus.flyway.mssql.migrate-at-start", "true");
}
Loading

0 comments on commit c208728

Please sign in to comment.