Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
716e2934cc | |||
2626ba7ffd | |||
b28d9e0645 | |||
edbb75d292 | |||
6b215cc337 | |||
2ec91e3dcf | |||
e8f3b45c68 | |||
3567912fd9 | |||
32e8e2deb8 | |||
f44e19f6d5 | |||
bd8e3b284b | |||
a5d7837c7d | |||
06a716dc00 | |||
7a168bbb05 | |||
71af157e3a | |||
fd45d8af02 | |||
f2d5f203c6 | |||
0c2465df58 | |||
caebbc59a0 | |||
3119173d87 | |||
0742ab40d7 | |||
edc88bdb9a | |||
0f75a1c261 | |||
1b17ed8d79 | |||
98016830dd | |||
ba15dfc9d4 |
@ -2,7 +2,7 @@ name: Publish Release
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master, develop]
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
@ -58,14 +58,13 @@ jobs:
|
|||||||
|
|
||||||
# Publish to Maven
|
# Publish to Maven
|
||||||
- name: Publish to Maven
|
- name: Publish to Maven
|
||||||
run: |
|
run: mvn deploy -Pgen-javadocs -B -Dstyle.color=always --update-snapshots -T6C -e
|
||||||
chmod +x ./scripts/deploy.sh
|
|
||||||
./scripts/deploy.sh
|
|
||||||
|
|
||||||
# Generate changelog
|
# Generate changelog
|
||||||
- name: Generate Changelog
|
- name: Generate Changelog
|
||||||
id: changelog
|
id: changelog
|
||||||
uses: https://github.com/mathiasvr/command-output@v2.0.0
|
uses: https://github.com/mathiasvr/command-output@v2.0.0
|
||||||
|
if: ${{ github.ref.action == 'master' }}
|
||||||
with:
|
with:
|
||||||
run: |
|
run: |
|
||||||
npx conventional-changelog-cli -p angular -i CHANGELOG.md -s --skip-unstable
|
npx conventional-changelog-cli -p angular -i CHANGELOG.md -s --skip-unstable
|
||||||
@ -76,6 +75,7 @@ jobs:
|
|||||||
# so we can use it later
|
# so we can use it later
|
||||||
- name: Extract Maven project version
|
- name: Extract Maven project version
|
||||||
shell: bash -l {0}
|
shell: bash -l {0}
|
||||||
|
if: ${{ github.ref.action == 'master' }}
|
||||||
run: |
|
run: |
|
||||||
RELEASE_VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
|
RELEASE_VERSION=$(mvn -q -Dexec.executable=echo -Dexec.args='${project.version}' --non-recursive exec:exec)
|
||||||
echo "Project version: $RELEASE_VERSION"
|
echo "Project version: $RELEASE_VERSION"
|
||||||
@ -85,6 +85,7 @@ jobs:
|
|||||||
- name: Publish Release
|
- name: Publish Release
|
||||||
id: publish-release
|
id: publish-release
|
||||||
uses: https://git.rainnny.club/Rainnny/release-action@main
|
uses: https://git.rainnny.club/Rainnny/release-action@main
|
||||||
|
if: ${{ github.ref.action == 'master' }}
|
||||||
with:
|
with:
|
||||||
api_key: ${{ secrets.RELEASE_ACCESS_TOKEN }}
|
api_key: ${{ secrets.RELEASE_ACCESS_TOKEN }}
|
||||||
tag: Feather-${{ env.RELEASE_VERSION }}
|
tag: Feather-${{ env.RELEASE_VERSION }}
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ cmake-build-*/
|
|||||||
out/
|
out/
|
||||||
build/
|
build/
|
||||||
work/
|
work/
|
||||||
|
target/
|
||||||
.idea_modules/
|
.idea_modules/
|
||||||
atlassian-ide-plugin.xml
|
atlassian-ide-plugin.xml
|
||||||
com_crashlytics_export_strings.xml
|
com_crashlytics_export_strings.xml
|
||||||
|
@ -91,9 +91,6 @@
|
|||||||
<!-- See: https://checkstyle.org/checks/javadoc/javadocmissingwhitespaceafterasterisk.html#JavadocMissingWhitespaceAfterAsterisk -->
|
<!-- See: https://checkstyle.org/checks/javadoc/javadocmissingwhitespaceafterasterisk.html#JavadocMissingWhitespaceAfterAsterisk -->
|
||||||
<module name="JavadocMissingWhitespaceAfterAsterisk" />
|
<module name="JavadocMissingWhitespaceAfterAsterisk" />
|
||||||
|
|
||||||
<!-- See: https://checkstyle.org/checks/javadoc/javadocparagraph.html#JavadocParagraph -->
|
|
||||||
<module name="JavadocParagraph" />
|
|
||||||
|
|
||||||
<!-- See: https://checkstyle.org/checks/javadoc/javadocstyle.html#JavadocStyle -->
|
<!-- See: https://checkstyle.org/checks/javadoc/javadocstyle.html#JavadocStyle -->
|
||||||
<module name="JavadocStyle" />
|
<module name="JavadocStyle" />
|
||||||
|
|
||||||
@ -215,11 +212,6 @@
|
|||||||
<!-- See: https://checkstyle.org/checks/javadoc/singlelinejavadoc.html#SingleLineJavadoc -->
|
<!-- See: https://checkstyle.org/checks/javadoc/singlelinejavadoc.html#SingleLineJavadoc -->
|
||||||
<module name="SingleLineJavadoc" />
|
<module name="SingleLineJavadoc" />
|
||||||
|
|
||||||
<!-- See: https://checkstyle.org/checks/javadoc/requireemptylinebeforeblocktaggroup.html#RequireEmptyLineBeforeBlockTagGroup -->
|
|
||||||
<module name="RequireEmptyLineBeforeBlockTagGroup">
|
|
||||||
<property name="violateExecutionOnNonTightHtml" value="true" />
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- See: https://checkstyle.org/checks/whitespace/singlespaceseparator.html#SingleSpaceSeparator -->
|
<!-- See: https://checkstyle.org/checks/whitespace/singlespaceseparator.html#SingleSpaceSeparator -->
|
||||||
<module name="SingleSpaceSeparator" />
|
<module name="SingleSpaceSeparator" />
|
||||||
|
|
||||||
|
49
pom.xml
49
pom.xml
@ -7,7 +7,7 @@
|
|||||||
<!--Project Details-->
|
<!--Project Details-->
|
||||||
<groupId>me.braydon</groupId>
|
<groupId>me.braydon</groupId>
|
||||||
<artifactId>Feather</artifactId>
|
<artifactId>Feather</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.1-dev</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>8</java.version>
|
<java.version>8</java.version>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<!--Used for compiling the source code with the proper Java version-->
|
<!-- Used for compiling the source code with the proper Java version -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
@ -27,13 +27,13 @@
|
|||||||
<source>${java.version}</source>
|
<source>${java.version}</source>
|
||||||
<target>${java.version}</target>
|
<target>${java.version}</target>
|
||||||
|
|
||||||
<!--Enable incremental builds, this is reversed due to-->
|
<!-- Enable incremental builds, this is reversed due to -->
|
||||||
<!--a bug as seen in https://issues.apache.org/jira/browse/MCOMPILER-209-->
|
<!-- a bug as seen in https://issues.apache.org/jira/browse/MCOMPILER-209 -->
|
||||||
<useIncrementalCompilation>false</useIncrementalCompilation>
|
<useIncrementalCompilation>false</useIncrementalCompilation>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<!--Handles shading of dependencies in the final output jar-->
|
<!-- Handles shading of dependencies in the final output jar -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
@ -70,7 +70,7 @@
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<!--Used for generating a git properties file during build-->
|
<!-- Used for generating a git properties file during build -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>pl.project13.maven</groupId>
|
<groupId>pl.project13.maven</groupId>
|
||||||
<artifactId>git-commit-id-plugin</artifactId>
|
<artifactId>git-commit-id-plugin</artifactId>
|
||||||
@ -168,6 +168,13 @@
|
|||||||
</repository>
|
</repository>
|
||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>rainnny-repo-public</id>
|
||||||
|
<url>https://maven.rainnny.club/public</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<!-- Depends -->
|
<!-- Depends -->
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -176,31 +183,43 @@
|
|||||||
<version>1.18.30</version>
|
<version>1.18.30</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<version>32.1.3-jre</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.10.1</version>
|
<version>2.10.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-common</artifactId>
|
||||||
|
<version>4.1.104.Final</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Databases -->
|
<!-- Databases -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongodb-driver-sync</artifactId>
|
<artifactId>mongodb-driver-sync</artifactId>
|
||||||
<version>4.11.1</version>
|
<version>4.11.1</version>
|
||||||
<scope>compile</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.lettuce</groupId>
|
<groupId>io.lettuce</groupId>
|
||||||
<artifactId>lettuce-core</artifactId>
|
<artifactId>lettuce-core</artifactId>
|
||||||
<version>6.3.0.RELEASE</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
<scope>compile</scope>
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>4.0.3</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
<version>3.3.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Switch dir
|
|
||||||
cd "$(dirname "$0")/.." || exit
|
|
||||||
|
|
||||||
# Deploy
|
|
||||||
mvn deploy -Pgen-javadocs -B -Dstyle.color=always --update-snapshots -T6C -e
|
|
20
src/main/java/me/braydon/feather/annotation/RawData.java
Normal file
20
src/main/java/me/braydon/feather/annotation/RawData.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Field}'s tagged with this annotation
|
||||||
|
* will be set to the raw data from the document
|
||||||
|
* it is in.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Documented @Inherited
|
||||||
|
public @interface RawData { }
|
@ -7,16 +7,17 @@ package me.braydon.feather.data;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import me.braydon.feather.FeatherSettings;
|
import me.braydon.feather.FeatherSettings;
|
||||||
import me.braydon.feather.annotation.Field;
|
import me.braydon.feather.annotation.Field;
|
||||||
import me.braydon.feather.annotation.Id;
|
import me.braydon.feather.annotation.Id;
|
||||||
|
import me.braydon.feather.annotation.RawData;
|
||||||
import me.braydon.feather.annotation.Serializable;
|
import me.braydon.feather.annotation.Serializable;
|
||||||
import me.braydon.feather.common.FieldUtils;
|
import me.braydon.feather.common.FieldUtils;
|
||||||
import me.braydon.feather.common.Tuple;
|
import me.braydon.feather.common.Tuple;
|
||||||
import me.braydon.feather.database.IDatabase;
|
import me.braydon.feather.database.IDatabase;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -29,10 +30,9 @@ import java.util.UUID;
|
|||||||
* document is universal between all {@link IDatabase}'s.
|
* document is universal between all {@link IDatabase}'s.
|
||||||
*
|
*
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
* @param <V> the type of value this document holds
|
|
||||||
*/
|
*/
|
||||||
@ThreadSafe @Getter @ToString
|
@Getter @ToString
|
||||||
public class Document<V> {
|
public class Document {
|
||||||
/**
|
/**
|
||||||
* The key to use for the id field.
|
* The key to use for the id field.
|
||||||
*/
|
*/
|
||||||
@ -51,15 +51,20 @@ public class Document<V> {
|
|||||||
* a tuple that contains the Java field, as well as
|
* a tuple that contains the Java field, as well as
|
||||||
* the field value.
|
* the field value.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
|
||||||
* @see V for value type
|
|
||||||
*/
|
*/
|
||||||
private final Map<String, Tuple<java.lang.reflect.Field, V>> mappedData = Collections.synchronizedMap(new LinkedHashMap<>());
|
private final Map<String, Tuple<java.lang.reflect.Field, Object>> mappedData = Collections.synchronizedMap(new LinkedHashMap<>());
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
public Document(@NonNull Object element) {
|
public Document(@NonNull Object element) {
|
||||||
Class<?> clazz = element.getClass(); // Get the element class
|
Class<?> clazz = element.getClass(); // Get the element class
|
||||||
String idKey = null; // The key for the id field
|
String idKey = null; // The key for the id field
|
||||||
|
java.lang.reflect.Field rawDataField = null; // The raw data field if defined
|
||||||
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
|
for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
|
||||||
|
// Raw data field, save it for later
|
||||||
|
if (field.isAnnotationPresent(RawData.class)) {
|
||||||
|
rawDataField = field;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Field is missing the @Field annotation, skip it
|
// Field is missing the @Field annotation, skip it
|
||||||
if (!field.isAnnotationPresent(Field.class)) {
|
if (!field.isAnnotationPresent(Field.class)) {
|
||||||
continue;
|
continue;
|
||||||
@ -72,24 +77,24 @@ public class Document<V> {
|
|||||||
idKey = key;
|
idKey = key;
|
||||||
}
|
}
|
||||||
Class<?> fieldType = field.getType(); // The type of the field
|
Class<?> fieldType = field.getType(); // The type of the field
|
||||||
try {
|
Object value = field.get(element); // The value of the field
|
||||||
Object value = field.get(element); // The value of the field
|
|
||||||
|
if (field.isAnnotationPresent(Serializable.class)) { // Serialize the field if @Serializable is present
|
||||||
if (field.isAnnotationPresent(Serializable.class)) { // Serialize the field if @Serializable is present
|
value = FeatherSettings.getGson().toJson(field.get(element));
|
||||||
value = FeatherSettings.getGson().toJson(field.get(element));
|
} else if (fieldType == UUID.class) { // Convert UUIDs into strings
|
||||||
} else if (fieldType == UUID.class) { // Convert UUIDs into strings
|
value = value.toString();
|
||||||
value = value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
mappedData.put(key, new Tuple<>(field, (V) value)); // Store in our map
|
|
||||||
} catch (IllegalAccessException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mappedData.put(key, new Tuple<>(field, value)); // Store in our map
|
||||||
}
|
}
|
||||||
assert idKey != null; // We need an id key
|
assert idKey != null; // We need an id key
|
||||||
|
if (rawDataField != null) { // We have a raw data field, set it
|
||||||
|
rawDataField.setAccessible(true); // Make our field accessible
|
||||||
|
rawDataField.set(element, toMappedData()); // Set the raw data field to our mapped document
|
||||||
|
}
|
||||||
this.idKey = idKey; // Set our id key
|
this.idKey = idKey; // Set our id key
|
||||||
|
|
||||||
Tuple<java.lang.reflect.Field, V> key = mappedData.get(idKey); // Get the id from the data map
|
Tuple<java.lang.reflect.Field, Object> key = mappedData.get(idKey); // Get the id from the data map
|
||||||
if (key == null) { // The element is missing an id field
|
if (key == null) { // The element is missing an id field
|
||||||
throw new IllegalArgumentException("No @Id annotated field found in " + clazz.getSimpleName());
|
throw new IllegalArgumentException("No @Id annotated field found in " + clazz.getSimpleName());
|
||||||
}
|
}
|
||||||
@ -103,9 +108,9 @@ public class Document<V> {
|
|||||||
* @see #mappedData for stored data
|
* @see #mappedData for stored data
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public Map<String, V> toMappedData() {
|
public Map<String, Object> toMappedData() {
|
||||||
Map<String, V> mappedData = new LinkedHashMap<>(); // The mapped data
|
Map<String, Object> mappedData = new LinkedHashMap<>(); // The mapped data
|
||||||
for (Map.Entry<String, Tuple<java.lang.reflect.Field, V>> entry : this.mappedData.entrySet()) {
|
for (Map.Entry<String, Tuple<java.lang.reflect.Field, Object>> entry : this.mappedData.entrySet()) {
|
||||||
mappedData.put(entry.getKey(), entry.getValue().getRight());
|
mappedData.put(entry.getKey(), entry.getValue().getRight());
|
||||||
}
|
}
|
||||||
return mappedData;
|
return mappedData;
|
||||||
|
@ -29,6 +29,7 @@ public interface IDatabase<B, C> extends Closeable {
|
|||||||
*
|
*
|
||||||
* @param credentials the optional credentials to use
|
* @param credentials the optional credentials to use
|
||||||
* @throws IllegalStateException if already connected
|
* @throws IllegalStateException if already connected
|
||||||
|
* @see C for credentials
|
||||||
*/
|
*/
|
||||||
void connect(C credentials) throws IllegalStateException;
|
void connect(C credentials) throws IllegalStateException;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import me.braydon.feather.FeatherSettings;
|
import me.braydon.feather.FeatherSettings;
|
||||||
|
import me.braydon.feather.annotation.RawData;
|
||||||
import me.braydon.feather.annotation.Serializable;
|
import me.braydon.feather.annotation.Serializable;
|
||||||
import me.braydon.feather.common.FieldUtils;
|
import me.braydon.feather.common.FieldUtils;
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A repository belonging to a {@link IDatabase}.
|
* A repository belonging to an {@link IDatabase}.
|
||||||
*
|
*
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
* @param <D> the database this repository uses
|
* @param <D> the database this repository uses
|
||||||
@ -120,8 +121,18 @@ public abstract class Repository<D extends IDatabase<?, ?>, ID, E> {
|
|||||||
Constructor<? extends E> constructor = entityClass.getConstructor(); // Get the no args constructor
|
Constructor<? extends E> constructor = entityClass.getConstructor(); // Get the no args constructor
|
||||||
E entity = constructor.newInstance(); // Create the entity
|
E entity = constructor.newInstance(); // Create the entity
|
||||||
|
|
||||||
// Get the field tagged with @Id
|
// Get the field tagged with @Field
|
||||||
|
java.lang.reflect.Field rawDataField = null; // The raw data field if defined
|
||||||
for (Field field : entityClass.getDeclaredFields()) {
|
for (Field field : entityClass.getDeclaredFields()) {
|
||||||
|
// Raw data field, save it for later
|
||||||
|
if (field.isAnnotationPresent(RawData.class)) {
|
||||||
|
rawDataField = field;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Not the field we're looking for
|
||||||
|
if (!field.isAnnotationPresent(me.braydon.feather.annotation.Field.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String key = FieldUtils.extractKey(field); // The key of the database field
|
String key = FieldUtils.extractKey(field); // The key of the database field
|
||||||
Class<?> type = field.getType(); // The type of the field
|
Class<?> type = field.getType(); // The type of the field
|
||||||
Object value = mappedData.get(key); // The value of the field
|
Object value = mappedData.get(key); // The value of the field
|
||||||
@ -137,6 +148,10 @@ public abstract class Repository<D extends IDatabase<?, ?>, ID, E> {
|
|||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(entity, value);
|
field.set(entity, value);
|
||||||
}
|
}
|
||||||
|
if (rawDataField != null) { // We have a raw data field, set it
|
||||||
|
rawDataField.setAccessible(true); // Make our field accessible
|
||||||
|
rawDataField.set(entity, mappedData); // Set the raw data field to our mapped document
|
||||||
|
}
|
||||||
return entity;
|
return entity;
|
||||||
} catch (NoSuchMethodException ex) { // We need our no args constructor
|
} catch (NoSuchMethodException ex) { // We need our no args constructor
|
||||||
throw new IllegalStateException("Entity " + entityClass.getName() + " is missing no args constructor");
|
throw new IllegalStateException("Entity " + entityClass.getName() + " is missing no args constructor");
|
||||||
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.mariadb;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import me.braydon.feather.database.IDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link IDatabase} implementation for MariaDB (and other MySQL servers).
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
* @see HikariDataSource for the bootstrap class
|
||||||
|
* @see MariaDBAuthorization for the credentials class
|
||||||
|
* @see <a href="https://github.com/brettwooldridge/HikariCP">HikariCP Official GitHub</a>
|
||||||
|
*/
|
||||||
|
public class MariaDB implements IDatabase<HikariDataSource, MariaDBAuthorization> {
|
||||||
|
/**
|
||||||
|
* The current {@link HikariDataSource} instance.
|
||||||
|
*/
|
||||||
|
private HikariDataSource dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of this database.
|
||||||
|
*
|
||||||
|
* @return the database name
|
||||||
|
*/
|
||||||
|
@Override @NonNull
|
||||||
|
public String getName() {
|
||||||
|
return "MariaDB";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a connection to this database.
|
||||||
|
*
|
||||||
|
* @param credentials the optional credentials to use
|
||||||
|
* @throws IllegalArgumentException if no credentials are provided
|
||||||
|
* @throws IllegalStateException if already connected
|
||||||
|
* @see MariaDBAuthorization for credentials
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void connect(MariaDBAuthorization credentials) throws IllegalArgumentException, IllegalStateException {
|
||||||
|
// if (credentials == null) { // We need valid credentials
|
||||||
|
// throw new IllegalArgumentException("No credentials defined");
|
||||||
|
// }
|
||||||
|
// if (isConnected()) { // Already connected
|
||||||
|
// throw new IllegalStateException("Already connected");
|
||||||
|
// }
|
||||||
|
// if (dataSource != null) { // We have a data source, close it first
|
||||||
|
// dataSource.close();
|
||||||
|
// }
|
||||||
|
// HikariConfig config = credentials.getHikariConfig(); // Get the custom config
|
||||||
|
// if (config == null) { // No custom config, make a new one
|
||||||
|
// config = new HikariConfig();
|
||||||
|
// }
|
||||||
|
// config.setJdbcUrl(credentials.getJdbcUrl()); // Set the JDBC connection URL
|
||||||
|
// config.setUsername(credentials.getUsername()); // Set the username
|
||||||
|
// config.setPassword(credentials.getPassword()); // Set the password
|
||||||
|
// dataSource = new HikariDataSource(config); // Create a new data source
|
||||||
|
throw new UnsupportedOperationException(); // Not impl yet
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this database is connected.
|
||||||
|
*
|
||||||
|
* @return the database connection state
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return dataSource != null && (dataSource.isRunning() && !dataSource.isClosed());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latency to this database.
|
||||||
|
*
|
||||||
|
* @return the latency, -1 if not connected
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getLatency() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bootstrap class
|
||||||
|
* instance for this database.
|
||||||
|
*
|
||||||
|
* @return the bootstrap class instance, null if none
|
||||||
|
* @see HikariDataSource for bootstrap class
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public HikariDataSource getBootstrap() {
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this stream and releases any system resources associated
|
||||||
|
* with it. If the stream is already closed then invoking this
|
||||||
|
* method has no effect.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (dataSource != null) {
|
||||||
|
dataSource.close();
|
||||||
|
}
|
||||||
|
dataSource = null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.mariadb;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorization for a {@link MariaDB} database.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor @AllArgsConstructor @Getter @ToString
|
||||||
|
public final class MariaDBAuthorization {
|
||||||
|
/**
|
||||||
|
* The JDBC connection URL for the database.
|
||||||
|
*/
|
||||||
|
@NonNull private final String jdbcUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username to use for authenticating with the database.
|
||||||
|
*/
|
||||||
|
@NonNull private final String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The password to use for authenticating with the database.
|
||||||
|
*/
|
||||||
|
@NonNull private final String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional {@link HikariConfig} to use.
|
||||||
|
*/
|
||||||
|
private HikariConfig hikariConfig;
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.mariadb;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import me.braydon.feather.database.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link MariaDB} {@link Repository} implementation.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
* @param <ID> the identifier for type for entities
|
||||||
|
* @param <E> the entity type this repository stores
|
||||||
|
*/
|
||||||
|
public class MariaDBRepository<ID, E> extends Repository<MariaDB, ID, E> {
|
||||||
|
public MariaDBRepository(@NonNull MariaDB database, @NonNull Class<? extends E> entityClass) {
|
||||||
|
super(database, entityClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the entity with the given id.
|
||||||
|
*
|
||||||
|
* @param id the entity id
|
||||||
|
* @return the entity with the id, null if none
|
||||||
|
* @see ID for id
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public E find(@NonNull ID id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all entities within this repository.
|
||||||
|
*
|
||||||
|
* @return the entities
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<E> findAll() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the given entities.
|
||||||
|
*
|
||||||
|
* @param entities the entities to save
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void saveAll(@NonNull E... entities) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the amount of stored entities.
|
||||||
|
*
|
||||||
|
* @return the amount of stored entities
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long count() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop the entity with the given id.
|
||||||
|
*
|
||||||
|
* @param id the entity id to drop
|
||||||
|
* @see ID for id
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void dropById(@NonNull ID id) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drop the given entity.
|
||||||
|
*
|
||||||
|
* @param entity the entity to drop
|
||||||
|
* @see E for entity
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void drop(@NonNull E entity) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.mariadb.queries;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.Singular;
|
||||||
|
import me.braydon.feather.database.impl.mariadb.MariaDB;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for {@link MariaDB} update queries.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@Builder @Getter
|
||||||
|
public class UpdateQuery {
|
||||||
|
/**
|
||||||
|
* The table to execute the update in.
|
||||||
|
*/
|
||||||
|
@NonNull private String table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mapped values (by column) for this query.
|
||||||
|
*/
|
||||||
|
@NonNull @Singular private Map<String, Object> values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The where clause for this query.
|
||||||
|
*/
|
||||||
|
@NonNull private WhereClause whereClause;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build this query.
|
||||||
|
*
|
||||||
|
* @return the built query
|
||||||
|
*/
|
||||||
|
@Override @NonNull
|
||||||
|
public String toString() {
|
||||||
|
// Build the values
|
||||||
|
StringBuilder valuesBuilder = new StringBuilder();
|
||||||
|
for (Map.Entry<String, Object> entry : values.entrySet()) {
|
||||||
|
valuesBuilder.append("`").append(entry.getKey()).append("`")
|
||||||
|
.append("='").append(entry.getValue()).append("', ");
|
||||||
|
}
|
||||||
|
String values = valuesBuilder.toString(); // The built values string
|
||||||
|
values = values.substring(0, values.length() - 2); // Remove the trailing comma
|
||||||
|
|
||||||
|
// Build the query
|
||||||
|
return String.format("UPDATE `%s` SET %s WHERE %s;",
|
||||||
|
table, values, whereClause
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The where clause for this query.
|
||||||
|
*/
|
||||||
|
@Builder @Getter
|
||||||
|
public static class WhereClause {
|
||||||
|
/**
|
||||||
|
* The column to target.
|
||||||
|
*/
|
||||||
|
@NonNull private String column;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value of the column to target.
|
||||||
|
*/
|
||||||
|
@NonNull private Object value;
|
||||||
|
|
||||||
|
@Override @NonNull
|
||||||
|
public String toString() {
|
||||||
|
return column + "='" + value + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -49,6 +49,7 @@ public class MongoDB implements IDatabase<MongoClient, ConnectionString> {
|
|||||||
* @param credentials the optional credentials to use
|
* @param credentials the optional credentials to use
|
||||||
* @throws IllegalArgumentException if no credentials or database name is provided
|
* @throws IllegalArgumentException if no credentials or database name is provided
|
||||||
* @throws IllegalStateException if already connected
|
* @throws IllegalStateException if already connected
|
||||||
|
* @see ConnectionString for credentials
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void connect(ConnectionString credentials) throws IllegalArgumentException, IllegalStateException {
|
public void connect(ConnectionString credentials) throws IllegalArgumentException, IllegalStateException {
|
||||||
@ -91,8 +92,8 @@ public class MongoDB implements IDatabase<MongoClient, ConnectionString> {
|
|||||||
}
|
}
|
||||||
// Return ping
|
// Return ping
|
||||||
long before = System.currentTimeMillis();
|
long before = System.currentTimeMillis();
|
||||||
database.runCommand(new BasicDBObject("ping", "1"));
|
database.runCommand(new BasicDBObject("ping", "1")); // Send a ping command
|
||||||
return System.currentTimeMillis() - before;
|
return System.currentTimeMillis() - before; // Return time difference
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,7 +124,7 @@ public class MongoDB implements IDatabase<MongoClient, ConnectionString> {
|
|||||||
if (!isConnected()) { // Not connected
|
if (!isConnected()) { // Not connected
|
||||||
throw new IllegalStateException("Not connected");
|
throw new IllegalStateException("Not connected");
|
||||||
}
|
}
|
||||||
return new MongoRepository<>(this, entityClass, database.getCollection(collectionName));
|
return new MongoRepository<>(this, entityClass, collectionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,16 +12,16 @@ import com.mongodb.client.model.Indexes;
|
|||||||
import com.mongodb.client.model.UpdateOneModel;
|
import com.mongodb.client.model.UpdateOneModel;
|
||||||
import com.mongodb.client.model.UpdateOptions;
|
import com.mongodb.client.model.UpdateOptions;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import me.braydon.feather.common.Tuple;
|
import me.braydon.feather.common.Tuple;
|
||||||
import me.braydon.feather.database.Repository;
|
import me.braydon.feather.database.Repository;
|
||||||
|
import me.braydon.feather.database.impl.mongodb.annotation.CustomDocument;
|
||||||
import me.braydon.feather.database.impl.mongodb.annotation.Index;
|
import me.braydon.feather.database.impl.mongodb.annotation.Index;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MongoDB} {@link Repository} implementation.
|
* The {@link MongoDB} {@link Repository} implementation.
|
||||||
@ -36,6 +36,10 @@ public class MongoRepository<ID, E> extends Repository<MongoDB, ID, E> {
|
|||||||
*/
|
*/
|
||||||
@NonNull private final MongoCollection<Document> collection;
|
@NonNull private final MongoCollection<Document> collection;
|
||||||
|
|
||||||
|
public MongoRepository(@NonNull MongoDB database, @NonNull Class<? extends E> entityClass, @NonNull String collectionName) {
|
||||||
|
this(database, entityClass, database.getDatabase().getCollection(collectionName));
|
||||||
|
}
|
||||||
|
|
||||||
public MongoRepository(@NonNull MongoDB database, @NonNull Class<? extends E> entityClass, @NonNull MongoCollection<Document> collection) {
|
public MongoRepository(@NonNull MongoDB database, @NonNull Class<? extends E> entityClass, @NonNull MongoCollection<Document> collection) {
|
||||||
super(database, entityClass);
|
super(database, entityClass);
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
@ -90,17 +94,29 @@ public class MongoRepository<ID, E> extends Repository<MongoDB, ID, E> {
|
|||||||
* @param entities the entities to save
|
* @param entities the entities to save
|
||||||
* @see E for entity
|
* @see E for entity
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override @SneakyThrows
|
||||||
public void saveAll(@NonNull E... entities) {
|
public void saveAll(@NonNull E... entities) {
|
||||||
List<UpdateOneModel<Document>> updateModels = new ArrayList<>(); // The update models to bulk write
|
List<UpdateOneModel<Document>> updateModels = new ArrayList<>(); // The update models to bulk write
|
||||||
|
|
||||||
for (E entity : entities) {
|
for (E entity : entities) {
|
||||||
me.braydon.feather.data.Document<Object> document = new me.braydon.feather.data.Document<>(entity); // Create a document from the entity
|
me.braydon.feather.data.Document document = new me.braydon.feather.data.Document(entity); // Create a document from the entity
|
||||||
|
Document bsonDocument; // The Bson document to save
|
||||||
|
|
||||||
|
Method customDocumentMethod = Arrays.stream(entity.getClass().getDeclaredMethods())
|
||||||
|
.filter(method -> method.isAnnotationPresent(CustomDocument.class))
|
||||||
|
.findFirst().orElse(null); // Get the @CustomDocument method
|
||||||
|
|
||||||
|
// We have a custom document method
|
||||||
|
if (customDocumentMethod != null && (customDocumentMethod.getReturnType() == Document.class)) {
|
||||||
|
bsonDocument = (Document) customDocumentMethod.invoke(entity); // Get our custom document
|
||||||
|
} else { // Otherwise, use our mapped data
|
||||||
|
bsonDocument = new Document(document.toMappedData());
|
||||||
|
}
|
||||||
|
|
||||||
// Add our update model to the list
|
// Add our update model to the list
|
||||||
updateModels.add(new UpdateOneModel<>(
|
updateModels.add(new UpdateOneModel<>(
|
||||||
Filters.eq(document.getIdKey(), document.getKey()),
|
Filters.eq(document.getIdKey(), document.getKey()),
|
||||||
new Document("$set", new Document(document.toMappedData())),
|
new Document("$set", bsonDocument),
|
||||||
new UpdateOptions().upsert(true)
|
new UpdateOptions().upsert(true)
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -162,7 +178,7 @@ public class MongoRepository<ID, E> extends Repository<MongoDB, ID, E> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void drop(@NonNull E entity) {
|
public void drop(@NonNull E entity) {
|
||||||
me.braydon.feather.data.Document<Object> document = new me.braydon.feather.data.Document<>(entity); // Create a document from the entity
|
me.braydon.feather.data.Document document = new me.braydon.feather.data.Document(entity); // Create a document from the entity
|
||||||
collection.deleteOne(new Document(document.getIdKey(), document.getKey())); // Delete the entity
|
collection.deleteOne(new Document(document.getIdKey(), document.getKey())); // Delete the entity
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.mongodb.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods tagged with this annotation will be invoked
|
||||||
|
* when a document is being saved to the database, this
|
||||||
|
* allows is to save a custom document, rather than
|
||||||
|
* parsing the entity and creating one that way.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Documented @Inherited
|
||||||
|
public @interface CustomDocument { }
|
@ -19,7 +19,7 @@ import me.braydon.feather.database.IDatabase;
|
|||||||
* @see RedisURI for the credentials class
|
* @see RedisURI for the credentials class
|
||||||
* @see <a href="https://redis.io">Redis Official Site</a>
|
* @see <a href="https://redis.io">Redis Official Site</a>
|
||||||
*/
|
*/
|
||||||
public class Redis implements IDatabase<StatefulRedisConnection<String, String>, RedisURI> {
|
public class Redis implements IDatabase<StatefulRedisConnection<String, String>, String> {
|
||||||
/**
|
/**
|
||||||
* The current {@link RedisClient} instance.
|
* The current {@link RedisClient} instance.
|
||||||
*/
|
*/
|
||||||
@ -43,25 +43,25 @@ public class Redis implements IDatabase<StatefulRedisConnection<String, String>,
|
|||||||
/**
|
/**
|
||||||
* Initialize a connection to this database.
|
* Initialize a connection to this database.
|
||||||
*
|
*
|
||||||
* @param credentials the optional credentials to use
|
* @param uri the optional credentials to use
|
||||||
* @throws IllegalArgumentException if no credentials are provided
|
* @throws IllegalArgumentException if no credentials are provided
|
||||||
* @throws IllegalStateException if already connected
|
* @throws IllegalStateException if already connected
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void connect(RedisURI credentials) throws IllegalArgumentException, IllegalStateException {
|
public void connect(String uri) throws IllegalArgumentException, IllegalStateException {
|
||||||
if (credentials == null) { // We need valid credentials
|
if (uri == null) { // We need valid credentials
|
||||||
throw new IllegalArgumentException("No credentials defined");
|
throw new IllegalArgumentException("No credentials defined");
|
||||||
}
|
}
|
||||||
if (isConnected()) { // Already connected
|
if (isConnected()) { // Already connected
|
||||||
throw new IllegalStateException("Already connected");
|
throw new IllegalStateException("Already connected");
|
||||||
}
|
}
|
||||||
if (client != null) { // We have a client, close it first
|
if (client != null) { // We have a client, close it first
|
||||||
client.close();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
if (connection != null) { // We have a connection, close it first
|
if (connection != null) { // We have a connection, close it first
|
||||||
connection.close();
|
connection.close();
|
||||||
}
|
}
|
||||||
client = RedisClient.create(credentials); // Create a new client
|
client = RedisClient.create(uri); // Create a new client
|
||||||
connection = client.connect(); // Connect to the Redis server
|
connection = client.connect(); // Connect to the Redis server
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,13 @@ public class Redis implements IDatabase<StatefulRedisConnection<String, String>,
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long getLatency() {
|
public long getLatency() {
|
||||||
return 0;
|
if (!isConnected()) { // Not connected
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
// Return ping
|
||||||
|
long before = System.currentTimeMillis();
|
||||||
|
connection.sync().ping(); // Send a ping command
|
||||||
|
return System.currentTimeMillis() - before; // Return time difference
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,7 +145,7 @@ public class Redis implements IDatabase<StatefulRedisConnection<String, String>,
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
client.close();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
connection.close();
|
connection.close();
|
||||||
|
@ -7,12 +7,13 @@ package me.braydon.feather.database.impl.redis;
|
|||||||
|
|
||||||
import io.lettuce.core.api.sync.RedisCommands;
|
import io.lettuce.core.api.sync.RedisCommands;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import me.braydon.feather.common.Tuple;
|
||||||
import me.braydon.feather.data.Document;
|
import me.braydon.feather.data.Document;
|
||||||
import me.braydon.feather.database.Repository;
|
import me.braydon.feather.database.Repository;
|
||||||
|
import me.braydon.feather.database.impl.redis.annotation.TTL;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link Redis} {@link Repository} implementation.
|
* The {@link Redis} {@link Repository} implementation.
|
||||||
@ -78,8 +79,24 @@ public class RedisRepository<ID, E> extends Repository<Redis, ID, E> {
|
|||||||
commands.multi();
|
commands.multi();
|
||||||
}
|
}
|
||||||
for (E entity : entities) { // Set our entities
|
for (E entity : entities) { // Set our entities
|
||||||
Document<String> document = new Document<>(entity); // Create a document from the entity
|
Document document = new Document(entity); // Create a document from the entity
|
||||||
commands.hmset(keyPrefix + ":" + document.getKey(), document.toMappedData());
|
String key = keyPrefix + ":" + document.getKey(); // The key of this entity
|
||||||
|
|
||||||
|
Map<String, String> mappedData = new HashMap<>();
|
||||||
|
for (Map.Entry<String, Tuple<Field, Object>> entry : document.getMappedData().entrySet()) {
|
||||||
|
mappedData.put(entry.getKey(), String.valueOf(entry.getValue().getRight()));
|
||||||
|
}
|
||||||
|
commands.hmset(key, mappedData); // Set the mapped document in the database
|
||||||
|
|
||||||
|
// Handling @TTL annotations
|
||||||
|
Class<?> clazz = entity.getClass(); // The entity class
|
||||||
|
if (!clazz.isAnnotationPresent(TTL.class)) { // Missing @TTL
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long ttl = clazz.getAnnotation(TTL.class).value(); // Get the ttl value
|
||||||
|
if (ttl > 0L) { // Value is above zero, set it
|
||||||
|
commands.expire(key, ttl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (multi) { // Execute the commands in bulk
|
if (multi) { // Execute the commands in bulk
|
||||||
commands.exec();
|
commands.exec();
|
||||||
@ -117,7 +134,7 @@ public class RedisRepository<ID, E> extends Repository<Redis, ID, E> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void drop(@NonNull E entity) {
|
public void drop(@NonNull E entity) {
|
||||||
me.braydon.feather.data.Document<Object> document = new me.braydon.feather.data.Document<>(entity); // Create a document from the entity
|
me.braydon.feather.data.Document document = new me.braydon.feather.data.Document(entity); // Create a document from the entity
|
||||||
getDatabase().getBootstrap().sync().del(keyPrefix + ":" + document.getKey());
|
getDatabase().getBootstrap().sync().del(keyPrefix + ":" + document.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Braydon (Rainnny). All rights reserved.
|
||||||
|
*
|
||||||
|
* For inquiries, please contact braydonrainnny@gmail.com
|
||||||
|
*/
|
||||||
|
package me.braydon.feather.database.impl.redis.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entities tagged with this annotation will
|
||||||
|
* expire after the amount of defined seconds.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@Documented @Inherited
|
||||||
|
public @interface TTL {
|
||||||
|
/**
|
||||||
|
* The time-to-live value.
|
||||||
|
* <p>
|
||||||
|
* If the value is zero or
|
||||||
|
* below, then there will
|
||||||
|
* be no expiration.
|
||||||
|
* <p>
|
||||||
|
* The key this TTL rule is assigned
|
||||||
|
* to will expire in the defined amount
|
||||||
|
* of seconds from when the key was updated.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the value in seconds
|
||||||
|
*/
|
||||||
|
long value() default -1L;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user