Package: python-mf-data
Python Micro Framework Data한국어Python Micro Framework Data makes database connections easier in microframeworks likeFalconandFastAPI.This library is created with the motive ofSpring Data Commons, and the relational database is implemented based onSQLAlchemyCurrently, this library isstill under development. The only stable database,SQLAlchemy, is the relational database, and we plan to implement it so that it can be used separately according to synchronous and asynchronous processing.How to install (rdb)If you are installing the Python Micro Framework Data library for a relational database, enter the command below.$pipinstallpython-mf-data[rdb]$poetryadd"python-mf-data[rdb]"You must enterrdbin the extra option to install sub-dependencies such as SQLAlchemy.Connection Example (rdb)If you want to create a connection in SQLAlchemy usingpymfdata, please follow the instructions below.frompymfdata.rdb.connectionimportAsyncSQLAlchemyconnection=AsyncSQLAlchemy(db_uri='postgresql+asyncpg://{}:{}@{}:{}/{}'.format('postgres','postgres','127.0.0.1','5432','test'))frompymfdata.rdb.connectionimportSyncSQLAlchemyconnection=SyncSQLAlchemy(db_uri='postgresql+psycopg2://{}:{}@{}:{}/{}'.format('postgres','postgres','127.0.0.1','5432','test'))When creating a connection, make sure that the application you are developing supports asynchronous processing, and then use the correct one.(This code is an example of connectingPostgreSQLDialect. If you want to use a different database dialect, enter the connection address for their dependency.)MySQL (https://docs.sqlalchemy.org/en/14/dialects/mysql.html#module-sqlalchemy.dialects.mysql.pymysql)Oracle (https://docs.sqlalchemy.org/en/14/dialects/oracle.html)PostgreSQL (https://docs.sqlalchemy.org/en/14/dialects/postgresql.html)Microsoft SQL Server (https://docs.sqlalchemy.org/en/14/dialects/mssql.html)SQLite (https://docs.sqlalchemy.org/en/14/dialects/sqlite.html)You can specify options for connection pool settings such as connection pool size and recycling as shown below.awaitconnection.connect(pool_size=5,pool_recycle=3600)connection.connect(pool_size=5,pool_recycle=3600)When using a connection resource, you must call theconnect()method.Session Factory Example (rdb)If you want to allocate and use DB Session right away, initialize session_factory using the code below.connection.init_session_factory()init_session_factory()is allocatedper thread and task by default. In the case of the synchronous method, each thread is given a unique session, and in the case of the asynchronous method, each task is given a unique session. This is using thescoped_session()method provided bySQLAlchemyand their unit of work pattern.asyncwithconnection.session()assession:stmt="SELECT * from test"result=awaitsession.execute(stmt)withconnection.session()assession:stmt="SELECT * from test"result=session.execute(stmt)The initializedsession_factorycan be used by assigning asessionusing the Python context manager.Repository Example (rdb)When using the repository pattern, it is used after entering the data type of the pre-defined entity model and primary key as generic arguments.frompymfdata.rdb.connectionimportBasefromsqlalchemyimportBigInteger,Column,String,TextfromtypingimportUnionclassMemoEntity(Base):__tablename__='memo'id:Union[int,Column]=Column(BigInteger,primary_key=True,autoincrement=True)title:Union[str,Column]=Column(String(128),nullable=True)content:Union[str,Column]=Column(Text,nullable=True)ORM models can be created using SQLAlchemy'sdeclarative_baseand contain variables already defined in pymfdata.frompymfdata.rdb.repositoryimportAsyncRepository,AsyncSessionfromtypingimportOptionalclassMemoRepository(AsyncRepository[MemoEntity,int]):def__init__(self,session:Optional[AsyncSession]):self._session=sessionasyncdeffind_by_title(title:str)->MemoEntity:# Todo: define session codeWhen using the Repository protocol provided by pymfdata, the following basic methods are provided.delete(entity_model): This method receives the orm model as an argument and deletes a row from the database.find_by_pk(pk): This method receives the primary key as an argument and returns the entity corresponding to the key.(:=find_by_idinSpring Data JPA)find_by_col(**kwargs): A method that uses a column name as an argument key and returns an entity whose value exists in that column when the value is inserted.find_all(**kwargs): A method that uses a column name as an argument key and returns all entities that have a value in that column when the value is inserted. (:=  find_all inSpring Data JPA)is_exists(**kwargs): A method that uses a column name as an argument key and returns whether the row exists when the value is inserted.create(entity_model): This method receives the orm model as an argument and add a row from the database.update(entity_model, req_dict): A method that receives an ORM model and a dictionary as arguments and modifies the ORM model with the data received as a dictionaryIn addition to the methods provided by default in pymfdata, you can also create and use methods as in the code above.Since the repository ofpymfdatauses the PythonProtocol, it can be used like a Java interface by implementing a separate Protocol.frompymfdata.rdb.repositoryimportAsyncRepository,AsyncSessionfrompymfdata.rdb.transactionimportasync_transactionalfromtypingimportOptionalclassMemoRepository(AsyncRepository[MemoEntity,int]):def__init__(self,session:Optional[AsyncSession]):self._session=session@async_transactional(read_only=True)asyncdeffind_by_title(title:str)->MemoEntity:# Todo: Implement the session code, but omit the session begin and commit code.Additionally, it provides a way to reduce duplicated code in a session by using thetransactionaldecorator. Thetransactionaldecorator is divided into asynchronous and synchronous, and must be used according to the implemented connection.Unit Of Work Example (rdb)SQLAlchemy uses the unit of work pattern by default, but if you want to define your own unit of work, you can use this library to define it.fromsqlalchemy.engineimportEnginefromsqlalchemy.ext.asyncioimportAsyncEnginefrompymfdata.common.usecaseimportBaseUseCasefrompymfdata.rdb.usecaseimportAsyncSQLAlchemyUnitOfWork,SyncSQLAlchemyUnitOfWorkfrompymfdata.rdb.transactionimportasync_transactionalclassAsyncMemoUseCaseUnitOfWork(AsyncSQLAlchemyUnitOfWork):def__init__(self,engine:AsyncEngine)->None:super().__init__(engine)asyncdef__aenter__(self):awaitsuper().__aenter__()self.memo_repository:MemoRepository=MemoRepository(self.session)classMemoUseCase(BaseUseCase):def__init__(self,uow:AsyncMemoUseCaseUnitOfWork)->None:self._uow=uow@async_transactional(read_only=True)asyncdeffind_by_id(self,item_id:int):returnawaitself.uow.memo_repository.find_by_pk(item_id)The unit of work pattern is also divided into asynchronous and synchronous classes, and it must be used according to the connection.The created unit of work class can be used in the class containing business logic, and we define them asUseCase. This class contains the business logic of the application.When using the unit of work pattern, use the transactional decorator on business logic methods to handle transaction processing.(If you are usingtransactionaldecorators, please use theBaseUseCaseclass provided by pymfdata.)FastAPI ExampleIf you want to actively use pymfdata in FastAPI, please refer to this example.https://github.com/NEONKID/python-mf-data-example