diff --git a/.gitignore b/.gitignore
index 8c967c2..0c6da4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,3 +81,7 @@ gradle-app.setting
# Cache of project
.gradletasknamecache
+
+# Others
+docs/todos.md
+/src/test/resources/application.properties
diff --git a/README.md b/README.md
index 158c85e..e82d5e6 100644
--- a/README.md
+++ b/README.md
@@ -13,16 +13,12 @@ The application is developed using the Quarkus framework and uses `MongoDB` as i
This application is a RESTful service designed to emulate a basic Pokemong management system. It allows users to perform
CRUD operations on Pokemongs, trainers, moves, and types.
-🗂️ See the DCM
+### 🗂️ DCM
-
-
-🧬 See the UML Class diagram
+### 🧬 UML Class diagram
-
-
## Prep steps
### ♨️ Java version
@@ -83,10 +79,18 @@ You can run the application in dev mode using:
## API testing
+### 🏴☠️ SwaggerUI
+
+Thanks to this project's OpenAPI specs, you can explore the API in a lot of ways.
+A popular choice is SwaggerUI -- after you run the app, just go to http://localhost:8080/q/swagger-ui and have fun.
+
+⚠️ Unfortunately, Swagger or Quarkus or SmallRye adds the field `id` to all request examples, but in fact ***you should
+not include id** when you POST a new document.*
+
### 🩺 API testing tools
-It is recommended to use an API testing tool such as [Postman](https://www.postman.com/)
-or [Insomnia](https://insomnia.rest/), while playing around with this app.
+You can use an API testing tool such as [Postman](https://www.postman.com/)
+or [Insomnia](https://insomnia.rest/) to test this app.
### 📱 Front end (later)
diff --git a/build.gradle b/build.gradle
index 5091209..ae4479e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,43 +1,43 @@
-plugins {
- id 'java'
- id 'io.quarkus'
-}
-
-repositories {
- mavenCentral()
- mavenLocal()
-}
-
-dependencies {
- // FIXME "Provides transitive vulnerable dependency maven:org.jboss.resteasy:resteasy-core:6.2.1.Final
- // CVE-2023-0482 7.8 Creation of Temporary File With Insecure Permissions vulnerability with medium severity found
- // Results powered by Checkmarx(c)"
- implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
- implementation 'io.quarkus:quarkus-resteasy:3.0.0.Alpha6'
- implementation 'io.quarkus:quarkus-resteasy-jackson:3.0.0.Alpha6'
- implementation 'io.quarkus:quarkus-arc:3.0.0.Alpha6'
- implementation 'io.quarkus:quarkus-mongodb-client:3.0.0.Alpha6'
- implementation 'org.mongodb:mongodb-driver-sync:4.9.1'
- testImplementation 'io.quarkus:quarkus-junit5:3.0.0.Alpha6'
- testImplementation 'io.rest-assured:rest-assured:5.3.0'
-}
-
-group 'fr.uca.iut'
-version '1.0-SNAPSHOT'
-
-java {
- sourceCompatibility = JavaVersion.VERSION_17
- targetCompatibility = JavaVersion.VERSION_17
-}
-
-test {
- systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
-}
-compileJava {
- options.encoding = 'UTF-8'
- options.compilerArgs << '-parameters'
-}
-
-compileTestJava {
- options.encoding = 'UTF-8'
-}
+plugins {
+ id 'java'
+ id 'io.quarkus'
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+dependencies {
+ implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
+ implementation 'io.quarkus:quarkus-resteasy:3.0.0.Alpha6'
+ implementation 'io.quarkus:quarkus-resteasy-jackson:3.0.0.Alpha6'
+ implementation 'io.quarkus:quarkus-arc:3.0.0.Alpha6'
+ implementation 'io.quarkus:quarkus-mongodb-client:3.0.0.Alpha6'
+ implementation 'org.mongodb:mongodb-driver-sync:4.9.1'
+ implementation 'org.jetbrains:annotations:24.0.1'
+ implementation 'io.quarkus:quarkus-smallrye-openapi:2.16.4.Final'
+ implementation 'io.quarkus:quarkus-swagger-ui:2.16.4.Final'
+ testImplementation 'io.quarkus:quarkus-junit5:3.0.0.Alpha6'
+ testImplementation 'io.rest-assured:rest-assured:5.3.0'
+}
+
+group 'fr.uca.iut'
+version '1.0-SNAPSHOT'
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+test {
+ systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
+}
+compileJava {
+ options.encoding = 'UTF-8'
+ options.compilerArgs << '-parameters'
+}
+
+compileTestJava {
+ options.encoding = 'UTF-8'
+}
diff --git a/docs/DB.md b/docs/DB.md
index ce5bce5..f7dfcb2 100644
--- a/docs/DB.md
+++ b/docs/DB.md
@@ -6,11 +6,11 @@
* _id: ObjectId
* name: string
- * (_indexed_: would be queried often in a dashboard situation)
+ * (_indexed_: would often be queried in a dashboard situation)
* dob: date
* wins: int
* losses: int
-* past_opponents: array of ObjectId (references to other trainers)
+* pastOpponents: array of ObjectId (references to other trainers)
* (_indexed_: reflexivity would make deep queries quite slow, so it seems worthwhile)
* pokemongs: array of ObjectId (references to owned pokemongs) + denormalizing on "nickname" and "species"
* (_indexed_: to improve speed when querying non-denormalized fields)
@@ -18,58 +18,70 @@
### pokemongs collection
* _id: ObjectId
-* nickname: string
+* nickname: string?
* dob: date
* level: int
-* pokedex_id: int
-* evo_stage: int
- * (_indexed_: "species" is calculated as evo_track[evo_stage], and would be queried often)
-* evo_track: array of strings (therefore "species" is evo_track[evo_stage], and "evo_base" is evo_track[0])
- * (_indexed_: "species" is calculated as evo_track[evo_stage], and xould be queried often)
-* is_mega_evolved: boolean
- * **polymorphic**: this field is only here for mature_pokemongs, i.e. pokemongs who have reached their last evo_stage
+* pokedexId: int
+* evoStage: int
+ * (_indexed_: "species" is calculated as evoTrack[evoStage], and would often be queried)
+* evoTrack: array of strings (therefore "species" is evoTrack[evoStage], and "evoBase" is evoTrack[0])
+ * (_indexed_: "species" is calculated as evoTrack[evoStage], and would be queried often)
* trainer: ObjectId? (reference to a trainer) (but can be "wild" instead, if ref is null)
* (_indexed_: could be queried often in a dashboard situation)
* types: embedded type, or array of embedded types
- * (_indexed_: would be queried often in a dashboard situation)
-* move_set: array of ObjectId (references to known moves) + denormalizing on "name"
+ * (_indexed_: would often be queried in a dashboard situation)
+* moveSet: array of ObjectId (references to known moves) + denormalizing on "name"
### moves collection
* _id: ObjectId
* name: string
- * (_indexed_: would be queried often in a dashboard situation)
+ * (_indexed_: would often be queried in a dashboard situation)
* category: string (can be "physical", "special", or "status")
-* pp: int
* power: int
- * (_indexed_: would be used often in sorts, in a dashboard situation)
+ * (_indexed_: would often be used in sorts, in a dashboard situation)
* accuracy: int
* type: embedded type
- * (_indexed_: would be queried often in a dashboard situation)
-
+ * (_indexed_: would often be queried in a dashboard situation)
### types collection
* _id: ObjectId
* name: string
- * (_indexed_: would be queried often in a dashboard situation)
-* weak_against: array of strings (denormalized type names)
-* effective_against: array of strings (denormalized type names)
+ * (_indexed_: would often be queried in a dashboard situation)
+* weakAgainst: array of strings (denormalized type names)
+* effectiveAgainst: array of strings (denormalized type names)
## Relationships
-* trainers.past_opponents: one-to-many and reflexive
- * => referencing
-* trainers.pokemongs: one-to-many
- * => referencing + denormalizing on "nickname" and "species"
-* pokemongs.trainer: many-to-one
- * => referencing
-* pokemongs.types: one-to-few [1;2] but will also need to be queried independently
- * => denormalizing on all fields
-* pokemongs.move_set: one-to-few [1;4] but will also need to be queried independently
- * => referencing + denormalizing on "name"
-* moves.type: one-to-one [1;1] but will also need to be queried independently
- * => denormalizing on all fields
-* types.weak_against & types.effective_against: one-to-few but reflexive
- * => denormalizing on "name"
-
\ No newline at end of file
+- Trainer
+ - [x] trainers.pastOpponents: one-to-many and reflexive
+ * => referencing
+ - [x] trainers.pokemongs: one-to-many
+ * => referencing + denormalizing on "nickname" and "species"
+- Pokemong
+ - [x] pokemongs.trainer: many-to-one
+ * => referencing
+ - [x] pokemongs.types: one-to-few [1;2]
+ * => embedding
+ - [x] pokemongs.moveSet: one-to-few [1;4] but will also need to be queried independently
+ * => referencing + denormalizing on "name"
+- Move
+ - [x] moves.type: one-to-one [1;1]
+ * => embedding
+- Type
+ - [x] types.weakAgainst & types.effectiveAgainst: one-to-few, but reflexive
+ * => denormalizing on "name"
+
+## Cascades
+
+- Pokemong
+ - [x] delete ~> trainer.pokemongs
+ - [x] update ~> trainer.pokemongs (denormalizing on "nickname" and "species")
+ - [x] create ~> trainer.pokemongs
+- Trainer
+ - [x] delete ~> pokemong.trainer
+ - [x] create ~> pokemong.trainer
+- Move
+ - [x] delete ~> pokemong.moveSet
+ - [x] update ~> pokemong.moveSet (denormalizing on "name")
diff --git a/docs/mcd.png b/docs/mcd.png
index a8ef40a..20e3532 100644
Binary files a/docs/mcd.png and b/docs/mcd.png differ
diff --git a/docs/nosql_uml.png b/docs/nosql_uml.png
index 0979200..e32ec6f 100644
Binary files a/docs/nosql_uml.png and b/docs/nosql_uml.png differ
diff --git a/src/main/java/fr/uca/iut/codecs/GenericCodec.java b/src/main/java/fr/uca/iut/codecs/GenericCodec.java
index c948176..25faad3 100644
--- a/src/main/java/fr/uca/iut/codecs/GenericCodec.java
+++ b/src/main/java/fr/uca/iut/codecs/GenericCodec.java
@@ -1,48 +1,41 @@
-package fr.uca.iut.codecs;
-
-import com.mongodb.MongoClientSettings;
-import fr.uca.iut.entities.GenericEntity;
-import org.bson.*;
-import org.bson.codecs.Codec;
-import org.bson.codecs.CollectibleCodec;
-import org.bson.codecs.DecoderContext;
-import org.bson.codecs.EncoderContext;
-import org.bson.types.ObjectId;
-
-public abstract class GenericCodec implements CollectibleCodec {
- private final Codec documentCodec;
- protected GenericCodec() {
- this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
- .get(Document.class);
- }
-
- public Codec getDocumentCodec() {
- return documentCodec;
- }
- @Override
- public abstract void encode(BsonWriter writer, T entity, EncoderContext encoderContext);
-
- @Override
- public abstract Class getEncoderClass();
-
- @Override
- public T generateIdIfAbsentFromDocument(T document) {
- if (!documentHasId(document)) {
- document.setId(new ObjectId().toString());
- }
- return document;
- }
-
- @Override
- public boolean documentHasId(T document) {
- return document.getId() != null;
- }
-
- @Override
- public BsonValue getDocumentId(T document) {
- return new BsonObjectId(new ObjectId(document.getId()));
- }
-
- @Override
- public abstract T decode(BsonReader reader, DecoderContext decoderContext);
-}
+package fr.uca.iut.codecs;
+
+import fr.uca.iut.entities.GenericEntity;
+import org.bson.BsonObjectId;
+import org.bson.BsonReader;
+import org.bson.BsonValue;
+import org.bson.BsonWriter;
+import org.bson.codecs.CollectibleCodec;
+import org.bson.codecs.DecoderContext;
+import org.bson.codecs.EncoderContext;
+import org.bson.types.ObjectId;
+
+public abstract class GenericCodec implements CollectibleCodec {
+
+ @Override
+ public abstract void encode(BsonWriter writer, T entity, EncoderContext encoderContext);
+
+ @Override
+ public abstract Class getEncoderClass();
+
+ @Override
+ public T generateIdIfAbsentFromDocument(T document) {
+ if (!documentHasId(document)) {
+ document.setId(new ObjectId().toString());
+ }
+ return document;
+ }
+
+ @Override
+ public boolean documentHasId(T document) {
+ return document.getId() != null;
+ }
+
+ @Override
+ public BsonValue getDocumentId(T document) {
+ return new BsonObjectId(new ObjectId(document.getId()));
+ }
+
+ @Override
+ public abstract T decode(BsonReader reader, DecoderContext decoderContext);
+}
diff --git a/src/main/java/fr/uca/iut/codecs/move/MoveCodec.java b/src/main/java/fr/uca/iut/codecs/move/MoveCodec.java
new file mode 100644
index 0000000..13b7ec8
--- /dev/null
+++ b/src/main/java/fr/uca/iut/codecs/move/MoveCodec.java
@@ -0,0 +1,78 @@
+package fr.uca.iut.codecs.move;
+
+import com.mongodb.MongoClientSettings;
+import fr.uca.iut.codecs.GenericCodec;
+import fr.uca.iut.codecs.type.TypeCodecUtil;
+import fr.uca.iut.entities.Move;
+import fr.uca.iut.entities.Type;
+import fr.uca.iut.utils.enums.MoveCategoryName;
+import org.bson.BsonReader;
+import org.bson.BsonWriter;
+import org.bson.Document;
+import org.bson.codecs.Codec;
+import org.bson.codecs.DecoderContext;
+import org.bson.codecs.EncoderContext;
+import org.bson.types.ObjectId;
+
+public class MoveCodec extends GenericCodec {
+ private final Codec documentCodec;
+
+ public MoveCodec() {
+ this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
+ .get(Document.class);
+ }
+
+ @Override
+ public void encode(BsonWriter writer, Move move, EncoderContext encoderContext) {
+ Document doc = new Document();
+
+ doc.put("_id", new ObjectId(move.getId()));
+
+ doc.put("name", move.getName());
+
+ doc.put("category", move.getCategory());
+
+ doc.put("power", move.getPower());
+
+ doc.put("accuracy", move.getAccuracy());
+
+ Type moveType = move.getType();
+ Document typeDoc = new Document();
+ typeDoc.put("name",
+ moveType.getName()
+ .toString());
+ typeDoc.put("weakAgainst", moveType.getWeakAgainst());
+ typeDoc.put("effectiveAgainst", moveType.getEffectiveAgainst());
+ doc.put("type", typeDoc);
+
+ documentCodec.encode(writer, doc, encoderContext);
+ }
+
+ @Override
+ public Class getEncoderClass() {
+ return Move.class;
+ }
+
+ @Override
+ public Move decode(BsonReader reader, DecoderContext decoderContext) {
+ Document document = documentCodec.decode(reader, decoderContext);
+ Move move = new Move();
+
+ move.setId(document.getObjectId("_id")
+ .toString());
+
+ move.setName(document.getString("name"));
+
+ move.setCategory(MoveCategoryName.valueOf(document.getString("category")));
+
+ move.setPower(document.getInteger("power"));
+
+ move.setAccuracy(document.getInteger("accuracy"));
+
+ Document typeDoc = (Document) document.get("type");
+
+ move.setType(TypeCodecUtil.extractType(typeDoc));
+
+ return move;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/codecs/move/MoveCodecProvider.java b/src/main/java/fr/uca/iut/codecs/move/MoveCodecProvider.java
new file mode 100644
index 0000000..312afd9
--- /dev/null
+++ b/src/main/java/fr/uca/iut/codecs/move/MoveCodecProvider.java
@@ -0,0 +1,18 @@
+package fr.uca.iut.codecs.move;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.Move;
+import org.bson.codecs.Codec;
+import org.bson.codecs.configuration.CodecProvider;
+import org.bson.codecs.configuration.CodecRegistry;
+
+public class MoveCodecProvider implements CodecProvider {
+ @Nullable
+ @Override
+ public Codec get(Class clazz, CodecRegistry registry) {
+ if (clazz.equals(Move.class)) {
+ return (Codec) new MoveCodec();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodec.java b/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodec.java
index 0610934..de7c7fa 100644
--- a/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodec.java
+++ b/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodec.java
@@ -1,127 +1,153 @@
-package fr.uca.iut.codecs.pokemong;
-
-import com.mongodb.MongoClientSettings;
-import fr.uca.iut.codecs.GenericCodec;
-import fr.uca.iut.entities.Pokemong;
-import fr.uca.iut.entities.Type;
-import fr.uca.iut.utils.PokemongName;
-import fr.uca.iut.utils.TypeName;
-import org.bson.*;
-import org.bson.codecs.*;
-import org.bson.types.ObjectId;
-
-import java.time.ZoneId;
-import java.util.*;
-import java.util.stream.Collectors;
-
-public class PokemongCodec extends GenericCodec {
- private final Codec documentCodec;
-
- public PokemongCodec() {
- this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
- .get(Document.class);
- }
-
- @Override
- public void encode(BsonWriter writer, Pokemong pokemong, EncoderContext encoderContext) {
- Document doc = new Document();
- doc.put("_id", new ObjectId(pokemong.getId()));
- doc.put("nickname", pokemong.getNickname());
- doc.put("dob",
- Date.from(pokemong.getDob()
- .atStartOfDay(ZoneId.systemDefault())
- .toInstant()));
- doc.put("level", pokemong.getLevel());
- doc.put("pokedexId", pokemong.getPokedexId());
- doc.put("evoStage", pokemong.getEvoStage());
- List evoTrack = Optional.ofNullable(pokemong.getEvoTrack())
- .orElse(Collections.emptyList())
- .stream()
- .map(Enum::name)
- .collect(Collectors.toList());
-
- doc.put("evoTrack", evoTrack);
- doc.put("isMegaEvolved", pokemong.getMegaEvolved());
- doc.put("trainer", pokemong.getTrainer());
- List types = Optional.ofNullable(pokemong.getTypes())
- .orElse(Collections.emptyList())
- .stream()
- .map(type -> {
- Document typeDoc = new Document();
- typeDoc.put("name",
- type.getName()
- .name());
- List weakAgainst = type.getWeakAgainst()
- .stream()
- .map(Enum::name)
- .collect(Collectors.toList());
- typeDoc.put("weakAgainst", weakAgainst);
- List effectiveAgainst = type.getEffectiveAgainst()
- .stream()
- .map(Enum::name)
- .collect(Collectors.toList());
- typeDoc.put("effectiveAgainst", effectiveAgainst);
- return typeDoc;
- })
- .collect(Collectors.toList());
- doc.put("types", types);
- doc.put("moveSet", pokemong.getMoveSet());
- documentCodec.encode(writer, doc, encoderContext);
- }
-
- @Override
- public Class getEncoderClass() {
- return Pokemong.class;
- }
-
- @Override
- public Pokemong decode(BsonReader reader, DecoderContext decoderContext) {
- Document document = documentCodec.decode(reader, decoderContext);
- Pokemong pokemong = new Pokemong();
- pokemong.setId(document.getObjectId("_id").toString());
- pokemong.setNickname(document.getString("nickname"));
- Date dob = document.getDate("dob");
- if (dob != null) {
- pokemong.setDob(dob.toInstant()
- .atZone(ZoneId.systemDefault())
- .toLocalDate());
- }
- pokemong.setPokedexId(document.getInteger("pokedexId"));
- pokemong.setEvoStage(document.getInteger("evoStage"));
- List evoTrack = Optional.ofNullable((List) document.get("evoTrack"))
- .orElse(Collections.emptyList())
- .stream()
- .map(PokemongName::valueOf)
- .collect(Collectors.toList());
- pokemong.setEvoTrack(evoTrack);
- pokemong.setMegaEvolved(document.getBoolean("isMegaEvolved"));
- pokemong.setTrainer(document.getObjectId("trainer"));
- List types = Optional.ofNullable((List) document.get("types"))
- .orElse(Collections.emptyList())
- .stream()
- .map(typeDoc -> {
- Type type = new Type();
- type.setName(TypeName.valueOf(typeDoc.getString("name")));
- List weakAgainst = Optional
- .ofNullable((List) typeDoc.get("weakAgainst"))
- .orElse(Collections.emptyList())
- .stream()
- .map(TypeName::valueOf)
- .collect(Collectors.toList());
- type.setWeakAgainst(weakAgainst);
- List effectiveAgainst = Optional
- .ofNullable((List) typeDoc.get("effectiveAgainst"))
- .orElse(Collections.emptyList())
- .stream()
- .map(TypeName::valueOf)
- .collect(Collectors.toList());
- type.setEffectiveAgainst(effectiveAgainst);
- return type;
- })
- .collect(Collectors.toList());
- pokemong.setTypes(types);
- pokemong.setMoveSet(Optional.ofNullable(document.getList("moveSet", ObjectId.class))
- .orElse(Collections.emptyList()));
- return pokemong;
- }
-}
+package fr.uca.iut.codecs.pokemong;
+
+import com.mongodb.MongoClientSettings;
+import fr.uca.iut.codecs.GenericCodec;
+import fr.uca.iut.codecs.type.TypeCodecUtil;
+import fr.uca.iut.entities.Pokemong;
+import fr.uca.iut.entities.PokemongMove;
+import fr.uca.iut.entities.Type;
+import fr.uca.iut.utils.enums.PokemongName;
+import org.bson.BsonReader;
+import org.bson.BsonWriter;
+import org.bson.Document;
+import org.bson.codecs.Codec;
+import org.bson.codecs.DecoderContext;
+import org.bson.codecs.EncoderContext;
+import org.bson.types.ObjectId;
+
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class PokemongCodec extends GenericCodec {
+ private final Codec documentCodec;
+
+ public PokemongCodec() {
+ this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
+ .get(Document.class);
+ }
+
+ @Override
+ public void encode(BsonWriter writer, Pokemong pokemong, EncoderContext encoderContext) {
+ Document doc = new Document();
+
+ doc.put("_id", new ObjectId(pokemong.getId()));
+
+ doc.put("nickname", pokemong.getNickname());
+
+ doc.put("dob",
+ Date.from(pokemong.getDob()
+ .atStartOfDay(ZoneId.systemDefault())
+ .toInstant()));
+
+ doc.put("level", pokemong.getLevel());
+
+ doc.put("pokedexId", pokemong.getPokedexId());
+
+ doc.put("evoStage", pokemong.getEvoStage());
+
+ List evoTrack = pokemong.getEvoTrack()
+ .stream()
+ .map(Enum::name)
+ .collect(Collectors.toList());
+ doc.put("evoTrack", evoTrack);
+
+ if (pokemong.getTrainer() != null) {
+ doc.put("trainer", new ObjectId(pokemong.getTrainer()));
+ }
+
+ List types = pokemong.getTypes()
+ .stream()
+ .map(type -> {
+ Document typeDoc = new Document();
+ typeDoc.put("name",
+ type.getName()
+ .name());
+ List weakAgainst = type.getWeakAgainst()
+ .stream()
+ .map(Enum::name)
+ .collect(Collectors.toList());
+ typeDoc.put("weakAgainst", weakAgainst);
+ List effectiveAgainst = type.getEffectiveAgainst()
+ .stream()
+ .map(Enum::name)
+ .collect(Collectors.toList());
+ typeDoc.put("effectiveAgainst", effectiveAgainst);
+ return typeDoc;
+ })
+ .collect(Collectors.toList());
+ doc.put("types", types);
+
+ List moveSetDocs = pokemong.getMoveSet()
+ .stream()
+ .map(move -> {
+ Document moveDoc = new Document();
+ moveDoc.put("_id", new ObjectId(move.getId()));
+ moveDoc.put("name", move.getName());
+ return moveDoc;
+ })
+ .collect(Collectors.toList());
+ doc.put("moveSet", moveSetDocs);
+
+ documentCodec.encode(writer, doc, encoderContext);
+ }
+
+ @Override
+ public Class getEncoderClass() {
+ return Pokemong.class;
+ }
+
+ @Override
+ public Pokemong decode(BsonReader reader, DecoderContext decoderContext) {
+ Document document = documentCodec.decode(reader, decoderContext);
+ Pokemong pokemong = new Pokemong();
+
+ pokemong.setId(document.getObjectId("_id")
+ .toString());
+
+ pokemong.setNickname(document.getString("nickname"));
+
+ Date dob = document.getDate("dob");
+ if (dob != null) {
+ pokemong.setDob(dob.toInstant()
+ .atZone(ZoneId.systemDefault())
+ .toLocalDate());
+ }
+
+ pokemong.setLevel(document.getInteger("level"));
+
+ pokemong.setPokedexId(document.getInteger("pokedexId"));
+
+ pokemong.setEvoStage(document.getInteger("evoStage"));
+
+ List evoTrack = document.getList("evoTrack", String.class)
+ .stream()
+ .map(PokemongName::valueOf)
+ .collect(Collectors.toList());
+ pokemong.setEvoTrack(evoTrack);
+
+ pokemong.setTrainer(document.getObjectId("trainer")
+ .toString());
+
+ List types = document.getList("types", Document.class)
+ .stream()
+ .map(TypeCodecUtil::extractType)
+ .collect(Collectors.toList());
+ pokemong.setTypes(types);
+
+ Set moveSet = document.getList("moveSet", Document.class)
+ .stream()
+ .map(pokemongMoveDoc -> {
+ PokemongMove move = new PokemongMove();
+ move.setId(((ObjectId) pokemongMoveDoc.get("_id")).toString());
+ move.setName(pokemongMoveDoc.getString("name"));
+ return move;
+ })
+ .collect(Collectors.toSet());
+ pokemong.setMoveSet(moveSet);
+
+ return pokemong;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodecProvider.java b/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodecProvider.java
index 376412f..7327c19 100644
--- a/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodecProvider.java
+++ b/src/main/java/fr/uca/iut/codecs/pokemong/PokemongCodecProvider.java
@@ -1,16 +1,18 @@
-package fr.uca.iut.codecs.pokemong;
-
-import fr.uca.iut.entities.Pokemong;
-import org.bson.codecs.Codec;
-import org.bson.codecs.configuration.CodecProvider;
-import org.bson.codecs.configuration.CodecRegistry;
-
-public class PokemongCodecProvider implements CodecProvider {
- @Override
- public Codec get(Class clazz, CodecRegistry registry) {
- if (clazz.equals(Pokemong.class)) {
- return (Codec) new PokemongCodec();
- }
- return null;
- }
+package fr.uca.iut.codecs.pokemong;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.Pokemong;
+import org.bson.codecs.Codec;
+import org.bson.codecs.configuration.CodecProvider;
+import org.bson.codecs.configuration.CodecRegistry;
+
+public class PokemongCodecProvider implements CodecProvider {
+ @Nullable
+ @Override
+ public Codec get(Class clazz, CodecRegistry registry) {
+ if (clazz.equals(Pokemong.class)) {
+ return (Codec) new PokemongCodec();
+ }
+ return null;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodec.java b/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodec.java
index ea2a396..f9c0041 100644
--- a/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodec.java
+++ b/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodec.java
@@ -1,57 +1,117 @@
-package fr.uca.iut.codecs.trainer;
-
-import com.mongodb.MongoClientSettings;
-import fr.uca.iut.codecs.GenericCodec;
-import fr.uca.iut.entities.Trainer;
-import org.bson.*;
-import org.bson.codecs.Codec;
-import org.bson.codecs.DecoderContext;
-import org.bson.codecs.EncoderContext;
-import org.bson.types.ObjectId;
-
-import java.time.ZoneId;
-import java.util.Date;
-
-public class TrainerCodec extends GenericCodec {
- private final Codec documentCodec;
-
- public TrainerCodec() {
- this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
- .get(Document.class);
- }
-
- @Override
- public void encode(BsonWriter writer, Trainer trainer, EncoderContext encoderContext) {
- Document doc = new Document();
- doc.put("_id", new ObjectId(trainer.getId()));
- doc.put("name", trainer.getName());
- doc.put("dob", Date.from(trainer.getDob().atStartOfDay(ZoneId.systemDefault()).toInstant()));
- doc.put("wins", trainer.getWins());
- doc.put("losses", trainer.getLosses());
- doc.put("pastOpponents", trainer.getPastOpponents());
- doc.put("pokemongs", trainer.getPokemongs());
- documentCodec.encode(writer, doc, encoderContext);
- }
-
- @Override
- public Class getEncoderClass() {
- return Trainer.class;
- }
-
- @Override
- public Trainer decode(BsonReader reader, DecoderContext decoderContext) {
- Document document = documentCodec.decode(reader, decoderContext);
- Trainer trainer = new Trainer();
- trainer.setId(document.getObjectId("_id").toString());
- trainer.setName(document.getString("name"));
- Date dob = document.getDate("dob");
- if (dob != null) {
- trainer.setDob(dob.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
- }
- trainer.setWins(document.getInteger("wins", 0));
- trainer.setLosses(document.getInteger("losses", 0));
- trainer.setPastOpponents(document.getList("pastOpponents", ObjectId.class));
- trainer.setPokemongs(document.getList("pokemongs", ObjectId.class));
- return trainer;
- }
-}
+package fr.uca.iut.codecs.trainer;
+
+import com.mongodb.MongoClientSettings;
+import fr.uca.iut.codecs.GenericCodec;
+import fr.uca.iut.entities.Trainer;
+import fr.uca.iut.entities.TrainerPokemong;
+import fr.uca.iut.utils.enums.PokemongName;
+import org.bson.BsonReader;
+import org.bson.BsonWriter;
+import org.bson.Document;
+import org.bson.codecs.Codec;
+import org.bson.codecs.DecoderContext;
+import org.bson.codecs.EncoderContext;
+import org.bson.types.ObjectId;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TrainerCodec extends GenericCodec {
+ private final Codec documentCodec;
+
+ public TrainerCodec() {
+ this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
+ .get(Document.class);
+ }
+
+ @Override
+ public void encode(BsonWriter writer, Trainer trainer, EncoderContext encoderContext) {
+ Document doc = new Document();
+
+ doc.put("_id", new ObjectId(trainer.getId()));
+
+ doc.put("name", trainer.getName());
+
+ LocalDate dob = trainer.getDob();
+ if (dob != null) {
+ doc.put("dob", Date.from(dob.atStartOfDay(ZoneId.systemDefault())
+ .toInstant()));
+ }
+
+ doc.put("wins", trainer.getWins());
+
+ doc.put("losses", trainer.getLosses());
+
+ List pastOpponentsIds = trainer.getPastOpponents()
+ .stream()
+ .map(ObjectId::new)
+ .collect(Collectors.toList());
+ doc.put("pastOpponents", pastOpponentsIds);
+
+ List pokemongListDoc = trainer.getPokemongs()
+ .stream()
+ .map(pokemong -> {
+ Document moveDoc = new Document();
+ moveDoc.put("_id", new ObjectId(pokemong.getId()));
+ moveDoc.put("nickname", pokemong.getNickname());
+ moveDoc.put("species",
+ pokemong.getSpecies()
+ .name());
+ return moveDoc;
+ })
+ .collect(Collectors.toList());
+ doc.put("pokemongs", pokemongListDoc);
+
+ documentCodec.encode(writer, doc, encoderContext);
+ }
+
+ @Override
+ public Class getEncoderClass() {
+ return Trainer.class;
+ }
+
+ @Override
+ public Trainer decode(BsonReader reader, DecoderContext decoderContext) {
+ Document document = documentCodec.decode(reader, decoderContext);
+ Trainer trainer = new Trainer();
+
+ trainer.setId(document.getObjectId("_id")
+ .toString());
+
+ trainer.setName(document.getString("name"));
+
+ Date dob = document.getDate("dob");
+ if (dob != null) {
+ trainer.setDob(dob.toInstant()
+ .atZone(ZoneId.systemDefault())
+ .toLocalDate());
+ }
+
+ trainer.setWins(document.getInteger("wins"));
+
+ trainer.setLosses(document.getInteger("losses"));
+
+ List pastOpponentsIds = document.getList("pastOpponents", ObjectId.class)
+ .stream()
+ .map(ObjectId::toString)
+ .collect(Collectors.toList());
+ trainer.setPastOpponents(pastOpponentsIds);
+
+ List pokemongList = document
+ .getList("pokemongs", Document.class)
+ .stream()
+ .map(pokemongDoc -> {
+ TrainerPokemong pokemong = new TrainerPokemong();
+ pokemong.setId(((ObjectId) pokemongDoc.get("_id")).toString());
+ pokemong.setNickname(pokemongDoc.getString("nickname"));
+ pokemong.setSpecies(PokemongName.valueOf(pokemongDoc.getString("species")));
+ return pokemong;
+ })
+ .collect(Collectors.toList());
+ trainer.setPokemongs(pokemongList);
+ return trainer;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodecProvider.java b/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodecProvider.java
index 80c178e..0c3e37a 100644
--- a/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodecProvider.java
+++ b/src/main/java/fr/uca/iut/codecs/trainer/TrainerCodecProvider.java
@@ -1,16 +1,18 @@
-package fr.uca.iut.codecs.trainer;
-
-import fr.uca.iut.entities.Trainer;
-import org.bson.codecs.Codec;
-import org.bson.codecs.configuration.CodecProvider;
-import org.bson.codecs.configuration.CodecRegistry;
-
-public class TrainerCodecProvider implements CodecProvider {
- @Override
- public Codec get(Class clazz, CodecRegistry registry) {
- if (clazz.equals(Trainer.class)) {
- return (Codec) new TrainerCodec();
- }
- return null;
- }
-}
+package fr.uca.iut.codecs.trainer;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.Trainer;
+import org.bson.codecs.Codec;
+import org.bson.codecs.configuration.CodecProvider;
+import org.bson.codecs.configuration.CodecRegistry;
+
+public class TrainerCodecProvider implements CodecProvider {
+ @Nullable
+ @Override
+ public Codec get(Class clazz, CodecRegistry registry) {
+ if (clazz.equals(Trainer.class)) {
+ return (Codec) new TrainerCodec();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/codecs/type/TypeCodec.java b/src/main/java/fr/uca/iut/codecs/type/TypeCodec.java
deleted file mode 100644
index 8b01381..0000000
--- a/src/main/java/fr/uca/iut/codecs/type/TypeCodec.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package fr.uca.iut.codecs.type;
-
-import com.mongodb.MongoClientSettings;
-import fr.uca.iut.entities.Type;
-import fr.uca.iut.utils.TypeName;
-import org.bson.*;
-import org.bson.codecs.Codec;
-import org.bson.codecs.DecoderContext;
-import org.bson.codecs.EncoderContext;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-public class TypeCodec implements Codec {
- private final Codec documentCodec;
-
- public TypeCodec() {
- this.documentCodec = MongoClientSettings.getDefaultCodecRegistry()
- .get(Document.class);
- }
-
- @Override
- public void encode(BsonWriter writer, Type type, EncoderContext encoderContext) {
- Document doc = new Document();
- Optional.ofNullable(type.getName())
- .map(Enum::name)
- .ifPresent(name -> doc.put("name", name));
-
- Optional.ofNullable(type.getWeakAgainst())
- .map(weakAgainst -> weakAgainst.stream().map(Enum::name).collect(Collectors.toList()))
- .ifPresent(weakAgainst -> doc.put("weakAgainst", weakAgainst));
-
- Optional.ofNullable(type.getEffectiveAgainst())
- .map(effectiveAgainst -> effectiveAgainst.stream().map(Enum::name).collect(Collectors.toList()))
- .ifPresent(effectiveAgainst -> doc.put("effectiveAgainst", effectiveAgainst));
-
- documentCodec.encode(writer, doc, encoderContext);
- }
-
- @Override
- public Class getEncoderClass() {
- return Type.class;
- }
-
- @Override
- public Type decode(BsonReader reader, DecoderContext decoderContext) {
- Document document = documentCodec.decode(reader, decoderContext);
- Type type = new Type();
-
- Optional.ofNullable(document.getString("name"))
- .map(TypeName::valueOf)
- .ifPresent(type::setName);
-
- Optional.ofNullable(document.get("weakAgainst"))
- .filter(obj -> obj instanceof List>)
- .map(obj -> ((List) obj).stream().map(TypeName::valueOf).collect(Collectors.toList()))
- .ifPresent(type::setWeakAgainst);
-
- Optional.ofNullable(document.get("effectiveAgainst"))
- .filter(obj -> obj instanceof List>)
- .map(obj -> ((List) obj).stream().map(TypeName::valueOf).collect(Collectors.toList()))
- .ifPresent(type::setEffectiveAgainst);
-
- return type;
- }
-}
diff --git a/src/main/java/fr/uca/iut/codecs/type/TypeCodecProvider.java b/src/main/java/fr/uca/iut/codecs/type/TypeCodecProvider.java
deleted file mode 100644
index 4a75c95..0000000
--- a/src/main/java/fr/uca/iut/codecs/type/TypeCodecProvider.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package fr.uca.iut.codecs.type;
-
-import fr.uca.iut.entities.Type;
-import org.bson.codecs.Codec;
-import org.bson.codecs.configuration.CodecProvider;
-import org.bson.codecs.configuration.CodecRegistry;
-
-public class TypeCodecProvider implements CodecProvider {
- @Override
- public Codec get(Class clazz, CodecRegistry registry) {
- if (clazz.equals(Type.class)) {
- return (Codec) new TypeCodec();
- }
- return null;
- }
-}
diff --git a/src/main/java/fr/uca/iut/codecs/type/TypeCodecUtil.java b/src/main/java/fr/uca/iut/codecs/type/TypeCodecUtil.java
new file mode 100644
index 0000000..bd45965
--- /dev/null
+++ b/src/main/java/fr/uca/iut/codecs/type/TypeCodecUtil.java
@@ -0,0 +1,27 @@
+package fr.uca.iut.codecs.type;
+
+import fr.uca.iut.entities.Type;
+import fr.uca.iut.utils.enums.TypeName;
+import org.bson.Document;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TypeCodecUtil {
+ public static Type extractType(Document typeDoc) {
+ Type type = new Type();
+ type.setName(TypeName.valueOf(typeDoc.getString("name")));
+ List weakAgainst = typeDoc.getList("weakAgainst", String.class)
+ .stream()
+ .map(TypeName::valueOf)
+ .collect(Collectors.toList());
+ type.setWeakAgainst(weakAgainst);
+ List effectiveAgainst = typeDoc.getList("effectiveAgainst",
+ String.class)
+ .stream()
+ .map(TypeName::valueOf)
+ .collect(Collectors.toList());
+ type.setEffectiveAgainst(effectiveAgainst);
+ return type;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/controllers/GenericController.java b/src/main/java/fr/uca/iut/controllers/GenericController.java
new file mode 100644
index 0000000..70b30d2
--- /dev/null
+++ b/src/main/java/fr/uca/iut/controllers/GenericController.java
@@ -0,0 +1,108 @@
+package fr.uca.iut.controllers;
+
+import fr.uca.iut.entities.GenericEntity;
+import fr.uca.iut.services.GenericService;
+import fr.uca.iut.utils.exceptions.NonValidEntityException;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+public abstract class GenericController {
+
+ protected GenericService service;
+
+ public void setService(GenericService service) {
+ this.service = service;
+ }
+
+ @GET
+ @Path("/{id}")
+ public Response getOneById(@PathParam("id") String id) {
+ try {
+ T entity = service.getOneById(id);
+ if (entity != null) {
+ return Response.ok(entity)
+ .build();
+ }
+ else {
+ return Response.status(Response.Status.NOT_FOUND)
+ .entity("Entity not found for id: " + id)
+ .build();
+ }
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Invalid id format: " + id)
+ .build();
+ }
+ }
+
+ @GET
+ public Response getAll() {
+ return Response.ok(service.getAll())
+ .build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response createOne(T entity) {
+
+ try {
+ service.validateOne(entity);
+ T newEntity = service.addOne(entity);
+
+ return Response.status(Response.Status.CREATED)
+ .entity(newEntity)
+ .build();
+
+ } catch (NonValidEntityException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity(e.getMessage())
+ .build();
+ }
+ }
+
+ @PUT
+ @Path("/{id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response updateOne(@PathParam("id") String id, T entity) {
+ try {
+ service.validateOne(entity);
+ entity.setId(id);
+ T updatedEntity = service.updateOne(entity);
+
+ if (updatedEntity != null) {
+ return Response.status(Response.Status.OK)
+ .entity(updatedEntity)
+ .build();
+ }
+ else {
+ return Response.status(Response.Status.NOT_FOUND)
+ .entity("Entity not found for id: " + id)
+ .build();
+ }
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Invalid id format: " + id)
+ .build();
+ } catch (NonValidEntityException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity(e.getMessage())
+ .build();
+ }
+ }
+
+ @DELETE
+ @Path("/{id}")
+ public Response deleteOneById(@PathParam("id") String id) {
+ try {
+ service.deleteOneById(id);
+ return Response.ok()
+ .build();
+
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Invalid id format: " + id)
+ .build();
+ }
+ }
+}
diff --git a/src/main/java/fr/uca/iut/controllers/MoveController.java b/src/main/java/fr/uca/iut/controllers/MoveController.java
new file mode 100644
index 0000000..ff4dbaf
--- /dev/null
+++ b/src/main/java/fr/uca/iut/controllers/MoveController.java
@@ -0,0 +1,22 @@
+package fr.uca.iut.controllers;
+
+import fr.uca.iut.entities.Move;
+import fr.uca.iut.services.MoveService;
+import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/move")
+@Produces(MediaType.APPLICATION_JSON)
+public class MoveController extends GenericController {
+
+ @Inject
+ MoveService moveService;
+
+ @PostConstruct
+ public void init() {
+ setService(moveService);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/controllers/PokemongController.java b/src/main/java/fr/uca/iut/controllers/PokemongController.java
index 9032f87..43f4000 100644
--- a/src/main/java/fr/uca/iut/controllers/PokemongController.java
+++ b/src/main/java/fr/uca/iut/controllers/PokemongController.java
@@ -1,102 +1,22 @@
-package fr.uca.iut.controllers;
-
-import fr.uca.iut.entities.Pokemong;
-import fr.uca.iut.services.PokemongService;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.*;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-
-@Path("/pokemong")
-@Produces(MediaType.APPLICATION_JSON)
-public class PokemongController {
-
- @Inject
- PokemongService pokemongService;
-
- @GET
- @Path("/{id}")
- public Response getPokemong(@PathParam("id") String id) {
- try {
- Pokemong pokemong = pokemongService.getPokemong(id);
- if (pokemong != null) {
- return Response.ok(pokemong)
- .build();
- }
- else {
- return Response.status(Response.Status.NOT_FOUND)
- .entity("Pokemong not found for id: " + id)
- .build();
- }
- } catch (IllegalArgumentException e) {
- return Response.status(Response.Status.BAD_REQUEST)
- .entity("Invalid id format: " + id)
- .build();
- }
- }
-
- @GET
- public Response getAllPokemongs() {
- return Response.ok(pokemongService.getAllPokemongs())
- .build();
- }
-
- @POST
- @Consumes(MediaType.APPLICATION_JSON)
- public Response createPokemong(Pokemong pokemong) {
-
- if (pokemongService.isNotMature(pokemong)) {
- pokemong.setMegaEvolved(null);
- }
-
- Pokemong newPokemong = pokemongService.addPokemong(pokemong);
-
- return Response.status(Response.Status.CREATED)
- .entity(newPokemong)
- .build();
- }
-
- @PUT
- @Path("/{id}")
- @Consumes(MediaType.APPLICATION_JSON)
- public Response updatePokemong(@PathParam("id") String id, Pokemong pokemong) {
- try {
- if (pokemongService.isNotMature(pokemong)) {
- pokemong.setMegaEvolved(null);
- }
-
- pokemong.setId(id);
- Pokemong updatedPokemong = pokemongService.updatePokemong(pokemong);
-
- if (updatedPokemong != null) {
- return Response.status(Response.Status.OK)
- .entity(updatedPokemong)
- .build();
- }
- else {
- return Response.status(Response.Status.NOT_FOUND)
- .entity("Pokemong not found for id: " + id)
- .build();
- }
- } catch (IllegalArgumentException e) {
- return Response.status(Response.Status.BAD_REQUEST)
- .entity("Invalid id format: " + id)
- .build();
- }
- }
-
- @DELETE
- @Path("/{id}")
- public Response deletePokemong(@PathParam("id") String id) {
- try {
- pokemongService.deletePokemong(id);
- return Response.ok()
- .build();
-
- } catch (IllegalArgumentException e) {
- return Response.status(Response.Status.BAD_REQUEST)
- .entity("Invalid id format: " + id)
- .build();
- }
- }
-}
+package fr.uca.iut.controllers;
+
+import fr.uca.iut.entities.Pokemong;
+import fr.uca.iut.services.PokemongService;
+import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/pokemong")
+@Produces(MediaType.APPLICATION_JSON)
+public class PokemongController extends GenericController {
+
+ @Inject
+ PokemongService pokemongService;
+
+ @PostConstruct
+ public void init() {
+ setService(pokemongService);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/controllers/TrainerController.java b/src/main/java/fr/uca/iut/controllers/TrainerController.java
new file mode 100644
index 0000000..da58bb3
--- /dev/null
+++ b/src/main/java/fr/uca/iut/controllers/TrainerController.java
@@ -0,0 +1,22 @@
+package fr.uca.iut.controllers;
+
+import fr.uca.iut.entities.Trainer;
+import fr.uca.iut.services.TrainerService;
+import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/trainer")
+@Produces(MediaType.APPLICATION_JSON)
+public class TrainerController extends GenericController {
+
+ @Inject
+ TrainerService trainerService;
+
+ @PostConstruct
+ public void init() {
+ setService(trainerService);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/entities/GenericEntity.java b/src/main/java/fr/uca/iut/entities/GenericEntity.java
index bcfbf04..f98460a 100644
--- a/src/main/java/fr/uca/iut/entities/GenericEntity.java
+++ b/src/main/java/fr/uca/iut/entities/GenericEntity.java
@@ -1,32 +1,32 @@
-package fr.uca.iut.entities;
-
-import org.bson.codecs.pojo.annotations.BsonId;
-
-import java.util.Objects;
-
-public abstract class GenericEntity {
-
- @BsonId
- private String id;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- GenericEntity entity = (GenericEntity) o;
- return Objects.equals(id, entity.id);
- }
-}
+package fr.uca.iut.entities;
+
+import org.bson.codecs.pojo.annotations.BsonId;
+
+import java.util.Objects;
+
+public abstract class GenericEntity {
+
+ @BsonId
+ private String id;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ GenericEntity entity = (GenericEntity) o;
+ return Objects.equals(id, entity.id);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/entities/Move.java b/src/main/java/fr/uca/iut/entities/Move.java
index d0dacc0..da98c37 100644
--- a/src/main/java/fr/uca/iut/entities/Move.java
+++ b/src/main/java/fr/uca/iut/entities/Move.java
@@ -1,65 +1,55 @@
-package fr.uca.iut.entities;
-
-import org.bson.codecs.pojo.annotations.BsonId;
-
-public class Move extends GenericEntity {
- public static final String COLLECTION_NAME = "moves";
-
- @BsonId
- private String id;
- private String name;
- private String category;
- private Integer power;
- private Integer accuracy;
- private Type type;
-
- public Move() {}
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getCategory() {
- return category;
- }
-
- public void setCategory(String category) {
- this.category = category;
- }
-
- public Integer getPower() {
- return power;
- }
-
- public void setPower(Integer power) {
- this.power = power;
- }
-
- public Integer getAccuracy() {
- return accuracy;
- }
-
- public void setAccuracy(Integer accuracy) {
- this.accuracy = accuracy;
- }
-
- public Type getType() {
- return type;
- }
-
- public void setType(Type type) {
- this.type = type;
- }
+package fr.uca.iut.entities;
+
+import fr.uca.iut.utils.enums.MoveCategoryName;
+
+public class Move extends GenericEntity {
+ public static final String COLLECTION_NAME = "moves";
+
+ private String name;
+ private MoveCategoryName category;
+ private Integer power;
+ private Integer accuracy;
+ private Type type;
+
+ public Move() {}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public MoveCategoryName getCategory() {
+ return category;
+ }
+
+ public void setCategory(MoveCategoryName category) {
+ this.category = category;
+ }
+
+ public Integer getPower() {
+ return power;
+ }
+
+ public void setPower(Integer power) {
+ this.power = power;
+ }
+
+ public Integer getAccuracy() {
+ return accuracy;
+ }
+
+ public void setAccuracy(Integer accuracy) {
+ this.accuracy = accuracy;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public void setType(Type type) {
+ this.type = type;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/fr/uca/iut/entities/Pokemong.java b/src/main/java/fr/uca/iut/entities/Pokemong.java
index d55deee..1acd9e4 100644
--- a/src/main/java/fr/uca/iut/entities/Pokemong.java
+++ b/src/main/java/fr/uca/iut/entities/Pokemong.java
@@ -1,119 +1,127 @@
-package fr.uca.iut.entities;
-
-import fr.uca.iut.utils.PokemongName;
-import org.bson.codecs.pojo.annotations.BsonId;
-import org.bson.types.ObjectId;
-
-import java.time.LocalDate;
-import java.util.List;
-
-public class Pokemong extends GenericEntity {
- public static final String COLLECTION_NAME = "pokemongs";
- @BsonId
- private String id;
- private String nickname;
- private LocalDate dob;
- private Integer level;
- private Integer pokedexId;
- private Integer evoStage;
- private List evoTrack;
- private Boolean isMegaEvolved;
- private ObjectId trainer;
- private List types; // TODO Bound this within [1;2] (in controller)
- private List moveSet; // TODO Bound this within [1;4] (in controller) and denormalize move "name"
-
- public Pokemong() {}
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getNickname() {
- return nickname;
- }
-
- public void setNickname(String nickname) {
- this.nickname = nickname;
- }
-
- public LocalDate getDob() {
- return dob;
- }
-
- public void setDob(LocalDate dob) {
- this.dob = dob;
- }
-
- public Integer getLevel() {
- return level;
- }
-
- public void setLevel(Integer level) {
- this.level = level;
- }
-
- public Integer getPokedexId() {
- return pokedexId;
- }
-
- public void setPokedexId(Integer pokedexId) {
- this.pokedexId = pokedexId;
- }
-
- public Integer getEvoStage() {
- return evoStage;
- }
-
- public void setEvoStage(Integer evoStage) {
- this.evoStage = evoStage;
- }
-
- public List getEvoTrack() {
- return evoTrack;
- }
-
- public void setEvoTrack(List evoTrack) {
- this.evoTrack = evoTrack;
- }
-
- public Boolean getMegaEvolved() {
- return isMegaEvolved;
- }
-
- public void setMegaEvolved(Boolean megaEvolved) {
- isMegaEvolved = megaEvolved;
- }
-
- public ObjectId getTrainer() {
- return trainer;
- }
-
- public void setTrainer(ObjectId trainer) {
- this.trainer = trainer;
- }
-
- // TODO take particular care with collections
-
- // TODO study the question of encapsulation when it comes to using these dependencies...
- public List getTypes() {
- return types;
- }
-
- public void setTypes(List types) {
- this.types = types;
- }
-
- public List getMoveSet() {
- return moveSet;
- }
-
- public void setMoveSet(List moveSet) {
- this.moveSet = moveSet;
- }
-
-}
-
+package fr.uca.iut.entities;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.utils.enums.PokemongName;
+
+import java.time.LocalDate;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class Pokemong extends GenericEntity {
+ public static final String COLLECTION_NAME = "pokemongs";
+
+ @Nullable
+ private String nickname;
+ private LocalDate dob;
+ private Integer level;
+ private Integer pokedexId;
+ private Integer evoStage;
+ private List evoTrack;
+ @Nullable
+ private String trainer;
+ private List types;
+
+ /**
+ * pokemong.moveSet: [{_id: ObjectId, name: String}]
+ */
+ private Set moveSet;
+
+ public Pokemong() {}
+
+ @Nullable
+ public String getNickname() {
+ return nickname;
+ }
+
+ public void setNickname(@Nullable String nickname) {
+ this.nickname = nickname;
+ }
+
+ public LocalDate getDob() {
+ return dob;
+ }
+
+ public void setDob(LocalDate dob) {
+ this.dob = dob;
+ }
+
+ public Integer getLevel() {
+ return level;
+ }
+
+ public void setLevel(Integer level) {
+ this.level = level;
+ }
+
+ public Integer getPokedexId() {
+ return pokedexId;
+ }
+
+ public void setPokedexId(Integer pokedexId) {
+ this.pokedexId = pokedexId;
+ }
+
+ @Nullable
+ public String getTrainer() {
+ return trainer;
+ }
+
+ public void setTrainer(@Nullable String trainer) {
+ this.trainer = trainer;
+ }
+
+ public List getTypes() {
+ return Collections.unmodifiableList(types);
+ }
+
+ public void setTypes(List types) {
+ this.types = types;
+ }
+
+ public Set getMoveSet() {
+ return Collections.unmodifiableSet(moveSet);
+ }
+
+ public void setMoveSet(Set moveSet) {
+ this.moveSet = moveSet;
+ }
+
+ public void removeMove(String id) {
+ PokemongMove pokemongMove = new PokemongMove();
+ pokemongMove.setId(id);
+ moveSet.remove(pokemongMove);
+ }
+
+ public void updateMove(String id, String name) {
+ for (PokemongMove move : moveSet) {
+ if (move.getId()
+ .equals(id))
+ {
+ move.setName(name);
+ break;
+ }
+ }
+ }
+
+ public PokemongName getSpecies() {
+ return getEvoTrack().get(getEvoStage());
+ }
+
+ public List getEvoTrack() {
+ return evoTrack;
+ }
+
+ public Integer getEvoStage() {
+ return evoStage;
+ }
+
+ public void setEvoStage(Integer evoStage) {
+ this.evoStage = evoStage;
+ }
+
+ public void setEvoTrack(List evoTrack) {
+ this.evoTrack = evoTrack;
+ }
+}
+
diff --git a/src/main/java/fr/uca/iut/entities/PokemongMove.java b/src/main/java/fr/uca/iut/entities/PokemongMove.java
new file mode 100644
index 0000000..13c4c31
--- /dev/null
+++ b/src/main/java/fr/uca/iut/entities/PokemongMove.java
@@ -0,0 +1,16 @@
+package fr.uca.iut.entities;
+
+public class PokemongMove extends GenericEntity {
+
+ private String name;
+
+ public PokemongMove() {}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/entities/Trainer.java b/src/main/java/fr/uca/iut/entities/Trainer.java
index 7b920e3..6586349 100644
--- a/src/main/java/fr/uca/iut/entities/Trainer.java
+++ b/src/main/java/fr/uca/iut/entities/Trainer.java
@@ -1,78 +1,66 @@
-package fr.uca.iut.entities;
-
-import org.bson.codecs.pojo.annotations.BsonId;
-import org.bson.types.ObjectId;
-
-import java.time.LocalDate;
-import java.util.List;
-
-public class Trainer extends GenericEntity {
- public static final String COLLECTION_NAME = "trainers";
-
- @BsonId
- private String id;
- private String name;
- private LocalDate dob;
- private Integer wins;
- private Integer losses;
- private List pastOpponents;
- private List pokemongs;
-
- public Trainer() {}
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public LocalDate getDob() {
- return dob;
- }
-
- public void setDob(LocalDate dob) {
- this.dob = dob;
- }
-
- public Integer getWins() {
- return wins;
- }
-
- public void setWins(Integer wins) {
- this.wins = wins;
- }
-
- public Integer getLosses() {
- return losses;
- }
-
- public void setLosses(Integer losses) {
- this.losses = losses;
- }
-
- public List getPastOpponents() {
- return pastOpponents;
- }
-
- public void setPastOpponents(List pastOpponents) {
- this.pastOpponents = pastOpponents;
- }
-
- public List getPokemongs() {
- return pokemongs;
- }
-
- public void setPokemongs(List pokemongs) {
- this.pokemongs = pokemongs;
- }
-}
+package fr.uca.iut.entities;
+
+import java.time.LocalDate;
+import java.util.Collections;
+import java.util.List;
+
+public class Trainer extends GenericEntity {
+ public static final String COLLECTION_NAME = "trainers";
+
+ private String name;
+ private LocalDate dob;
+ private Integer wins;
+ private Integer losses;
+ private List pastOpponents;
+ private List pokemongs;
+
+ public Trainer() {}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public LocalDate getDob() {
+ return dob;
+ }
+
+ public void setDob(LocalDate dob) {
+ this.dob = dob;
+ }
+
+ public Integer getWins() {
+ return wins;
+ }
+
+ public void setWins(Integer wins) {
+ this.wins = wins;
+ }
+
+ public Integer getLosses() {
+ return losses;
+ }
+
+ public void setLosses(Integer losses) {
+ this.losses = losses;
+ }
+
+ public List getPastOpponents() {
+ return Collections.unmodifiableList(pastOpponents);
+ }
+
+ public void setPastOpponents(List pastOpponents) {
+ this.pastOpponents = pastOpponents;
+ }
+
+ public List getPokemongs() {
+ return Collections.unmodifiableList(pokemongs);
+ }
+
+ public void setPokemongs(List pokemongs) {
+ this.pokemongs = pokemongs;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/entities/TrainerPokemong.java b/src/main/java/fr/uca/iut/entities/TrainerPokemong.java
new file mode 100644
index 0000000..f63fcb5
--- /dev/null
+++ b/src/main/java/fr/uca/iut/entities/TrainerPokemong.java
@@ -0,0 +1,30 @@
+package fr.uca.iut.entities;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.utils.enums.PokemongName;
+
+public class TrainerPokemong extends GenericEntity {
+ @Nullable
+ private String nickname;
+
+ private PokemongName species;
+
+ public TrainerPokemong() {}
+
+ @Nullable
+ public String getNickname() {
+ return nickname;
+ }
+
+ public void setNickname(@Nullable String nickname) {
+ this.nickname = nickname;
+ }
+
+ public PokemongName getSpecies() {
+ return species;
+ }
+
+ public void setSpecies(PokemongName species) {
+ this.species = species;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/entities/Type.java b/src/main/java/fr/uca/iut/entities/Type.java
index 6eb5756..f9e3022 100644
--- a/src/main/java/fr/uca/iut/entities/Type.java
+++ b/src/main/java/fr/uca/iut/entities/Type.java
@@ -1,55 +1,56 @@
-package fr.uca.iut.entities;
-
-import fr.uca.iut.utils.TypeName;
-
-import java.util.List;
-import java.util.Objects;
-
-public class Type {
-
- private TypeName name;
- private List weakAgainst;
- private List effectiveAgainst;
-
- public Type() {}
-
- public TypeName getName() {
- return name;
- }
-
- public void setName(TypeName name) {
- this.name = name;
- }
-
- public List getWeakAgainst() {
- return weakAgainst;
- }
-
- public void setWeakAgainst(List weakAgainst) {
- this.weakAgainst = weakAgainst;
- }
-
- public List getEffectiveAgainst() {
- return effectiveAgainst;
- }
-
- public void setEffectiveAgainst(List effectiveAgainst) {
- this.effectiveAgainst = effectiveAgainst;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, weakAgainst, effectiveAgainst);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Type type = (Type) o;
- return Objects.equals(name, type.name) &&
- Objects.equals(weakAgainst, type.weakAgainst) &&
- Objects.equals(effectiveAgainst, type.effectiveAgainst);
- }
-
+package fr.uca.iut.entities;
+
+import fr.uca.iut.utils.enums.TypeName;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+public class Type {
+
+ private TypeName name;
+ private List weakAgainst;
+ private List effectiveAgainst;
+
+ public Type() {}
+
+ public TypeName getName() {
+ return name;
+ }
+
+ public void setName(TypeName name) {
+ this.name = name;
+ }
+
+ public List getWeakAgainst() {
+ return Collections.unmodifiableList(weakAgainst);
+ }
+
+ public void setWeakAgainst(List weakAgainst) {
+ this.weakAgainst = weakAgainst;
+ }
+
+ public List getEffectiveAgainst() {
+ return Collections.unmodifiableList(effectiveAgainst);
+ }
+
+ public void setEffectiveAgainst(List effectiveAgainst) {
+ this.effectiveAgainst = effectiveAgainst;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, weakAgainst, effectiveAgainst);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Type type = (Type) o;
+ return Objects.equals(name, type.name) &&
+ Objects.equals(weakAgainst, type.weakAgainst) &&
+ Objects.equals(effectiveAgainst, type.effectiveAgainst);
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/fr/uca/iut/package-info.java b/src/main/java/fr/uca/iut/package-info.java
new file mode 100644
index 0000000..3d301f9
--- /dev/null
+++ b/src/main/java/fr/uca/iut/package-info.java
@@ -0,0 +1,4 @@
+@NonNullApi
+package fr.uca.iut;
+
+import com.mongodb.lang.NonNullApi;
diff --git a/src/main/java/fr/uca/iut/repositories/GenericRepository.java b/src/main/java/fr/uca/iut/repositories/GenericRepository.java
new file mode 100644
index 0000000..649e2a4
--- /dev/null
+++ b/src/main/java/fr/uca/iut/repositories/GenericRepository.java
@@ -0,0 +1,60 @@
+package fr.uca.iut.repositories;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.model.ReplaceOptions;
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.GenericEntity;
+import org.bson.Document;
+import org.bson.types.ObjectId;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.mongodb.client.model.Filters.eq;
+
+public abstract class GenericRepository {
+ protected MongoClient mongoClient;
+ @ConfigProperty(name = "quarkus.mongodb.database")
+ String DB_NAME;
+
+ public void setMongoClient(MongoClient mongoClient) {
+ this.mongoClient = mongoClient;
+ }
+
+ @Nullable
+ public T findById(String id) {
+ return getCollection().find(eq("_id", new ObjectId(id)))
+ .first();
+ }
+
+ protected abstract MongoCollection getCollection();
+
+ public void persist(@NotNull T entity) {
+ getCollection().insertOne(entity);
+ }
+
+ public List listAll() {
+ return getCollection().find()
+ .into(new ArrayList<>());
+ }
+
+ public void persistOrUpdate(@NotNull T entity) {
+ getCollection().replaceOne(
+ eq("_id", new ObjectId(entity.getId())),
+ entity,
+ new ReplaceOptions().upsert(true)
+ );
+ }
+
+ public void delete(@NotNull T entity) {
+ getCollection().deleteOne(eq("_id", new ObjectId(entity.getId())));
+ }
+
+ public boolean existsById(String id) {
+ Document query = new Document("_id", new ObjectId(id));
+ return getCollection().countDocuments(query) > 0;
+ }
+}
diff --git a/src/main/java/fr/uca/iut/repositories/MoveRepository.java b/src/main/java/fr/uca/iut/repositories/MoveRepository.java
new file mode 100644
index 0000000..0226f04
--- /dev/null
+++ b/src/main/java/fr/uca/iut/repositories/MoveRepository.java
@@ -0,0 +1,32 @@
+package fr.uca.iut.repositories;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import fr.uca.iut.entities.Move;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+@ApplicationScoped
+public class MoveRepository extends GenericRepository {
+
+ // FIX?ME
+ /**
+ * Warns that "Unsatisfied dependency: no bean matches the injection point"
+ * but the app works
+ */
+ @Inject
+ MongoClient mongoClient;
+
+ @PostConstruct
+ public void init() {
+ setMongoClient(mongoClient);
+ }
+
+ @Override
+ protected MongoCollection getCollection() {
+ MongoDatabase db = mongoClient.getDatabase(DB_NAME);
+ return db.getCollection(Move.COLLECTION_NAME, Move.class);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/repositories/PokemongRepository.java b/src/main/java/fr/uca/iut/repositories/PokemongRepository.java
index f60ec5d..3da2595 100644
--- a/src/main/java/fr/uca/iut/repositories/PokemongRepository.java
+++ b/src/main/java/fr/uca/iut/repositories/PokemongRepository.java
@@ -1,58 +1,45 @@
-package fr.uca.iut.repositories;
-
-import com.mongodb.client.MongoClient;
-import com.mongodb.client.MongoCollection;
-import com.mongodb.client.MongoDatabase;
-import com.mongodb.client.model.ReplaceOptions;
-import fr.uca.iut.entities.Pokemong;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import org.bson.types.ObjectId;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.mongodb.client.model.Filters.eq;
-
-@ApplicationScoped
-public class PokemongRepository {
-
- // FIXME? or suppress warning: "Unsatisfied dependency: no bean matches the injection point"
- @Inject
- MongoClient mongoClient;
-
- @ConfigProperty(name = "quarkus.mongodb.database")
- String DB_NAME;
-
- private MongoCollection getCollection() {
- MongoDatabase db = mongoClient.getDatabase(DB_NAME);
- return db.getCollection(Pokemong.COLLECTION_NAME, Pokemong.class);
- }
-
- public Pokemong findById(String id) {
- return getCollection().find(eq("_id", new ObjectId(id)))
- .first();
- }
-
- public void persist(Pokemong pokemong) {
- getCollection().insertOne(pokemong);
- }
-
- public List listAll() {
- return getCollection().find()
- .into(new ArrayList<>());
- }
-
- public void delete(Pokemong pokemong) {
- getCollection().deleteOne(eq("_id", new ObjectId(pokemong.getId())));
- }
-
- public void persistOrUpdate(Pokemong pokemong) {
- getCollection().replaceOne(
- eq("_id", new ObjectId(pokemong.getId())),
- pokemong,
- new ReplaceOptions().upsert(true)
- );
- }
-}
+package fr.uca.iut.repositories;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.Filters;
+import fr.uca.iut.entities.Pokemong;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.bson.conversions.Bson;
+import org.bson.types.ObjectId;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ApplicationScoped
+public class PokemongRepository extends GenericRepository {
+
+ // FIX?ME
+ /**
+ * Warns that "Unsatisfied dependency: no bean matches the injection point"
+ * but the app works
+ */
+ @Inject
+ MongoClient mongoClient;
+
+ @PostConstruct
+ public void init() {
+ setMongoClient(mongoClient);
+ }
+
+ public List findByMove(String moveId) {
+ Bson filter = Filters.elemMatch("moveSet", Filters.eq("_id", new ObjectId(moveId)));
+ return getCollection().find(filter)
+ .into(new ArrayList<>());
+ }
+
+ @Override
+ protected MongoCollection getCollection() {
+ MongoDatabase db = mongoClient.getDatabase(DB_NAME);
+ return db.getCollection(Pokemong.COLLECTION_NAME, Pokemong.class);
+ }
+
+}
diff --git a/src/main/java/fr/uca/iut/repositories/TrainerRepository.java b/src/main/java/fr/uca/iut/repositories/TrainerRepository.java
new file mode 100644
index 0000000..35ff7ed
--- /dev/null
+++ b/src/main/java/fr/uca/iut/repositories/TrainerRepository.java
@@ -0,0 +1,32 @@
+package fr.uca.iut.repositories;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import fr.uca.iut.entities.Trainer;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+@ApplicationScoped
+public class TrainerRepository extends GenericRepository {
+
+ // FIX?ME
+ /**
+ * Warns that "Unsatisfied dependency: no bean matches the injection point"
+ * but the app works
+ */
+ @Inject
+ MongoClient mongoClient;
+
+ @PostConstruct
+ public void init() {
+ setMongoClient(mongoClient);
+ }
+
+ @Override
+ protected MongoCollection getCollection() {
+ MongoDatabase db = mongoClient.getDatabase(DB_NAME);
+ return db.getCollection(Trainer.COLLECTION_NAME, Trainer.class);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/services/GenericService.java b/src/main/java/fr/uca/iut/services/GenericService.java
new file mode 100644
index 0000000..3bd1435
--- /dev/null
+++ b/src/main/java/fr/uca/iut/services/GenericService.java
@@ -0,0 +1,51 @@
+package fr.uca.iut.services;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.GenericEntity;
+import fr.uca.iut.repositories.GenericRepository;
+import fr.uca.iut.utils.exceptions.NonValidEntityException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public abstract class GenericService {
+
+ protected GenericRepository repository;
+
+ public void setRepository(GenericRepository repository) {
+ this.repository = repository;
+ }
+
+ public T addOne(@NotNull T entity) {
+ repository.persist(entity);
+ return entity;
+ }
+
+ @Nullable
+ public T getOneById(String id) {
+ return repository.findById(id);
+ }
+
+ public List getAll() {
+ return repository.listAll();
+ }
+
+ public void deleteOneById(String id) {
+ T entity = repository.findById(id);
+ if (entity != null) {
+ repository.delete(entity);
+ }
+ }
+
+ @Nullable
+ public abstract T updateOne(@NotNull T entity);
+
+ /**
+ * Override me and start with `super.validateOne(entity);`
+ */
+ public void validateOne(T entity) {
+ if (entity == null) {
+ throw new NonValidEntityException("entity was null");
+ }
+ }
+}
diff --git a/src/main/java/fr/uca/iut/services/MoveService.java b/src/main/java/fr/uca/iut/services/MoveService.java
new file mode 100644
index 0000000..ed30c0e
--- /dev/null
+++ b/src/main/java/fr/uca/iut/services/MoveService.java
@@ -0,0 +1,100 @@
+package fr.uca.iut.services;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.Move;
+import fr.uca.iut.entities.Pokemong;
+import fr.uca.iut.repositories.MoveRepository;
+import fr.uca.iut.utils.StringUtils;
+import fr.uca.iut.utils.exceptions.NonValidEntityException;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ApplicationScoped
+public class MoveService extends GenericService {
+
+ @Inject
+ MoveRepository moveRepository;
+ @Inject
+ PokemongService pokemongService;
+
+ @PostConstruct
+ public void init() {
+ setRepository(moveRepository);
+ }
+
+ @Override
+ public void deleteOneById(String id) {
+ super.deleteOneById(id);
+ List pokemongs = pokemongService.findByMove(id);
+ for (Pokemong pokemong : pokemongs) {
+ pokemong.removeMove(id);
+ pokemongService.updateOne(pokemong);
+ }
+ }
+
+ @Override
+ @Nullable
+ public Move updateOne(@NotNull Move move) {
+ Move existingMove = moveRepository.findById(move.getId());
+ if (existingMove != null) {
+ if (!existingMove.getName()
+ .equals(move.getName()))
+ {
+ existingMove.setName(move.getName());
+ List pokemongs = pokemongService.findByMove(move.getId());
+ for (Pokemong pokemong : pokemongs) {
+ pokemong.updateMove(move.getId(), move.getName());
+ pokemongService.updateOne(pokemong);
+ }
+ }
+
+ existingMove.setPower(move.getPower());
+ existingMove.setCategory(move.getCategory());
+ existingMove.setAccuracy(move.getAccuracy());
+ existingMove.setType(move.getType());
+ moveRepository.persistOrUpdate(existingMove);
+ }
+ return existingMove;
+ }
+
+ @Override
+ public void validateOne(Move move) {
+
+ super.validateOne(move);
+
+ List errors = new ArrayList<>();
+
+ if (StringUtils.isBlankStringOrNull(move.getName())) {
+ errors.add("move name was null, blank or empty");
+ }
+
+ if (move.getPower() == null || move.getPower() < 0) {
+ errors.add("move power was null or negative");
+ }
+
+ if (move.getCategory() == null) {
+ errors.add("move category was null or invalid");
+ }
+
+ if (move.getAccuracy() == null || move.getAccuracy() < 0) {
+ errors.add("move accuracy was null or negative");
+ }
+
+ if (move.getType() == null) {
+ errors.add("move type was null or invalid");
+ }
+
+ if (!errors.isEmpty()) {
+ throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
+ }
+ }
+
+ public boolean existsById(String moveId) {
+ return moveRepository.existsById(moveId);
+ }
+}
diff --git a/src/main/java/fr/uca/iut/services/PokemongService.java b/src/main/java/fr/uca/iut/services/PokemongService.java
index b7d47a5..ae9afd9 100644
--- a/src/main/java/fr/uca/iut/services/PokemongService.java
+++ b/src/main/java/fr/uca/iut/services/PokemongService.java
@@ -1,65 +1,202 @@
-package fr.uca.iut.services;
-
-import fr.uca.iut.entities.Pokemong;
-import fr.uca.iut.repositories.PokemongRepository;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-
-import java.util.List;
-
-@ApplicationScoped
-public class PokemongService {
-
- @Inject
- PokemongRepository pokemongRepository;
-
- public Pokemong addPokemong(Pokemong pokemong) {
- pokemongRepository.persist(pokemong);
- return pokemong;
- }
-
- public Pokemong getPokemong(String id) {
- return pokemongRepository.findById(id);
- }
-
- public List getAllPokemongs() {
- return pokemongRepository.listAll();
- }
-
- public void deletePokemong(String id) {
- Pokemong pokemong = pokemongRepository.findById(id);
- if (pokemong != null) {
- pokemongRepository.delete(pokemong);
- }
- }
-
- public Pokemong updatePokemong(Pokemong pokemong) {
- Pokemong existingPokemong = pokemongRepository.findById(pokemong.getId());
- if (existingPokemong != null) {
- existingPokemong.setNickname(pokemong.getNickname());
- existingPokemong.setDob(pokemong.getDob());
- existingPokemong.setLevel(pokemong.getLevel());
- existingPokemong.setPokedexId(pokemong.getPokedexId());
- existingPokemong.setEvoStage(pokemong.getEvoStage());
- existingPokemong.setEvoTrack(pokemong.getEvoTrack());
- existingPokemong.setMegaEvolved(pokemong.getMegaEvolved());
- existingPokemong.setTrainer(pokemong.getTrainer());
- existingPokemong.setTypes(pokemong.getTypes());
- existingPokemong.setMoveSet(pokemong.getMoveSet());
- pokemongRepository.persistOrUpdate(existingPokemong);
- }
- return existingPokemong;
- }
-
- public boolean isNotMature(Pokemong pokemong) {
- return pokemong == null
- || pokemong.getEvoStage() == null
- || pokemong.getEvoTrack() == null
- || pokemong.getEvoTrack()
- .isEmpty()
- || (pokemong.getEvoStage() != pokemong.getEvoTrack()
- .size() - 1);
- }
-
- // TODO PATCH ?
-}
+package fr.uca.iut.services;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.*;
+import fr.uca.iut.repositories.PokemongRepository;
+import fr.uca.iut.utils.StringUtils;
+import fr.uca.iut.utils.enums.PokemongName;
+import fr.uca.iut.utils.exceptions.NonValidEntityException;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+@ApplicationScoped
+public class PokemongService extends GenericService {
+
+ @Inject
+ PokemongRepository pokemongRepository;
+
+ @Inject
+ MoveService moveService;
+
+ @Inject
+ TrainerService trainerService;
+
+ @PostConstruct
+ public void init() {
+ setRepository(pokemongRepository);
+ }
+
+ @Override
+ public Pokemong addOne(@NotNull Pokemong pokemong) {
+ Pokemong persistedPokemong = super.addOne(pokemong);
+
+ Trainer trainer = trainerService.getOneById(pokemong.getTrainer());
+ if (trainer != null) {
+ TrainerPokemong trainerPokemong = new TrainerPokemong();
+ trainerPokemong.setId(pokemong.getId());
+ trainerPokemong.setNickname(pokemong.getNickname());
+ trainerPokemong.setSpecies(pokemong.getSpecies());
+ trainer.getPokemongs()
+ .add(trainerPokemong);
+ trainerService.updateOne(trainer);
+ }
+ return persistedPokemong;
+ }
+
+ @Override
+ public void deleteOneById(String id) {
+ Pokemong pokemong = getOneById(id);
+ if (pokemong != null && pokemong.getTrainer() != null) {
+ Trainer trainer = trainerService.getOneById(pokemong.getTrainer());
+ if (trainer != null) {
+ trainer.getPokemongs()
+ .removeIf(trainerPokemong -> trainerPokemong.getId()
+ .equals(id));
+ trainerService.updateOne(trainer);
+ }
+ }
+ super.deleteOneById(id);
+ }
+
+ @Override
+ @Nullable
+ public Pokemong updateOne(@NotNull Pokemong pokemong) {
+ Pokemong existingPokemong = pokemongRepository.findById(pokemong.getId());
+ if (existingPokemong != null) {
+ boolean nicknameChanged = !Objects.equals(existingPokemong.getNickname(), pokemong.getNickname());
+ boolean evoStageChanged = !Objects.equals(existingPokemong.getEvoStage(), pokemong.getEvoStage());
+ boolean evoTrackChanged = !Objects.equals(existingPokemong.getEvoTrack(), pokemong.getEvoTrack());
+
+ existingPokemong.setNickname(pokemong.getNickname());
+ existingPokemong.setDob(pokemong.getDob());
+ existingPokemong.setLevel(pokemong.getLevel());
+ existingPokemong.setPokedexId(pokemong.getPokedexId());
+ existingPokemong.setEvoStage(pokemong.getEvoStage());
+ existingPokemong.setEvoTrack(pokemong.getEvoTrack());
+ existingPokemong.setTrainer(pokemong.getTrainer());
+ existingPokemong.setTypes(pokemong.getTypes());
+ existingPokemong.setMoveSet(pokemong.getMoveSet());
+
+ pokemongRepository.persistOrUpdate(existingPokemong);
+
+ if (nicknameChanged || evoStageChanged || evoTrackChanged) {
+ Trainer trainer = trainerService.getOneById(existingPokemong.getTrainer());
+ if (trainer != null) {
+ TrainerPokemong trainerPokemong = trainer.getPokemongs()
+ .stream()
+ .filter(tp -> tp.getId()
+ .equals(existingPokemong.getId()))
+ .findFirst()
+ .orElse(null);
+
+ if (trainerPokemong != null) {
+ if (nicknameChanged) {
+ trainerPokemong.setNickname(existingPokemong.getNickname());
+ }
+
+ if (evoStageChanged || evoTrackChanged) {
+ trainerPokemong.setSpecies(existingPokemong.getSpecies());
+ }
+
+ trainerService.updateOne(trainer);
+ }
+ }
+ }
+ }
+ return existingPokemong;
+ }
+
+ @Override
+ public void validateOne(Pokemong pokemong) {
+
+ super.validateOne(pokemong);
+
+ List errors = new ArrayList<>();
+
+ if (pokemong.getDob() == null) {
+ errors.add("pokemong date of birth was null or invalid");
+ }
+
+ if (pokemong.getLevel() == null || pokemong.getLevel() < 1) {
+ errors.add("pokemong level was null or less than 1");
+ }
+
+ if (pokemong.getPokedexId() == null || pokemong.getPokedexId() < 1) {
+ errors.add("pokemong pokedex id was null or less than 1");
+ }
+
+ if (pokemong.getEvoStage() == null || pokemong.getEvoStage() < 0) {
+ errors.add("pokemong evo stage was null or negative");
+ }
+
+ if (pokemong.getEvoTrack() == null) {
+ errors.add("pokemong evo track was null or invalid");
+ }
+
+ List types = pokemong.getTypes();
+ if (types == null
+ || types.size() == 0
+ || types.size() > 2)
+ {
+ errors.add("pokemong types was null or empty or had more than 2 types");
+ }
+
+ Set moveSet = pokemong.getMoveSet();
+ if (moveSet == null) {
+ errors.add("pokemong move set was null");
+ }
+ else {
+ if (moveSet.size() == 0 || moveSet.size() > 4) {
+ errors.add("pokemong move set was empty or had more than 4 moves");
+ }
+ for (PokemongMove move : moveSet) {
+ String moveId = move.getId();
+ String moveName = move.getName();
+ if (StringUtils.isBlankStringOrNull(moveId) || !moveService.existsById(moveId)) {
+ errors.add("move with id " + moveId + " does not exist");
+ }
+ if (StringUtils.isBlankStringOrNull(moveName)) {
+ errors.add("move name was null, blank or empty");
+ }
+ // We don't check whether the move name is consistent with the original -- trainers can rename moves
+ // locally in a pokemong. If once in a while a Move has its name updated, the change will be reflected
+ // in all the PokemongMoves, and the local aliases will be lost
+ }
+ }
+
+ if (!errors.isEmpty()) {
+ throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
+ }
+ }
+
+ public List findByMove(String id) {
+ return pokemongRepository.findByMove(id);
+ }
+
+ public boolean isEvoValid(String id, PokemongName species) {
+ Pokemong pokemong = pokemongRepository.findById(id);
+
+ return pokemong != null && pokemong.getSpecies() == species;
+ }
+
+ public boolean existsById(String pokemongId) {
+ return repository.existsById(pokemongId);
+ }
+
+ public void batchUpdatePokemongTrainers(List trainerPokemongs, @Nullable String trainerId) {
+ for (TrainerPokemong trainerPokemong : trainerPokemongs) {
+ Pokemong pokemong = getOneById(trainerPokemong.getId());
+ if (pokemong != null) {
+ pokemong.setTrainer(trainerId);
+ updateOne(pokemong);
+ }
+ }
+ }
+}
diff --git a/src/main/java/fr/uca/iut/services/TrainerService.java b/src/main/java/fr/uca/iut/services/TrainerService.java
new file mode 100644
index 0000000..65d8a88
--- /dev/null
+++ b/src/main/java/fr/uca/iut/services/TrainerService.java
@@ -0,0 +1,136 @@
+package fr.uca.iut.services;
+
+import com.mongodb.lang.Nullable;
+import fr.uca.iut.entities.Pokemong;
+import fr.uca.iut.entities.Trainer;
+import fr.uca.iut.entities.TrainerPokemong;
+import fr.uca.iut.repositories.TrainerRepository;
+import fr.uca.iut.utils.StringUtils;
+import fr.uca.iut.utils.exceptions.NonValidEntityException;
+import jakarta.annotation.PostConstruct;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@ApplicationScoped
+public class TrainerService extends GenericService {
+
+ @Inject
+ TrainerRepository trainerRepository;
+
+ @Inject
+ PokemongService pokemongService;
+
+ @PostConstruct
+ public void init() {
+ setRepository(trainerRepository);
+ }
+
+ @Override
+ public Trainer addOne(@NotNull Trainer trainer) {
+ Trainer persistedTrainer = super.addOne(trainer);
+
+ pokemongService.batchUpdatePokemongTrainers(trainer.getPokemongs(), trainer.getId());
+
+ return persistedTrainer;
+ }
+
+ @Override
+ public void deleteOneById(String id) {
+ Trainer trainer = getOneById(id);
+
+ if (trainer != null) {
+ pokemongService.batchUpdatePokemongTrainers(trainer.getPokemongs(), null);
+ }
+
+ super.deleteOneById(id);
+ }
+
+ @Nullable
+ @Override
+ public Trainer updateOne(@NotNull Trainer trainer) {
+ Trainer existingTrainer = trainerRepository.findById(trainer.getId());
+ if (existingTrainer != null) {
+ existingTrainer.setName(trainer.getName());
+ existingTrainer.setDob(trainer.getDob());
+ existingTrainer.setWins(trainer.getLosses());
+ existingTrainer.setLosses(trainer.getLosses());
+ existingTrainer.setPastOpponents(trainer.getPastOpponents());
+ existingTrainer.setPokemongs(trainer.getPokemongs());
+ trainerRepository.persistOrUpdate(existingTrainer);
+ }
+ return existingTrainer;
+ }
+
+ @Override
+ public void validateOne(Trainer trainer) {
+
+ super.validateOne(trainer);
+
+ List errors = new ArrayList<>();
+
+ if (StringUtils.isBlankStringOrNull(trainer.getName())) {
+ errors.add("trainer name was null, blank or empty");
+ }
+
+ if (trainer.getDob() == null) {
+ errors.add("trainer date of birth was null or invalid");
+ }
+
+ if (trainer.getLosses() == null || trainer.getLosses() < 0) {
+ errors.add("trainer losses was null or negative");
+ }
+
+ if (trainer.getWins() == null || trainer.getWins() < 0) {
+ errors.add("trainer wins was null or negative");
+ }
+
+ List pastOpponents = trainer.getPastOpponents();
+
+ if (pastOpponents == null) {
+ errors.add("trainer past opponents collection was null");
+ }
+ else {
+ for (String trainerId : pastOpponents) {
+ if (StringUtils.isBlankStringOrNull(trainerId) || !trainerRepository.existsById(trainerId)) {
+ errors.add("trainer past opponents collection contained an invalid or unknown id");
+ }
+ }
+ }
+
+ List pokemongs = trainer.getPokemongs();
+
+ if (pokemongs == null) {
+ errors.add("trainer pokemongs collection was null or invalid");
+ }
+ else {
+ for (TrainerPokemong pokemong : pokemongs) {
+ String pokemongId = pokemong.getId();
+ if (StringUtils.isBlankStringOrNull(pokemongId) || !pokemongService.existsById(pokemongId)) {
+ errors.add("pokemong with id " + pokemongId + " does not exist");
+ }
+ else {
+ if (!pokemongService.isEvoValid(pokemongId, pokemong.getSpecies())) {
+ errors.add("pokemong with id " + pokemongId + " cannot be a " +
+ pokemong.getSpecies());
+ }
+ Pokemong pokemongBehind = pokemongService.getOneById(pokemongId);
+ if (pokemong.getNickname() != null
+ && pokemongBehind != null
+ && !pokemong.getNickname()
+ .equals(pokemongBehind.getNickname()))
+ {
+ errors.add("pokemong with id " + pokemongId + " already has a nickname");
+ }
+ }
+ }
+ }
+
+ if (!errors.isEmpty()) {
+ throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
+ }
+ }
+}
diff --git a/src/main/java/fr/uca/iut/utils/StringUtils.java b/src/main/java/fr/uca/iut/utils/StringUtils.java
new file mode 100644
index 0000000..453af77
--- /dev/null
+++ b/src/main/java/fr/uca/iut/utils/StringUtils.java
@@ -0,0 +1,7 @@
+package fr.uca.iut.utils;
+
+public class StringUtils {
+ public static boolean isBlankStringOrNull(String string) {
+ return string == null || string.isBlank();
+ }
+}
diff --git a/src/main/java/fr/uca/iut/utils/enums/MoveCategoryName.java b/src/main/java/fr/uca/iut/utils/enums/MoveCategoryName.java
new file mode 100644
index 0000000..dd1466c
--- /dev/null
+++ b/src/main/java/fr/uca/iut/utils/enums/MoveCategoryName.java
@@ -0,0 +1,7 @@
+package fr.uca.iut.utils.enums;
+
+public enum MoveCategoryName {
+ PHYSICAL,
+ SPECIAL,
+ STATUS
+}
diff --git a/src/main/java/fr/uca/iut/utils/PokemongName.java b/src/main/java/fr/uca/iut/utils/enums/PokemongName.java
similarity index 99%
rename from src/main/java/fr/uca/iut/utils/PokemongName.java
rename to src/main/java/fr/uca/iut/utils/enums/PokemongName.java
index dcd0723..a6296c0 100644
--- a/src/main/java/fr/uca/iut/utils/PokemongName.java
+++ b/src/main/java/fr/uca/iut/utils/enums/PokemongName.java
@@ -1,4 +1,4 @@
-package fr.uca.iut.utils;
+package fr.uca.iut.utils.enums;
public enum PokemongName {
BULBASAUR,
diff --git a/src/main/java/fr/uca/iut/utils/TypeName.java b/src/main/java/fr/uca/iut/utils/enums/TypeName.java
similarity index 87%
rename from src/main/java/fr/uca/iut/utils/TypeName.java
rename to src/main/java/fr/uca/iut/utils/enums/TypeName.java
index 3383d2d..757b1c6 100644
--- a/src/main/java/fr/uca/iut/utils/TypeName.java
+++ b/src/main/java/fr/uca/iut/utils/enums/TypeName.java
@@ -1,4 +1,4 @@
-package fr.uca.iut.utils;
+package fr.uca.iut.utils.enums;
public enum TypeName {
NORMAL,
diff --git a/src/main/java/fr/uca/iut/utils/exceptions/NonValidEntityException.java b/src/main/java/fr/uca/iut/utils/exceptions/NonValidEntityException.java
new file mode 100644
index 0000000..2d0bf42
--- /dev/null
+++ b/src/main/java/fr/uca/iut/utils/exceptions/NonValidEntityException.java
@@ -0,0 +1,7 @@
+package fr.uca.iut.utils.exceptions;
+
+public class NonValidEntityException extends RuntimeException {
+ public NonValidEntityException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/META-INF/openapi.yaml b/src/main/resources/META-INF/openapi.yaml
new file mode 100644
index 0000000..b3192f0
--- /dev/null
+++ b/src/main/resources/META-INF/openapi.yaml
@@ -0,0 +1,1748 @@
+openapi: "3.0.3"
+info:
+ title: "Pokemong API"
+ description: "Pokemong API"
+ version: "1.0.0"
+servers:
+ - url: "http://localhost:8080"
+
+paths:
+
+ /pokemong/{id}:
+
+ get:
+ summary: Get a Pokemong by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the Pokemong
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pokemong'
+ '400':
+ description: Invalid ID format
+ '404':
+ description: Entity not found for given ID
+
+ put:
+ summary: Update a Pokemong by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the Pokemong
+ schema:
+ type: string
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pokemong'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pokemong'
+ '400':
+ description: Invalid ID format or Non-valid entity
+ '404':
+ description: Entity not found for given ID
+
+ delete:
+ summary: Delete a Pokemong by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the Pokemong
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ '400':
+ description: Invalid ID format
+
+ /pokemong:
+
+ get:
+ summary: Get all Pokemongs
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pokemong'
+
+ post:
+ summary: Create a new Pokemong
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pokemong'
+ responses:
+ '201':
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pokemong'
+ '400':
+ description: Non-valid entity
+
+ /move/{id}:
+
+ get:
+ summary: Get a move by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the move
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Move'
+ '400':
+ description: Invalid ID format
+ '404':
+ description: Entity not found for given ID
+
+ put:
+ summary: Update a move by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the move
+ schema:
+ type: string
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Move'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Move'
+ '400':
+ description: Invalid ID format or Non-valid entity
+ '404':
+ description: Entity not found for given ID
+
+ delete:
+ summary: Delete a move by ID
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The ID of the move
+ schema:
+ type: string
+ responses:
+ '200':
+ description: OK
+ '400':
+ description: Invalid ID format
+
+ /move:
+
+ get:
+ summary: Get all moves
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Move'
+
+ post:
+ summary: Create a new move
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Move'
+ responses:
+ '201':
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Move'
+ '400':
+ description: Non-valid entity
+
+ /trainer:
+
+ get:
+ summary: Returns a list of all trainers
+ responses:
+ '200':
+ description: A list of trainers
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Trainer'
+
+ post:
+ summary: Creates a new trainer
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Trainer'
+ responses:
+ '201':
+ description: The created trainer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Trainer'
+ '400':
+ description: Bad request - invalid trainer data
+
+ /trainer/{id}:
+
+ get:
+ summary: Returns a trainer by ID
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: A single trainer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Trainer'
+ '404':
+ description: Trainer not found
+
+ put:
+ summary: Updates a trainer by ID
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Trainer'
+ responses:
+ '200':
+ description: The updated trainer
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Trainer'
+ '400':
+ description: Bad request - invalid trainer data
+ '404':
+ description: Trainer not found
+
+ delete:
+ summary: Deletes a trainer by ID
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Trainer successfully deleted
+ '400':
+ description: Bad request - invalid trainer ID
+ '404':
+ description: Trainer not found
+
+components:
+
+ schemas:
+
+ Pokemong:
+ type: object
+ required:
+ - dob
+ - level
+ - pokedexId
+ - evoStage
+ - evoTrack
+ - types
+ - moveSet
+ properties:
+ nickname:
+ type: string
+ nullable: true
+ dob:
+ type: string
+ format: date
+ level:
+ type: integer
+ minimum: 1
+ pokedexId:
+ type: integer
+ minimum: 1
+ evoStage:
+ type: integer
+ minimum: 0
+ evoTrack:
+ type: array
+ minItems: 1
+ items:
+ $ref: '#/components/schemas/PokemongName'
+ trainer:
+ type: string
+ description: MongoDB ObjectId referencing a document in a collection
+ nullable: true
+ types:
+ type: array
+ minItems: 1
+ maxItems: 2
+ items:
+ $ref: '#/components/schemas/TypeName'
+ moveSet:
+ type: array
+ minItems: 1
+ maxItems: 4
+ items:
+ $ref: '#/components/schemas/PokemongMove'
+
+ Move:
+ type: object
+ required:
+ - name
+ - power
+ - category
+ - accuracy
+ - type
+ properties:
+ name:
+ type: string
+ minLength: 1
+ category:
+ $ref: '#/components/schemas/MoveCategoryName'
+ power:
+ type: integer
+ minimum: 0
+ accuracy:
+ type: integer
+ minimum: 0
+ type:
+ $ref: '#/components/schemas/TypeName'
+
+ Trainer:
+ type: object
+ required:
+ - name
+ - dob
+ - wins
+ - losses
+ - pastOpponents
+ - pokemongs
+ properties:
+ name:
+ type: string
+ minLength: 1
+ dob:
+ type: string
+ format: date
+ wins:
+ type: integer
+ minimum: 0
+ losses:
+ type: integer
+ minimum: 0
+ pastOpponents:
+ type: array
+ items:
+ type: string
+ minLength: 1
+ pokemongs:
+ type: array
+ items:
+ $ref: '#/components/schemas/TrainerPokemong'
+
+ PokemongMove:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: string
+ minLength: 1
+ name:
+ type: string
+ minLength: 1
+
+ TrainerPokemong:
+ type: object
+ required:
+ - id
+ - species
+ properties:
+ id:
+ type: string
+ minLength: 1
+ nickname:
+ type: string
+ nullable: true
+ species:
+ $ref: '#/components/schemas/PokemongName'
+
+ MoveCategoryName:
+ type: string
+ enum: [
+ PHYSICAL,
+ SPECIAL,
+ STATUS ]
+
+ TypeName:
+ type: string
+ enum: [
+ NORMAL,
+ GRASS,
+ ELECTRIC,
+ WATER,
+ FIRE,
+ BUG,
+ GHOST,
+ PSYCHIC,
+ STEEL,
+ DARK,
+ FLYING,
+ ICE,
+ POISON,
+ GROUND,
+ ROCK,
+ DRAGON,
+ FIGHTING,
+ FAIRY
+ ]
+
+ PokemongName:
+ type: string
+ enum: [
+ BULBASAUR,
+ IVYSAUR,
+ VENUSAUR,
+ CHARMANDER,
+ CHARMELEON,
+ CHARIZARD,
+ SQUIRTLE,
+ WARTORTLE,
+ BLASTOISE,
+ CATERPIE,
+ METAPOD,
+ BUTTERFREE,
+ WEEDLE,
+ KAKUNA,
+ BEEDRILL,
+ PIDGEY,
+ PIDGEOTTO,
+ PIDGEOT,
+ RATTATA,
+ RATICATE,
+ SPEAROW,
+ FEAROW,
+ EKANS,
+ ARBOK,
+ PIKACHU,
+ RAICHU,
+ SANDSHREW,
+ SANDSLASH,
+ NIDORAN_F,
+ NIDORINA,
+ NIDOQUEEN,
+ NIDORAN_M,
+ NIDORINO,
+ NIDOKING,
+ CLEFAIRY,
+ CLEFABLE,
+ VULPIX,
+ NINETALES,
+ JIGGLYPUFF,
+ WIGGLYTUFF,
+ ZUBAT,
+ GOLBAT,
+ ODDISH,
+ GLOOM,
+ VILEPLUME,
+ PARAS,
+ PARASECT,
+ VENONAT,
+ VENOMOTH,
+ DIGLETT,
+ DUGTRIO,
+ MEOWTH,
+ PERSIAN,
+ PSYDUCK,
+ GOLDUCK,
+ MANKEY,
+ PRIMEAPE,
+ GROWLITHE,
+ ARCANINE,
+ POLIWAG,
+ POLIWHIRL,
+ POLIWRATH,
+ ABRA,
+ KADABRA,
+ ALAKAZAM,
+ MACHOP,
+ MACHOKE,
+ MACHAMP,
+ BELLSPROUT,
+ WEEPINBELL,
+ VICTREEBEL,
+ TENTACOOL,
+ TENTACRUEL,
+ GEODUDE,
+ GRAVELER,
+ GOLEM,
+ PONYTA,
+ RAPIDASH,
+ SLOWPOKE,
+ SLOWBRO,
+ MAGNEMITE,
+ MAGNETON,
+ FARFETCHD,
+ DODUO,
+ DODRIO,
+ SEEL,
+ DEWGONG,
+ GRIMER,
+ MUK,
+ SHELLDER,
+ CLOYSTER,
+ GASTLY,
+ HAUNTER,
+ GENGAR,
+ ONIX,
+ DROWZEE,
+ HYPNO,
+ KRABBY,
+ KINGLER,
+ VOLTORB,
+ ELECTRODE,
+ EXEGGCUTE,
+ EXEGGUTOR,
+ CUBONE,
+ MAROWAK,
+ HITMONLEE,
+ HITMONCHAN,
+ LICKITUNG,
+ KOFFING,
+ WEEZING,
+ RHYHORN,
+ RHYDON,
+ CHANSEY,
+ TANGELA,
+ KANGASKHAN,
+ HORSEA,
+ SEADRA,
+ GOLDEEN,
+ SEAKING,
+ STARYU,
+ STARMIE,
+ MR_MIME,
+ SCYTHER,
+ JYNX,
+ ELECTABUZZ,
+ MAGMAR,
+ PINSIR,
+ TAUROS,
+ MAGIKARP,
+ GYARADOS,
+ LAPRAS,
+ DITTO,
+ EEVEE,
+ VAPOREON,
+ JOLTEON,
+ FLAREON,
+ PORYGON,
+ OMANYTE,
+ OMASTAR,
+ KABUTO,
+ KABUTOPS,
+ AERODACTYL,
+ SNORLAX,
+ ARTICUNO,
+ ZAPDOS,
+ MOLTRES,
+ DRATINI,
+ DRAGONAIR,
+ DRAGONITE,
+ MEWTWO,
+ MEW,
+ CHIKORITA,
+ BAYLEEF,
+ MEGANIUM,
+ CYNDAQUIL,
+ QUILAVA,
+ TYPHLOSION,
+ TOTODILE,
+ CROCONAW,
+ FERALIGATR,
+ SENTRET,
+ FURRET,
+ HOOTHOOT,
+ NOCTOWL,
+ LEDYBA,
+ LEDIAN,
+ SPINARAK,
+ ARIADOS,
+ CROBAT,
+ CHINCHOU,
+ LANTURN,
+ PICHU,
+ CLEFFA,
+ IGGLYBUFF,
+ TOGEPI,
+ TOGETIC,
+ NATU,
+ XATU,
+ MAREEP,
+ FLAAFFY,
+ AMPHAROS,
+ BELLOSSOM,
+ MARILL,
+ AZUMARILL,
+ SUDOWOODO,
+ POLITOED,
+ HOPPIP,
+ SKIPLOOM,
+ JUMPLUFF,
+ AIPOM,
+ SUNKERN,
+ SUNFLORA,
+ YANMA,
+ WOOPER,
+ QUAGSIRE,
+ ESPEON,
+ UMBREON,
+ MURKROW,
+ SLOWKING,
+ MISDREAVUS,
+ UNOWN,
+ WOBBUFFET,
+ GIRAFARIG,
+ PINECO,
+ FORRETRESS,
+ DUNSPARCE,
+ GLIGAR,
+ STEELIX,
+ SNUBBULL,
+ GRANBULL,
+ QWILFISH,
+ SCIZOR,
+ SHUCKLE,
+ HERACROSS,
+ SNEASEL,
+ TEDDIURSA,
+ URSARING,
+ SLUGMA,
+ MAGCARGO,
+ SWINUB,
+ PILOSWINE,
+ CORSOLA,
+ REMORAID,
+ OCTILLERY,
+ DELIBIRD,
+ MANTINE,
+ SKARMORY,
+ HOUNDOUR,
+ HOUNDOOM,
+ KINGDRA,
+ PHANPY,
+ DONPHAN,
+ PORYGON2,
+ STANTLER,
+ SMEARGLE,
+ TYROGUE,
+ HITMONTOP,
+ SMOOCHUM,
+ ELEKID,
+ MAGBY,
+ MILTANK,
+ BLISSEY,
+ RAIKOU,
+ ENTEI,
+ SUICUNE,
+ LARVITAR,
+ PUPITAR,
+ TYRANITAR,
+ LUGIA,
+ HO_OH,
+ CELEBI,
+ TREECKO,
+ GROVYLE,
+ SCEPTILE,
+ TORCHIC,
+ COMBUSKEN,
+ BLAZIKEN,
+ MUDKIP,
+ MARSHTOMP,
+ SWAMPERT,
+ POOCHYENA,
+ MIGHTYENA,
+ ZIGZAGOON,
+ LINOONE,
+ WURMPLE,
+ SILCOON,
+ BEAUTIFLY,
+ CASCOON,
+ DUSTOX,
+ LOTAD,
+ LOMBRE,
+ LUDICOLO,
+ SEEDOT,
+ NUZLEAF,
+ SHIFTRY,
+ TAILLOW,
+ SWELLOW,
+ WINGULL,
+ PELIPPER,
+ RALTS,
+ KIRLIA,
+ GARDEVOIR,
+ SURSKIT,
+ MASQUERAIN,
+ SHROOMISH,
+ BRELOOM,
+ SLAKOTH,
+ VIGOROTH,
+ SLAKING,
+ NINCADA,
+ NINJASK,
+ SHEDINJA,
+ WHISMUR,
+ LOUDRED,
+ EXPLOUD,
+ MAKUHITA,
+ HARIYAMA,
+ AZURILL,
+ NOSEPASS,
+ SKITTY,
+ DELCATTY,
+ SABLEYE,
+ MAWILE,
+ ARON,
+ LAIRON,
+ AGGRON,
+ MEDITITE,
+ MEDICHAM,
+ ELECTRIKE,
+ MANECTRIC,
+ PLUSLE,
+ MINUN,
+ VOLBEAT,
+ ILLUMISE,
+ ROSELIA,
+ GULPIN,
+ SWALOT,
+ CARVANHA,
+ SHARPEDO,
+ WAILMER,
+ WAILORD,
+ NUMEL,
+ CAMERUPT,
+ TORKOAL,
+ SPOINK,
+ GRUMPIG,
+ SPINDA,
+ TRAPINCH,
+ VIBRAVA,
+ FLYGON,
+ CACNEA,
+ CACTURNE,
+ SWABLU,
+ ALTARIA,
+ ZANGOOSE,
+ SEVIPER,
+ LUNATONE,
+ SOLROCK,
+ BARBOACH,
+ WHISCASH,
+ CORPHISH,
+ CRAWDAUNT,
+ BALTOY,
+ CLAYDOL,
+ LILEEP,
+ CRADILY,
+ ANORITH,
+ ARMALDO,
+ FEEBAS,
+ MILOTIC,
+ CASTFORM,
+ KECLEON,
+ SHUPPET,
+ BANETTE,
+ DUSKULL,
+ DUSCLOPS,
+ TROPIUS,
+ CHIMECHO,
+ ABSOL,
+ WYNAUT,
+ SNORUNT,
+ GLALIE,
+ SPHEAL,
+ SEALEO,
+ WALREIN,
+ CLAMPERL,
+ HUNTAIL,
+ GOREBYSS,
+ RELICANTH,
+ LUVDISC,
+ BAGON,
+ SHELGON,
+ SALAMENCE,
+ BELDUM,
+ METANG,
+ METAGROSS,
+ REGIROCK,
+ REGICE,
+ REGISTEEL,
+ LATIAS,
+ LATIOS,
+ KYOGRE,
+ GROUDON,
+ RAYQUAZA,
+ JIRACHI,
+ DEOXYS_NORMAL,
+ TURTWIG,
+ GROTLE,
+ TORTERRA,
+ CHIMCHAR,
+ MONFERNO,
+ INFERNAPE,
+ PIPLUP,
+ PRINPLUP,
+ EMPOLEON,
+ STARLY,
+ STARAVIA,
+ STARAPTOR,
+ BIDOOF,
+ BIBAREL,
+ KRICKETOT,
+ KRICKETUNE,
+ SHINX,
+ LUXIO,
+ LUXRAY,
+ BUDEW,
+ ROSERADE,
+ CRANIDOS,
+ RAMPARDOS,
+ SHIELDON,
+ BASTIODON,
+ BURMY,
+ WORMADAM_PLANT,
+ MOTHIM,
+ COMBEE,
+ VESPIQUEN,
+ PACHIRISU,
+ BUIZEL,
+ FLOATZEL,
+ CHERUBI,
+ CHERRIM,
+ SHELLOS,
+ GASTRODON,
+ AMBIPOM,
+ DRIFLOON,
+ DRIFBLIM,
+ BUNEARY,
+ LOPUNNY,
+ MISMAGIUS,
+ HONCHKROW,
+ GLAMEOW,
+ PURUGLY,
+ CHINGLING,
+ STUNKY,
+ SKUNTANK,
+ BRONZOR,
+ BRONZONG,
+ BONSLY,
+ MIME_JR,
+ HAPPINY,
+ CHATOT,
+ SPIRITOMB,
+ GIBLE,
+ GABITE,
+ GARCHOMP,
+ MUNCHLAX,
+ RIOLU,
+ LUCARIO,
+ HIPPOPOTAS,
+ HIPPOWDON,
+ SKORUPI,
+ DRAPION,
+ CROAGUNK,
+ TOXICROAK,
+ CARNIVINE,
+ FINNEON,
+ LUMINEON,
+ MANTYKE,
+ SNOVER,
+ ABOMASNOW,
+ WEAVILE,
+ MAGNEZONE,
+ LICKILICKY,
+ RHYPERIOR,
+ TANGROWTH,
+ ELECTIVIRE,
+ MAGMORTAR,
+ TOGEKISS,
+ YANMEGA,
+ LEAFEON,
+ GLACEON,
+ GLISCOR,
+ MAMOSWINE,
+ PORYGON_Z,
+ GALLADE,
+ PROBOPASS,
+ DUSKNOIR,
+ FROSLASS,
+ ROTOM,
+ UXIE,
+ MESPRIT,
+ AZELF,
+ DIALGA,
+ PALKIA,
+ HEATRAN,
+ REGIGIGAS,
+ GIRATINA_ALTERED,
+ CRESSELIA,
+ PHIONE,
+ MANAPHY,
+ DARKRAI,
+ SHAYMIN_LAND,
+ ARCEUS,
+ VICTINI,
+ SNIVY,
+ SERVINE,
+ SERPERIOR,
+ TEPIG,
+ PIGNITE,
+ EMBOAR,
+ OSHAWOTT,
+ DEWOTT,
+ SAMUROTT,
+ PATRAT,
+ WATCHOG,
+ LILLIPUP,
+ HERDIER,
+ STOUTLAND,
+ PURRLOIN,
+ LIEPARD,
+ PANSAGE,
+ SIMISAGE,
+ PANSEAR,
+ SIMISEAR,
+ PANPOUR,
+ SIMIPOUR,
+ MUNNA,
+ MUSHARNA,
+ PIDOVE,
+ TRANQUILL,
+ UNFEZANT,
+ BLITZLE,
+ ZEBSTRIKA,
+ ROGGENROLA,
+ BOLDORE,
+ GIGALITH,
+ WOOBAT,
+ SWOOBAT,
+ DRILBUR,
+ EXCADRILL,
+ AUDINO,
+ TIMBURR,
+ GURDURR,
+ CONKELDURR,
+ TYMPOLE,
+ PALPITOAD,
+ SEISMITOAD,
+ THROH,
+ SAWK,
+ SEWADDLE,
+ SWADLOON,
+ LEAVANNY,
+ VENIPEDE,
+ WHIRLIPEDE,
+ SCOLIPEDE,
+ COTTONEE,
+ WHIMSICOTT,
+ PETILIL,
+ LILLIGANT,
+ BASCULIN_RED_STRIPED,
+ SANDILE,
+ KROKOROK,
+ KROOKODILE,
+ DARUMAKA,
+ DARMANITAN_STANDARD,
+ MARACTUS,
+ DWEBBLE,
+ CRUSTLE,
+ SCRAGGY,
+ SCRAFTY,
+ SIGILYPH,
+ YAMASK,
+ COFAGRIGUS,
+ TIRTOUGA,
+ CARRACOSTA,
+ ARCHEN,
+ ARCHEOPS,
+ TRUBBISH,
+ GARBODOR,
+ ZORUA,
+ ZOROARK,
+ MINCCINO,
+ CINCCINO,
+ GOTHITA,
+ GOTHORITA,
+ GOTHITELLE,
+ SOLOSIS,
+ DUOSION,
+ REUNICLUS,
+ DUCKLETT,
+ SWANNA,
+ VANILLITE,
+ VANILLISH,
+ VANILLUXE,
+ DEERLING,
+ SAWSBUCK,
+ EMOLGA,
+ KARRABLAST,
+ ESCAVALIER,
+ FOONGUS,
+ AMOONGUSS,
+ FRILLISH,
+ JELLICENT,
+ ALOMOMOLA,
+ JOLTIK,
+ GALVANTULA,
+ FERROSEED,
+ FERROTHORN,
+ KLINK,
+ KLANG,
+ KLINKLANG,
+ TYNAMO,
+ EELEKTRIK,
+ EELEKTROSS,
+ ELGYEM,
+ BEHEEYEM,
+ LITWICK,
+ LAMPENT,
+ CHANDELURE,
+ AXEW,
+ FRAXURE,
+ HAXORUS,
+ CUBCHOO,
+ BEARTIC,
+ CRYOGONAL,
+ SHELMET,
+ ACCELGOR,
+ STUNFISK,
+ MIENFOO,
+ MIENSHAO,
+ DRUDDIGON,
+ GOLETT,
+ GOLURK,
+ PAWNIARD,
+ BISHARP,
+ BOUFFALANT,
+ RUFFLET,
+ BRAVIARY,
+ VULLABY,
+ MANDIBUZZ,
+ HEATMOR,
+ DURANT,
+ DEINO,
+ ZWEILOUS,
+ HYDREIGON,
+ LARVESTA,
+ VOLCARONA,
+ COBALION,
+ TERRAKION,
+ VIRIZION,
+ TORNADUS_INCARNATE,
+ THUNDURUS_INCARNATE,
+ RESHIRAM,
+ ZEKROM,
+ LANDORUS_INCARNATE,
+ KYUREM,
+ KELDEO_ORDINARY,
+ MELOETTA_ARIA,
+ GENESECT,
+ CHESPIN,
+ QUILLADIN,
+ CHESNAUGHT,
+ FENNEKIN,
+ BRAIXEN,
+ DELPHOX,
+ FROAKIE,
+ FROGADIER,
+ GRENINJA,
+ BUNNELBY,
+ DIGGERSBY,
+ FLETCHLING,
+ FLETCHINDER,
+ TALONFLAME,
+ SCATTERBUG,
+ SPEWPA,
+ VIVILLON,
+ LITLEO,
+ PYROAR,
+ FLABEBE,
+ FLOETTE,
+ FLORGES,
+ SKIDDO,
+ GOGOAT,
+ PANCHAM,
+ PANGORO,
+ FURFROU,
+ ESPURR,
+ MEOWSTIC_MALE,
+ HONEDGE,
+ DOUBLADE,
+ AEGISLASH_SHIELD,
+ SPRITZEE,
+ AROMATISSE,
+ SWIRLIX,
+ SLURPUFF,
+ INKAY,
+ MALAMAR,
+ BINACLE,
+ BARBARACLE,
+ SKRELP,
+ DRAGALGE,
+ CLAUNCHER,
+ CLAWITZER,
+ HELIOPTILE,
+ HELIOLISK,
+ TYRUNT,
+ TYRANTRUM,
+ AMAURA,
+ AURORUS,
+ SYLVEON,
+ HAWLUCHA,
+ DEDENNE,
+ CARBINK,
+ GOOMY,
+ SLIGGOO,
+ GOODRA,
+ KLEFKI,
+ PHANTUMP,
+ TREVENANT,
+ PUMPKABOO_AVERAGE,
+ GOURGEIST_AVERAGE,
+ BERGMITE,
+ AVALUGG,
+ NOIBAT,
+ NOIVERN,
+ XERNEAS,
+ YVELTAL,
+ ZYGARDE_50,
+ DIANCIE,
+ HOOPA,
+ VOLCANION,
+ ROWLET,
+ DARTRIX,
+ DECIDUEYE,
+ LITTEN,
+ TORRACAT,
+ INCINEROAR,
+ POPPLIO,
+ BRIONNE,
+ PRIMARINA,
+ PIKIPEK,
+ TRUMBEAK,
+ TOUCANNON,
+ YUNGOOS,
+ GUMSHOOS,
+ GRUBBIN,
+ CHARJABUG,
+ VIKAVOLT,
+ CRABRAWLER,
+ CRABOMINABLE,
+ ORICORIO_BAILE,
+ CUTIEFLY,
+ RIBOMBEE,
+ ROCKRUFF,
+ LYCANROC_MIDDAY,
+ WISHIWASHI_SOLO,
+ MAREANIE,
+ TOXAPEX,
+ MUDBRAY,
+ MUDSDALE,
+ DEWPIDER,
+ ARAQUANID,
+ FOMANTIS,
+ LURANTIS,
+ MORELULL,
+ SHIINOTIC,
+ SALANDIT,
+ SALAZZLE,
+ STUFFUL,
+ BEWEAR,
+ BOUNSWEET,
+ STEENEE,
+ TSAREENA,
+ COMFEY,
+ ORANGURU,
+ PASSIMIAN,
+ WIMPOD,
+ GOLISOPOD,
+ SANDYGAST,
+ PALOSSAND,
+ PYUKUMUKU,
+ TYPE_NULL,
+ SILVALLY,
+ MINIOR_RED_METEOR,
+ KOMALA,
+ TURTONATOR,
+ TOGEDEMARU,
+ MIMIKYU_DISGUISED,
+ BRUXISH,
+ DRAMPA,
+ DHELMISE,
+ JANGMO_O,
+ HAKAMO_O,
+ KOMMO_O,
+ TAPU_KOKO,
+ TAPU_LELE,
+ TAPU_BULU,
+ TAPU_FINI,
+ COSMOG,
+ COSMOEM,
+ SOLGALEO,
+ LUNALA,
+ NIHILEGO,
+ BUZZWOLE,
+ PHEROMOSA,
+ XURKITREE,
+ CELESTEELA,
+ KARTANA,
+ GUZZLORD,
+ NECROZMA,
+ MAGEARNA,
+ MARSHADOW,
+ POIPOLE,
+ NAGANADEL,
+ STAKATAKA,
+ BLACEPHALON,
+ ZERAORA,
+ MELTAN,
+ MELMETAL,
+ GROOKEY,
+ THWACKEY,
+ RILLABOOM,
+ SCORBUNNY,
+ RABOOT,
+ CINDERACE,
+ SOBBLE,
+ DRIZZILE,
+ INTELEON,
+ SKWOVET,
+ GREEDENT,
+ ROOKIDEE,
+ CORVISQUIRE,
+ CORVIKNIGHT,
+ BLIPBUG,
+ DOTTLER,
+ ORBEETLE,
+ NICKIT,
+ THIEVUL,
+ GOSSIFLEUR,
+ ELDEGOSS,
+ WOOLOO,
+ DUBWOOL,
+ CHEWTLE,
+ DREDNAW,
+ YAMPER,
+ BOLTUND,
+ ROLYCOLY,
+ CARKOL,
+ COALOSSAL,
+ APPLIN,
+ FLAPPLE,
+ APPLETUN,
+ SILICOBRA,
+ SANDACONDA,
+ CRAMORANT,
+ ARROKUDA,
+ BARRASKEWDA,
+ TOXEL,
+ TOXTRICITY_AMPED,
+ SIZZLIPEDE,
+ CENTISKORCH,
+ CLOBBOPUS,
+ GRAPPLOCT,
+ SINISTEA,
+ POLTEAGEIST,
+ HATENNA,
+ HATTREM,
+ HATTERENE,
+ IMPIDIMP,
+ MORGREM,
+ GRIMMSNARL,
+ OBSTAGOON,
+ PERRSERKER,
+ CURSOLA,
+ SIRFETCHD,
+ MR_RIME,
+ RUNERIGUS,
+ MILCERY,
+ ALCREMIE,
+ FALINKS,
+ PINCURCHIN,
+ SNOM,
+ FROSMOTH,
+ STONJOURNER,
+ EISCUE_ICE,
+ INDEEDEE_MALE,
+ MORPEKO_FULL_BELLY,
+ CUFANT,
+ COPPERAJAH,
+ DRACOZOLT,
+ ARCTOZOLT,
+ DRACOVISH,
+ ARCTOVISH,
+ DURALUDON,
+ DREEPY,
+ DRAKLOAK,
+ DRAGAPULT,
+ ZACIAN,
+ ZAMAZENTA,
+ ETERNATUS,
+ KUBFU,
+ URSHIFU_SINGLE_STRIKE,
+ ZARUDE,
+ REGIELEKI,
+ REGIDRAGO,
+ GLASTRIER,
+ SPECTRIER,
+ CALYREX,
+ WYRDEER,
+ KLEAVOR,
+ URSALUNA,
+ BASCULEGION_MALE,
+ SNEASLER,
+ OVERQWIL,
+ ENAMORUS_INCARNATE,
+ SPRIGATITO,
+ FLORAGATO,
+ MEOWSCARADA,
+ FUECOCO,
+ CROCALOR,
+ SKELEDIRGE,
+ QUAXLY,
+ QUAXWELL,
+ QUAQUAVAL,
+ LECHONK,
+ OINKOLOGNE,
+ TAROUNTULA,
+ SPIDOPS,
+ NYMBLE,
+ LOKIX,
+ PAWMI,
+ PAWMO,
+ PAWMOT,
+ TANDEMAUS,
+ MAUSHOLD,
+ FIDOUGH,
+ DACHSBUN,
+ SMOLIV,
+ DOLLIV,
+ ARBOLIVA,
+ SQUAWKABILLY,
+ NACLI,
+ NACLSTACK,
+ GARGANACL,
+ CHARCADET,
+ ARMAROUGE,
+ CERULEDGE,
+ TADBULB,
+ BELLIBOLT,
+ WATTREL,
+ KILOWATTREL,
+ MASCHIFF,
+ MABOSSTIFF,
+ SHROODLE,
+ GRAFAIAI,
+ BRAMBLIN,
+ BRAMBLEGHAST,
+ TOEDSCOOL,
+ TOEDSCRUEL,
+ KLAWF,
+ CAPSAKID,
+ SCOVILLAIN,
+ RELLOR,
+ RABSCA,
+ FLITTLE,
+ ESPATHRA,
+ TINKATINK,
+ TINKATUFF,
+ TINKATON,
+ WIGLETT,
+ WUGTRIO,
+ BOMBIRDIER,
+ FINIZEN,
+ PALAFIN,
+ VAROOM,
+ REVAVROOM,
+ CYCLIZAR,
+ ORTHWORM,
+ GLIMMET,
+ GLIMMORA,
+ GREAVARD,
+ HOUNDSTONE,
+ FLAMIGO,
+ CETODDLE,
+ CETITAN,
+ VELUZA,
+ DONDOZO,
+ TATSUGIRI,
+ ANNIHILAPE,
+ CLODSIRE,
+ FARIGIRAF,
+ DUDUNSPARCE,
+ KINGAMBIT,
+ GREAT_TUSK,
+ SCREAM_TAIL,
+ BRUTE_BONNET,
+ FLUTTER_MANE,
+ SLITHER_WING,
+ SANDY_SHOCKS,
+ IRON_TREADS,
+ IRON_BUNDLE,
+ IRON_HANDS,
+ IRON_JUGULIS,
+ IRON_MOTH,
+ IRON_THORNS,
+ FRIGIBAX,
+ ARCTIBAX,
+ BAXCALIBUR,
+ GIMMIGHOUL,
+ GHOLDENGO,
+ WO_CHIEN,
+ CHIEN_PAO,
+ TING_LU,
+ CHI_YU,
+ ROARING_MOON,
+ IRON_VALIANT,
+ KORAIDON,
+ MIRAIDON,
+ WALKING_WAKE,
+ IRON_LEAVES,
+ DEOXYS_ATTACK,
+ DEOXYS_DEFENSE,
+ DEOXYS_SPEED,
+ WORMADAM_SANDY,
+ WORMADAM_TRASH,
+ SHAYMIN_SKY,
+ GIRATINA_ORIGIN,
+ ROTOM_HEAT,
+ ROTOM_WASH,
+ ROTOM_FROST,
+ ROTOM_FAN,
+ ROTOM_MOW,
+ CASTFORM_SUNNY,
+ CASTFORM_RAINY,
+ CASTFORM_SNOWY,
+ BASCULIN_BLUE_STRIPED,
+ DARMANITAN_ZEN,
+ MELOETTA_PIROUETTE,
+ TORNADUS_THERIAN,
+ THUNDURUS_THERIAN,
+ LANDORUS_THERIAN,
+ KYUREM_BLACK,
+ KYUREM_WHITE,
+ KELDEO_RESOLUTE,
+ MEOWSTIC_FEMALE,
+ AEGISLASH_BLADE,
+ PUMPKABOO_SMALL,
+ PUMPKABOO_LARGE,
+ PUMPKABOO_SUPER,
+ GOURGEIST_SMALL,
+ GOURGEIST_LARGE,
+ GOURGEIST_SUPER,
+ VENUSAUR_MEGA,
+ CHARIZARD_MEGA_X,
+ CHARIZARD_MEGA_Y,
+ BLASTOISE_MEGA,
+ ALAKAZAM_MEGA,
+ GENGAR_MEGA,
+ KANGASKHAN_MEGA,
+ PINSIR_MEGA,
+ GYARADOS_MEGA,
+ AERODACTYL_MEGA,
+ MEWTWO_MEGA_X,
+ MEWTWO_MEGA_Y,
+ AMPHAROS_MEGA,
+ SCIZOR_MEGA,
+ HERACROSS_MEGA,
+ HOUNDOOM_MEGA,
+ TYRANITAR_MEGA,
+ BLAZIKEN_MEGA,
+ GARDEVOIR_MEGA,
+ MAWILE_MEGA,
+ AGGRON_MEGA,
+ MEDICHAM_MEGA,
+ MANECTRIC_MEGA,
+ BANETTE_MEGA,
+ ABSOL_MEGA,
+ GARCHOMP_MEGA,
+ LUCARIO_MEGA,
+ ABOMASNOW_MEGA,
+ FLOETTE_ETERNAL,
+ LATIAS_MEGA,
+ LATIOS_MEGA,
+ SWAMPERT_MEGA,
+ SCEPTILE_MEGA,
+ SABLEYE_MEGA,
+ ALTARIA_MEGA,
+ GALLADE_MEGA,
+ AUDINO_MEGA,
+ SHARPEDO_MEGA,
+ SLOWBRO_MEGA,
+ STEELIX_MEGA,
+ PIDGEOT_MEGA,
+ GLALIE_MEGA,
+ DIANCIE_MEGA,
+ METAGROSS_MEGA,
+ KYOGRE_PRIMAL,
+ GROUDON_PRIMAL,
+ RAYQUAZA_MEGA,
+ PIKACHU_ROCK_STAR,
+ PIKACHU_BELLE,
+ PIKACHU_POP_STAR,
+ PIKACHU_PHD,
+ PIKACHU_LIBRE,
+ PIKACHU_COSPLAY,
+ HOOPA_UNBOUND,
+ CAMERUPT_MEGA,
+ LOPUNNY_MEGA,
+ SALAMENCE_MEGA,
+ BEEDRILL_MEGA,
+ RATTATA_ALOLA,
+ RATICATE_ALOLA,
+ RATICATE_TOTEM_ALOLA,
+ PIKACHU_ORIGINAL_CAP,
+ PIKACHU_HOENN_CAP,
+ PIKACHU_SINNOH_CAP,
+ PIKACHU_UNOVA_CAP,
+ PIKACHU_KALOS_CAP,
+ PIKACHU_ALOLA_CAP,
+ RAICHU_ALOLA,
+ SANDSHREW_ALOLA,
+ SANDSLASH_ALOLA,
+ VULPIX_ALOLA,
+ NINETALES_ALOLA,
+ DIGLETT_ALOLA,
+ DUGTRIO_ALOLA,
+ MEOWTH_ALOLA,
+ PERSIAN_ALOLA,
+ GEODUDE_ALOLA,
+ GRAVELER_ALOLA,
+ GOLEM_ALOLA,
+ GRIMER_ALOLA,
+ MUK_ALOLA,
+ EXEGGUTOR_ALOLA,
+ MAROWAK_ALOLA,
+ GRENINJA_BATTLE_BOND,
+ GRENINJA_ASH,
+ ZYGARDE_10_POWER_CONSTRUCT,
+ ZYGARDE_50_POWER_CONSTRUCT,
+ ZYGARDE_COMPLETE,
+ GUMSHOOS_TOTEM,
+ VIKAVOLT_TOTEM,
+ ORICORIO_POM_POM,
+ ORICORIO_PAU,
+ ORICORIO_SENSU,
+ LYCANROC_MIDNIGHT,
+ WISHIWASHI_SCHOOL,
+ LURANTIS_TOTEM,
+ SALAZZLE_TOTEM,
+ MINIOR_ORANGE_METEOR,
+ MINIOR_YELLOW_METEOR,
+ MINIOR_GREEN_METEOR,
+ MINIOR_BLUE_METEOR,
+ MINIOR_INDIGO_METEOR,
+ MINIOR_VIOLET_METEOR,
+ MINIOR_RED,
+ MINIOR_ORANGE,
+ MINIOR_YELLOW,
+ MINIOR_GREEN,
+ MINIOR_BLUE,
+ MINIOR_INDIGO,
+ MINIOR_VIOLET,
+ MIMIKYU_BUSTED,
+ MIMIKYU_TOTEM_DISGUISED,
+ MIMIKYU_TOTEM_BUSTED,
+ KOMMO_O_TOTEM,
+ MAGEARNA_ORIGINAL,
+ PIKACHU_PARTNER_CAP,
+ MAROWAK_TOTEM,
+ RIBOMBEE_TOTEM,
+ ROCKRUFF_OWN_TEMPO,
+ LYCANROC_DUSK,
+ ARAQUANID_TOTEM,
+ TOGEDEMARU_TOTEM,
+ NECROZMA_DUSK,
+ NECROZMA_DAWN,
+ NECROZMA_ULTRA,
+ PIKACHU_STARTER,
+ EEVEE_STARTER,
+ PIKACHU_WORLD_CAP,
+ MEOWTH_GALAR,
+ PONYTA_GALAR,
+ RAPIDASH_GALAR,
+ SLOWPOKE_GALAR,
+ SLOWBRO_GALAR,
+ FARFETCHD_GALAR,
+ WEEZING_GALAR,
+ MR_MIME_GALAR,
+ ARTICUNO_GALAR,
+ ZAPDOS_GALAR,
+ MOLTRES_GALAR,
+ SLOWKING_GALAR,
+ CORSOLA_GALAR,
+ ZIGZAGOON_GALAR,
+ LINOONE_GALAR,
+ DARUMAKA_GALAR,
+ DARMANITAN_GALAR_STANDARD,
+ DARMANITAN_GALAR_ZEN,
+ YAMASK_GALAR,
+ STUNFISK_GALAR,
+ ZYGARDE_10,
+ CRAMORANT_GULPING,
+ CRAMORANT_GORGING,
+ TOXTRICITY_LOW_KEY,
+ EISCUE_NOICE,
+ INDEEDEE_FEMALE,
+ MORPEKO_HANGRY,
+ ZACIAN_CROWNED,
+ ZAMAZENTA_CROWNED,
+ ETERNATUS_ETERNAMAX,
+ URSHIFU_RAPID_STRIKE,
+ ZARUDE_DADA,
+ CALYREX_ICE,
+ CALYREX_SHADOW,
+ VENUSAUR_GMAX,
+ CHARIZARD_GMAX,
+ BLASTOISE_GMAX,
+ BUTTERFREE_GMAX,
+ PIKACHU_GMAX,
+ MEOWTH_GMAX,
+ MACHAMP_GMAX,
+ GENGAR_GMAX,
+ KINGLER_GMAX,
+ LAPRAS_GMAX,
+ EEVEE_GMAX,
+ SNORLAX_GMAX,
+ GARBODOR_GMAX,
+ MELMETAL_GMAX,
+ RILLABOOM_GMAX,
+ CINDERACE_GMAX,
+ INTELEON_GMAX,
+ CORVIKNIGHT_GMAX,
+ ORBEETLE_GMAX,
+ DREDNAW_GMAX,
+ COALOSSAL_GMAX,
+ FLAPPLE_GMAX,
+ APPLETUN_GMAX,
+ SANDACONDA_GMAX,
+ TOXTRICITY_AMPED_GMAX,
+ CENTISKORCH_GMAX,
+ HATTERENE_GMAX,
+ GRIMMSNARL_GMAX,
+ ALCREMIE_GMAX,
+ COPPERAJAH_GMAX,
+ DURALUDON_GMAX,
+ URSHIFU_SINGLE_STRIKE_GMAX,
+ URSHIFU_RAPID_STRIKE_GMAX,
+ TOXTRICITY_LOW_KEY_GMAX,
+ GROWLITHE_HISUI,
+ ARCANINE_HISUI,
+ VOLTORB_HISUI,
+ ELECTRODE_HISUI,
+ TYPHLOSION_HISUI,
+ QWILFISH_HISUI,
+ SNEASEL_HISUI,
+ SAMUROTT_HISUI,
+ LILLIGANT_HISUI,
+ ZORUA_HISUI,
+ ZOROARK_HISUI,
+ BRAVIARY_HISUI,
+ SLIGGOO_HISUI,
+ GOODRA_HISUI,
+ AVALUGG_HISUI,
+ DECIDUEYE_HISUI,
+ DIALGA_ORIGIN,
+ PALKIA_ORIGIN,
+ BASCULIN_WHITE_STRIPED,
+ BASCULEGION_FEMALE,
+ ENAMORUS_THERIAN,
+ TAUROS_PALDEA_COMBAT_BREED,
+ TAUROS_PALDEA_BLAZE_BREED,
+ TAUROS_PALDEA_AQUA_BREED,
+ WOOPER_PALDEA,
+ OINKOLOGNE_FEMALE,
+ DUDUNSPARCE_THREE_SEGMENT,
+ PALAFIN_HERO,
+ MAUSHOLD_FAMILY_OF_THREE,
+ TATSUGIRI_DROOPY,
+ TATSUGIRI_STRETCHY,
+ SQUAWKABILLY_BLUE_PLUMAGE,
+ SQUAWKABILLY_YELLOW_PLUMAGE,
+ SQUAWKABILLY_WHITE_PLUMAGE,
+ GIMMIGHOUL_ROAMING,
+ KORAIDON_LIMITED_BUILD,
+ KORAIDON_SPRINTING_BUILD,
+ KORAIDON_SWIMMING_BUILD,
+ KORAIDON_GLIDING_BUILD,
+ MIRAIDON_LOW_POWER_MODE,
+ MIRAIDON_DRIVE_MODE,
+ MIRAIDON_AQUATIC_MODE,
+ MIRAIDON_GLIDE_MODE
+ ]
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 6ba7462..008c4b3 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,2 +1,3 @@
-quarkus.mongodb.connection-string=mongodb+srv://:@..mongodb.net
-quarkus.mongodb.database=
\ No newline at end of file
+quarkus.mongodb.connection-string=mongodb+srv://:@..mongodb.net
+quarkus.mongodb.database=
+quarkus.smallrye-openapi.path=META-INF/openapi.yaml