diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f0fec5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +mylib.db +databaseClasses/__pycache__ +tables/__pycache__ +services/__pycache__ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5671541 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "app.py", + "console": "integratedTerminal", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..219ef98 --- /dev/null +++ b/app.py @@ -0,0 +1,18 @@ +from services.customerService import CustomerService +from tables.customer import Customer + +customerService = CustomerService() +customer = Customer() +customer.customerName = "Test" +customer.contactLastName = "Test" +customer.contactFirstName = "Test" +customer.phone = "Test" +customer.addressLine1 = "Test" +customer.addressLine2 = "Test" +customer.city = "Test" +customer.state = "Test" +customer.postalCode = "Test" +customer.country = "Test" +customer.creditLimit = 1 + +customerService.addCustomer(customer,"Murphy") \ No newline at end of file diff --git a/databaseClasses/column.py b/databaseClasses/column.py new file mode 100644 index 0000000..3724d6b --- /dev/null +++ b/databaseClasses/column.py @@ -0,0 +1,40 @@ +from enum import Enum + +class ColumnDataType(Enum): + id = 1, + idIncrement = 2, + idFloat = 3, + idString = 4, + string = 5, + dateTime = 6, + bool = 7, + int = 8, + float = 9, + blob = 10, + + +class Column: + name = str() + dataType = ColumnDataType + nullable = bool() + + def __init__(self, name : str, dataType : ColumnDataType, nullable : bool = False): + self.name = name + self.dataType = dataType + self.nullable = nullable + + def isPrimaryKey(self): + return self.dataType == ColumnDataType.id or self.dataType == ColumnDataType.idIncrement or self.dataType == ColumnDataType.idFloat or self.dataType == ColumnDataType.idString + + def isIncrement(self): + return self.dataType == ColumnDataType.idIncrement + + def getSqlValue(self,item): + temp = "" + keys = vars(item).keys() + if(self.name in keys): + temp = vars(item)[self.name] + if(self.dataType in [ColumnDataType.string,ColumnDataType.idString]): + temp = f"'{temp}'" + return temp + \ No newline at end of file diff --git a/databaseClasses/database.py b/databaseClasses/database.py new file mode 100644 index 0000000..de40c15 --- /dev/null +++ b/databaseClasses/database.py @@ -0,0 +1,56 @@ +import mysql.connector +from databaseClasses.table import Table +from databaseClasses.query import Query +from tables.customer import Customer +from tables.employee import Employee +from tables.office import Office +from tables.orderdetail import OrderDetail +from tables.order import Order +from tables.payment import Payment +from tables.productline import ProductLine +from tables.product import Product + + +def dict_factory(cursor, row): + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + +class Database : + __con : str = None + tables : list[Table] = [ + Customer(), + Employee(), + Office(), + OrderDetail(), + Order(), + Payment(), + ProductLine(), + Product(), + ] + DataBaseName = "classicmodels" + host="localhost" + user="root" + password="123456" + __cur : str = None + + + + def __init__(self): + if(Database.__con == None): + Database.__con = mysql.connector.connect(host=self.host,user=self.user,password=self.password) + Database.__cur = Database.__con.cursor() + Database.__con.row_factory = dict_factory + Database.__cur.execute(f"use {Database.DataBaseName}") + + + + def executeQuery(self,query : str = "",commit : bool = False): + Database.__cur.execute(query) + if(commit): + Database.__con.commit() + res = [dict_factory(Database.__cur, row) for row in Database.__cur.fetchall()] + return res + + diff --git a/databaseClasses/query.py b/databaseClasses/query.py new file mode 100644 index 0000000..7f05431 --- /dev/null +++ b/databaseClasses/query.py @@ -0,0 +1,79 @@ +from databaseClasses.table import Table + +class Query: + + def listQuery(table : Table,where : str = "",order: str = ""): + query = f"SELECT * FROM {table.tableName}" + if(len(where) > 0): + query += f" WHERE {where}" + if(len(order) > 0): + query += f" ORDER BY {order}" + return query + + def pageQuery(table : Table,where : str = "",order: str = "",skip : int = 0,take : int = 10): + query = f"SELECT * FROM {table.tableName}" + if(len(where) > 0): + query += f" WHERE {where}" + if(len(order) > 0): + query += f" ORDER BY {order}" + query += f" LIMIT {skip},{take}" + return query + + def insertQuery(table : Table): + query = f"INSERT INTO {table.tableName}(" + for column in table.columns: + if(column.isIncrement() == False): + query += f"{column.name}," + query = query[:-1] + query += ") VALUES(" + for column in table.columns: + if(column.isIncrement() == False): + query += f"{column.getSqlValue(table)}," + query = query[:-1] + query += ")" + return query + + def updateQuery(table : Table): + query = f"UPDATE {table.tableName} SET " + for column in table.columns: + if(column.isPrimaryKey() == False): + query += f"{column.name} = {column.getSqlValue(table)}," + query = query[:-1] + primaryColumn = next(filter(lambda c: c.isPrimaryKey(),table.columns)) + query += f" WHERE {primaryColumn.name} = '{primaryColumn.getSqlValue(table)}'" + return query + + def insertUpdateQuery(table : Table): + query = f"INSERT OR REPLACE INTO {table.tableName}(" + for column in table.columns: + if(column.isIncrement() == False): + query += f"{column.name}," + query = query[:-1] + query += ") VALUES(" + for column in table.columns: + if(column.isIncrement() == False): + query += f"{column.getSqlValue(table)}," + query = query[:-1] + query += ")" + return query + + def deleteQuery(table : Table,id): + query = f"DELETE FROM {table.tableName}" + primaryColumn = next(filter(lambda c: c.isPrimaryKey(),table.columns)) + query += f" WHERE {primaryColumn.name} = '{id}'" + return query + + def deleteAllQuery(table : Table): + query = f"DELETE FROM {table.tableName}" + return query + + def deleteWithConditionQuery(table : Table,where : str): + query = f"DELETE FROM {table.tableName}" + query += f" WHERE {where}" + return query + + def countQuery(table : Table,where : str = ""): + query = f"SELECT COUNT(*) AS count FROM {table.tableName}" + if(len(where) > 0): + query += f" WHERE {where}" + return query \ No newline at end of file diff --git a/databaseClasses/table.py b/databaseClasses/table.py new file mode 100644 index 0000000..80b409b --- /dev/null +++ b/databaseClasses/table.py @@ -0,0 +1,14 @@ +from databaseClasses.column import Column + +class Table: + tableName : str() + columns : list[Column] + def __init__(self,tableName : str = ""): + self.tableName = tableName if len(tableName ) > 0 else type(self).__name__ + self.__getColumns() + + def __getColumns(self): + self.columns = list() + for c in type(self).__annotations__.keys(): + temp = Column(vars(type(self).__annotations__[c])['name'],vars(type(self).__annotations__[c])['dataType'],vars(type(self).__annotations__[c])['nullable']) + self.columns.append(temp) diff --git a/databaseClasses/tableRepository.py b/databaseClasses/tableRepository.py new file mode 100644 index 0000000..ee64d52 --- /dev/null +++ b/databaseClasses/tableRepository.py @@ -0,0 +1,103 @@ +from databaseClasses.table import Table +from databaseClasses.database import Database +from databaseClasses.query import Query + +class TableRepository: + table : Table + def __init__(self, table:Table): + self.table = table + + def __convertData(self,data): + list : list[type(self)] = [] + for item in data: + temp = type(self)() + for column in temp.table.columns: + setattr(temp,column.name,item[column.name]) + list.append(temp) + return list + + def getListDictionary(self,where : str = "",order: str = ""): + database = Database() + query = Query.listQuery(self.table,where,order) + result = database.executeQuery(query) + return result + + def getList(self,where : str = "",order: str = ""): + return self.__convertData(self.getListDictionary(where,order)) + + def getPageDictionary(self,where : str = "",order: str = "",skip : int = 0,take : int = 10): + database = Database() + query = Query.pageQuery(self.table,where,order,skip,take) + result = database.executeQuery(query) + return result + + def getPage(self,where : str = "",order: str = "",skip : int = 0,take : int = 10): + return self.__convertData(self.getPageDictionary(where,order,skip,take)) + + def getById(self,id): + primaryColumn = next(filter(lambda c: c.isPrimaryKey(),self.table.columns)) + list = self.getList(f"'{primaryColumn.name}' = '{id}'") + if(len(list) > 0): + return list[0] + + def getFirst(self,where : str = "",order: str = ""): + list = self.getPage(where,order,0,1) + if(len(list) > 0): + return list[0] + + def getCount(self,where : str = ""): + database = Database() + query = Query.countQuery(self.table,where) + result = database.executeQuery(query) + return result[0]["count"] + + def add(self,table : Table): + database = Database() + query = Query.insertQuery(table) + database.executeQuery(query,True) + + def update(self,table : Table): + database = Database() + query = Query.updateQuery(table) + database.executeQuery(query,True) + + def addOrUpdate(self,table : Table): + database = Database() + query = Query.insertUpdateQuery(table) + database.executeQuery(query,True) + + def addRange(self,list : list[Table]): + for item in list: + self.add(item) + + def updateRange(self,list : list[Table]): + for item in list: + self.update(item) + + def addOrUpdateRange(self,list : list[Table]): + for item in list: + self.addOrUpdate(item) + + def delete(self,id): + database = Database() + query = Query.deleteQuery(self.table,id) + database.executeQuery(query,True) + + def deleteRange(self,list : list[str]): + for item in list: + self.delete(item) + + def deleteWithCondition(self,where : str): + database = Database() + query = Query.deleteWithConditionQuery(self.table,where) + database.executeQuery(query,True) + + def deleteAll(self): + database = Database() + query = Query.deleteAllQuery(self.table) + database.executeQuery(query,True) + + def rawQuery(self,query:str,commit:bool): + database = Database() + result = database.executeQuery(query,commit) + return result diff --git a/services/customerService.py b/services/customerService.py new file mode 100644 index 0000000..b3083c3 --- /dev/null +++ b/services/customerService.py @@ -0,0 +1,28 @@ +from databaseClasses.tableRepository import TableRepository +from tables.customer import Customer +from tables.employee import Employee +from services.employeeService import EmployeeService +import random +import string + + +class CustomerService(TableRepository): + employeeService : EmployeeService + def __init__(self): + CustomerService.employeeService = EmployeeService() + super().__init__(Customer()) + + def __getNewCustomerNumber(self): + temp = self.getFirst(order="customerNumber desc") + if(temp == None): + return 1 + else: + return temp.customerNumber + 1 + + def addCustomer(self,data:Customer,employeeName:str): + data.customerNumber = self.__getNewCustomerNumber() + employee = CustomerService.employeeService.searchByName(employeeName) + if(employee == None): + raise Exception("Employee not found") + data.salesRepEmployeeNumber = employee.employeeNumber + self.add(data) \ No newline at end of file diff --git a/services/employeeService.py b/services/employeeService.py new file mode 100644 index 0000000..35dbac8 --- /dev/null +++ b/services/employeeService.py @@ -0,0 +1,16 @@ +from databaseClasses.tableRepository import TableRepository +from tables.employee import Employee +import random +import string + + +class EmployeeService(TableRepository): + def __init__(self): + super().__init__(Employee()) + + def searchByName(self,name:str): + temp = self.getFirst(where=f"concat(firstName, ' ', lastName) like '%{name}%'") + return temp + + + \ No newline at end of file diff --git a/tables/customer.py b/tables/customer.py new file mode 100644 index 0000000..8ec7292 --- /dev/null +++ b/tables/customer.py @@ -0,0 +1,21 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Customer(Table): + customerNumber : Column('customerNumber',ColumnDataType.id) = 0 + customerName : Column('customerName',ColumnDataType.string) = '' + contactLastName : Column('contactLastName', ColumnDataType.string) = '' + contactFirstName : Column('contactFirstName', ColumnDataType.string) = '' + phone : Column('phone', ColumnDataType.string) = '' + addressLine1 : Column('addressLine1', ColumnDataType.string) = '' + addressLine2 : Column('addressLine2', ColumnDataType.string,True) = '' + city : Column('city', ColumnDataType.string) = '' + state : Column('state', ColumnDataType.string,True) = '' + postalCode : Column('postalCode', ColumnDataType.string,True) = '' + country : Column('country', ColumnDataType.string) = '' + salesRepEmployeeNumber : Column('salesRepEmployeeNumber', ColumnDataType.int) = 0 + creditLimit : Column('creditLimit', ColumnDataType.float) = 0 + + def __init__(self): + super().__init__("customers") + diff --git a/tables/employee.py b/tables/employee.py new file mode 100644 index 0000000..73d83df --- /dev/null +++ b/tables/employee.py @@ -0,0 +1,16 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Employee(Table): + employeeNumber : Column('employeeNumber',ColumnDataType.id) = 0 + lastName : Column('lastName',ColumnDataType.string) = '' + firstName : Column('firstName', ColumnDataType.string) = '' + extension : Column('extension', ColumnDataType.string) = '' + email : Column('email', ColumnDataType.string) = '' + officeCode : Column('officeCode', ColumnDataType.string) = '' + reportsTo : Column('reportsTo', ColumnDataType.int,True) = 0 + jobTitle : Column('jobTitle', ColumnDataType.string) = '' + + def __init__(self): + super().__init__("employees") + diff --git a/tables/office.py b/tables/office.py new file mode 100644 index 0000000..9ddf707 --- /dev/null +++ b/tables/office.py @@ -0,0 +1,17 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Office(Table): + officeCode : Column('officeCode',ColumnDataType.id) = 0 + city : Column('city',ColumnDataType.string) = '' + phone : Column('phone', ColumnDataType.string) = '' + addressLine1 : Column('addressLine1', ColumnDataType.string) = '' + addressLine2 : Column('addressLine2', ColumnDataType.string,True) = '' + state : Column('state', ColumnDataType.string,True) = '' + country : Column('country', ColumnDataType.string) = '' + postalCode : Column('postalCode', ColumnDataType.string) = '' + territory : Column('territory', ColumnDataType.string) = '' + + def __init__(self): + super().__init__("offices") + \ No newline at end of file diff --git a/tables/order.py b/tables/order.py new file mode 100644 index 0000000..5d01bd8 --- /dev/null +++ b/tables/order.py @@ -0,0 +1,15 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Order(Table): + orderNumber : Column('orderNumber',ColumnDataType.id) = 0 + orderDate : Column('orderDate',ColumnDataType.dateTime) = '' + requiredDate : Column('requiredDate', ColumnDataType.dateTime) = '' + shippedDate : Column('shippedDate', ColumnDataType.dateTime) = '' + status : Column('status', ColumnDataType.string) = '' + comments : Column('comments', ColumnDataType.string,True) = '' + customerNumber : Column('customerNumber', ColumnDataType.int) = '' + + def __init__(self): + super().__init__("orders") + \ No newline at end of file diff --git a/tables/orderdetail.py b/tables/orderdetail.py new file mode 100644 index 0000000..900bad3 --- /dev/null +++ b/tables/orderdetail.py @@ -0,0 +1,13 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class OrderDetail(Table): + orderNumber : Column('orderNumber',ColumnDataType.id) = 0 + productCode : Column('productCode',ColumnDataType.string) = '' + quantityOrdered : Column('quantityOrdered', ColumnDataType.int) = 0 + priceEach : Column('priceEach', ColumnDataType.float) = 0 + orderLineNumber : Column('orderLineNumber', ColumnDataType.int) = 0 + + def __init__(self): + super().__init__("orderdetails") + \ No newline at end of file diff --git a/tables/payment.py b/tables/payment.py new file mode 100644 index 0000000..5bd4d19 --- /dev/null +++ b/tables/payment.py @@ -0,0 +1,12 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Payment(Table): + customerNumber : Column('customerNumber',ColumnDataType.id) = 0 + checkNumber : Column('checkNumber',ColumnDataType.string) = '' + paymentDate : Column('paymentDate', ColumnDataType.dateTime) = '' + amount : Column('amount', ColumnDataType.float) = 0 + + def __init__(self): + super().__init__("payments") + \ No newline at end of file diff --git a/tables/product.py b/tables/product.py new file mode 100644 index 0000000..58dfe89 --- /dev/null +++ b/tables/product.py @@ -0,0 +1,17 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class Product(Table): + productCode : Column('productCode',ColumnDataType.idString) = '' + productName : Column('productName',ColumnDataType.string) = '' + productLine : Column('productLine',ColumnDataType.string) = '' + productScale : Column('productScale',ColumnDataType.string) = '' + productVendor : Column('productVendor',ColumnDataType.string) = '' + productDescription : Column('productDescription',ColumnDataType.string) = '' + quantityInStock : Column('quantityInStock',ColumnDataType.int) = 0 + buyPrice : Column('buyPrice',ColumnDataType.float) = 0 + MSRP : Column('MSRP',ColumnDataType.float) = 0 + + def __init__(self): + super().__init__("products") + \ No newline at end of file diff --git a/tables/productline.py b/tables/productline.py new file mode 100644 index 0000000..da4a085 --- /dev/null +++ b/tables/productline.py @@ -0,0 +1,12 @@ +from databaseClasses.table import Table +from databaseClasses.column import Column ,ColumnDataType + +class ProductLine(Table): + productLine : Column('productLine',ColumnDataType.idString) = '' + textDescription : Column('textDescription',ColumnDataType.string,True) = '' + htmlDescription : Column('htmlDescription', ColumnDataType.string,True) = '' + image : Column('image', ColumnDataType.blob) = '' + + def __init__(self): + super().__init__("productlines") + \ No newline at end of file