Added more documentation to PerfinApp.java, and added JSON export.
This commit is contained in:
parent
6d720b9645
commit
71cc5b1612
|
@ -30,7 +30,9 @@ import java.util.function.Consumer;
|
||||||
public class PerfinApp extends Application {
|
public class PerfinApp extends Application {
|
||||||
private static final Logger log = LoggerFactory.getLogger(PerfinApp.class);
|
private static final Logger log = LoggerFactory.getLogger(PerfinApp.class);
|
||||||
public static final Path APP_DIR = Path.of(System.getProperty("user.home", "."), ".perfin");
|
public static final Path APP_DIR = Path.of(System.getProperty("user.home", "."), ".perfin");
|
||||||
|
/** The singleton instance of the application. */
|
||||||
public static PerfinApp instance;
|
public static PerfinApp instance;
|
||||||
|
/** The singleton profile loader for the application. */
|
||||||
public static ProfileLoader profileLoader;
|
public static ProfileLoader profileLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,20 +68,28 @@ public class PerfinApp extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of the app's startup, where the main scene is initialized.
|
||||||
|
* @param stage The JavaFX stage where the scene will be placed.
|
||||||
|
* @param msgConsumer A message consumer to relay status messages to the user.
|
||||||
|
*/
|
||||||
private void initMainScreen(Stage stage, Consumer<String> msgConsumer) {
|
private void initMainScreen(Stage stage, Consumer<String> msgConsumer) {
|
||||||
msgConsumer.accept("Initializing main screen.");
|
msgConsumer.accept("Initializing main screen.");
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
stage.hide();
|
stage.hide();
|
||||||
Scene mainViewScene = SceneUtil.load("/main-view.fxml");
|
Scene mainViewScene = SceneUtil.load("/main-view.fxml");
|
||||||
mainViewScene.getStylesheets().addAll(
|
SceneUtil.addStylesheets(mainViewScene, "/style/base.css");
|
||||||
PerfinApp.class.getResource("/style/base.css").toExternalForm()
|
|
||||||
);
|
|
||||||
stage.setScene(mainViewScene);
|
stage.setScene(mainViewScene);
|
||||||
stage.setTitle("Perfin");
|
stage.setTitle("Perfin");
|
||||||
stage.getIcons().add(ImageCache.getLogo256());
|
stage.getIcons().add(ImageCache.getLogo256());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of the app's startup, where all the app's routes to various views
|
||||||
|
* are defined.
|
||||||
|
* @param msgConsumer A message consumer to relay status messages to the user.
|
||||||
|
*/
|
||||||
private static void defineRoutes(Consumer<String> msgConsumer) {
|
private static void defineRoutes(Consumer<String> msgConsumer) {
|
||||||
msgConsumer.accept("Initializing application views.");
|
msgConsumer.accept("Initializing application views.");
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
|
@ -111,6 +121,11 @@ public class PerfinApp extends Application {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A part of the app's startup which ensures that the main directory exists.
|
||||||
|
* @param msgConsumer A message consumer to relay status messages to the user.
|
||||||
|
* @throws Exception If file operations fail.
|
||||||
|
*/
|
||||||
private static void initAppDir(Consumer<String> msgConsumer) throws Exception {
|
private static void initAppDir(Consumer<String> msgConsumer) throws Exception {
|
||||||
msgConsumer.accept("Validating application files.");
|
msgConsumer.accept("Validating application files.");
|
||||||
if (Files.notExists(APP_DIR)) {
|
if (Files.notExists(APP_DIR)) {
|
||||||
|
@ -124,6 +139,13 @@ public class PerfinApp extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The final part of the app's startup sequence, where the last profile is
|
||||||
|
* loaded and set as the current profile. Calling `Profile.setCurrent`
|
||||||
|
* triggers many components to refresh their data for the current profile.
|
||||||
|
* @param msgConsumer A message consumer to relay status messages to the user.
|
||||||
|
* @throws Exception If the profile could not be loaded for some reason.
|
||||||
|
*/
|
||||||
private static void loadLastUsedProfile(Consumer<String> msgConsumer) throws Exception {
|
private static void loadLastUsedProfile(Consumer<String> msgConsumer) throws Exception {
|
||||||
String lastProfile = ProfileLoader.getLastProfile();
|
String lastProfile = ProfileLoader.getLastProfile();
|
||||||
msgConsumer.accept("Loading the most recent profile: \"" + lastProfile + "\".");
|
msgConsumer.accept("Loading the most recent profile: \"" + lastProfile + "\".");
|
||||||
|
@ -135,6 +157,9 @@ public class PerfinApp extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all application fonts from the bundled resource files.
|
||||||
|
*/
|
||||||
private static void loadFonts() {
|
private static void loadFonts() {
|
||||||
List<String> fontResources = List.of(
|
List<String> fontResources = List.of(
|
||||||
"/font/JetBrainsMono-2.304/fonts/ttf/JetBrainsMono-Regular.ttf",
|
"/font/JetBrainsMono-2.304/fonts/ttf/JetBrainsMono-Regular.ttf",
|
||||||
|
|
|
@ -5,6 +5,10 @@ import com.andrewlalis.perfin.data.SavedQueryRepository;
|
||||||
import com.andrewlalis.perfin.data.impl.JdbcDataSource;
|
import com.andrewlalis.perfin.data.impl.JdbcDataSource;
|
||||||
import com.andrewlalis.perfin.data.util.FileUtil;
|
import com.andrewlalis.perfin.data.util.FileUtil;
|
||||||
import com.andrewlalis.perfin.model.Profile;
|
import com.andrewlalis.perfin.model.Profile;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
@ -24,6 +28,7 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -145,8 +150,7 @@ public class SqlConsoleViewController implements RouteSelectionListener {
|
||||||
if (name.endsWith(".csv")) {
|
if (name.endsWith(".csv")) {
|
||||||
writeQueryResultsToCsv(rs, chosenFile.toPath());
|
writeQueryResultsToCsv(rs, chosenFile.toPath());
|
||||||
} else if (name.endsWith(".json")) {
|
} else if (name.endsWith(".json")) {
|
||||||
// writeQueryResultsToJson(rs, chosenFile.toPath());
|
writeQueryResultsToJson(rs, chosenFile.toPath());
|
||||||
Popups.message(sqlEditorTextArea, "JSON not yet supported.");
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Popups.error(sqlEditorTextArea, e);
|
Popups.error(sqlEditorTextArea, e);
|
||||||
|
@ -173,6 +177,33 @@ public class SqlConsoleViewController implements RouteSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeQueryResultsToJson(ResultSet rs, Path file) throws SQLException, IOException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNodeFactory nf = mapper.getNodeFactory();
|
||||||
|
final int columnCount = rs.getMetaData().getColumnCount();
|
||||||
|
try (
|
||||||
|
var out = Files.newOutputStream(file);
|
||||||
|
var arrayWriter = mapper.writerWithDefaultPrettyPrinter().writeValuesAsArray(out)
|
||||||
|
) {
|
||||||
|
while (rs.next()) {
|
||||||
|
ObjectNode obj = mapper.createObjectNode();
|
||||||
|
for (int i = 1; i <= columnCount; i++) {
|
||||||
|
String label = rs.getMetaData().getColumnLabel(i);
|
||||||
|
int type = rs.getMetaData().getColumnType(i);
|
||||||
|
JsonNode valueNode = switch (type) {
|
||||||
|
case Types.INTEGER | Types.BIGINT -> nf.numberNode(rs.getLong(i));
|
||||||
|
case Types.FLOAT | Types.DECIMAL -> nf.numberNode(rs.getDouble(i));
|
||||||
|
case Types.NUMERIC -> nf.numberNode(rs.getBigDecimal(i));
|
||||||
|
case Types.BOOLEAN -> nf.booleanNode(rs.getBoolean(i));
|
||||||
|
default -> nf.textNode(rs.getString(i));
|
||||||
|
};
|
||||||
|
obj.set(label, valueNode);
|
||||||
|
}
|
||||||
|
arrayWriter.write(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshSavedQueries() {
|
private void refreshSavedQueries() {
|
||||||
savedQueriesVBox.getChildren().clear();
|
savedQueriesVBox.getChildren().clear();
|
||||||
List<String> savedQueries = Profile.getCurrent().dataSource()
|
List<String> savedQueries = Profile.getCurrent().dataSource()
|
||||||
|
|
|
@ -14,6 +14,7 @@ module com.andrewlalis.perfin {
|
||||||
exports com.andrewlalis.perfin to javafx.graphics;
|
exports com.andrewlalis.perfin to javafx.graphics;
|
||||||
exports com.andrewlalis.perfin.view to javafx.graphics;
|
exports com.andrewlalis.perfin.view to javafx.graphics;
|
||||||
exports com.andrewlalis.perfin.model to javafx.graphics;
|
exports com.andrewlalis.perfin.model to javafx.graphics;
|
||||||
|
exports com.andrewlalis.perfin.data.util to javafx.graphics;
|
||||||
|
|
||||||
opens com.andrewlalis.perfin.control to javafx.fxml;
|
opens com.andrewlalis.perfin.control to javafx.fxml;
|
||||||
opens com.andrewlalis.perfin.view to javafx.fxml;
|
opens com.andrewlalis.perfin.view to javafx.fxml;
|
||||||
|
|
Loading…
Reference in New Issue