# db-able
![release](https://img.shields.io/github/package-json/v/timdaviss/db-able?label=release&logo=release&style=flat-square)
![build](https://img.shields.io/github/workflow/status/timdaviss/db-able/test?style=flat-square)
![coverage](https://img.shields.io/codecov/c/github/timdaviss/db-able?style=flat-square)
![dependencies](https://img.shields.io/librariesio/release/pypi/db-able?style=flat-square)
Framework to implement basic CRUD operations with DB for [DataObject](https://github.com/do-py-together/do-py).
## Quick start
Set up your connection string to your database.
```python
from db_able import client
client.CONN_STR = '{dialect}+{driver}://{username}:{password}@{host}:{port}/{database}?{query_args}'
```
Implement the mixins into your DataObject to inject CRUD methods.
```python
from do_py import R
from db_able import Creatable, Deletable, Loadable, Savable
class MyObject(Creatable, Deletable, Loadable, Savable):
db = '{schema_name}'
_restrictions = {
'id': R.INT,
'key': R.INT
}
load_params = ['id']
create_params = ['key']
delete_params = ['id']
save_params = ['id', 'key']
my_obj = MyObject.create(key=555)
my_obj = MyObject.load(id=my_obj.id)
my_obj.key = 777
my_obj.save()
my_obj.delete()
```
Classmethods `create`, `load`, and methods `save` and `delete` are made available
to your DataObject class.
Use provided SQL Generating utils to expedite implementation.
```python
from db_able.utils.sql_generator import print_all_sps
from examples.a import A
print_all_sps(A)
```
## Examples
### "A" Python implementation
```python
from do_py import DataObject, R
from db_able import Creatable, Loadable, Savable, Deletable
class Json(DataObject):
""" Nested Json object for A. """
_restrictions = {
'x': R.INT,
'y': R.INT
}
class A(Creatable, Loadable, Savable, Deletable):
""" Basic DBAble implementation for unit tests. """
db = 'testing'
_restrictions = {
'id': R.INT,
'string': R.NULL_STR,
'json': R(Json, type(None)),
'int': R.NULL_INT,
'float': R.NULL_FLOAT,
'datetime': R.NULL_DATETIME
}
load_params = ['id']
create_params = ['string', 'json', 'int', 'float', 'datetime']
save_params = ['id', 'string', 'json', 'int', 'float', 'datetime']
delete_params = ['id']
```
### "A" MySQL Table structure
```mysql
CREATE TABLE IF NOT EXISTS `testing`.`a`
(
`id` INT NOT NULL AUTO_INCREMENT,
`string` VARCHAR(45) NULL,
`json` JSON NULL,
`int` INT(11) NULL,
`float` FLOAT NULL,
`datetime` TIMESTAMP NULL,
PRIMARY KEY (`id`)
);
```
### "A" MySQL CRUD Stored Procedures
```mysql
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`A_create`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`A_create`
(
IN `_string` VARCHAR(45),
IN `_json` JSON,
IN `_int` INT,
IN `_float` FLOAT,
IN `_datetime` TIMESTAMP
)
BEGIN
INSERT INTO
`testing`.`a`
(
`string`,
`json`,
`int`,
`float`,
`datetime`
)
VALUES
(
`_string`,
`_json`,
`_int`,
`_float`,
`_datetime`
);
CALL `testing`.`A_load`(LAST_INSERT_ID());
END;
$$
DELIMITER ;
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`A_delete`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`A_delete`
(
IN `_id` INT
)
BEGIN
DELETE
FROM
`testing`.`a`
WHERE
`id` = `_id`;
SELECT ROW_COUNT() AS `deleted`;
END;
$$
DELIMITER ;
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`A_load`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`A_load`
(
IN `_id` INT
)
BEGIN
SELECT *
FROM
`testing`.`a`
WHERE
`id` = `_id`;
END;
$$
DELIMITER ;
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`A_save`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`A_save`
(
IN `_id` INT,
IN `_string` VARCHAR(45),
IN `_json` JSON,
IN `_int` INT,
IN `_float` FLOAT,
IN `_datetime` TIMESTAMP
)
BEGIN
UPDATE
`testing`.`a`
SET
`string`=`_string`,
`json`=`_json`,
`int`=`_int`,
`float`=`_float`,
`datetime`=`_datetime`
WHERE
`id`=`_id`;
CALL `testing`.`A_load`(`_id`);
END;
$$
DELIMITER ;
```
## Advanced Use Cases
### User
This implementation requires extension of core functionality
to support salting, hashing, and standard password security practices.
```python
import crypt
import hashlib
from do_py import R
from db_able import Loadable, Creatable, Savable, Deletable
class User(Loadable, Creatable, Savable, Deletable):
"""
User DataObject with DB CRUD implementation.
Customized to handle password encryption and security standards.
"""
db = 'testing'
_restrictions = {
'user_id': R.INT,
'username': R.STR,
'salt': R.STR,
'hash': R.STR
}
_extra_restrictions = {
'password': R.STR,
}
load_params = ['user_id']
create_params = ['username', 'salt', 'hash'] # password is required. salt and hash are generated.
save_params = ['user_id', 'username', 'salt', 'hash']
delete_params = ['user_id']
@classmethod
def generate_salt(cls):
"""
:rtype: str
"""
return crypt.mksalt(crypt.METHOD_SHA512)
@classmethod
def generate_hash(cls, password, salt):
"""
:type password: str
:type salt: str
:rtype: str
"""
salted_password = password + salt
return hashlib.sha512(salted_password.encode()).hexdigest()
@classmethod
def create(cls, password=None, **kwargs):
"""
Overloaded to prevent handling raw password in DB.
:type password: str
:keyword username: str
:rtype: User
"""
password = cls.kwargs_validator('password', password=password)[0][1]
salt = cls.generate_salt()
kwargs.update({
'salt': salt,
'hash': cls.generate_hash(password, salt)
})
return super(User, cls).create(**kwargs)
def save(self, password=None):
"""
Overloaded to support updating password with security.
:type password: str
:rtype: bool
"""
if password:
password = self.kwargs_validator('password', password=password)[0][1]
self.salt = self.generate_salt()
self.hash = self.generate_hash(password, self.salt)
return super(User, self).save()
```
### User MySQL Table Structure
```mysql
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`salt` varchar(255) NOT NULL,
`hash` varchar(255) NOT NULL,
PRIMARY KEY (`user_id`)
);
```
### User MySQL CRUD Stored Procedures
```mysql
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`User_load`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`User_load`
(
IN `_user_id` VARCHAR(255)
)
BEGIN
SELECT * FROM `testing`.`user` WHERE `user_id` = `_user_id`;
END;
$$
DELIMITER ;
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`User_create`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`User_create`
(
IN `_username` VARCHAR(255),
IN `_salt` VARCHAR(255),
IN `_hash` VARCHAR(255)
)
BEGIN
INSERT INTO `testing`.`user` (`username`, `salt`, `hash`) VALUES (`_username`, `_salt`, `_hash`);
CALL `testing`.`User_load`(LAST_INSERT_ID());
END;
$$
DELIMITER ;
USE `testing`;
DROP PROCEDURE IF EXISTS `testing`.`User_save`;
DELIMITER $$
CREATE
DEFINER = `root`@`localhost` PROCEDURE `testing`.`User_save`
(
IN `_user_id` VARCHAR(255),
IN `_username
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
共40个文件
py:31个
txt:4个
pkg-info:2个
资源分类:Python库 所属语言:Python 资源全名:db-able-2.1.2.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源推荐
资源详情
资源评论
收起资源包目录
db-able-2.1.2.tar.gz (40个子文件)
db-able-2.1.2
PKG-INFO 10KB
db_able.egg-info
PKG-INFO 10KB
requires.txt 48B
SOURCES.txt 924B
top_level.txt 23B
dependency_links.txt 1B
tests
conftest.py 285B
__init__.py 0B
utils
__init__.py 0B
test_sql_generator.py 14KB
test_db_able.py 1KB
base_model
test_params.py 903B
__init__.py 0B
test_kwargs_validator.py 2KB
test_database_abc.py 1KB
test_client.py 3KB
LICENSE 1KB
setup.cfg 38B
examples
user.py 2KB
__init__.py 0B
c.py 428B
b.py 569B
a.py 759B
setup.py 1KB
db_able
client
__init__.py 6KB
loadable.py 2KB
savable.py 2KB
__init__.py 285B
creatable.py 2KB
mgmt
const.py 323B
__init__.py 0B
listable.py 11KB
utils
sql_generator.py 10KB
__init__.py 0B
deletable.py 2KB
base_model
kwargs_validator.py 3KB
params.py 750B
database_abc.py 1KB
__init__.py 0B
README.md 9KB
共 40 条
- 1
资源评论
挣扎的蓝藻
- 粉丝: 13w+
- 资源: 15万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功