first commit

master
old-tom 2 years ago
commit 25f99025ea

162
.gitignore vendored

@ -0,0 +1,162 @@
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

@ -0,0 +1 @@
futool-db-lite

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Pipenv (futool-db-lite)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

@ -0,0 +1,22 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N813" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="object.transform" />
<option value="object.cluster_centers_" />
<option value="object.labels_" />
<option value="nodes" />
</list>
</option>
</inspection_tool>
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Pipenv (futool-db-lite)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/../futool-db-lite/.idea/futool-db-lite.iml" filepath="$PROJECT_DIR$/../futool-db-lite/.idea/futool-db-lite.iml" />
</modules>
</component>
</project>

@ -0,0 +1,12 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
[dev-packages]
[requires]
python_version = "3.8"
python_full_version = "3.8.10"

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:58
# @Author : old tom
# @File : __init__.py.py
# @Project : futool-db-lite
# @Desc :

@ -0,0 +1,61 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:58
# @Author : old tom
# @File : db_config.py
# @Project : futool-db-lite
# @Desc :
import os
from pydantic import BaseModel
import toml
# 默认配置文件名
DEFAULT_CONF_NAME = 'db-conf.toml'
path = os.path.dirname(__file__)
path = os.path.dirname(path)
# 默认配置文件位置
DEFAULT_CONF_PATH = os.path.join(path, DEFAULT_CONF_NAME)
# 配置项名称
DB_CONF_ITEM_NAME = ['dialect', 'host', 'port', 'user', 'passwd', 'database']
class DbConfigNotFoundError(Exception):
"""
配置不存在异常
"""
def __init__(self, msg):
Exception.__init__(self, msg)
class DbConf(BaseModel):
dialect: str
host: str
port: int
user: str
passwd: str
database: str
pool_size: int
pool_recycle: int
show_sql: bool = False
class DbConfigLoader(object):
"""
数据库连接加载
"""
def __init__(self, db_name, conf_path):
if not os.path.isfile(conf_path):
raise DbConfigNotFoundError(f'数据配置文件{DEFAULT_CONF_NAME}不存在')
self.db_conf = self.load(db_name, conf_path)
@staticmethod
def load(dbname, conf_path) -> DbConf:
"""
校验并加载配置
:return:
"""
conf = toml.load(conf_path)
return DbConf(**conf[dbname])

@ -0,0 +1,19 @@
[testdb]
# 方言
dialect = 'postgresql'
# ip
host = '127.0.0.1'
# 端口
port = 5432
# 用户名
user = 'postgres'
# 密码
passwd = 'root@123'
# 数据库
database = 'postgres'
# 连接池大小
pool_size = 15
# 连接超时回收(秒)
pool_recycle = 3600
# 打印SQL
show_sql = true

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 21:55
# @Author : old tom
# @File : __init__.py.py
# @Project : futool-db-lite
# @Desc :

@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 21:55
# @Author : old tom
# @File : sql_executor.py
# @Project : futool-db-lite
# @Desc : 获取游标,执行SQL
from sqlalchemy import text, CursorResult
from transaction.connect_transaction import Transaction
class SQLExecutorError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
class SQLExecutor(object):
def __init__(self, tx: Transaction):
self._tx = tx
self._conn = tx.get_connection()
@staticmethod
def _format_sql(sql):
return text(sql)
def query(self, sql) -> CursorResult:
try:
return self._conn.execute(self._format_sql(sql))
except Exception as e:
raise SQLExecutorError(msg=f'{e}')
def execute_update(self, sql) -> int:
try:
self._tx.begin_transaction()
rt = self._conn.execute(self._format_sql(sql))
self._tx.commit()
return rt.rowcount
except Exception as e:
self._tx.rollback()
raise SQLExecutorError(msg=f'{e}')
def get_connection(self):
return self._conn
def get_transaction(self):
return self._tx

@ -0,0 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 21:55
# @Author : old tom
# @File : main.py
# @Project : futool-db-lite
# @Desc : 数据库测试
from session.engine.dbengine import DatabaseEngine
if __name__ == '__main__':
db_engine = DatabaseEngine('testdb')
session_factory = db_engine.create_session_factory()
sql_session = session_factory.open_session()
# print(sql_session.select_all('select * from metadata_object'))
sql_session.select_one('select * from metadata_object')
sql_session.select_many('select * from metadata_object', 2)
# print(sql_session.delete('delete from metadata_object where meta_id=1657707190871527425'))
sql_session.close()

Binary file not shown.

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:52
# @Author : old tom
# @File : __init__.py.py
# @Project : futool-db-lite
# @Desc :

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:53
# @Author : old tom
# @File : __init__.py.py
# @Project : futool-db-lite
# @Desc :

@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:54
# @Author : old tom
# @File : dbengine.py
# @Project : futool-db-lite
# @Desc :
from urllib.parse import quote_plus as urlquote
from sqlalchemy import create_engine
from config.db_config import DbConfigLoader, DEFAULT_CONF_PATH
from session.session import SqlsessionFactory
class DatabaseEngineError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
class DatabaseEngine(object):
"""
数据库连接
dialect+driver://username:password@host:port/database
mysql: mysql+pymysql://scott:tiger@localhost/foo
sqlserver: mssql+pymssql://scott:tiger@hostname:port/dbname
"""
DB_URL = {
'postgresql': 'postgresql+psycopg2://{0}:{1}@{2}:{3}/{4}',
'oracle': 'oracle+cx_oracle://{0}:{1}@{2}:{3}/?service_name={4}'
}
def __init__(self, db_name, conf_path=DEFAULT_CONF_PATH):
"""
pool_size:连接池大小
pool_recycle:连接回收
pool_pre_ping:测试连接执行select 1
参考 https://docs.sqlalchemy.org/en/20/core/pooling.html#connection-pool-configuration
"""
loader = DbConfigLoader(db_name, conf_path)
# 数据库配置
conf = loader.db_conf
if conf.dialect not in self.DB_URL:
raise DatabaseEngineError(msg='不支持的数据库类型')
# urlquote 处理密码中的特殊字符
url = self.DB_URL[conf.dialect].format(conf.user, urlquote(conf.passwd), conf.host, conf.port, conf.database)
self.engine = create_engine(url, pool_size=conf.pool_size, pool_recycle=conf.pool_recycle, pool_pre_ping=True,
echo=conf.show_sql)
def create_session_factory(self):
"""
创建session工厂
:return:
"""
return SqlsessionFactory(self.engine)

@ -0,0 +1,85 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 19:53
# @Author : old tom
# @File : session.py
# @Project : futool-db-lite
# @Desc :
from sqlalchemy import Engine
from executor.sql_executor import SQLExecutor
from transaction.connect_transaction import TransactionFactory
class CreateSessionError(Exception):
def __init__(self, msg):
Exception.__init__(self, msg)
class SqlsessionFactory(object):
"""
工厂模式创建sqlSession
"""
def __init__(self, engine: Engine):
self._engine = engine
def open_session(self):
try:
conn = self._engine.connect()
tx_factory = TransactionFactory(conn)
tx = tx_factory.create_transaction()
executor = SQLExecutor(tx)
return Sqlsession(executor)
except Exception as e:
raise CreateSessionError(msg=f'创建sqlSession异常,e={e}')
class Sqlsession(object):
def __init__(self, executor: SQLExecutor):
self.executor = executor
def select_one(self, sql):
return self.executor.query(sql).fetchone()
def select_many(self, sql, size):
return self.executor.query(sql).fetchmany(size)
def select_all(self, sql):
return self.executor.query(sql).fetchall()
def insert(self, sql):
return self.executor.execute_update(sql)
def update(self, sql):
return self.executor.execute_update(sql)
def delete(self, sql):
return self.executor.execute_update(sql)
def begin_transaction(self):
"""
开启事务
:return:
"""
self.executor.get_transaction().begin_transaction()
def commit(self):
"""
提交
:return:
"""
self.executor.get_transaction().commit()
def rollback(self):
"""
回滚
:return:
"""
self.executor.get_transaction().rollback()
def close(self):
"""
关闭连接
:return:
"""
self.executor.get_connection().close()

@ -0,0 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 21:35
# @Author : old tom
# @File : __init__.py.py
# @Project : futool-db-lite
# @Desc :

@ -0,0 +1,34 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/6/22 21:37
# @Author : old tom
# @File : connect_transaction.py
# @Project : futool-db-lite
# @Desc :
from sqlalchemy import Connection
class TransactionFactory(object):
def __init__(self, conn: Connection):
self.conn = conn
def create_transaction(self):
return Transaction(self.conn)
class Transaction(object):
def __init__(self, conn: Connection):
self.conn = conn
def begin_transaction(self):
self.conn.begin()
def commit(self):
self.conn.commit()
def rollback(self):
self.conn.rollback()
def get_connection(self):
return self.conn
Loading…
Cancel
Save