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>
|
<artifactId>lombok</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.spullara.mustache.java</groupId>
|
||||||
|
<artifactId>compiler</artifactId>
|
||||||
|
<version>0.9.6</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-test</artifactId>
|
<artifactId>spring-security-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@ package com.mobtools.server.controllers;
|
||||||
import com.mobtools.server.constants.Url;
|
import com.mobtools.server.constants.Url;
|
||||||
import com.mobtools.server.domains.Query;
|
import com.mobtools.server.domains.Query;
|
||||||
import com.mobtools.server.dtos.CommandQueryParams;
|
import com.mobtools.server.dtos.CommandQueryParams;
|
||||||
import com.mobtools.server.dtos.ResponseDto;
|
|
||||||
import com.mobtools.server.services.QueryService;
|
import com.mobtools.server.services.QueryService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
|
@ -21,7 +19,6 @@ public class QueryController extends BaseController<QueryService, Query, String>
|
||||||
|
|
||||||
@PostMapping("/execute/{id}")
|
@PostMapping("/execute/{id}")
|
||||||
public Flux<Object> executeQuery(@PathVariable String id, @RequestBody CommandQueryParams params) {
|
public Flux<Object> executeQuery(@PathVariable String id, @RequestBody CommandQueryParams params) {
|
||||||
return service.executeQuery(id, params)
|
return service.executeQuery(id, params);
|
||||||
.map(result -> new ResponseDto<>(HttpStatus.OK.value(), result, null));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,78 @@
|
||||||
package com.mobtools.server.services;
|
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;
|
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;
|
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 org.springframework.stereotype.Component;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@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
|
@Override
|
||||||
public Flux<Object> execute() {
|
public Flux<Object> execute(Query queryObj, CommandQueryParams params) {
|
||||||
Property prop = new Property();
|
if(conn == null) {
|
||||||
prop.setKey("name");
|
init();
|
||||||
prop.setValue("val");
|
}
|
||||||
|
ArrayList list = new ArrayList(50);
|
||||||
|
try {
|
||||||
|
Statement statement = conn.createStatement();
|
||||||
|
String queryTemplate = queryObj.getCommandTemplate();
|
||||||
|
|
||||||
List<Property> props= new ArrayList<>();
|
ResultSet resultSet = statement.executeQuery(queryTemplate);
|
||||||
props.add(prop);
|
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 com.mobtools.server.dtos.CommandQueryParams;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
import java.util.stream.DoubleStream;
|
|
||||||
|
|
||||||
public interface QueryService extends CrudService<Query, String> {
|
public interface QueryService extends CrudService<Query, String> {
|
||||||
|
|
||||||
Flux<Object> executeQuery(String id, CommandQueryParams params);
|
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);
|
log.debug("Going to execute query with id: {}", id);
|
||||||
|
|
||||||
// 1. Fetch the query from the DB to get the type
|
// 1. Fetch the query from the DB to get the type
|
||||||
return repository.findById(id)
|
Mono<Query> queryMono = repository.findById(id)
|
||||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new MobtoolsException("Unable to find query by id: " + 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
|
// 2. Instantiate the implementation class based on the query type
|
||||||
.map(queryObj -> pluginService.getPluginExecutor(queryObj.getPlugin().getType(), queryObj.getPlugin().getExecutorClass()))
|
Mono<PluginExecutor> pluginExecutorMono = queryMono.map(queryObj ->
|
||||||
|
pluginService.getPluginExecutor(queryObj.getPlugin().getType(), queryObj.getPlugin().getExecutorClass()));
|
||||||
|
|
||||||
// 3. Execute the query
|
// 3. Execute the query
|
||||||
.flatMapMany(plugin -> plugin.execute());
|
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.port=27017
|
||||||
#spring.data.mongodb.username=
|
#spring.data.mongodb.username=
|
||||||
#spring.data.mongodb.password=
|
#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.database=mobtools
|
||||||
spring.data.mongodb.uri=mongodb+srv://admin:Y9PuxM52gcP3Dgfo@mobtools-test-cluster-swrsq.mongodb.net/mobtools?retryWrites=true
|
spring.data.mongodb.uri=mongodb+srv://admin:Y9PuxM52gcP3Dgfo@mobtools-test-cluster-swrsq.mongodb.net/mobtools?retryWrites=true
|
||||||
spring.data.mongodb.authentication-database=admin
|
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