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

cli basic working

parent 566e586a
DB_USER=snvercil
DB_PASSWORD=32darklink
DB_HOST=127.0.0.1
DB_NAME=EDUCATION
......@@ -7,6 +7,7 @@ name = "pypi"
flask-sqlalchemy = "*"
mysql-connector-python = "*"
sqlalchemy = "*"
python-dotenv = "*"
[dev-packages]
......
{
"_meta": {
"hash": {
"sha256": "53a9b6cd40ded12dfe07a052c8300d69e9e2cbe874dd380b5dd25204c6487cda"
"sha256": "4a16aef273b7263586f32b2172d8e4d37ce476bbd45b1cd492c3ca6214c6abc5"
},
"pipfile-spec": 6,
"requires": {
......@@ -239,6 +239,14 @@
],
"version": "==3.19.1"
},
"python-dotenv": {
"hashes": [
"sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3",
"sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"
],
"index": "pypi",
"version": "==0.19.2"
},
"sqlalchemy": {
"hashes": [
"sha256:0072f9887aabe66db23f818bbe950cfa1b6127c5cb769b00bcc07935b3adb0ad",
......
import argparse
import sys
sys.path.insert(0, "..") # import parent folde
from controller import Controller
from error_handler import ErrorHandler
class CliTool:
actions = ["get", 'modify', "insert", "delete"]
def __init__(self) -> None:
self.controller = Controller()
self.__parser__init__()
def __parser__init__(self):
self.parser = argparse.ArgumentParser(description="Process some integers.")
self.parser.add_argument(
"action", help="select an action item from [get, modify, insert, delete]"
)
self.parser.add_argument(
"--relation",
choices=self.controller.relations_list(),
help=f"specify the table to perform action on",
required=True,
)
args = self.parser.parse_args()
print(args)
def run(self):
while True:
self.process_line()
def process_line(self):
line = input()
print("Starting CLI .... ")
CliTool().run()
import os
from flask import Flask
class AppConfig:
@staticmethod
def db_config():
config = {
'user':os.environ["DB_USER"],
'password': os.environ["DB_PASSWORD"],
'host':os.environ["DB_HOST"],
'database':os.environ["DB_NAME"],
'use_pure': True # uses C extension
}
return config
import mysql.connector
mydb = mysql.connector.connect(
host="",
user="",
database=""
)
db_client = mydb.cursor()
# the 0th index in every one of these should be the PK
get_attributes_from_tablename = {
"courseInfo" : [
"course_id",
"course_code",
"description"
],
"assessments" : [
"id_assessment",
"course_offering_id",
"date",
"weight",
"assessment_type"
],
"studentAssessments" : [
"id_assessment",
"id_student",
"date_submitted",
"is_banked",
"score",
"failed"
],
"courseOfferings" : [
"course_offering_id",
"course_offering_length_in_days",
"year",
"semester"
],
"studentInfo" : [
"id_student",
"highest_education",
"num_of_prev_attempts",
"studied_credits",
"course_offering_id",
"age_range",
"regionid",
"education_rank",
"gender",
"imd_band"
],
"region" : [
"regionid",
"name"
],
"educationLevel" : [
"education_rank",
"education_level"
],
"vle" : [
"id_site",
"activity_type",
"week_from",
"week_to",
"course_offering_id"
],
"studentUnregistration" : [
"id_unregistration",
"id_student",
"date_unregistration",
"course_offering_id",
"id_registration"
],
"studentRegistration" : [
"id_registration",
"id_student",
"date_registration",
"date_unregistration",
"course_offering_id"
],
"studentVle" : [
"id_student",
"id_site",
"date",
"interactions",
"course_offering_id",
"id"
]
}
attribute_type = {
"course_id": int,
"course_code": str,
"description" : str,
"id_assessment": int,
"course_offering_id": int,
"date": int,
"weight": int,
"assessment_type": str, # enum
"id_assessment" : int,
"id_student" : int,
"date_submitted" : int,
"is_banked" : bool,
"score": int,
"failed": bool,
"course_offering_length_in_days": int,
"year": int,
"semester": str, # enum
"highest_education": str,
"num_of_prev_attempts": int,
"studied_credits": int,
"age_range": str, # enum
"regionid": int,
"education_rank": int,
"gender": str, # enum
"imd_band": int,
"name": str,
"education_level": str,
"id_site": int,
"activity_type": str,
"week_from": int,
"week_to": int,
"id_unregistration": int,
"id_student": int,
"date_unregistration": int,
"id_registration": int,
"date_registration": int,
"interactions": int,
"id": int
}
\ No newline at end of file
from logging import error
import sys
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.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.assessments import Assessments
from utils.data_structures.sql_object import (
Attributes,
Filter,
Operator,
AttributeValue,
)
model = BaseModel()
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
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
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"}
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
OBJ_CLS = controller.relation_2_class_map[modify_table_args.table]
new_row = OBJ_CLS.clean_row(new_row)
OBJ_CLS(**new_row)
print(f"INSERTING row: \n {new_row} \n into table {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
)
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_args.table](skip_creation=True)
OBJ_CLS._delete_from_where(
relation=delete_rows_args.table,
conditions=conditions,
)
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__())
import argparse
import sys
sys.path.insert(0, "..") # import parent folde
from controller import Controller
from error_handler import ErrorHandler
class CliTool:
actions = ["get", 'modify', "insert", "delete"]
def __init__(self) -> None:
self.controller = Controller()
self.__parser__init__()
def __parser__init__(self):
self.parser = argparse.ArgumentParser(description="Process some integers.")
self.parser.add_argument(
"action", help="select an action item from [get, modify, insert, delete]"
)
self.parser.add_argument(
"--relation",
choices=self.controller.relations_list(),
help=f"specify the table to perform action on",
required=True,
)
args = self.parser.parse_args()
print(args)
def run(self):
while True:
self.process_line()
def process_line(self):
line = input()
print("Starting CLI .... ")
CliTool().run()
from dotenv import load_dotenv
from os.path import join, dirname
load_dotenv(join(dirname(__file__), ".env"))
from handle_parse import *
from parser import *
options_switchcase = {
"insert" : insert_base_func,
"modify" : modify_base_func,
"df" : delete_base_func,
"get-from" : get_base_func
}
if __name__ == "__main__":
# message at the start:
print(
'''
Welcome to our ECE 356 final project client!
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
get-from - fetches a set of rows from a table in the DB
These are the more 'user friendly' commands:
create-new-student
create-new-course
create-new-vle
create-new-assessment
assign-assessment-to-student
unregister-student
get-all-courses
get-course-offerings-by-year
''')
while True:
command = input("Command: ").split()
if len(command) == 0: continue
if command[0] not in options_switchcase:
print(f"Error: command not in options. Options are:\n {list(options_switchcase.keys())}")
continue
if command[0] == "exit":
exit("Terminating...")
# pick the appropirate function given command[0]
options_switchcase[command[0]](command)
\ No newline at end of file
import argparse
# the base table specifications - for the table at hand
tables=[
"courseInfo",
"assessments",
"studentAssessments",
"courseOfferings",
"studentInfo",
"region",
"educationLevel",
"vle",
"studentUnregistration",
"studentRegistration",
"studentVle"
]
# ========== INSERT ENTRY SECTION ==========
insert_entry_parser = argparse.ArgumentParser()
insert_entry_parser.add_argument(
"--table",
dest="table",
choices=tables,
help="specify the table to perform CRUD on",
required=True
)
# ========== MODIFY TABLE SECTION ==========
modify_table_parser = argparse.ArgumentParser()
modify_table_parser.add_argument(
"--table",
dest="table",
choices=tables,
help="specify the table to perform CRUD on",
required=True
)
# ========== DELETE SECTION ==========
delete_rows_parser = argparse.ArgumentParser()
delete_rows_parser.add_argument(
"--table",
dest="table",
choices=tables,
help="specify the table to perform CRUD on",
required=True
)
# ========== GET SECTION ==========
get_rows_parser = argparse.ArgumentParser()
get_rows_parser.add_argument(
"--table",
dest="table",
choices=tables,
help="specify the table to perform CRUD on",
required=True
)
\ No newline at end of file
......@@ -4,6 +4,7 @@ from models.courseOfferings import CourseOfferings
from models.studentAssements import StudentAssessments
from models.studentInfo import StudentInfo
from models.studentRegistration import StudentRegistration
from models.studentUnregistration import StudentUnregistration