mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-06-09 05:48:20 +00:00
WIP SQL console: pagination
This commit is contained in:
parent
d3f516edaf
commit
10af1b9020
@ -66,6 +66,7 @@ import tech.ailef.dbadmin.external.dto.CompareOperator;
|
|||||||
import tech.ailef.dbadmin.external.dto.FacetedSearchRequest;
|
import tech.ailef.dbadmin.external.dto.FacetedSearchRequest;
|
||||||
import tech.ailef.dbadmin.external.dto.LogsSearchRequest;
|
import tech.ailef.dbadmin.external.dto.LogsSearchRequest;
|
||||||
import tech.ailef.dbadmin.external.dto.PaginatedResult;
|
import tech.ailef.dbadmin.external.dto.PaginatedResult;
|
||||||
|
import tech.ailef.dbadmin.external.dto.PaginationInfo;
|
||||||
import tech.ailef.dbadmin.external.dto.QueryFilter;
|
import tech.ailef.dbadmin.external.dto.QueryFilter;
|
||||||
import tech.ailef.dbadmin.external.dto.ValidationErrorsContainer;
|
import tech.ailef.dbadmin.external.dto.ValidationErrorsContainer;
|
||||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||||
@ -101,7 +102,7 @@ public class DefaultDbAdminController {
|
|||||||
private ConsoleQueryRepository consoleQueryRepository;
|
private ConsoleQueryRepository consoleQueryRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JdbcTemplate jdbTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserSettingsRepository userSettingsRepo;
|
private UserSettingsRepository userSettingsRepo;
|
||||||
@ -596,7 +597,13 @@ public class DefaultDbAdminController {
|
|||||||
@GetMapping("/console/run/{queryId}")
|
@GetMapping("/console/run/{queryId}")
|
||||||
public String consoleRun(Model model, @RequestParam(required = false) String query,
|
public String consoleRun(Model model, @RequestParam(required = false) String query,
|
||||||
@RequestParam(required = false) String queryTitle,
|
@RequestParam(required = false) String queryTitle,
|
||||||
|
@RequestParam(required = false) Integer page,
|
||||||
|
@RequestParam(required = false) Integer pageSize,
|
||||||
@PathVariable String queryId) {
|
@PathVariable String queryId) {
|
||||||
|
|
||||||
|
if (page == null || page <= 0) page = 1;
|
||||||
|
if (pageSize == null) pageSize = 50;
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
if (!properties.isSqlConsoleEnabled()) {
|
if (!properties.isSqlConsoleEnabled()) {
|
||||||
@ -623,9 +630,10 @@ public class DefaultDbAdminController {
|
|||||||
List<ConsoleQuery> tabs = consoleQueryRepository.findAll();
|
List<ConsoleQuery> tabs = consoleQueryRepository.findAll();
|
||||||
model.addAttribute("tabs", tabs);
|
model.addAttribute("tabs", tabs);
|
||||||
|
|
||||||
|
List<DbQueryResultRow> results = new ArrayList<>();
|
||||||
if (activeQuery.getSql() != null && !activeQuery.getSql().isBlank()) {
|
if (activeQuery.getSql() != null && !activeQuery.getSql().isBlank()) {
|
||||||
try {
|
try {
|
||||||
List<DbQueryResultRow> results = jdbTemplate.query(activeQuery.getSql(), (rs, rowNum) -> {
|
results = jdbcTemplate.query(activeQuery.getSql(), (rs, rowNum) -> {
|
||||||
Map<DbQueryOutputField, Object> result = new HashMap<>();
|
Map<DbQueryOutputField, Object> result = new HashMap<>();
|
||||||
|
|
||||||
ResultSetMetaData metaData = rs.getMetaData();
|
ResultSetMetaData metaData = rs.getMetaData();
|
||||||
@ -640,14 +648,32 @@ public class DefaultDbAdminController {
|
|||||||
result.put(field, o);
|
result.put(field, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DbQueryResultRow(result, query);
|
DbQueryResultRow row = new DbQueryResultRow(result, query);
|
||||||
|
|
||||||
|
result.keySet().forEach(f -> {
|
||||||
|
f.setResult(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
return row;
|
||||||
});
|
});
|
||||||
model.addAttribute("results", new DbQueryResult(results));
|
|
||||||
} catch (DataAccessException e) {
|
} catch (DataAccessException e) {
|
||||||
model.addAttribute("error", e.getMessage());
|
model.addAttribute("error", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!results.isEmpty()) {
|
||||||
|
int maxPage = (int)(Math.ceil ((double)results.size() / pageSize));
|
||||||
|
PaginationInfo pagination = new PaginationInfo(page, maxPage, pageSize, results.size(), null, null);
|
||||||
|
int startOffset = (page - 1) * pageSize;
|
||||||
|
int endOffset = (page) * pageSize;
|
||||||
|
|
||||||
|
endOffset = Math.min(results.size(), endOffset);
|
||||||
|
|
||||||
|
results = results.subList(startOffset, endOffset);
|
||||||
|
model.addAttribute("pagination", pagination);
|
||||||
|
model.addAttribute("results", new DbQueryResult(results));
|
||||||
|
}
|
||||||
|
|
||||||
double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0;
|
double elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0;
|
||||||
model.addAttribute("elapsedTime", new DecimalFormat("0.0#").format(elapsedTime));
|
model.addAttribute("elapsedTime", new DecimalFormat("0.0#").format(elapsedTime));
|
||||||
return "console";
|
return "console";
|
||||||
|
@ -4,8 +4,10 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import tech.ailef.dbadmin.external.DbAdmin;
|
import tech.ailef.dbadmin.external.DbAdmin;
|
||||||
import tech.ailef.dbadmin.external.dbmapping.DbField;
|
import tech.ailef.dbadmin.external.dbmapping.DbField;
|
||||||
|
import tech.ailef.dbadmin.external.dbmapping.DbFieldType;
|
||||||
import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema;
|
import tech.ailef.dbadmin.external.dbmapping.DbObjectSchema;
|
||||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||||
|
import tech.ailef.dbadmin.external.exceptions.UnsupportedFieldTypeException;
|
||||||
|
|
||||||
public class DbQueryOutputField {
|
public class DbQueryOutputField {
|
||||||
private String name;
|
private String name;
|
||||||
@ -14,6 +16,8 @@ public class DbQueryOutputField {
|
|||||||
|
|
||||||
private DbField dbField;
|
private DbField dbField;
|
||||||
|
|
||||||
|
private DbQueryResultRow result;
|
||||||
|
|
||||||
public DbQueryOutputField(String name, String table, DbAdmin dbAdmin) {
|
public DbQueryOutputField(String name, String table, DbAdmin dbAdmin) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.table = table;
|
this.table = table;
|
||||||
@ -29,14 +33,26 @@ public class DbQueryOutputField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the column name of the field
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the table name of the field
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String getTable() {
|
public String getTable() {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this field is a primary key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean isPrimaryKey() {
|
public boolean isPrimaryKey() {
|
||||||
return dbField != null && dbField.isPrimaryKey();
|
return dbField != null && dbField.isPrimaryKey();
|
||||||
}
|
}
|
||||||
@ -67,26 +83,56 @@ public class DbQueryOutputField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the type of the field, only in the case the field
|
* Returns the type of the field.
|
||||||
* has been mapped to a table
|
* If the field has been mapped to a table column returns the
|
||||||
|
* type of the column, otherwise tries to parse the field
|
||||||
|
* field type from the raw value returned by the database.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String getType() {
|
public String getType() {
|
||||||
|
// If the field has been mapped to the database
|
||||||
if (dbField != null)
|
if (dbField != null)
|
||||||
return dbField.getType().toString();
|
return dbField.getType().toString();
|
||||||
|
|
||||||
|
// If the row this fields belongs to is defined
|
||||||
|
if (result != null) {
|
||||||
|
try {
|
||||||
|
DbFieldType type = DbFieldType.fromClass(result.get(this).getClass());
|
||||||
|
return type.toString();
|
||||||
|
} catch (UnsupportedFieldTypeException e) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "-";
|
return "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java name of the field, if mapped to a table column
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String getJavaName() {
|
public String getJavaName() {
|
||||||
if (dbField == null) return null;
|
if (dbField == null) return null;
|
||||||
return dbField.getJavaName();
|
return dbField.getJavaName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Java class of the field, if mapped to a table column
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String getEntityClassName() {
|
public String getEntityClassName() {
|
||||||
if (dbField == null) return null;
|
if (dbField == null) return null;
|
||||||
return dbField.getSchema().getClassName();
|
return dbField.getSchema().getClassName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the row object this field belongs to
|
||||||
|
* @param result
|
||||||
|
*/
|
||||||
|
public void setResult(DbQueryResultRow result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(name, table);
|
return Objects.hash(name, table);
|
||||||
|
@ -48,10 +48,124 @@
|
|||||||
|
|
||||||
<div th:if="${error == null && activeQuery.getSql() != null}">
|
<div th:if="${error == null && activeQuery.getSql() != null}">
|
||||||
<div class="separator mt-3 mb-3"></div>
|
<div class="separator mt-3 mb-3"></div>
|
||||||
<span class="text-muted mb-1 d-inline-block">
|
|
||||||
[[ ${results.size()} ]] results in [[ ${elapsedTime} ]] seconds
|
<!-- Pagination -->
|
||||||
</span>
|
<nav aria-label="Results pagination">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div th:if="${pagination != null && pagination.getMaxPage() != 1}" class="d-flex">
|
||||||
|
<ul class="pagination me-3">
|
||||||
|
<li class="page-item" th:if="${pagination.getCurrentPage() != 1}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(pagination.getCurrentPage() - 1)}|}"
|
||||||
|
aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item" th:each="p : ${pagination.getBeforePages()}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(p)}|}" th:text="${p}"></a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item active">
|
||||||
|
<a class="page-link" href="#" th:text="${pagination.getCurrentPage()}"></a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item" th:each="p : ${pagination.getAfterPages()}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(p)}|}"
|
||||||
|
th:text="${p}"></a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link"
|
||||||
|
th:if="${!pagination.isLastPage()}"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(pagination.getCurrentPage() + 1)}|}"
|
||||||
|
aria-label="Next">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="d-flex align-items-center" th:if="${pagination.getMaxPage() > 1}">
|
||||||
|
<p class="m-0 p-0">
|
||||||
|
<i>Showing [[ ${results.size()} ]] of [[ ${pagination.getMaxElement()} ]]
|
||||||
|
results in [[ ${elapsedTime} ]] seconds</i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center" th:if="${pagination.getMaxPage() == 1}">
|
||||||
|
<p class="m-0 p-0">
|
||||||
|
<i>Showing [[ ${results.size()} ]] of [[ ${pagination.getMaxElement()} ]]
|
||||||
|
results in [[ ${elapsedTime} ]] seconds</i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div th:replace="~{fragments/generic_table :: table(results=${results})}"></div>
|
<div th:replace="~{fragments/generic_table :: table(results=${results})}"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<nav aria-label="Results pagination">
|
||||||
|
<div class="d-flex justify-content-between">
|
||||||
|
<div th:if="${pagination != null && pagination.getMaxPage() != 1}" class="d-flex">
|
||||||
|
<ul class="pagination me-3">
|
||||||
|
<li class="page-item" th:if="${pagination.getCurrentPage() != 1}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(pagination.getCurrentPage() - 1)}|}"
|
||||||
|
aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item" th:each="p : ${pagination.getBeforePages()}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(p)}|}" th:text="${p}"></a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item active">
|
||||||
|
<a class="page-link" href="#" th:text="${pagination.getCurrentPage()}"></a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="page-item" th:each="p : ${pagination.getAfterPages()}">
|
||||||
|
<a class="page-link"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(p)}|}"
|
||||||
|
th:text="${p}"></a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link"
|
||||||
|
th:if="${!pagination.isLastPage()}"
|
||||||
|
th:href="@{|${dbadmin_requestUrl}${pagination.getLink(pagination.getCurrentPage() + 1)}|}"
|
||||||
|
aria-label="Next">
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="d-flex align-items-center" th:if="${pagination.getMaxPage() > 1}">
|
||||||
|
<p class="m-0 p-0">
|
||||||
|
<i>Showing [[ ${results.size()} ]] of [[ ${pagination.getMaxElement()} ]]
|
||||||
|
results in [[ ${elapsedTime} ]] seconds</i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center" th:if="${pagination.getMaxPage() == 1}">
|
||||||
|
<p class="m-0 p-0">
|
||||||
|
<i>Showing [[ ${results.size()} ]] of [[ ${pagination.getMaxElement()} ]]
|
||||||
|
results in [[ ${elapsedTime} ]] seconds</i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${error != null}">
|
<div th:if="${error != null}">
|
||||||
<div class="separator mt-3 mb-3"></div>
|
<div class="separator mt-3 mb-3"></div>
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
</th:block>
|
</th:block>
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block th:if="${!field.isBinary()}">
|
<th:block th:if="${!field.isBinary()}">
|
||||||
<span th:text="${object.get(field)}"></span>
|
|
||||||
|
<span th:if="${object.get(field) != null}" th:text="${object.get(field)}"></span>
|
||||||
|
<span th:if="${object.get(field) == null}" class="null-label font-monospace">NULL</span>
|
||||||
</th:block>
|
</th:block>
|
||||||
</th:block>
|
</th:block>
|
||||||
<!-- end data-row-field fragment -->
|
<!-- end data-row-field fragment -->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user