mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-06-09 05:48:20 +00:00
WIP
This commit is contained in:
commit
ba0b816241
26
.github/workflows/release.yml
vendored
Normal file
26
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Publish package to the Maven Central Repository
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
- name: Publish package
|
||||
env:
|
||||
JRELEASER_NEXUS2_USERNAME: ${{ secrets.JRELEASER_NEXUS2_USERNAME }}
|
||||
JRELEASER_NEXUS2_PASSWORD: ${{ secrets.JRELEASER_NEXUS2_PASSWORD }}
|
||||
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
|
||||
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
|
||||
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
|
||||
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./mvnw -Prelease -DskipTests deploy jreleaser:deploy -DaltDeploymentRepository=local::file:./target/staging-deploy
|
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
@ -76,6 +76,15 @@ If you find a problem or a bug, please report it as issue. When doing so, includ
|
||||
|
||||
## Changelog
|
||||
|
||||
* provide the code for the involved `@Entity` classes, if possible
|
||||
* provide the full stack trace of the error
|
||||
* specify if you are using any particular configuration either in your `application.properties` or through annotations
|
||||
|
||||
**0.1.2**
|
||||
- Better handling of large text fields (shown as `textarea`)
|
||||
- Added `CATEGORICAL` option to `Filterable`
|
||||
- Several bug fixes
|
||||
|
||||
**0.1.0**
|
||||
- Implemented action logs
|
||||
- Implemented user settings
|
||||
|
308
mvnw
vendored
Executable file
308
mvnw
vendored
Executable file
@ -0,0 +1,308 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
fi
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
70
pom.xml
70
pom.xml
@ -13,10 +13,78 @@
|
||||
<artifactId>spring-boot-db-admin</artifactId>
|
||||
<version>0.1.2</version>
|
||||
<name>spring-boot-db-admin</name>
|
||||
<description>Srping Boot DB Admin Dashboard</description>
|
||||
<description>Srping Boot Database Admin is an auto-generated CRUD admin panel for Spring Boot apps</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GPL-v3.0</name>
|
||||
<url>http://www.gnu.org/licenses/gpl-3.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jreleaser</groupId>
|
||||
<artifactId>jreleaser-maven-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
<configuration>
|
||||
<jreleaser>
|
||||
<signing>
|
||||
<active>ALWAYS</active>
|
||||
<armored>true</armored>
|
||||
</signing>
|
||||
<deploy>
|
||||
<maven>
|
||||
<nexus2>
|
||||
<maven-central>
|
||||
<active>ALWAYS</active>
|
||||
<url>https://s01.oss.sonatype.org/service/local</url>
|
||||
<closeRepository>true</closeRepository>
|
||||
<releaseRepository>true</releaseRepository>
|
||||
<stagingRepositories>target/staging-deploy</stagingRepositories>
|
||||
</maven-central>
|
||||
</nexus2>
|
||||
</maven>
|
||||
</deploy>
|
||||
</jreleaser>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadoc</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-source</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.atteo/evo-inflector -->
|
||||
<dependency>
|
||||
|
@ -53,6 +53,12 @@ public class DbAdmin {
|
||||
|
||||
private String modelsPackage;
|
||||
|
||||
/**
|
||||
* Builds the DbAdmin instance by scanning the `@Entity` beans and loading
|
||||
* the schemas.
|
||||
* @param entityManager the entity manager
|
||||
* @param properties the configuration properties
|
||||
*/
|
||||
public DbAdmin(@Autowired EntityManager entityManager, @Autowired DbAdminProperties properties) {
|
||||
this.modelsPackage = properties.getModelsPackage();
|
||||
this.entityManager = entityManager;
|
||||
@ -71,7 +77,7 @@ public class DbAdmin {
|
||||
|
||||
/**
|
||||
* Returns all the loaded schemas (i.e. entity classes)
|
||||
* @return
|
||||
* @return the list of loaded schemas from the `@Entity` classes
|
||||
*/
|
||||
public List<DbObjectSchema> getSchemas() {
|
||||
return Collections.unmodifiableList(schemas);
|
||||
@ -80,7 +86,7 @@ public class DbAdmin {
|
||||
/**
|
||||
* Finds a schema by its full class name
|
||||
* @param className qualified class name
|
||||
* @return
|
||||
* @return the schema with this class name
|
||||
* @throws DbAdminException if corresponding schema not found
|
||||
*/
|
||||
public DbObjectSchema findSchemaByClassName(String className) {
|
||||
@ -92,7 +98,7 @@ public class DbAdmin {
|
||||
/**
|
||||
* Finds a schema by its table name
|
||||
* @param tableName the table name on the database
|
||||
* @return
|
||||
* @return the schema with this table name
|
||||
* @throws DbAdminException if corresponding schema not found
|
||||
*/
|
||||
public DbObjectSchema findSchemaByTableName(String tableName) {
|
||||
@ -102,9 +108,9 @@ public class DbAdmin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a schema by its class
|
||||
* @param klass
|
||||
* @return
|
||||
* Finds a schema by its class object
|
||||
* @param the `@Entity` class you want to find the schema for
|
||||
* @return the schema for the `@Entity` class
|
||||
* @throws DbAdminException if corresponding schema not found
|
||||
*/
|
||||
public DbObjectSchema findSchemaByClass(Class<?> klass) {
|
||||
@ -118,7 +124,7 @@ public class DbAdmin {
|
||||
*
|
||||
* If any field is not mappable, the method will throw an exception.
|
||||
* @param bd
|
||||
* @return
|
||||
* @return a schema derived from the `@Entity` class
|
||||
*/
|
||||
private DbObjectSchema processBeanDefinition(BeanDefinition bd) {
|
||||
String fullClassName = bd.getBeanClassName();
|
||||
|
@ -21,6 +21,10 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import tech.ailef.dbadmin.internal.InternalDbAdminConfiguration;
|
||||
|
||||
/**
|
||||
* The configuration class that adds and configures the "internal" data source.
|
||||
*
|
||||
*/
|
||||
@ConditionalOnProperty(name = "dbadmin.enabled", matchIfMissing = true)
|
||||
@ComponentScan
|
||||
@EnableConfigurationProperties(DbAdminProperties.class)
|
||||
@ -56,7 +60,7 @@ public class DbAdminAutoConfiguration {
|
||||
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
|
||||
factoryBean.setDataSource(internalDataSource());
|
||||
factoryBean.setPersistenceUnitName("internal");
|
||||
factoryBean.setPackagesToScan("tech.ailef.dbadmin.internal.model"); // , "tech.ailef.dbadmin.repository");
|
||||
factoryBean.setPackagesToScan("tech.ailef.dbadmin.internal.model");
|
||||
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
|
||||
|
@ -26,6 +26,9 @@ public class DbAdminProperties {
|
||||
*/
|
||||
private String modelsPackage;
|
||||
|
||||
/**
|
||||
* Set to true when running the tests to configure the "internal" data source as in memory
|
||||
*/
|
||||
private boolean testMode = false;
|
||||
|
||||
public boolean isEnabled() {
|
||||
|
@ -13,5 +13,9 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DisplayFormat {
|
||||
/**
|
||||
* The format to apply to the field's value
|
||||
* @return
|
||||
*/
|
||||
public String format() default "";
|
||||
}
|
@ -16,5 +16,9 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Filterable {
|
||||
/**
|
||||
* The type of filter (DEFAULT or CATEGORICAL)
|
||||
* @return
|
||||
*/
|
||||
public FilterableType type() default FilterableType.DEFAULT;
|
||||
}
|
@ -1,5 +1,24 @@
|
||||
package tech.ailef.dbadmin.external.annotations;
|
||||
|
||||
/**
|
||||
* Type of filters that can be used in the faceted search.
|
||||
*
|
||||
*/
|
||||
public enum FilterableType {
|
||||
DEFAULT, CATEGORICAL;
|
||||
/**
|
||||
* The default filter provides a list of standard operators
|
||||
* customized to the field type (e.g. greater than/less than/equals for numbers,
|
||||
* after/before/equals for dates, contains/equals for strings, etc...), with,
|
||||
* if applicable, an autocomplete form if the field references a foreign key.
|
||||
*/
|
||||
DEFAULT,
|
||||
/**
|
||||
* The categorical filter provides the full list of possible values
|
||||
* for the field, rendered as a list of clickable items (that will
|
||||
* filter for equality). This provides a better UX if the field can take
|
||||
* a limited number of values and it's more convenient to have them all
|
||||
* on screen rather than typing them.
|
||||
*/
|
||||
CATEGORICAL;
|
||||
|
||||
}
|
||||
|
@ -37,6 +37,13 @@ public class DownloadController {
|
||||
private DbAdmin dbAdmin;
|
||||
|
||||
|
||||
/**
|
||||
* Serve a binary field as an image
|
||||
* @param className
|
||||
* @param fieldName
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value="/{className}/{fieldName}/{id}/image", produces = MediaType.IMAGE_JPEG_VALUE)
|
||||
@ResponseBody
|
||||
public ResponseEntity<byte[]> serveImage(@PathVariable String className,
|
||||
@ -58,6 +65,16 @@ public class DownloadController {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a binary field as a file. This tries to detect the file type using Tika
|
||||
* in order to serve the file with a plausible extension, since we don't have
|
||||
* any meta-data about what was originally uploaded and it is not feasible to
|
||||
* store it (it could be modified on another end and we wouldn't be aware of it).
|
||||
* @param className
|
||||
* @param fieldName
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/{className}/{fieldName}/{id}")
|
||||
@ResponseBody
|
||||
public ResponseEntity<byte[]> serveFile(@PathVariable String className,
|
||||
|
@ -36,7 +36,6 @@ public class GlobalController {
|
||||
|
||||
/**
|
||||
* The baseUrl as specified in the properties file by the user
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ModelAttribute("baseUrl")
|
||||
@ -44,11 +43,21 @@ public class GlobalController {
|
||||
return props.getBaseUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* The full request URL, not including the query string
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@ModelAttribute("requestUrl")
|
||||
public String getRequestUrl(HttpServletRequest request) {
|
||||
return request.getRequestURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* The UserConfiguration object used to retrieve values specified
|
||||
* in the settings table.
|
||||
* @return
|
||||
*/
|
||||
@ModelAttribute("userConf")
|
||||
public UserConfiguration getUserConf() {
|
||||
return userConf;
|
||||
|
@ -28,6 +28,12 @@ public class AutocompleteController {
|
||||
@Autowired
|
||||
private DbAdminRepository repository;
|
||||
|
||||
/**
|
||||
* Returns a list of entities from a given table that match an input query.
|
||||
* @param className
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/{className}")
|
||||
public ResponseEntity<?> autocomplete(@PathVariable String className, @RequestParam String query) {
|
||||
DbObjectSchema schema = dbAdmin.findSchemaByClassName(className);
|
||||
|
@ -80,6 +80,51 @@ public class CustomJpaRepository extends SimpleJpaRepository {
|
||||
.setFirstResult((page - 1) * pageSize).getResultList();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public int update(DbObjectSchema schema, Map<String, String> params, Map<String, MultipartFile> files) {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
CriteriaUpdate update = cb.createCriteriaUpdate(schema.getJavaClass());
|
||||
|
||||
Root root = update.from(schema.getJavaClass());
|
||||
|
||||
for (DbField field : schema.getSortedFields()) {
|
||||
if (field.isPrimaryKey()) continue;
|
||||
|
||||
boolean keepValue = params.getOrDefault("__keep_" + field.getName(), "off").equals("on");
|
||||
if (keepValue) continue;
|
||||
|
||||
String stringValue = params.get(field.getName());
|
||||
Object value = null;
|
||||
if (stringValue != null && stringValue.isBlank()) stringValue = null;
|
||||
if (stringValue != null) {
|
||||
value = field.getType().parseValue(stringValue);
|
||||
} else {
|
||||
try {
|
||||
MultipartFile file = files.get(field.getName());
|
||||
if (file != null) {
|
||||
if (file.isEmpty()) value = null;
|
||||
else value = file.getBytes();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new DbAdminException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (field.getConnectedSchema() != null)
|
||||
value = field.getConnectedSchema().getJpaRepository().findById(value).get();
|
||||
|
||||
update.set(root.get(field.getJavaName()), value);
|
||||
}
|
||||
|
||||
String pkName = schema.getPrimaryKey().getJavaName();
|
||||
update.where(cb.equal(root.get(pkName), params.get(schema.getPrimaryKey().getName())));
|
||||
|
||||
Query query = entityManager.createQuery(update);
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Predicate> buildPredicates(String q, Set<QueryFilter> queryFilters,
|
||||
CriteriaBuilder cb, Path root) {
|
||||
@ -155,48 +200,4 @@ public class CustomJpaRepository extends SimpleJpaRepository {
|
||||
}
|
||||
return finalPredicates;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public int update(DbObjectSchema schema, Map<String, String> params, Map<String, MultipartFile> files) {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
CriteriaUpdate update = cb.createCriteriaUpdate(schema.getJavaClass());
|
||||
|
||||
Root root = update.from(schema.getJavaClass());
|
||||
|
||||
for (DbField field : schema.getSortedFields()) {
|
||||
if (field.isPrimaryKey()) continue;
|
||||
|
||||
boolean keepValue = params.getOrDefault("__keep_" + field.getName(), "off").equals("on");
|
||||
if (keepValue) continue;
|
||||
|
||||
String stringValue = params.get(field.getName());
|
||||
Object value = null;
|
||||
if (stringValue != null && stringValue.isBlank()) stringValue = null;
|
||||
if (stringValue != null) {
|
||||
value = field.getType().parseValue(stringValue);
|
||||
} else {
|
||||
try {
|
||||
MultipartFile file = files.get(field.getName());
|
||||
if (file != null) {
|
||||
if (file.isEmpty()) value = null;
|
||||
else value = file.getBytes();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new DbAdminException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (field.getConnectedSchema() != null)
|
||||
value = field.getConnectedSchema().getJpaRepository().findById(value).get();
|
||||
|
||||
update.set(root.get(field.getJavaName()), value);
|
||||
}
|
||||
|
||||
String pkName = schema.getPrimaryKey().getJavaName();
|
||||
update.where(cb.equal(root.get(pkName), params.get(schema.getPrimaryKey().getName())));
|
||||
|
||||
Query query = entityManager.createQuery(update);
|
||||
return query.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,6 @@ public class DbAdminRepository {
|
||||
* Delete a specific object
|
||||
* @param schema
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Transactional("transactionManager")
|
||||
|
@ -13,13 +13,25 @@ import tech.ailef.dbadmin.external.annotations.Filterable;
|
||||
import tech.ailef.dbadmin.external.annotations.FilterableType;
|
||||
|
||||
public class DbField {
|
||||
/**
|
||||
* The inferred name of this field on the database
|
||||
*/
|
||||
protected String dbName;
|
||||
|
||||
/**
|
||||
* The name of this field in the Java code (instance variable)
|
||||
*/
|
||||
protected String javaName;
|
||||
|
||||
/**
|
||||
* The type of this field
|
||||
*/
|
||||
protected DbFieldType type;
|
||||
|
||||
@JsonIgnore
|
||||
/**
|
||||
* The primitive Field object from the Class
|
||||
*/
|
||||
protected Field field;
|
||||
|
||||
/**
|
||||
@ -29,12 +41,25 @@ public class DbField {
|
||||
@JsonIgnore
|
||||
private Class<?> connectedType;
|
||||
|
||||
/**
|
||||
* Whether this field is a primary key
|
||||
*/
|
||||
private boolean primaryKey;
|
||||
|
||||
/**
|
||||
* Whether this field is nullable
|
||||
*/
|
||||
private boolean nullable;
|
||||
|
||||
/**
|
||||
* The optional format to apply to this field, if the `@DisplayFormat`
|
||||
* annotation has been applied.
|
||||
*/
|
||||
private String format;
|
||||
|
||||
/**
|
||||
* The schema this field belongs to
|
||||
*/
|
||||
@JsonIgnore
|
||||
private DbObjectSchema schema;
|
||||
|
||||
|
@ -14,6 +14,9 @@ import jakarta.persistence.OneToOne;
|
||||
import tech.ailef.dbadmin.external.dto.CompareOperator;
|
||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||
|
||||
/**
|
||||
* The list of supported field types
|
||||
*/
|
||||
public enum DbFieldType {
|
||||
INTEGER {
|
||||
@Override
|
||||
@ -27,7 +30,6 @@ public enum DbFieldType {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Class<?> getJavaClass() {
|
||||
return Integer.class;
|
||||
}
|
||||
|
@ -4,6 +4,10 @@ import java.util.Objects;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* Wrapper for the value of a field
|
||||
*
|
||||
*/
|
||||
public class DbFieldValue {
|
||||
private Object value;
|
||||
|
||||
|
@ -15,9 +15,19 @@ import tech.ailef.dbadmin.external.annotations.DisplayName;
|
||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||
import tech.ailef.dbadmin.external.misc.Utils;
|
||||
|
||||
/**
|
||||
* Wrapper for all objects retrieved from the database.
|
||||
*
|
||||
*/
|
||||
public class DbObject {
|
||||
/**
|
||||
* The instance of the object, i.e. an instance of the `@Entity` class
|
||||
*/
|
||||
private Object instance;
|
||||
|
||||
/**
|
||||
* The schema this object belongs to
|
||||
*/
|
||||
private DbObjectSchema schema;
|
||||
|
||||
public DbObject(Object instance, DbObjectSchema schema) {
|
||||
|
@ -22,6 +22,11 @@ import tech.ailef.dbadmin.external.annotations.ComputedColumn;
|
||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||
import tech.ailef.dbadmin.external.misc.Utils;
|
||||
|
||||
/**
|
||||
* A class that represents a table/`@Entity` as reconstructed from the
|
||||
* JPA annotations found on its fields.
|
||||
*
|
||||
*/
|
||||
public class DbObjectSchema {
|
||||
/**
|
||||
* All the fields in this table. The fields include all the
|
||||
@ -54,6 +59,13 @@ public class DbObjectSchema {
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* Initializes this schema for the specific `@Entity` class.
|
||||
* Determines the table name from the `@Table` annotation and also
|
||||
* which methods are `@ComputedColumn`s
|
||||
* @param klass the `@Entity` class
|
||||
* @param dbAdmin the DbAdmin instance
|
||||
*/
|
||||
public DbObjectSchema(Class<?> klass, DbAdmin dbAdmin) {
|
||||
this.dbAdmin = dbAdmin;
|
||||
this.entityClass = klass;
|
||||
@ -83,48 +95,103 @@ public class DbObjectSchema {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DbAdmin instance
|
||||
* @return the DbAdmin instance
|
||||
*/
|
||||
public DbAdmin getDbAdmin() {
|
||||
return dbAdmin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java class for the underlying `@Entity` this schema
|
||||
* corresponds to
|
||||
* @return the Java class for the `@Entity` this schema corresponds to
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Class<?> getJavaClass() {
|
||||
return entityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the Java class for the underlying `@Entity` this schema
|
||||
* corresponds to
|
||||
* @return the name of the Java class for the `@Entity` this schema corresponds to
|
||||
*/
|
||||
@JsonIgnore
|
||||
public String getClassName() {
|
||||
return entityClass.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable list of all the fields in the schema
|
||||
* @return an unmodifiable list of all the fields in the schema
|
||||
*/
|
||||
public List<DbField> getFields() {
|
||||
return Collections.unmodifiableList(fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field by its Java name, i.e. the name of the instance variable
|
||||
* in the `@Entity` class
|
||||
* @param name name of the instance variable
|
||||
* @return the DbField if found, null otherwise
|
||||
*/
|
||||
public DbField getFieldByJavaName(String name) {
|
||||
return fields.stream().filter(f -> f.getJavaName().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field by its database name, i.e. the name of the column corresponding
|
||||
* to the field
|
||||
* @param name name of the column
|
||||
* @return the DbField if found, null otherwise
|
||||
*/
|
||||
public DbField getFieldByName(String name) {
|
||||
return fields.stream().filter(f -> f.getName().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a field to this schema. This is used by the DbAdmin instance
|
||||
* during initialization and it's not supposed to be called afterwards
|
||||
* @param f the DbField to add
|
||||
*/
|
||||
public void addField(DbField f) {
|
||||
fields.add(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying CustomJpaRepository
|
||||
* @return
|
||||
*/
|
||||
public CustomJpaRepository getJpaRepository() {
|
||||
return jpaRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying CustomJpaRepository
|
||||
* @param jpaRepository
|
||||
*/
|
||||
public void setJpaRepository(CustomJpaRepository jpaRepository) {
|
||||
this.jpaRepository = jpaRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inferred table name for this schema
|
||||
* @return
|
||||
*/
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sorted list of physical fields (i.e., fields that correspond to
|
||||
* a column in the table as opposed to fields that are just present as
|
||||
* instance variables, like relationship fields). Sorted alphabetically
|
||||
* with priority to the primary key.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@JsonIgnore
|
||||
public List<DbField> getSortedFields() {
|
||||
return getFields().stream()
|
||||
@ -146,6 +213,10 @@ public class DbObjectSchema {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of relationship fields
|
||||
* @return
|
||||
*/
|
||||
public List<DbField> getRelationshipFields() {
|
||||
List<DbField> res = getFields().stream().filter(f -> {
|
||||
return f.getPrimitiveField().getAnnotation(OneToMany.class) != null
|
||||
@ -154,6 +225,11 @@ public class DbObjectSchema {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of ManyToMany fields owned by this class (i.e. they
|
||||
* do not have "mappedBy")
|
||||
* @return
|
||||
*/
|
||||
public List<DbField> getManyToManyOwnedFields() {
|
||||
List<DbField> res = getFields().stream().filter(f -> {
|
||||
ManyToMany anno = f.getPrimitiveField().getAnnotation(ManyToMany.class);
|
||||
@ -162,6 +238,10 @@ public class DbObjectSchema {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DbField which serves as the primary key for this schema
|
||||
* @return
|
||||
*/
|
||||
@JsonIgnore
|
||||
public DbField getPrimaryKey() {
|
||||
Optional<DbField> pk = fields.stream().filter(f -> f.isPrimaryKey()).findFirst();
|
||||
@ -171,21 +251,37 @@ public class DbObjectSchema {
|
||||
throw new RuntimeException("No primary key defined on " + entityClass.getName() + " (table `" + tableName + "`)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the `@ComputedColumn`s in this schema
|
||||
* @return
|
||||
*/
|
||||
public List<String> getComputedColumnNames() {
|
||||
return computedColumns.keySet().stream().sorted().toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method for the given `@ComputedColumn` name
|
||||
* @param name the name of the `@ComputedColumn`
|
||||
* @return the corresponding instance method if found, null otherwise
|
||||
*/
|
||||
public Method getComputedColumn(String name) {
|
||||
return computedColumns.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of fields that are `@Filterable`
|
||||
* @return
|
||||
*/
|
||||
public List<DbField> getFilterableFields() {
|
||||
return getSortedFields().stream().filter(f -> {
|
||||
return !f.isBinary() && !f.isPrimaryKey()
|
||||
&& f.isFilterable();
|
||||
return !f.isBinary() && !f.isPrimaryKey() && f.isFilterable();
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the data in this schema, as `DbObject`s
|
||||
* @return
|
||||
*/
|
||||
public List<DbObject> findAll() {
|
||||
List<?> r = jpaRepository.findAll();
|
||||
return r.stream().map(o -> new DbObject(o, this)).toList();
|
||||
|
@ -2,6 +2,11 @@ package tech.ailef.dbadmin.external.dto;
|
||||
|
||||
import tech.ailef.dbadmin.external.dbmapping.DbObject;
|
||||
|
||||
/**
|
||||
* An object to hold autocomplete results returned from the
|
||||
* respective AutocompleteController
|
||||
*
|
||||
*/
|
||||
public class AutocompleteSearchResult {
|
||||
private Object id;
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
package tech.ailef.dbadmin.external.dto;
|
||||
|
||||
/**
|
||||
* A list of operators that are used in faceted search.
|
||||
*
|
||||
*/
|
||||
public enum CompareOperator {
|
||||
GT {
|
||||
@Override
|
||||
|
@ -3,19 +3,45 @@ package tech.ailef.dbadmin.external.dto;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
/**
|
||||
* A client request for the Action logs page where
|
||||
* several filtering parameters are present
|
||||
*
|
||||
*/
|
||||
public class LogsSearchRequest {
|
||||
/**
|
||||
* The table name to filter on
|
||||
*/
|
||||
private String table;
|
||||
|
||||
/**
|
||||
* The action type to filter on (EDIT, CREATE, DELETE, ANY)
|
||||
*/
|
||||
private String actionType;
|
||||
|
||||
/**
|
||||
* The item id to filter on.
|
||||
*/
|
||||
private String itemId;
|
||||
|
||||
/**
|
||||
* The requested page
|
||||
*/
|
||||
private int page;
|
||||
|
||||
/**
|
||||
* The requested page size
|
||||
*/
|
||||
private int pageSize;
|
||||
|
||||
/**
|
||||
* The requested sort key
|
||||
*/
|
||||
private String sortKey;
|
||||
|
||||
/**
|
||||
* The requested sort order
|
||||
*/
|
||||
private String sortOrder;
|
||||
|
||||
public String getTable() {
|
||||
@ -80,6 +106,10 @@ public class LogsSearchRequest {
|
||||
+ page + ", pageSize=" + pageSize + ", sortKey=" + sortKey + ", sortOrder=" + sortOrder + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Spring PageRequest object from the parameters in this request
|
||||
* @return a Spring PageRequest object
|
||||
*/
|
||||
public PageRequest toPageRequest() {
|
||||
int actualPage = page - 1 < 0 ? 0 : page - 1;
|
||||
int actualPageSize = pageSize <= 0 ? 50 : pageSize;
|
||||
|
@ -2,9 +2,19 @@ package tech.ailef.dbadmin.external.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper class that holds info about the current pagination and one page
|
||||
* of returned result.
|
||||
*/
|
||||
public class PaginatedResult<T> {
|
||||
/**
|
||||
* The pagination settings used to produce this output
|
||||
*/
|
||||
private PaginationInfo pagination;
|
||||
|
||||
/**
|
||||
* The list of results in the current page
|
||||
*/
|
||||
private List<T> results;
|
||||
|
||||
public PaginatedResult(PaginationInfo pagination, List<T> page) {
|
||||
|
@ -29,6 +29,10 @@ public class QueryFilter {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a readable version of this query filter, customized
|
||||
* based on field type and/or operator.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (value != null && !value.toString().isBlank()) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
package tech.ailef.dbadmin.external.exceptions;
|
||||
|
||||
/**
|
||||
* Generic top-level exception for everything thrown by us
|
||||
*
|
||||
*/
|
||||
public class DbAdminException extends RuntimeException {
|
||||
private static final long serialVersionUID = 8120227031645804467L;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.ailef.dbadmin.external.misc;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -13,7 +14,38 @@ import tech.ailef.dbadmin.external.dto.CompareOperator;
|
||||
import tech.ailef.dbadmin.external.dto.QueryFilter;
|
||||
import tech.ailef.dbadmin.external.exceptions.DbAdminException;
|
||||
|
||||
/**
|
||||
* Collection of utility functions used across the project
|
||||
*
|
||||
*/
|
||||
public interface Utils {
|
||||
/**
|
||||
* Converts snake case to camel case
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static String snakeToCamel(String text) {
|
||||
boolean shouldConvertNextCharToLower = true;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char currentChar = text.charAt(i);
|
||||
if (currentChar == '_') {
|
||||
shouldConvertNextCharToLower = false;
|
||||
} else if (shouldConvertNextCharToLower) {
|
||||
builder.append(Character.toLowerCase(currentChar));
|
||||
} else {
|
||||
builder.append(Character.toUpperCase(currentChar));
|
||||
shouldConvertNextCharToLower = true;
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convers camel case to snake case
|
||||
* @param v
|
||||
* @return
|
||||
*/
|
||||
public static String camelToSnake(String v) {
|
||||
if (Character.isUpperCase(v.charAt(0))) {
|
||||
v = Character.toLowerCase(v.charAt(0)) + v.substring(1);
|
||||
@ -23,6 +55,12 @@ public interface Utils {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a set of query filters applied with the faceted search feature
|
||||
* to a multi value map
|
||||
* @param filters
|
||||
* @return
|
||||
*/
|
||||
public static MultiValueMap<String, String> computeParams(Set<QueryFilter> filters) {
|
||||
MultiValueMap<String, String> r = new LinkedMultiValueMap<>();
|
||||
if (filters == null)
|
||||
@ -41,6 +79,13 @@ public interface Utils {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a multi value map of parameters containing query filters applied
|
||||
* with the faceted search feature into a set of QueryFilter objects
|
||||
* @param schema
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
public static Set<QueryFilter> computeFilters(DbObjectSchema schema, MultiValueMap<String, String> params) {
|
||||
if (params == null)
|
||||
return new HashSet<>();
|
||||
@ -85,20 +130,4 @@ public interface Utils {
|
||||
return "?" + String.join("&", paramValues);
|
||||
}
|
||||
|
||||
public static String snakeToCamel(String text) {
|
||||
boolean shouldConvertNextCharToLower = true;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char currentChar = text.charAt(i);
|
||||
if (currentChar == '_') {
|
||||
shouldConvertNextCharToLower = false;
|
||||
} else if (shouldConvertNextCharToLower) {
|
||||
builder.append(Character.toLowerCase(currentChar));
|
||||
} else {
|
||||
builder.append(Character.toUpperCase(currentChar));
|
||||
shouldConvertNextCharToLower = true;
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user