Commit def0ae84 authored by Stefan Vercillo's avatar Stefan Vercillo
Browse files

cli update working

parent b0c2a642
DB_USER=snvercil
DB_PASSWORD=pass
DB_HOST=127.0.0.1
DB_NAME=education
DB_NAME=Education
......@@ -6,13 +6,13 @@ from get_attributes import *
from parser import *
sys.path.insert(0, "..") # import parent folde
from models.base_model import BaseModel
from models.assessments import Assessments
from models.base_model import BaseModel
from models.assessments import Assessments
from models.courseInfo import CourseInfo
from models.courseOfferings import CourseOfferings
from models.courseInfo import BaseModel
from controller import Controller
from models.base_model import BaseModel
from models.base_model import BaseModel
from models.assessments import Assessments
from utils.data_structures.sql_object import (
Attributes,
......@@ -27,167 +27,231 @@ controller = Controller()
def handle_collecting_insert_args(attributes, new_row):
# the first element in attributes is the PK
for i in range(len(attributes)):
if i == 0:
# new_row[attributes[i]] = input(f"specify {attributes[i]} (this is a PK - it is required): ")
# if new_row[attributes[i]] == '': return -1
continue
new_row[attributes[i]] = input(f"specify {attributes[i]} (blank space for none): ")
return 0
# the first element in attributes is the PK
for i in range(len(attributes)):
if i == 0:
# new_row[attributes[i]] = input(f"specify {attributes[i]} (this is a PK - it is required): ")
# if new_row[attributes[i]] == '': return -1
continue
new_row[attributes[i]] = input(
f"specify {attributes[i]} (blank space for none): "
)
return 0
def handle_collecting_modify_args(attributes, new_row):
# the first element in attributes is the PK
for i in range(len(attributes)):
if i == 0:
new_row[attributes[i]] = input(f"specify {attributes[i]} (this is a PK - it is required): ")
if new_row[attributes[i]] == '': return -1
continue
new_row[attributes[i]] = input(f"specify {attributes[i]} (blank space for no change): ")
return 0
# the first element in attributes is the PK
for i in range(len(attributes)):
new_row[attributes[i]] = input(
f"specify {attributes[i]} (blank space for no change): "
)
return 0
def handle_filtering_on_table(attributes, filters):
print(f"applying filters for {attributes}")
int_operators = ["=", ">", "<", ">=", "<=", "<>"]
string_operators = ["LIKE", "="]
bool_operators = ["="]
should_filter = input(f"Would you like to apply a filter for any of `{attributes}`? \n 'y' or 'yes': ") in {"y", "yes"}
while (should_filter):
filtering_attribute = input(f"Which would you like to filter on out of {attributes}: ")
while (filtering_attribute not in attributes):
filtering_attribute = input(f"Which would you like to filter on out of {attributes}: ")
print(f"Filtering on {filtering_attribute}. The type is {attribute_type[filtering_attribute]}")
if attribute_type[filtering_attribute] == int:
operator = input(f"Enter the operator (in {int_operators}): ")
while operator not in int_operators:
operator = input(f"Enter the operator (in {int_operators}): ")
value = int(input("Enter the filtering value (must be int): "))
if attribute_type[filtering_attribute] == str:
print("note: wildcard matching works on 'LIKE' operator")
operator = input(f"Pick an operator ({string_operators}): ")
while operator not in string_operators:
operator = input(f"Pick an operator ({string_operators}): ")
value = input("Enter the filtering value: ")
if attribute_type[filtering_attribute] == bool:
operator = input(f"Pick an operator ({bool_operators}): ")
while operator not in bool_operators:
operator = input(f"Pick an operator ({bool_operators}): ")
value = input("Enter the filtering value (1 or 0): ")
while value not in {"0", "1"}:
value = input("Enter the filtering value (1 or 0): ")
filters.append({
"attribute" : filtering_attribute,
"value" : value,
"operator" : operator
})
should_filter = input(f"Would you like to apply another filter for any of `{attributes}`? \n 'y' or 'yes': ") in {"y", "yes"}
print(f"applying filters for {attributes}")
int_operators = ["=", ">", "<", ">=", "<=", "<>"]
string_operators = ["LIKE", "="]
bool_operators = ["="]
should_filter = input(
f"Would you like to apply a filter for any of `{attributes}`? \n 'y' or 'yes': "
) in {"y", "yes"}
while should_filter:
filtering_attribute = input(
f"Which would you like to filter on out of {attributes}: "
)
while filtering_attribute not in attributes:
filtering_attribute = input(
f"Which would you like to filter on out of {attributes}: "
)
print(
f"Filtering on {filtering_attribute}. The type is {attribute_type[filtering_attribute]}"
)
if attribute_type[filtering_attribute] == int:
operator = input(f"Enter the operator (in {int_operators}): ")
while operator not in int_operators:
operator = input(f"Enter the operator (in {int_operators}): ")
value = int(input("Enter the filtering value (must be int): "))
if attribute_type[filtering_attribute] == str:
print("note: wildcard matching works on 'LIKE' operator")
operator = input(f"Pick an operator ({string_operators}): ")
while operator not in string_operators:
operator = input(f"Pick an operator ({string_operators}): ")
value = input("Enter the filtering value: ")
if attribute_type[filtering_attribute] == bool:
operator = input(f"Pick an operator ({bool_operators}): ")
while operator not in bool_operators:
operator = input(f"Pick an operator ({bool_operators}): ")
value = input("Enter the filtering value (1 or 0): ")
while value not in {"0", "1"}:
value = input("Enter the filtering value (1 or 0): ")
filters.append(
{"attribute": filtering_attribute, "value": value, "operator": operator}
)
should_filter = input(
f"Would you like to apply another filter for any of `{attributes}`? \n 'y' or 'yes': "
) in {"y", "yes"}
def insert_base_func(command):
insert_entry_args = insert_entry_parser.parse_args(command[1:])
new_row = dict()
# branch based on the table
if handle_collecting_insert_args(
attributes=get_attributes_from_tablename[insert_entry_args.table],
new_row=new_row
) == -1: return
OBJ_CLS = controller.relation_2_class_map[insert_entry_args.table]
new_row = OBJ_CLS.clean_row(new_row)
OBJ_CLS(**new_row)
print(f"INSERTING row: \n {new_row} \n into table {insert_entry_args.table}")
def modify_base_func(command):
modify_table_args = modify_table_parser.parse_args(command[1:])
new_row = dict()
# branch based on the table
if handle_collecting_modify_args(
attributes=get_attributes_from_tablename[modify_table_args.table],
new_row=new_row
) == -1: return
def insert_base_func(command):
insert_entry_args = insert_entry_parser.parse_args(command[1:])
new_row = dict()
OBJ_CLS = controller.relation_2_class_map[modify_table_args.table]
# branch based on the table
if (
handle_collecting_insert_args(
attributes=get_attributes_from_tablename[insert_entry_args.table],
new_row=new_row,
)
== -1
):
return
new_row = OBJ_CLS.clean_row(new_row)
OBJ_CLS(**new_row)
OBJ_CLS = controller.relation_2_class_map[insert_entry_args.table]
new_row = OBJ_CLS.clean_row(new_row)
OBJ_CLS(**new_row)
print(f"INSERTING row: \n {new_row} \n into table {insert_entry_args.table}")
print(f"INSERTING row: \n {new_row} \n into table {modify_table_args.table}")
def modify_base_func(command):
modify_table_args = modify_table_parser.parse_args(command[1:])
new_row = dict()
# branch based on the table
if (
handle_collecting_modify_args(
attributes=get_attributes_from_tablename[modify_table_args.table],
new_row=new_row,
)
== -1
):
return
filters = []
if (
handle_filtering_on_table(
attributes=get_attributes_from_tablename[modify_table_args.table],
filters=filters,
)
== -1
):
return
to_pop = []
for e in new_row:
if new_row[e] == "" or len(new_row[e]) == 0:
to_pop.append(e)
for e in to_pop:
new_row.pop(e)
if len(new_row) == 0:
print("Error: specify attribute to update")
to_set_conds = []
for e in new_row:
to_set_conds.append(
Filter(Attributes(e), Operator("="), AttributeValue(new_row[e]))
)
filter_conds = []
for f in filters:
filter_conds.append(
Filter(
Attributes(f["attribute"]),
Operator(f["operator"]),
AttributeValue(f["value"]),
)
)
OBJ_CLS = controller.relation_2_class_map[modify_table_args.table](
skip_creation=False
)
new_row = OBJ_CLS.clean_row(new_row)
OBJ_CLS._update_set_where(OBJ_CLS.__tablename__, to_set_conds, filter_conds)
print(
f"Updating rows where: \n {filters if len(filters) != 0 else 'TRUE'} \n {modify_table_args.table}"
)
def delete_base_func(command):
delete_rows_args = delete_rows_parser.parse_args(command[1:])
filters = list()
# branch based on the table
handle_filtering_on_table(
attributes=get_attributes_from_tablename[delete_rows_args.table],
filters=filters
) == -1: return
conditions = []
for f in filters:
conditions.append(Filter(Attributes(f['attribute']), Operator(f['operator']), AttributeValue(f['value'])))
OBJ_CLS = controller.relation_2_class_map[delete_rows_parser.table](skip_creation=True)
OBJ_CLS._delete_from_where(
relation=delete_rows_parser.table,
conditions=conditions,
)
delete_rows_args = delete_rows_parser.parse_args(command[1:])
filters = list()
# branch based on the table
if (
handle_filtering_on_table(
attributes=get_attributes_from_tablename[delete_rows_args.table],
filters=filters,
)
== -1
):
return
conditions = []
for f in filters:
conditions.append(
Filter(
Attributes(f["attribute"]),
Operator(f["operator"]),
AttributeValue(f["value"]),
)
)
OBJ_CLS = controller.relation_2_class_map[delete_rows_parser.table](
skip_creation=True
)
OBJ_CLS._delete_from_where(
relation=delete_rows_parser.table,
conditions=conditions,
)
print(f"DELETING rows from {delete_rows_args.table}: \n with filters: {filters} \n")
print("\nSUCCESS!\n")
print(f"DELETING rows from {delete_rows_args.table}: \n with filters: {filters} \n")
print("\nSUCCESS!\n")
def get_base_func(command):
get_rows_args = get_rows_parser.parse_args(command[1:])
filters = list()
attrbutes = get_attributes_from_tablename[get_rows_args.table]
# apply filters
handle_filtering_on_table(
attributes=attrbutes,
filters=filters
)
print(f"Attributse : {attrbutes, type(attrbutes)}\n\n\n")
conditions = []
for f in filters:
conditions.append(Filter(Attributes(f['attribute']), Operator(f['operator']), AttributeValue(f['value'])))
OBJ_CLS = controller.relation_2_class_map[get_rows_args.table](skip_creation=True)
res = OBJ_CLS._select_from_where_join(
attributes=Attributes("*"),
relation=get_rows_args.table,
conditions=conditions,
)
print(f"GETTING rows from {get_rows_args.table}: \n with filters: {filters} \n")
for r in res:
print(r.__as_dict__())
get_rows_args = get_rows_parser.parse_args(command[1:])
filters = list()
attrbutes = get_attributes_from_tablename[get_rows_args.table]
# apply filters
if handle_filtering_on_table(attributes=attrbutes, filters=filters) == -1:
return
print(f"Attributse : {attrbutes, type(attrbutes)}\n\n\n")
conditions = []
for f in filters:
conditions.append(
Filter(
Attributes(f["attribute"]),
Operator(f["operator"]),
AttributeValue(f["value"]),
)
)
OBJ_CLS = controller.relation_2_class_map[get_rows_args.table](skip_creation=True)
res = OBJ_CLS._select_from_where_join(
attributes=Attributes("*"),
relation=get_rows_args.table,
conditions=conditions,
)
print(f"GETTING rows from {get_rows_args.table}: \n with filters: {filters} \n")
for r in res:
print(r.__as_dict__())
......@@ -9,7 +9,7 @@ from parser import *
options_switchcase = {
"insert" : insert_base_func,
"modify" : modify_base_func,
"df" : delete_base_func,
"delete-from" : delete_base_func,
"get-from" : get_base_func
}
......@@ -23,7 +23,7 @@ if __name__ == "__main__":
These are our base commands. For each of them, you must start by specifying the --table:
insert - inserts an entry into the table
modify - modifies an entry in a table by primary key
df - deletes a row (or mulitple rows) from the table
delete-from - deletes a row (or mulitple rows) from the table
get-from - fetches a set of rows from a table in the DB
These are the more 'user friendly' commands:
......
from api.models.courseInfo import CourseInfo
from models.studentUnregistration import StudentUnregistration
from models.assessments import Assessments
from models.courseOfferings import CourseOfferings
......@@ -18,31 +19,38 @@ class Controller:
self.relation_2_class_map[CourseOfferings.__tablename__] = CourseOfferings
self.relation_2_class_map[StudentAssessments.__tablename__] = StudentAssessments
self.relation_2_class_map[StudentRegistration.__tablename__] = StudentInfo
self.relation_2_class_map[StudentUnregistration.__tablename__] = StudentUnregistration
self.relation_2_class_map[
StudentUnregistration.__tablename__
] = StudentUnregistration
self.relation_2_class_map[StudentInfo.__tablename__] = StudentInfo
self.relation_2_class_map[CourseInfo.__tablename__] = CourseInfo
# self.relation_2_class_map[
# StudentRegistration.__tablename__
# ] = StudentRegistration
# JOINABLE TABLES
# JOINABLE TABLES
self.joinable_tables_map[Assessments.__tablename__] = set(
[StudentAssessments, CourseOfferings]
)
self.joinable_tables_map[CourseOfferings.__tablename__] = set(
[StudentAssessments, Assessments, StudentInfo, StudentRegistration, StudentUnregistration]
) # TODO add course info
[
StudentAssessments,
Assessments,
StudentInfo,
StudentRegistration,
StudentUnregistration,
]
) # TODO add course info
self.joinable_tables_map[StudentAssessments.__tablename__] = set(
[Assessments, StudentInfo]
)
)
self.joinable_tables_map[StudentInfo.__tablename__] = set(
[CourseOfferings, StudentAssessments]
)
def relations_list(self):
return list(self.relation_2_class_map.keys())
......@@ -23,7 +23,7 @@ from utils.data_structures.sql_object import (
from utils.abstract import AbstractBaseClass, abstractmethod
class BaseModel():
class BaseModel:
_dev_mode = True
_db_connections = DatabaseConnectionsQueue(
......@@ -38,7 +38,6 @@ class BaseModel():
def _get_columns(self) -> list:
pass
def __as_small_dict__(self):
pass
......@@ -94,7 +93,7 @@ class BaseModel():
)
return res
def _delete_from_where_str(
self,
relation: str,
......@@ -114,15 +113,53 @@ class BaseModel():
if i != len(conditions) - 1:
where_clause += " AND"
res = (
f"DELETE "
+ f"FROM {relation} "
+ f"{where_clause} ;"
)
res = f"DELETE " + f"FROM {relation} " + f"{where_clause} ;"
print(res)
return res
def _update_set_where_str(
self,
relation: str,
to_set_conds: list = [],
filter_conds: list = [], # list of type Filter
):
print("NNNNN")
print(filter_conds)
print(to_set_conds)
if type(to_set_conds) != list:
to_set_conds = [to_set_conds]
set_clause = ""
for i, sv in enumerate(to_set_conds):
set_clause += str(sv.attribute_name)
set_clause += " = "
set_clause += str(sv.attribute_val)
if i != len(to_set_conds):
set_clause += ", "
if type(filter_conds) != list:
filter_conds = [filter_conds]
where_clause = "" if len(filter_conds) == 0 else "WHERE"
for i in range(len(filter_conds)):
_filter = filter_conds[i]
assert "Filter" in str(
type(_filter)
), f"EXPECTED `Filter` TYPE NOT `{type(_filter)}`"
where_clause += f" {str(_filter)}"
if i != len(filter_conds) - 1:
where_clause += " AND"
res = f"UPDATE {relation} " + f"SET " + f"{set_clause} " + f"{where_clause} ;"
print(res)
return res
def _select_from_where_join(
self,
attributes: Attributes,
......@@ -148,10 +185,20 @@ class BaseModel():
conditions: list,
):
res = self._query(
self._delete_from_where_str(
relation, conditions
),
select=False
self._delete_from_where_str(relation, conditions), select=False
)
return True
def _update_set_where(
self,
relation: str,
to_set_values: list,
conditions: list,
):
res = self._query(
self._update_set_where_str(relation, to_set_values, conditions),
select=False,
)
return True
......@@ -172,7 +219,7 @@ class BaseModel():
elif k == "course_offering_length_in_days":
row[k] = int(row[k])
return row
return row
def _create_self(self, obj):
self._insert(bulk_list=[obj])
......
......@@ -5,21 +5,19 @@ class CourseInfo(BaseModel):
__tablename__ = "courseInfo"
course_offering_id = None
course_offering_length_in_days = None
semester = None
course_id = None
course_code = None
description = None
year = None
def __init__(
self,
course_offering_length_in_days=None,
semester=None,
year=None,
course_code=None,
description=None,
skip_creation=False,
):
self.course_offering_length_in_days = course_offering_length_in_days
self.semester = semester
self.year = year
self.course_code = course_code
self.description = description
if not skip_creation:
self._create_self(self)
......@@ -27,19 +25,18 @@ class CourseInfo(BaseModel):