database_handler.py
DatabaseHandler
¶
Handles all operations related to the database including CRUD for the different db elements.
Attributes:
| Name | Type | Description |
|---|---|---|
database |
Database |
Object encapsulating the database in TinyDB format and usable tournament related objects. |
helper |
DatabaseHelper |
Object with helper methods to manipulate and transform db objects. |
players_table |
table.Table |
Instance of TinyDB "Players" Table. |
tournaments_table |
table.Table |
Instance of TinyDB "Tournaments" Table. |
rounds_table |
table.Table |
Instance of TinyDB "Rounds" Table. |
matches_table |
table.Table |
Instance of TinyDB "Matches" Table. |
__init__(self)
special
¶
Constructor for DatabaseHandler Class. Initiates database loading.
Source code in controller/database_handler.py
def __init__(self):
"""Constructor for DatabaseHandler Class. Initiates database loading."""
self.database = Database(_CONFIG.config["database_file"])
self.helper = DatabaseHelper(database=self.database)
self.players_table = None
self.tournaments_table = None
self.rounds_table = None
self.matches_table = None
self.load_database()
create_match(self, players, tournament_id, round_id, winner, id_num=0, no_db_save=False)
¶
Creates a Match object and saves it into Database attributes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
players |
tuple |
Tuple of the two facing players. |
required |
tournament_id |
int |
Match's tournament id. |
required |
round_id |
int |
Match's round id.. |
required |
winner |
int |
Match's winner. Either 1 (first player), 2 (second player) or 0 (draw). |
required |
id_num |
int |
Match's id. Defaults to 0. |
0 |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Source code in controller/database_handler.py
def create_match(
self, players: tuple, tournament_id: int, round_id: int, winner: int, id_num: int = 0, no_db_save: bool = False
):
"""Creates a Match object and saves it into Database attributes.
Args:
players (tuple): Tuple of the two facing players.
tournament_id (int): Match's tournament id.
round_id (int): Match's round id..
winner (int): Match's winner. Either 1 (first player), 2 (second player) or 0 (draw).
id_num (int, optional): Match's id. Defaults to 0.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
"""
if id_num == 0:
id_num = self.find_next_id(self.matches_table)
match = Match(
players=players,
tournament_id=tournament_id,
round_id=round_id,
winner=winner,
id_num=id_num,
)
self.save_match(match=match, no_db_save=no_db_save)
create_player(self, first_name, last_name, dob, gender, elo, id_num=0, is_deleted=False, no_db_save=False)
¶
Creates a Player object and saves it into Database attributes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
first_name |
str |
Player's first name. |
required |
last_name |
str |
Player's last name. |
required |
dob |
str |
Player's date of birth. |
required |
gender |
str |
Player's gender. |
required |
elo |
int |
Player's ELO ranking. |
required |
id_num |
int |
Player's id. Defaults to 0. |
0 |
is_deleted |
bool |
Is player deleted. Defaults to False. |
False |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Returns:
| Type | Description |
|---|---|
int |
Created player's id. |
Source code in controller/database_handler.py
def create_player(
self,
first_name: str,
last_name: str,
dob: str,
gender: str,
elo: int,
id_num: int = 0,
is_deleted: bool = False,
no_db_save: bool = False,
):
"""Creates a Player object and saves it into Database attributes.
Args:
first_name (str): Player's first name.
last_name (str): Player's last name.
dob (str): Player's date of birth.
gender (str): Player's gender.
elo (int): Player's ELO ranking.
id_num (int, optional): Player's id. Defaults to 0.
is_deleted (bool, optional): Is player deleted. Defaults to False.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
Returns:
int: Created player's id.
"""
if id_num == 0:
id_num = self.find_next_id(self.players_table)
player = Player(first_name, last_name, dob, gender.upper(), elo, id_num, is_deleted)
self.save_player(player=player, no_db_save=no_db_save)
return id_num
create_round(self, round_number, tournament_id, id_num=0, no_db_save=False)
¶
Creates a Round object and saves it into Database attributes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
round_number |
int |
Ordered round number. |
required |
tournament_id |
int |
Round's tournament id. |
required |
id_num |
int |
Round id. Defaults to 0. |
0 |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Returns:
| Type | Description |
|---|---|
int |
Created round id. |
Source code in controller/database_handler.py
def create_round(self, round_number: int, tournament_id: int, id_num: int = 0, no_db_save: bool = False):
"""Creates a Round object and saves it into Database attributes.
Args:
round_number (int): Ordered round number.
tournament_id (int): Round's tournament id.
id_num (int, optional): Round id. Defaults to 0.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
Returns:
int: Created round id.
"""
if id_num == 0:
id_num = self.find_next_id(self.rounds_table)
created_round = Round(round_number=round_number, tournament_id=tournament_id, id_num=id_num)
self.save_round(round_=created_round, no_db_save=no_db_save)
return id_num
create_tournament(self, name, location, date, number_of_rounds, time_control, description, players, leaderboard, id_num=0, is_finished=False, no_db_save=False)
¶
Creates a Tournament object and saves it into Database attributes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name |
str |
Tournament's name. |
required |
location |
str |
Tournament's physical location. |
required |
date |
str |
Tournament's date. |
required |
number_of_rounds |
int |
Number of rounds to be played. |
required |
time_control |
str |
Type of time control chosen. |
required |
description |
str |
Tournament's description. |
required |
players |
list |
Participating players ids. |
required |
leaderboard |
dict |
Tournament's leaderboard. |
required |
id_num |
int |
Tournament's id. Defaults to 0. |
0 |
is_finished |
bool |
Is tournament finished. Defaults to False. |
False |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Returns:
| Type | Description |
|---|---|
int |
Created tournament's id. |
Source code in controller/database_handler.py
def create_tournament(
self,
name: str,
location: str,
date: str,
number_of_rounds: int,
time_control: str,
description: str,
players: list[int],
leaderboard: dict,
id_num: int = 0,
is_finished: bool = False,
no_db_save: bool = False,
):
"""Creates a Tournament object and saves it into Database attributes.
Args:
name (str): Tournament's name.
location (str): Tournament's physical location.
date (str): Tournament's date.
number_of_rounds (int): Number of rounds to be played.
time_control (str): Type of time control chosen.
description (str): Tournament's description.
players (list[int]): Participating players ids.
leaderboard (dict): Tournament's leaderboard.
id_num (int, optional): Tournament's id. Defaults to 0.
is_finished (bool, optional): Is tournament finished. Defaults to False.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
Returns:
int: Created tournament's id.
"""
if id_num == 0:
id_num = self.find_next_id(self.tournaments_table)
# Create required list of Player objects from players ids.
player_objects = []
for player in players:
player_objects.append(self.database.players[player])
# Create an empty leaderboard if it doesn't exist yet.
if len(leaderboard) == 0:
for player in players:
leaderboard[str(player)] = 0
tournament = Tournament(
name=name,
location=location,
date=date,
number_of_rounds=number_of_rounds,
time_control=time_control,
description=description,
id_num=id_num,
is_finished=is_finished,
players=player_objects,
leaderboard=leaderboard,
)
self.save_tournament(tournament=tournament, no_db_save=no_db_save)
return id_num
delete_match(self, match)
¶
Deletes a match in database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
match |
Match |
Match to be deleted. |
required |
Source code in controller/database_handler.py
def delete_match(self, match: Match):
"""Deletes a match in database.
Args:
match (Match): Match to be deleted.
"""
query = Query()
self.matches_table.remove(query.id == int(match.id_num))
delete_player(self, player)
¶
Delete a player by setting a flag. User must persist in database for tournament history.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
player |
Player |
Player to be deleted. |
required |
Source code in controller/database_handler.py
def delete_player(self, player: Player):
"""Delete a player by setting a flag. User must persist in database for tournament history.
Args:
player (Player): Player to be deleted.
"""
player.is_deleted = True
self.save_player(player=player)
delete_round(self, round_)
¶
Deletes a round in database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
round_ |
Round |
Round to be deleted. |
required |
Source code in controller/database_handler.py
def delete_round(self, round_: Round):
"""Deletes a round in database.
Args:
round_ (Round): Round to be deleted.
"""
for match in round_.matches:
self.delete_match(match=round_.matches[match])
query = Query()
self.rounds_table.remove(query.id == int(round_.id_num))
delete_tournament(self, tournament)
¶
Deletes a tournament in database.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tournament |
Tournament |
Tournament to be deleted |
required |
Source code in controller/database_handler.py
def delete_tournament(self, tournament: Tournament):
"""Deletes a tournament in database.
Args:
tournament (Tournament): Tournament to be deleted
"""
self.load_rounds(tournament_id=tournament.id_num)
self.load_matches(tournament_id=tournament.id_num)
for round_ in tournament.rounds:
self.delete_round(round_=tournament.rounds[round_])
query = Query()
self.tournaments_table.remove(query.id == int(tournament.id_num))
del self.database.tournaments[int(tournament.id_num)]
find_next_id(self, table)
¶
Searches through a TinyDB table for the next biggest id number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
table |
Table |
TinyDB table to search in. |
required |
Returns:
| Type | Description |
|---|---|
int |
Next biggest id to be used. |
Source code in controller/database_handler.py
def find_next_id(self, table: table.Table):
"""Searches through a TinyDB table for the next biggest id number.
Args:
table (table.Table): TinyDB table to search in.
Returns:
int: Next biggest id to be used.
"""
if len(table) == 0:
return 1
query = Query()
biggest = 1
while len(table.search(query.id >= biggest)) > 0:
biggest += 1
return biggest
find_unfinished_tournaments(self)
¶
Searches through the Tournaments table for unfinished tournament.
Returns:
| Type | Description |
|---|---|
list[table.Document] |
Unfinished tournaments. |
Source code in controller/database_handler.py
def find_unfinished_tournaments(self):
"""Searches through the Tournaments table for unfinished tournament.
Returns:
list[table.Document]: Unfinished tournaments.
"""
query = Query()
result = self.tournaments_table.search(query["Is Finished"] is False)
return result
load_database(self)
¶
Instantiates the different tables in attributes and loads their content by creating corresponding objects.
Source code in controller/database_handler.py
def load_database(self):
"""Instantiates the different tables in attributes and loads their content
by creating corresponding objects.
"""
self.players_table = self.database.db.table("players")
self.tournaments_table = self.database.db.table("tournaments")
self.rounds_table = self.database.db.table("rounds")
self.matches_table = self.database.db.table("matches")
self.load_players()
self.load_tournaments()
load_matches(self, tournament_id)
¶
Uses TinyDB "Matches" table to create Match objects for one particular tournament.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tournament_id |
int |
Tournament to be considered. |
required |
Source code in controller/database_handler.py
def load_matches(self, tournament_id: int):
"""Uses TinyDB "Matches" table to create Match objects for one particular tournament.
Args:
tournament_id (int): Tournament to be considered.
"""
for match in self.matches_table:
if match["Tournament id"] != tournament_id:
continue
player_1 = self.database.players[match["Player 1"]]
player_2 = self.database.players[match["Player 2"]]
players = (player_1, player_2)
self.create_match(
players=players,
tournament_id=match["Tournament id"],
round_id=match["Round id"],
winner=match["Winner"],
id_num=match["id"],
no_db_save=True,
)
load_players(self)
¶
Uses TinyDB "Players" table to create Player objects.
Source code in controller/database_handler.py
def load_players(self):
"""Uses TinyDB "Players" table to create Player objects."""
for player in self.players_table:
self.create_player(
first_name=player["First Name"],
last_name=player["Last Name"],
dob=player["DOB"],
gender=player["Gender"],
elo=player["ELO"],
id_num=player["id"],
is_deleted=player["Is Deleted"],
no_db_save=True,
)
load_rounds(self, tournament_id)
¶
Uses TinyDB "Rounds" table to create Round objects for one particular tournament.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tournament_id |
int |
Tournament to be considered. |
required |
Source code in controller/database_handler.py
def load_rounds(self, tournament_id: int):
"""Uses TinyDB "Rounds" table to create Round objects for one particular tournament.
Args:
tournament_id (int): Tournament to be considered.
"""
for round_ in self.rounds_table:
if round_["Tournament id"] != tournament_id:
continue
self.create_round(
round_number=round_["Round number"],
tournament_id=round_["Tournament id"],
id_num=round_["id"],
no_db_save=True,
)
load_tournaments(self)
¶
Uses TinyDB "Tournaments" table to create Player objects.
Source code in controller/database_handler.py
def load_tournaments(self):
"""Uses TinyDB "Tournaments" table to create Player objects."""
for tournament in self.tournaments_table:
self.create_tournament(
name=tournament["Name"],
location=tournament["Location"],
date=tournament["Date"],
number_of_rounds=tournament["Number of rounds"],
time_control=tournament["Time Control"],
description=tournament["Description"],
id_num=tournament["id"],
is_finished=tournament["Is Finished"],
players=tournament["Players"],
leaderboard=tournament["Leaderboard"],
no_db_save=True,
)
save_match(self, match, no_db_save=False)
¶
Saves a Match object to memory and TinyDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
match |
Match |
Match object to be saved. |
required |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Source code in controller/database_handler.py
def save_match(self, match: Match, no_db_save: bool = False):
"""Saves a Match object to memory and TinyDB.
Args:
match (Match): Match object to be saved.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
"""
self.database.tournaments[match.tournament_id].rounds[match.round_id].matches[match.id_num] = match
if no_db_save:
return
query = Query()
self.matches_table.upsert(
{
"Player 1": match.player_1.id_num,
"Player 2": match.player_2.id_num,
"Winner": match.winner,
"Tournament id": int(match.tournament_id),
"Round id": int(match.round_id),
"id": int(match.id_num),
},
query.id == int(match.id_num),
)
save_player(self, player, no_db_save=False)
¶
Saves a Player object to TinyDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
player |
Player |
Player object to be saved. |
required |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Source code in controller/database_handler.py
def save_player(self, player: Player, no_db_save: bool = False):
"""Saves a Player object to TinyDB.
Args:
player (Player): Player object to be saved.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
"""
self.database.players[player.id_num] = player
if no_db_save:
return
query = Query()
self.players_table.upsert(
{
"First Name": player.first_name,
"Last Name": player.last_name,
"DOB": player.dob,
"Gender": player.gender,
"ELO": int(player.elo),
"id": int(player.id_num),
"Is Deleted": player.is_deleted,
},
query.id == int(player.id_num),
)
save_round(self, round_, no_db_save=False)
¶
Saves a Round object to memory and TinyDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
round_ |
Round |
Round object to be saved. Underscore added because of reserved keyword. |
required |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Source code in controller/database_handler.py
def save_round(self, round_: Round, no_db_save: bool = False):
"""Saves a Round object to memory and TinyDB.
Args:
round_ (Round): Round object to be saved. Underscore added because of reserved keyword.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
"""
self.database.tournaments[round_.tournament_id].rounds[round_.id_num] = round_
if no_db_save:
return
query = Query()
self.rounds_table.upsert(
{
"Round number": round_.round_number,
"Tournament id": int(round_.tournament_id),
"id": int(round_.id_num),
},
query.id == int(round_.id_num),
)
save_tournament(self, tournament, no_db_save=False)
¶
Saves a Tournament object to memory and TinyDB.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tournament |
Tournament |
Tournament object to be saved. |
required |
no_db_save |
bool |
If the object only needs to be saved in memory, not in db. Defaults to False. |
False |
Source code in controller/database_handler.py
def save_tournament(self, tournament: Tournament, no_db_save: bool = False):
"""Saves a Tournament object to memory and TinyDB.
Args:
tournament (Tournament): Tournament object to be saved.
no_db_save (bool, optional): If the object only needs to be saved in memory, not in db. Defaults to False.
"""
self.database.tournaments[tournament.id_num] = tournament
if no_db_save:
return
query = Query()
players_id = []
for player in tournament.players:
players_id.append(player.id_num)
self.tournaments_table.upsert(
{
"Name": tournament.name,
"Location": tournament.location,
"Date": tournament.date,
"Number of rounds": int(tournament.number_of_rounds),
"Time Control": tournament.time_control,
"Description": tournament.description,
"Players": players_id,
"Leaderboard": tournament.leaderboard,
"Is Finished": tournament.is_finished,
"id": int(tournament.id_num),
},
query.id == int(tournament.id_num),
)
update_leaderboard(self, tournament_id, player_id, points_earned)
¶
Updates a tournament's leaderboard by adding points to a player.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tournament_id |
int |
Tounament's id. |
required |
player_id |
int |
Player's id. |
required |
points_earned |
float |
Points earned by the player. |
required |
Source code in controller/database_handler.py
def update_leaderboard(self, tournament_id: int, player_id: int, points_earned: float):
"""Updates a tournament's leaderboard by adding points to a player.
Args:
tournament_id (int): Tounament's id.
player_id (int): Player's id.
points_earned (float): Points earned by the player.
"""
tournament = self.database.tournaments[tournament_id]
tournament.leaderboard[str(player_id)] += points_earned
self.save_tournament(tournament=tournament)
SingletonMeta
¶
Meta for singleton application. As DataHandler will be used by different modules there is no need to load the database multiple time. Singleton was kept simple and is currently not thread safe.