Adding mustache template substitution to QueryObj.
Now we can query postgres DB on the fly! Yipee!
This commit is contained in:
parent
28ef85b893
commit
a82a931093
|
|
@ -60,17 +60,24 @@
|
|||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.spullara.mustache.java</groupId>
|
||||
<artifactId>compiler</artifactId>
|
||||
<version>0.9.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ package com.mobtools.server.controllers;
|
|||
import com.mobtools.server.constants.Url;
|
||||
import com.mobtools.server.domains.Query;
|
||||
import com.mobtools.server.dtos.CommandQueryParams;
|
||||
import com.mobtools.server.dtos.ResponseDto;
|
||||
import com.mobtools.server.services.QueryService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
|
|
@ -21,7 +19,6 @@ public class QueryController extends BaseController<QueryService, Query, String>
|
|||
|
||||
@PostMapping("/execute/{id}")
|
||||
public Flux<Object> executeQuery(@PathVariable String id, @RequestBody CommandQueryParams params) {
|
||||
return service.executeQuery(id, params)
|
||||
.map(result -> new ResponseDto<>(HttpStatus.OK.value(), result, null));
|
||||
return service.executeQuery(id, params);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,78 @@
|
|||
package com.mobtools.server.services;
|
||||
|
||||
import com.github.mustachejava.DefaultMustacheFactory;
|
||||
import com.github.mustachejava.Mustache;
|
||||
import com.github.mustachejava.MustacheFactory;
|
||||
import com.mobtools.server.domains.Query;
|
||||
import com.mobtools.server.dtos.CommandQueryParams;
|
||||
import com.mobtools.server.dtos.Param;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
public interface PluginExecutor {
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
Flux<Object> execute();
|
||||
public abstract class PluginExecutor {
|
||||
|
||||
/**
|
||||
* This function executes the command against a backend datasource.
|
||||
* All the variables in commandTemplate of the Query object has already been replaced with actual values
|
||||
* by the #replaceTemplate() function
|
||||
*
|
||||
* @param query
|
||||
* @param params
|
||||
* @return Flux<Object>
|
||||
*/
|
||||
abstract Flux<Object> execute(Query query, CommandQueryParams params);
|
||||
|
||||
/**
|
||||
* This function should be run when the plugin is initialized
|
||||
*/
|
||||
abstract void init();
|
||||
|
||||
/**
|
||||
* This function should be run when the plugin is destroyed
|
||||
*/
|
||||
abstract void destroy();
|
||||
|
||||
/**
|
||||
* This function replaces the variables in the query commandTemplate with the actual params
|
||||
* Executors can override this function to provide their own implementation if they wish to do something custom
|
||||
*
|
||||
* @param query Query
|
||||
* @param params CommandQueryParams
|
||||
*/
|
||||
Query replaceTemplate(Query query, CommandQueryParams params) {
|
||||
MustacheFactory mf = new DefaultMustacheFactory();
|
||||
Mustache mustache = mf.compile(new StringReader(query.getCommandTemplate()), "commandTemplate");
|
||||
Writer writer = new StringWriter();
|
||||
|
||||
Map<String, String> queryMap = new HashMap<>();
|
||||
Map<String, String> headerMap = new HashMap<>();
|
||||
if(params.getQueryParams() != null) {
|
||||
queryMap = params
|
||||
.getQueryParams()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(Param::getKey, Param::getValue,
|
||||
// Incase there's a conflict, we pick the older value
|
||||
(oldValue, newValue) -> oldValue));
|
||||
}
|
||||
if(params.getHeaderParams() != null) {
|
||||
headerMap = params
|
||||
.getHeaderParams()
|
||||
.stream()
|
||||
.collect(
|
||||
Collectors.toMap(Param::getKey, Param::getValue,
|
||||
// Incase there's a conflict, we pick the older value
|
||||
(oldValue, newValue) -> oldValue));
|
||||
}
|
||||
mustache.execute(writer, queryMap);
|
||||
|
||||
query.setCommandTemplate(writer.toString());
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,81 @@
|
|||
package com.mobtools.server.services;
|
||||
|
||||
import com.mobtools.server.domains.Property;
|
||||
import com.mobtools.server.domains.Query;
|
||||
import com.mobtools.server.dtos.CommandQueryParams;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PostgresDBPluginExecutor implements PluginExecutor {
|
||||
public class PostgresDBPluginExecutor extends PluginExecutor {
|
||||
|
||||
// JDBC driver name and database URL
|
||||
@Value("${jdbc.postgres.driver}")
|
||||
static final String JDBC_DRIVER = "org.postgresql.Driver";
|
||||
|
||||
@Value("${jdbc.postgres.url}")
|
||||
static final String DB_URL = "jdbc:postgresql://localhost/mobtools";
|
||||
|
||||
// Database credentials
|
||||
@Value("${jdbc.postgres.username}")
|
||||
static final String DB_USER = "postgres";
|
||||
|
||||
@Value("${jdbc.postgres.password}")
|
||||
static final String DB_PASS = "root";
|
||||
|
||||
Connection conn = null;
|
||||
|
||||
@Override
|
||||
public Flux<Object> execute() {
|
||||
Property prop = new Property();
|
||||
prop.setKey("name");
|
||||
prop.setValue("val");
|
||||
public Flux<Object> execute(Query queryObj, CommandQueryParams params) {
|
||||
if(conn == null) {
|
||||
init();
|
||||
}
|
||||
ArrayList list = new ArrayList(50);
|
||||
try {
|
||||
Statement statement = conn.createStatement();
|
||||
String queryTemplate = queryObj.getCommandTemplate();
|
||||
|
||||
List<Property> props= new ArrayList<>();
|
||||
props.add(prop);
|
||||
ResultSet resultSet = statement.executeQuery(queryTemplate);
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
Integer colCount = metaData.getColumnCount();
|
||||
while(resultSet.next()) {
|
||||
HashMap row = new HashMap(colCount);
|
||||
for(int i = 1; i<=colCount; i++) {
|
||||
row.put(metaData.getColumnName(i), resultSet.getObject(i));
|
||||
}
|
||||
list.add(row);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Flux.fromIterable(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
log.debug("Going to initialize the PostgresDBPluginExecutor");
|
||||
try {
|
||||
// Load the class into JVM
|
||||
Class.forName(JDBC_DRIVER);
|
||||
|
||||
// Create the connection
|
||||
conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
return Flux.just(props);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import com.mobtools.server.domains.Query;
|
|||
import com.mobtools.server.dtos.CommandQueryParams;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.stream.DoubleStream;
|
||||
|
||||
public interface QueryService extends CrudService<Query, String> {
|
||||
|
||||
Flux<Object> executeQuery(String id, CommandQueryParams params);
|
||||
|
|
|
|||
|
|
@ -35,12 +35,20 @@ public class QueryServiceImpl extends BaseService<QueryRepository, Query, String
|
|||
log.debug("Going to execute query with id: {}", id);
|
||||
|
||||
// 1. Fetch the query from the DB to get the type
|
||||
return repository.findById(id)
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new MobtoolsException("Unable to find query by id: " + id))))
|
||||
// 2. Instantiate the implementation class based on the query type
|
||||
.map(queryObj -> pluginService.getPluginExecutor(queryObj.getPlugin().getType(), queryObj.getPlugin().getExecutorClass()))
|
||||
// 3. Execute the query
|
||||
.flatMapMany(plugin -> plugin.execute());
|
||||
Mono<Query> queryMono = repository.findById(id)
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new MobtoolsException("Unable to find query by id: " + id))));
|
||||
|
||||
// 2. Instantiate the implementation class based on the query type
|
||||
Mono<PluginExecutor> pluginExecutorMono = queryMono.map(queryObj ->
|
||||
pluginService.getPluginExecutor(queryObj.getPlugin().getType(), queryObj.getPlugin().getExecutorClass()));
|
||||
|
||||
// 3. Execute the query
|
||||
return queryMono
|
||||
.zipWith(pluginExecutorMono, (queryObj, pluginExecutor) -> {
|
||||
Query newQueryObj = pluginExecutor.replaceTemplate(queryObj, params);
|
||||
return pluginExecutor.execute(newQueryObj, params);
|
||||
})
|
||||
.flatMapIterable(Flux::toIterable).subscribeOn(scheduler);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,3 +4,11 @@ spring.data.mongodb.host=localhost
|
|||
spring.data.mongodb.port=27017
|
||||
#spring.data.mongodb.username=
|
||||
#spring.data.mongodb.password=
|
||||
|
||||
logging.level.com.mobtools=debug
|
||||
|
||||
# JDBC Postgres properties
|
||||
jdbc.postgres.driver=org.postgresql.Driver
|
||||
jdbc.postgres.url=jdbc:postgresql://localhost/mobtools
|
||||
jdbc.postgres.username=postgres
|
||||
jdbc.postgres.password=root
|
||||
|
|
|
|||
|
|
@ -2,3 +2,9 @@
|
|||
spring.data.mongodb.database=mobtools
|
||||
spring.data.mongodb.uri=mongodb+srv://admin:Y9PuxM52gcP3Dgfo@mobtools-test-cluster-swrsq.mongodb.net/mobtools?retryWrites=true
|
||||
spring.data.mongodb.authentication-database=admin
|
||||
|
||||
# JDBC Postgres properties
|
||||
jdbc.postgres.driver=org.postgresql.Driver
|
||||
jdbc.postgres.url=jdbc:postgresql://ec2-54-247-85-251.eu-west-1.compute.amazonaws.com/d266aalso50024
|
||||
jdbc.postgres.username=pornlzmggggpgk
|
||||
jdbc.postgres.password=09275163cd7e737baf4c210b5e8db8ed88ddb7a0ee9acc82416fd75346ea4bbb
|
||||
Loading…
Reference in New Issue
Block a user