Compare commits

...

2 Commits

@ -11,11 +11,18 @@
- [Schema Versioning Pattern](#schema-versioning-pattern)
- [Incremental Document Migration](#incremental-document-migration)
- [📇Indexes](#indexes)
- [`moves` collection](#moves-collection)
- [`pokemongs` collection](#pokemongs-collection)
- [`trainers` collection](#trainers-collection)
- [🐕🦺Services](#services)
- [🌺Special requests](#special-requests)
- [`Pokemong` by nickname](#pokemong-by-nickname)
- [`Pokemong` in date interval](#pokemong-in-date-interval)
- [🦚Aggregation pipeline](#aggregation-pipeline)
- [👔Some business rules](#some-business-rules)
- [`Move` CRUD cascade](#move-crud-cascade)
- [`Pokemong` CRUD cascade](#pokemong-crud-cascade)
- [`Trainer` CRUD cascade](#trainer-crud-cascade)
- [Prep steps](#prep-steps)
- [Java version](#java-version)
- [🔐Database connection](#database-connection)
@ -212,7 +219,36 @@ However, note that this strategy increases write operations to the database, whi
### 📇Indexes
// TODO pick it up here
Various indexes were created for fields that would often be queried in a dashboard situation. If there is an additional
reason, it will be specified below.
Unless otherwise specified, please consider indexes to be full, and ascending.
#### `moves` collection
In the front-end app, these are queried both in the detail screen and in the list screen.
* `name`
* `power`: Descending, because users are more likely to sort them in that order.
* `type`
#### `pokemongs` collection
* `nickname`: This field already has a dedicated endpoint for a nickname search filter.
* `dob`: Descending, because users are more likely to sort them in that order.
* `evoStage`: "Species" is calculated as `evoTrack[evoStage]`, and would often be queried.
* `evoTrack`: See `evoStage`. Yes, it's an array, but it's a one-to-few relationship.
* `trainer`: Partial index, to avoid indexing wild pokemongs there.
* `types`: It's an array, but it's a one-to-few relationship.
#### `trainers` collection
It was tempting to index `pastOpponents` and `pokemongs` in the `trainers` collection, but this array
could grow indefinitely, and the index may grow so large that it wouldn't fit in a server's RAM anymore.
* `name`
* `wins`: Descending, because users are more likely to sort them in that order for rankings.
* `losses`: Descending, because users are more likely to sort them in that order for rankings.
### 🐕🦺Services
@ -356,6 +392,30 @@ As an example of a potential output:
]
```
### 👔Some business rules
#### `Move` CRUD cascade
* When you delete a `move`, it also gets deleted from any `pokemong`'s `moveSet`.
* Since `pokemongMove` is denormalized on the `name` field, that field also gets updated when a `move`'s `name` is
updated.
#### `Pokemong` CRUD cascade
* When a `pokemong` is created, the new `pokemong`'s information is also added to the `pokemongs` array of any
associated `trainer` documents.
* When a `pokemong` is deleted, the `pokemongs` array in the associated `trainer` documents also has that specific
`pokemong` removed.
* Since `trainerPokemong` is denormalized on the `nickname` and `species` fields, those fields also get updated when
a `pokemong`'s `nickname` is updated, or when a `pokemong` evolves.
#### `Trainer` CRUD cascade
* When a `trainer` is created, the new `trainer`'s information is also updated in the `trainer` field of any associated
`pokemong` documents. Since a `pokemong` can only belong to one `trainer` at a time, that may mean removing it from
one to give it to the other.
* When a `trainer` is deleted, the `trainer` field in the associated `pokemong` documents is also removed.
## Prep steps
### ♨Java version

@ -1,427 +1,447 @@
{
"info": {
"_postman_id": "11aa7a76-83a4-4b92-940f-528e29b66df8",
"name": "PoKeMoNg",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "25802734"
},
"item": [
{
"name": "move",
"item": [
{
"name": "Create 1 move",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"Bubble beam\",\r\n \"category\": \"PHYSICAL\",\r\n \"power\": 10,\r\n \"accuracy\": 85,\r\n \"type\": \r\n {\r\n \"name\": \"WATER\",\r\n \"weakAgainst\": [\"GRASS\"],\r\n \"effectiveAgainst\": [\"FIRE\", \"GROUND\"]\r\n },\r\n \"schemaVersion\": 2\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/move",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move"
]
}
},
"response": []
},
{
"name": "Get all moves",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/move",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move"
]
}
},
"response": []
},
{
"name": "Get 1 move",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e917",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e917"
]
}
},
"response": []
},
{
"name": "Update 1 move",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 2,\r\n \"name\": \"Ember UPDATED\",\r\n \"category\": \"SPECIAL\",\r\n \"power\": 40,\r\n \"accuracy\": 100,\r\n \"type\": {\r\n \"name\": \"FIRE\",\r\n \"weakAgainst\": [\r\n \"WATER\",\r\n \"GROUND\"\r\n ],\r\n \"effectiveAgainst\": [\r\n \"GRASS\"\r\n ]\r\n }\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e917",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e917"
]
}
},
"response": []
},
{
"name": "Delete 1 move",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e913",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e913"
]
}
},
"response": []
}
]
},
{
"name": "pokemong",
"item": [
{
"name": "Create 1 pkmn",
"protocolProfileBehavior": {
"disabledSystemHeaders": {
"content-type": true
}
},
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"nickname\": \"Blappity-bloop\",\r\n \"dob\": \"2023-05-07\",\r\n \"level\": 1,\r\n \"pokedexId\": 172,\r\n \"evoStage\": 1,\r\n \"evoTrack\": [\"PICHU\", \"PIKACHU\", \"RAICHU\"],\r\n \"types\": [\r\n {\r\n \"name\": \"ELECTRIC\",\r\n \"weakAgainst\": [\"GROUND\", \"ROCK\"],\r\n \"effectiveAgainst\": [\"WATER\", \"FLYING\"]\r\n }\r\n ],\r\n \"moveSet\": \r\n [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e917\",\r\n \"name\": \"Ember\"\r\n }\r\n ],\r\n \"schemaVersion\": 1\r\n}"
},
"url": {
"raw": "http://localhost:8080/pokemong",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong"
]
}
},
"response": []
},
{
"name": "Get all pkmn",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong"
]
}
},
"response": []
},
{
"name": "Get 1 pkmn",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e911",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e911"
]
}
},
"response": []
},
{
"name": "Update 1 pkmn",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"schemaVersion\": 1,\n \"nickname\": \"Sparky UPDATED\",\n \"dob\": \"1994-02-18\",\n \"level\": 15,\n \"pokedexId\": 1,\n \"evoStage\": 1,\n \"evoTrack\": [\n \"BULBASAUR\",\n \"IVYSAUR\",\n \"VENUSAUR\"\n ],\n \"trainer\": \"60a64f7eae945a6e60b0e914\",\n \"types\": [\n {\n \"name\": \"GRASS\",\n \"weakAgainst\": [\n \"FIRE\"\n ],\n \"effectiveAgainst\": [\n \"WATER\",\n \"GROUND\"\n ]\n }\n ],\n \"moveSet\": [\n {\n \"id\": \"60a64f7eae945a6e60b0e912\",\n \"name\": \"Vine Whip\"\n }\n ]\n}"
},
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e911",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e911"
]
}
},
"response": []
},
{
"name": "Delete 1 pkmn",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e916",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e916"
]
}
},
"response": []
},
{
"name": "Get all pkmn by nickname",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/nickname/sparky",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"nickname",
"sparky"
]
}
},
"response": []
},
{
"name": "Gat all pkmn by date interval",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/dob/1995-01-01/1999-01-01",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"dob",
"1995-01-01",
"1999-01-01"
]
}
},
"response": []
}
]
},
{
"name": "trainer",
"item": [
{
"name": "Create 1 trainer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 1,\r\n \"name\": \"Bloop\",\r\n \"dob\": \"1997-02-18\",\r\n \"wins\": 1,\r\n \"losses\": 50,\r\n \"pastOpponents\": [\r\n \"60a64f7eae945a6e60b0e915\"\r\n ],\r\n \"pokemongs\": [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e911\",\r\n \"nickname\": \"Sparky UPDATED\",\r\n \"species\": \"IVYSAUR\"\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/trainer",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer"
]
}
},
"response": []
},
{
"name": "Get all trainers",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer"
]
}
},
"response": []
},
{
"name": "Get 1 trainer",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e914",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e914"
]
}
},
"response": []
},
{
"name": "Update 1 trainer",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 1,\r\n \"name\": \"Brock\",\r\n \"dob\": \"1994-02-18\",\r\n \"wins\": 60,\r\n \"losses\": 60,\r\n \"pastOpponents\": [\r\n \"60a64f7eae945a6e60b0e914\"\r\n ],\r\n \"pokemongs\": [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e911\",\r\n \"nickname\": \"Sparky UPDATED\",\r\n \"species\": \"IVYSAUR\"\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e915",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e915"
]
}
},
"response": []
},
{
"name": "Delete 1 trainer",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e914",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e914"
]
}
},
"response": []
}
]
}
]
"info": {
"_postman_id": "11aa7a76-83a4-4b92-940f-528e29b66df8",
"name": "PoKeMoNg",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "25802734"
},
"item": [
{
"name": "move",
"item": [
{
"name": "Create 1 move",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"Bubble beam\",\r\n \"category\": \"PHYSICAL\",\r\n \"power\": 10,\r\n \"accuracy\": 85,\r\n \"type\": \r\n {\r\n \"name\": \"WATER\",\r\n \"weakAgainst\": [\"GRASS\"],\r\n \"effectiveAgainst\": [\"FIRE\", \"GROUND\"]\r\n },\r\n \"schemaVersion\": 2\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/move",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move"
]
}
},
"response": []
},
{
"name": "Get all moves",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/move",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move"
]
}
},
"response": []
},
{
"name": "Get 1 move",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e917",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e917"
]
}
},
"response": []
},
{
"name": "Update 1 move",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 2,\r\n \"name\": \"Ember UPDATED\",\r\n \"category\": \"SPECIAL\",\r\n \"power\": 40,\r\n \"accuracy\": 100,\r\n \"type\": {\r\n \"name\": \"FIRE\",\r\n \"weakAgainst\": [\r\n \"WATER\",\r\n \"GROUND\"\r\n ],\r\n \"effectiveAgainst\": [\r\n \"GRASS\"\r\n ]\r\n }\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e917",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e917"
]
}
},
"response": []
},
{
"name": "Delete 1 move",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/move/60a64f7eae945a6e60b0e913",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"move",
"60a64f7eae945a6e60b0e913"
]
}
},
"response": []
}
]
},
{
"name": "pokemong",
"item": [
{
"name": "Create 1 pkmn",
"protocolProfileBehavior": {
"disabledSystemHeaders": {
"content-type": true
}
},
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"nickname\": \"Blappity-bloop\",\r\n \"dob\": \"2023-05-07\",\r\n \"level\": 1,\r\n \"pokedexId\": 172,\r\n \"evoStage\": 1,\r\n \"evoTrack\": [\"PICHU\", \"PIKACHU\", \"RAICHU\"],\r\n \"types\": [\r\n {\r\n \"name\": \"ELECTRIC\",\r\n \"weakAgainst\": [\"GROUND\", \"ROCK\"],\r\n \"effectiveAgainst\": [\"WATER\", \"FLYING\"]\r\n }\r\n ],\r\n \"moveSet\": \r\n [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e917\",\r\n \"name\": \"Ember\"\r\n }\r\n ],\r\n \"schemaVersion\": 1\r\n}"
},
"url": {
"raw": "http://localhost:8080/pokemong",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong"
]
}
},
"response": []
},
{
"name": "Get all pkmn",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong"
]
}
},
"response": []
},
{
"name": "Get 1 pkmn",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e911",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e911"
]
}
},
"response": []
},
{
"name": "Update 1 pkmn",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"schemaVersion\": 1,\n \"nickname\": \"Sparky UPDATED\",\n \"dob\": \"1994-02-18\",\n \"level\": 15,\n \"pokedexId\": 1,\n \"evoStage\": 1,\n \"evoTrack\": [\n \"BULBASAUR\",\n \"IVYSAUR\",\n \"VENUSAUR\"\n ],\n \"trainer\": \"60a64f7eae945a6e60b0e914\",\n \"types\": [\n {\n \"name\": \"GRASS\",\n \"weakAgainst\": [\n \"FIRE\"\n ],\n \"effectiveAgainst\": [\n \"WATER\",\n \"GROUND\"\n ]\n }\n ],\n \"moveSet\": [\n {\n \"id\": \"60a64f7eae945a6e60b0e912\",\n \"name\": \"Vine Whip\"\n }\n ]\n}"
},
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e911",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e911"
]
}
},
"response": []
},
{
"name": "Delete 1 pkmn",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/60a64f7eae945a6e60b0e916",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"60a64f7eae945a6e60b0e916"
]
}
},
"response": []
},
{
"name": "Get many pkmn by nickname",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/nickname/sparky",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"nickname",
"sparky"
]
}
},
"response": []
},
{
"name": "Get many pkmn by date interval",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/dob/1995-01-01/1999-01-01",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"dob",
"1995-01-01",
"1999-01-01"
]
}
},
"response": []
},
{
"name": "Get mapping of all pkmn count by evo stage",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/pokemong/count-by-evo-stage",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"pokemong",
"count-by-evo-stage"
]
}
},
"response": []
}
]
},
{
"name": "trainer",
"item": [
{
"name": "Create 1 trainer",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 1,\r\n \"name\": \"Bloop\",\r\n \"dob\": \"1997-02-18\",\r\n \"wins\": 1,\r\n \"losses\": 50,\r\n \"pastOpponents\": [\r\n \"60a64f7eae945a6e60b0e915\"\r\n ],\r\n \"pokemongs\": [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e911\",\r\n \"nickname\": \"Sparky UPDATED\",\r\n \"species\": \"IVYSAUR\"\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/trainer",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer"
]
}
},
"response": []
},
{
"name": "Get all trainers",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer"
]
}
},
"response": []
},
{
"name": "Get 1 trainer",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e914",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e914"
]
}
},
"response": []
},
{
"name": "Update 1 trainer",
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"schemaVersion\": 1,\r\n \"name\": \"Brock\",\r\n \"dob\": \"1994-02-18\",\r\n \"wins\": 60,\r\n \"losses\": 60,\r\n \"pastOpponents\": [\r\n \"60a64f7eae945a6e60b0e914\"\r\n ],\r\n \"pokemongs\": [\r\n {\r\n \"id\": \"60a64f7eae945a6e60b0e911\",\r\n \"nickname\": \"Sparky UPDATED\",\r\n \"species\": \"IVYSAUR\"\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e915",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e915"
]
}
},
"response": []
},
{
"name": "Delete 1 trainer",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "http://localhost:8080/trainer/60a64f7eae945a6e60b0e914",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"trainer",
"60a64f7eae945a6e60b0e914"
]
}
},
"response": []
}
]
}
]
}

@ -0,0 +1,46 @@
package fr.uca.iut;
import fr.uca.iut.entities.GenericEntity;
import fr.uca.iut.repositories.GenericRepository;
import fr.uca.iut.repositories.MoveRepository;
import fr.uca.iut.repositories.PokemongRepository;
import fr.uca.iut.repositories.TrainerRepository;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import org.bson.Document;
@ApplicationScoped
public class Startup {
@Inject
MoveRepository moveRepository;
@Inject
PokemongRepository pokemongRepository;
@Inject
TrainerRepository trainerRepository;
void onStart(@Observes StartupEvent ev) {
createIndex(moveRepository);
createIndex(pokemongRepository);
createIndex(trainerRepository);
}
private void createIndex(GenericRepository<? extends GenericEntity> repository) {
try {
repository.createIndexes();
printIndexes(repository);
} catch (Exception e) {
System.err.println("Error creating indexes for repository: " + repository.getClass());
e.printStackTrace();
}
}
private void printIndexes(GenericRepository<? extends GenericEntity> repository) {
System.out.println("indexes for " + repository.getClass());
for (Document index : repository.getCollection().listIndexes()) {
System.out.println(index.toJson());
}
}
}

@ -2,6 +2,7 @@ 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.ReplaceOneModel;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.WriteModel;
@ -56,7 +57,7 @@ public abstract class GenericRepository<T extends GenericEntity> {
*
* @return The MongoDB collection of entities of type T.
*/
protected abstract MongoCollection<T> getCollection();
public abstract MongoCollection<T> getCollection();
/**
* Inserts an entity into the collection.
@ -132,4 +133,14 @@ public abstract class GenericRepository<T extends GenericEntity> {
Document query = new Document("_id", new ObjectId(id));
return getCollection().countDocuments(query) > 0;
}
/**
* @return the MongoDB database
*/
@NotNull
public MongoDatabase getMongoDatabase() {
return mongoClient.getDatabase(DB_NAME);
}
public abstract void createIndexes();
}

@ -3,6 +3,7 @@ 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.Indexes;
import fr.uca.iut.entities.Move;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
@ -24,8 +25,15 @@ public class MoveRepository extends GenericRepository<Move> {
}
@Override
protected MongoCollection<Move> getCollection() {
public MongoCollection<Move> getCollection() {
MongoDatabase db = mongoClient.getDatabase(DB_NAME);
return db.getCollection(Move.COLLECTION_NAME, Move.class);
}
@Override
public void createIndexes() {
getCollection().createIndex(Indexes.ascending("name"));
getCollection().createIndex(Indexes.descending("power"));
getCollection().createIndex(Indexes.ascending("type"));
}
}

@ -3,10 +3,7 @@ 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.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.*;
import fr.uca.iut.entities.Pokemong;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
@ -14,7 +11,6 @@ import jakarta.inject.Inject;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDate;
import java.time.ZoneId;
@ -45,16 +41,11 @@ public class PokemongRepository extends GenericRepository<Pokemong> {
}
@Override
protected MongoCollection<Pokemong> getCollection() {
public MongoCollection<Pokemong> getCollection() {
MongoDatabase db = getMongoDatabase();
return db.getCollection(Pokemong.COLLECTION_NAME, Pokemong.class);
}
@NotNull
private MongoDatabase getMongoDatabase() {
return mongoClient.getDatabase(DB_NAME);
}
/**
* Fetches the list of Pokemong entities that have a nickname matching the provided nickname.
* The match is case-insensitive and ignores leading and trailing spaces.
@ -108,8 +99,18 @@ public class PokemongRepository extends GenericRepository<Pokemong> {
))
);
MongoCollection<Document> collection = getMongoDatabase().getCollection(getCollection().getNamespace().getCollectionName());
return collection.aggregate(pipeline, Document.class).into(new ArrayList<>());
return getCollection().aggregate(pipeline, Document.class).into(new ArrayList<>());
}
@Override
public void createIndexes() {
getCollection().createIndex(Indexes.ascending("nickname"));
getCollection().createIndex(Indexes.descending("dob"));
getCollection().createIndex(Indexes.ascending("evoStage"));
getCollection().createIndex(Indexes.ascending("evoTrack"));
getCollection().createIndex(Indexes.ascending("types"));
IndexOptions indexOptions = new IndexOptions().partialFilterExpression(Filters.exists("trainer", true));
getCollection().createIndex(Indexes.ascending("trainer"), indexOptions);
}
}

@ -3,6 +3,7 @@ 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.Indexes;
import fr.uca.iut.entities.Trainer;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
@ -24,8 +25,15 @@ public class TrainerRepository extends GenericRepository<Trainer> {
}
@Override
protected MongoCollection<Trainer> getCollection() {
public MongoCollection<Trainer> getCollection() {
MongoDatabase db = mongoClient.getDatabase(DB_NAME);
return db.getCollection(Trainer.COLLECTION_NAME, Trainer.class);
}
@Override
public void createIndexes() {
getCollection().createIndex(Indexes.ascending("name"));
getCollection().createIndex(Indexes.descending("wins"));
getCollection().createIndex(Indexes.descending("losses"));
}
}

Loading…
Cancel
Save