محمد، مهدی و پارسا به مسابقات ACM جهانی راهیافتهاند روز مسابقه هر تیم باید نام تیم خود را در فایل دیتابیس sqlite اضافه کند ما باید کتابخانهای بنویسیم که کار را برای ارتباط با دیتابیس برای مهدی و دوستان ساده کند. این کد قرار است شبیه به یک [ORM](https://en.wikipedia.org/wiki/Object-relational_mapping) کار کند.
در این سوال تنها کتابخانه sqlalchemy نصب شده است که میتوانید از آن استفاده کنید.
فایل اولیه را از [این لینک](http://bayanbox.ir/download/6840354036702869912/ORM-project.zip) دریافت کنید. تست نمونه در فایل قرار داده شده است. کد شما باید به صورت زیر باشد.
```python
from exceptions import *
class ORM:
def __init__(self, db_path):
self.db_path = db_path
self.create_database_if_not_exist()
def create_database_if_not_exist(self):
pass
def create_table(self, table_path, table_name):
pass
def add_value(self, table_path, table_name, **values):
pass
def add_values(self, table_path, table_name, values):
pass
def remove_value(self, table_path, table_name, **values):
pass
def remove_values(self, table_path, table_name, values):
pass
def get_values(self, table_path, table_name, **filters):
pass
```
۱. تابع `create_database_if_not_exist` در صورتی که فایل پایگاه داده تاکنون ساخته نشده آن را در آدرس `db_path` میسازد. نمونه `db_path` که به پوشه databases و پایگاه first.sqlite3 اشاره میکند (پوشه databases از قبل باید وجود داشته باشد) :
`db_path = r'databases/first.sqlite3''`
۲. تابع `create_table` قرار است مسیر تعریف `table` و نام آنرا دریافت کند و جدول را در پایگاه داده بسازد.
نحوه تعریف جدول در پایگاه داده به صورت زیر است.
```python
# path : tables/users.py
from sqlalchemy import Integer, Column, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
name = Column(String, primary_key=True)
family = Column(String, primary_key=True)
likes = Column(Integer)
order_fields = ['name', 'family']
def to_json(self):
return {
'name': self.name,
'family': self.family,
'likes': self.likes
}
```
در این صورت تابع را به صورت `create_table('tables.user', 'User')` صدا میزنیم. در صورت موجود بودن جدول در پایگاه داده، استثنا `TableExistsException` را باید `raise` کنید.
۳. تابع `add_value` مقدار جدید را میگیرد و در جدول مربوطه ذخیره میکند نحوه صدا زدن این تابع به صورت
`add_value('tables.user', 'User', name='mahdi', family='shokri', likes=3)`
است. در صورت موجود بودن مقدار از قبل در جدول باید استثنا `ValueExistException` و در صورت هرگونه مشکل دیگر باید استثنا `AddValueException` را `raise` کنیم.
۴. تابع `add_values` مقادیر جدید را میگیرد و در جدول مربوطه ذخیره میکند. نحوه صدا زدن این تابع به صورت
`add_values('tables.user', 'User', [{'name': 'mahdi', 'likes': 3, 'family': 'shokri' }])`
است. به ازای هر مورد در آرایه آنرا به جدول اضافه میکند. توجه کنید که یا همه موارد اضافه شوند یا در صورت هرگونه مشکل برای هرکدام از موارد آرایه باید استثنا `AddValuesException` را `raise` کنیم و پایگاه داده را به حالت قبل از این دستور، `rollback` کنیم.
۵. تابع `remove_value` مقداری را میگیرد و بر اساس آرگومانها موارد را فیلتر میکند و حذف مینماید. مثلا
`add_value('tables.user', 'User', name='mahdi')`
تمام افرادی که نامشان `mahdi` است را حذف میکند. در صورت نبودن سطری برای حذف شدن در جدول یا هرگونه مشکل دیگر باید استثنا `RemoveValueException` را `raise` کند.
۶. تابع `remove_values` آرایه ای از فیلترها میگیرد و به ازای هر کدام از فیلترها موارد مربوط به آن فیلتر را که در جدول مطابقت دارند حذف میکند.
`add_value('tables.user', 'User', [{'name': 'mahdi'}, {family': 'mohammadi'}])`
به ازای هرکدام از موارد در آرایه حداقل باید یک سطر برای حذف شدن وجود داشته باشد در غیر این صورت استثنا `RemoveValuesException` بازگردانده شود.
۷. تابع `get_values` مقادیر فیلتر را دریافت میکند و نتیجهای را به صورت `json` باز میگرداند. مثلا اگر تابع
`get_values('tables.user', 'User', name='mahdi')`
را صدا بزنیم تمام سطرهای جدول که `name` در آنها `mahdi` باشد را برمیگرداند. توجه کنید که ترتیب موارد در خروجی `json` باید بر اساس `order_fields` در تعریف جدول (در اینجا `User`) باشد.
```json
[
{
'name': 'mahdi',
'family': 'shokri',
'likes': 4
},
{
'name': 'mahdi',
'family': 'sorkhi',
'likes': 2
}
]
```
+ نکته: هر جدولی که برای تست به شما کد شما داده شود، حتما دارای تابع `to_json()` است و نیازی نیست شما آن را تبدیل به json کنید.
کد ارسالی شما باید به صورت زیر در ریشه فایل `zip` باشد. حتما قبل از ارسال تستهای نمونه را اجرا کنید.
```
<your-zip-name>.zip
└── orm.py
```
Python - محمد، مهدی و پارسا