Skip to content

Commit e3dc1b0

Browse files
authored
Merge pull request #18 from EtWnn/develop
Develop
2 parents 52d9c9e + 12e3968 commit e3dc1b0

18 files changed

+2859
-2
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,6 @@ dmypy.json
141141
# except README
142142
!**/README.md
143143

144-
# except credentials example
145-
!data/credentials.json.example
146144

147145
# except gitkeep
148146
!**/.gitkeep

BinanceWatch/BinanceManager.py

Lines changed: 683 additions & 0 deletions
Large diffs are not rendered by default.

BinanceWatch/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__version__ = "0.1.0"
2+
__author__ = 'EtWnn'

BinanceWatch/storage/BinanceDataBase.py

Lines changed: 1071 additions & 0 deletions
Large diffs are not rendered by default.

BinanceWatch/storage/DataBase.py

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
from enum import Enum
2+
from typing import List, Tuple, Optional, Any, Union
3+
import sqlite3
4+
5+
from BinanceWatch.storage.tables import Table
6+
from BinanceWatch.utils.LoggerGenerator import LoggerGenerator
7+
from BinanceWatch.utils.paths import get_data_path
8+
9+
10+
class SQLConditionEnum(Enum):
11+
"""
12+
https://www.techonthenet.com/sqlite/comparison_operators.php
13+
"""
14+
equal = '='
15+
greater_equal = '>='
16+
greater = '>'
17+
lower = '<'
18+
lower_equal = '<='
19+
diff = '!='
20+
21+
22+
class DataBase:
23+
"""
24+
This class will be used to interact with sqlite3 databases without having to generates sqlite commands
25+
"""
26+
27+
def __init__(self, name: str):
28+
self.name = name
29+
self.logger = LoggerGenerator.get_logger(self.name)
30+
self.save_path = get_data_path() / f"{name}.db"
31+
self.db_conn = sqlite3.connect(self.save_path)
32+
self.db_cursor = self.db_conn.cursor()
33+
34+
def _fetch_rows(self, execution_cmd: str):
35+
"""
36+
execute a command to fetch some rows and return them
37+
:param execution_cmd: the command to execute
38+
:return:
39+
"""
40+
rows = []
41+
try:
42+
self.db_cursor.execute(execution_cmd)
43+
except sqlite3.OperationalError:
44+
return rows
45+
while True:
46+
row = self.db_cursor.fetchone()
47+
if row is None:
48+
break
49+
rows.append(row)
50+
return rows
51+
52+
def get_row_by_key(self, table: Table, key_value) -> Optional[Tuple]:
53+
"""
54+
get the row identified by a primary key value from a table
55+
:param table: table to fetch the row from
56+
:param key_value: key value of the row
57+
:return: None or the row of value
58+
"""
59+
if table.primary_key is None:
60+
raise ValueError(f"table {table.name} has no explicit primary key")
61+
conditions_list = [(table.primary_key, SQLConditionEnum.equal, key_value)]
62+
rows = self.get_conditions_rows(table, conditions_list=conditions_list)
63+
if len(rows):
64+
return rows[0]
65+
66+
def get_conditions_rows(self, table: Table,
67+
selection: Optional[Union[str, List[str]]] = None,
68+
conditions_list: Optional[List[Tuple[str, SQLConditionEnum, Any]]] = None,
69+
order_list: Optional[List[str]] = None) -> List:
70+
if selection is None:
71+
selection = '*'
72+
elif isinstance(selection, List):
73+
selection = ','.join(selection)
74+
if conditions_list is None:
75+
conditions_list = []
76+
if order_list is None:
77+
order_list = []
78+
execution_cmd = f"SELECT {selection} from {table.name}"
79+
execution_cmd = self._add_conditions(execution_cmd, conditions_list=conditions_list)
80+
execution_cmd = self._add_order(execution_cmd, order_list=order_list)
81+
return self._fetch_rows(execution_cmd)
82+
83+
def get_all_rows(self, table: Table) -> List:
84+
return self.get_conditions_rows(table)
85+
86+
def add_row(self, table: Table, row: Tuple, auto_commit: bool = True, update_if_exists: bool = False):
87+
row_s = ", ".join(f"'{v}'" for v in row)
88+
row_s = f'({row_s})'
89+
execution_order = f"INSERT INTO {table.name} VALUES {row_s}"
90+
try:
91+
self.db_cursor.execute(execution_order)
92+
if auto_commit:
93+
self.commit()
94+
except sqlite3.OperationalError:
95+
self.create_table(table)
96+
self.db_cursor.execute(execution_order)
97+
if auto_commit:
98+
self.commit()
99+
except sqlite3.IntegrityError as err:
100+
if update_if_exists:
101+
self.update_row(table, row, auto_commit)
102+
else:
103+
raise err
104+
105+
def add_rows(self, table: Table, rows: List[Tuple], auto_commit: bool = True, update_if_exists: bool = False):
106+
for row in rows:
107+
self.add_row(table, row, auto_commit=False, update_if_exists=update_if_exists)
108+
if auto_commit:
109+
self.commit()
110+
111+
def update_row(self, table: Table, row: Tuple, auto_commit=True):
112+
row_s = ", ".join(f"{n} = {v}" for n, v in zip(table.columns_names, row))
113+
execution_order = f"UPDATE {table.name} SET {row_s} WHERE {table.primary_key} = {row[0]}"
114+
self.db_cursor.execute(execution_order)
115+
if auto_commit:
116+
self.commit()
117+
118+
def create_table(self, table: Table):
119+
"""
120+
create a table in the database
121+
:param table: Table instance with the config of the table to create
122+
:return:
123+
"""
124+
create_cmd = self.get_create_cmd(table)
125+
self.db_cursor.execute(create_cmd)
126+
self.db_conn.commit()
127+
128+
def drop_table(self, table: Union[Table, str]):
129+
"""
130+
delete a table from the database
131+
132+
:param table: table or table name to drop
133+
:type table: str or Table instance
134+
:return: None
135+
:rtype: None
136+
"""
137+
if isinstance(table, Table):
138+
table = table.name
139+
execution_order = f"DROP TABLE IF EXISTS {table}"
140+
self.db_cursor.execute(execution_order)
141+
self.db_conn.commit()
142+
143+
def drop_all_tables(self):
144+
"""
145+
drop all the tables existing in the database
146+
147+
:return: None
148+
:rtype: None
149+
"""
150+
tables_desc = self.get_all_tables()
151+
for table_desc in tables_desc:
152+
self.drop_table(table_desc[1])
153+
self.commit()
154+
155+
def get_all_tables(self) -> List[Tuple]:
156+
"""
157+
return all the tables existing in the database
158+
159+
:return: tables descriptions
160+
:rtype: List[Tuple]
161+
"""
162+
cmd = "SELECT * FROM sqlite_master WHERE type='table';"
163+
return self._fetch_rows(cmd)
164+
165+
def commit(self):
166+
"""
167+
submit and save the database state
168+
:return:
169+
"""
170+
self.db_conn.commit()
171+
172+
@staticmethod
173+
def _add_conditions(execution_cmd: str, conditions_list: List[Tuple[str, SQLConditionEnum, Any]]):
174+
"""
175+
add a list of condition to an SQL command
176+
:param execution_cmd: SQL command without 'WHERE' statement
177+
:type execution_cmd: str
178+
:param conditions_list:
179+
:return:
180+
"""
181+
if len(conditions_list):
182+
add_cmd = ' WHERE'
183+
for column_name, condition, value in conditions_list:
184+
add_cmd = add_cmd + f" {column_name} {condition.value} '{value}' AND"
185+
return execution_cmd + add_cmd[:-4]
186+
else:
187+
return execution_cmd
188+
189+
@staticmethod
190+
def _add_order(execution_cmd: str, order_list: List[str]):
191+
"""
192+
add an order specification to an SQL command
193+
194+
:param execution_cmd: SQL command without 'ORDER BY' statement
195+
:type execution_cmd: str
196+
:param order_list:
197+
:type order_list:
198+
:return:
199+
:rtype:
200+
"""
201+
if len(order_list):
202+
add_cmd = ' ORDER BY'
203+
for column_name in order_list:
204+
add_cmd = add_cmd + f" {column_name},"
205+
return execution_cmd + add_cmd[:-1] + ' ASC'
206+
else:
207+
return execution_cmd
208+
209+
@staticmethod
210+
def get_create_cmd(table: Table):
211+
"""
212+
return the command in string format to create a table in the database
213+
:param table: Table instance with the config if the table to create
214+
:return: execution command for the table creation
215+
"""
216+
cmd = ""
217+
if table.primary_key is not None:
218+
cmd = f"[{table.primary_key}] {table.primary_key_sql_type} PRIMARY KEY, "
219+
for arg_name, arg_type in zip(table.columns_names, table.columns_sql_types):
220+
cmd = cmd + f"[{arg_name}] {arg_type}, "
221+
return f"CREATE TABLE {table.name}\n({cmd[:-2]})"

BinanceWatch/storage/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)