diff --git a/.gitignore b/.gitignore index af0cb9bb0..a2a387774 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ build/* _site/ *.css !petclinic.css + +venv diff --git a/docker-compose.yml b/docker-compose.yml index 3d08a0ee6..75f3dd447 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,3 +25,13 @@ services: - POSTGRES_DB=petclinic profiles: - postgres + + mongodb: + image: mongo:7.0.4 + environment: + MONGO_INITDB_ROOT_USERNAME: petclinic + MONGO_INITDB_ROOT_PASSWORD: petclinic + ports: + - "27017:27017" + profiles: + - mongodb diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5d3eeed32..68311a6ac 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,6 +2,7 @@ database=h2 spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql spring.sql.init.data-locations=classpath*:db/${database}/data.sql +spring.h2.console.enabled=true # Web spring.thymeleaf.mode=HTML @@ -23,3 +24,4 @@ logging.level.org.springframework=INFO # Maximum time static resources should be cached spring.web.resources.cache.cachecontrol.max-age=12h + diff --git a/src/main/resources/db/mongo/README.md b/src/main/resources/db/mongo/README.md new file mode 100644 index 000000000..157c561ca --- /dev/null +++ b/src/main/resources/db/mongo/README.md @@ -0,0 +1,15 @@ +# Requirements +- python > 3.9 + +# How to set up python environment +- run `python -m venv venv` +- run `source venv/bin/activate` +- run `pip install -r requirements.txt` + +# How to set up mongo db +- run `docker-compose --profile=mongodb up` +- run `python migrate.py` +- connection string - `mongodb://petclinic:petclinic@localhost:27017/` +- username - `petclinic` +- password - `petclinic` +- db - `petclinic` diff --git a/src/main/resources/db/mongo/csv-files/owners.csv b/src/main/resources/db/mongo/csv-files/owners.csv new file mode 100644 index 000000000..863da3b74 --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/owners.csv @@ -0,0 +1,11 @@ +"ID";"FIRST_NAME";"LAST_NAME";"ADDRESS";"CITY";"TELEPHONE" +"1";"George";"Franklin";"110 W. Liberty St.";"Madison";"6085551023" +"2";"Betty";"Davis";"638 Cardinal Ave.";"Sun Prairie";"6085551749" +"3";"Eduardo";"Rodriquez";"2693 Commerce St.";"McFarland";"6085558763" +"4";"Harold";"Davis";"563 Friendly St.";"Windsor";"6085553198" +"5";"Peter";"McTavish";"2387 S. Fair Way";"Madison";"6085552765" +"6";"Jean";"Coleman";"105 N. Lake St.";"Monona";"6085552654" +"7";"Jeff";"Black";"1450 Oak Blvd.";"Monona";"6085555387" +"8";"Maria";"Escobito";"345 Maple St.";"Madison";"6085557683" +"9";"David";"Schroeder";"2749 Blackhawk Trail";"Madison";"6085559435" +"10";"Carlos";"Estaban";"2335 Independence La.";"Waunakee";"6085555487" diff --git a/src/main/resources/db/mongo/csv-files/pets.csv b/src/main/resources/db/mongo/csv-files/pets.csv new file mode 100644 index 000000000..4b8c10526 --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/pets.csv @@ -0,0 +1,14 @@ +"ID";"NAME";"BIRTH_DATE";"TYPE_ID";"OWNER_ID" +"1";"Leo";"2010-09-07";"1";"1" +"2";"Basil";"2012-08-06";"6";"2" +"3";"Rosy";"2011-04-17";"2";"3" +"4";"Jewel";"2010-03-07";"2";"3" +"5";"Iggy";"2010-11-30";"3";"4" +"6";"George";"2010-01-20";"4";"5" +"7";"Samantha";"2012-09-04";"1";"6" +"8";"Max";"2012-09-04";"1";"6" +"9";"Lucky";"2011-08-06";"5";"7" +"10";"Mulligan";"2007-02-24";"2";"8" +"11";"Freddy";"2010-03-09";"5";"9" +"12";"Lucky";"2010-06-24";"2";"10" +"13";"Sly";"2012-06-08";"1";"10" diff --git a/src/main/resources/db/mongo/csv-files/specs.csv b/src/main/resources/db/mongo/csv-files/specs.csv new file mode 100644 index 000000000..6346a33ec --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/specs.csv @@ -0,0 +1,4 @@ +"ID";"NAME" +"3";"dentistry" +"1";"radiology" +"2";"surgery" diff --git a/src/main/resources/db/mongo/csv-files/types.csv b/src/main/resources/db/mongo/csv-files/types.csv new file mode 100644 index 000000000..087fd1c0d --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/types.csv @@ -0,0 +1,7 @@ +"ID";"NAME" +"5";"bird" +"1";"cat" +"2";"dog" +"6";"hamster" +"3";"lizard" +"4";"snake" diff --git a/src/main/resources/db/mongo/csv-files/vets.csv b/src/main/resources/db/mongo/csv-files/vets.csv new file mode 100644 index 000000000..fda3c374c --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/vets.csv @@ -0,0 +1,7 @@ +"ID";"FIRST_NAME";"LAST_NAME" +"1";"James";"Carter" +"2";"Helen";"Leary" +"3";"Linda";"Douglas" +"4";"Rafael";"Ortega" +"5";"Henry";"Stevens" +"6";"Sharon";"Jenkins" diff --git a/src/main/resources/db/mongo/csv-files/vets_specs.csv b/src/main/resources/db/mongo/csv-files/vets_specs.csv new file mode 100644 index 000000000..de0608af7 --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/vets_specs.csv @@ -0,0 +1,6 @@ +"VET_ID";"SPECIALTY_ID" +"2";"1" +"3";"2" +"3";"3" +"4";"2" +"5";"1" diff --git a/src/main/resources/db/mongo/csv-files/visits.csv b/src/main/resources/db/mongo/csv-files/visits.csv new file mode 100644 index 000000000..113455c0c --- /dev/null +++ b/src/main/resources/db/mongo/csv-files/visits.csv @@ -0,0 +1,6 @@ +"ID";"PET_ID";"VISIT_DATE";"DESCRIPTION" +"1";"7";"2013-01-01";"rabies shot" +"2";"8";"2013-01-02";"rabies shot" +"3";"8";"2013-01-03";"neutered" +"4";"7";"2013-01-04";"spayed" +"5";"5";"2024-01-06";"kjhjkhhjk" diff --git a/src/main/resources/db/mongo/migrate.py b/src/main/resources/db/mongo/migrate.py new file mode 100644 index 000000000..4e41cf20c --- /dev/null +++ b/src/main/resources/db/mongo/migrate.py @@ -0,0 +1,200 @@ +from pymongo import MongoClient +from dataclasses import dataclass +from datetime import date, datetime +from uuid import UUID, uuid4 +import csv +from typing import Optional + + +FILE_PATHS = { + "vets": "csv-files/vets.csv", + "specs": "csv-files/specs.csv", + "vets_specs": "csv-files/vets_specs.csv", + "types": "csv-files/types.csv", + "owners": "csv-files/owners.csv", + "pets": "csv-files/pets.csv", + "visits": "csv-files/visits.csv" +} + + +@dataclass +class VetRow: + id: str + first_name: str + last_name: str + + +@dataclass +class Vet: + first_name: str + last_name: str + speciality: Optional[str] + + def to_dict(self) -> dict: + return { + "first_name": self.first_name, + "last_name": self.last_name, + "speciality": self.speciality + } + + +@dataclass +class VisitRow: + id: str + pet_id: str + visit_date: str + description: str + + +@dataclass +class Visit: + visit_date: date + description: str + + def to_dict(self) -> dict: + return { + "visit_date": self.visit_date, + "description": self.description + } + + +@dataclass +class PetRow: + id: str + name: str + birth_date: str + type_id: str + owner_id: str + + +@dataclass +class Pet: + name: str + birth_date: date + type: str + visits: list[Visit] + + def to_dict(self) -> dict: + return { + "name": self.name, + "birth_date": self.birth_date, + "type": self.type, + "visits": [visit.to_dict() for visit in self.visits] + } + + +@dataclass +class OwnerRow: + id: str + first_name: str + last_name: str + address: str + city: str + telephone: str + + +@dataclass +class Owner: + first_name: str + last_name: str + address: str + city: str + telephone: str + pets: dict[UUID: Pet] + + def to_dict(self) -> dict: + return { + "first_name": self.first_name, + "last_name": self.last_name, + "address": self.address, + "city": self.city, + "telephone": self.telephone, + "pets": {pet_id: pet.to_dict() for pet_id, pet in self.pets.items()} + } + + +def main() -> None: + with open(FILE_PATHS["types"], newline='') as types_file: + reader = csv.reader(types_file, delimiter=';') + next(reader, None) + types_map = {int(row[0]): row[1] for row in reader} + + with open(FILE_PATHS["specs"], newline='') as specs_file: + reader = csv.reader(specs_file, delimiter=';') + next(reader, None) + specs_map = {int(row[0]): row[1] for row in reader} + + with open(FILE_PATHS["vets_specs"], newline='') as vet_specs_file: + reader = csv.reader(vet_specs_file, delimiter=';') + next(reader, None) + vet_specs_map = {int(row[0]): int(row[1]) for row in reader} + + with open(FILE_PATHS["vets"], newline='') as vet_file: + reader = csv.reader(vet_file, delimiter=';') + next(reader, None) + vet_rows = [VetRow(*row) for row in reader] + + with open(FILE_PATHS["visits"], newline='') as visits_file: + reader = csv.reader(visits_file, delimiter=';') + next(reader, None) + visits_rows = [VisitRow(*row) for row in reader] + + with open(FILE_PATHS["pets"], newline='') as pets_file: + reader = csv.reader(pets_file, delimiter=';') + next(reader, None) + pet_rows = [PetRow(*row) for row in reader] + + with open(FILE_PATHS["owners"], newline='') as owners_file: + reader = csv.reader(owners_file, delimiter=';') + next(reader, None) + owner_rows = [OwnerRow(*row) for row in reader] + + vets = [ + Vet( + first_name=row.first_name, + last_name=row.last_name, + speciality=specs_map.get(vet_specs_map.get(int(row.id), -1)) + ) for row in vet_rows + ] + + owners = [ + Owner( + first_name=row.first_name, + last_name=row.last_name, + address=row.address, + city=row.city, + telephone=row.telephone, + pets={ + str(uuid4()): Pet( + name=pet_row.name, + birth_date=datetime.strptime(pet_row.birth_date, '%Y-%m-%d'), + type=types_map[int(pet_row.type_id)], + visits=[ + Visit( + visit_date=datetime.strptime(visit_row.visit_date, '%Y-%m-%d'), + description=visit_row.description + ) for visit_row in visits_rows + ] + ) for pet_row in pet_rows + } + ) for row in owner_rows + ] + + client = MongoClient('mongodb://petclinic:petclinic@localhost:27017/') + db = client['petclinic'] + + vets_collection = db['vets'] + owners_collection = db['owners'] + specs_collection = db["specializations"] + types_collection = db["types"] + + vets_collection.insert_many([vet.to_dict() for vet in vets]) + owners_collection.insert_many([owner.to_dict() for owner in owners]) + specs_collection.insert_many([{"name": name} for name in specs_map.values()]) + types_collection.insert_many([{"name": name} for name in types_map.values()]) + + print("Migration done") + + +if __name__ == "__main__": + main() diff --git a/src/main/resources/db/mongo/requirements.txt b/src/main/resources/db/mongo/requirements.txt new file mode 100644 index 000000000..de4887b56 --- /dev/null +++ b/src/main/resources/db/mongo/requirements.txt @@ -0,0 +1 @@ +pymongo