Add unique constraint, None option

This commit is contained in:
Ege Emir Özkan
2020-08-22 01:00:30 +03:00
parent 6f58590475
commit 768453ab39
10 changed files with 179 additions and 12 deletions

View File

@@ -1,3 +1,12 @@
__all__ = ['commons', 'datalite_decorator', 'fetch', 'migrations', 'datalite']
__all__ = ['commons', 'datalite_decorator', 'fetch', 'migrations', 'datalite', 'constraints']
from dataclasses import dataclass
from .datalite_decorator import datalite
@dataclass
class Student:
id_: int
name: str

View File

@@ -1,8 +1,14 @@
from dataclasses import Field
from typing import Any, Optional, Dict, List
from .constraints import Unique
import sqlite3 as sql
type_table: Dict[Optional[type], str] = {None: "NULL", int: "INTEGER", float: "REAL",
str: "TEXT", bytes: "BLOB"}
type_table.update({Unique[key]: f"{value} NOT NULL UNIQUE" for key, value in type_table.items()})
def _convert_type(type_: Optional[type], type_overload: Dict[Optional[type], str]) -> str:
"""
Given a Python type, return the str name of its
@@ -30,7 +36,9 @@ def _convert_sql_format(value: Any) -> str:
>>> _convert_sql_format("John Smith")
'"John Smith"'
"""
if isinstance(value, str):
if value is None:
return "NULL"
elif isinstance(value, str):
return f'"{value}"'
elif isinstance(value, bytes):
return '"' + str(value).replace("b'", "")[:-1] + '"'
@@ -82,5 +90,5 @@ def _create_table(class_: type, cursor: sql.Cursor, type_overload: Dict[Optional
sql_fields = "obj_id INTEGER PRIMARY KEY AUTOINCREMENT, " + sql_fields
cursor.execute(f"CREATE TABLE IF NOT EXISTS {class_.__name__.lower()} ({sql_fields});")
type_table: Dict[Optional[type], str] = {None: "NULL", int: "INTEGER", float: "REAL",
str: "TEXT", bytes: "BLOB"}

View File

@@ -0,0 +1,26 @@
"""
datalite.constraints module introduces constraint
types that can be used to hint field variables,
that can be used to signal datalite decorator
constraints in the database.
"""
from typing import TypeVar, Union, Tuple
T = TypeVar('T')
class ConstraintFailedError(Exception):
"""
This exception is raised when a Constraint fails.
"""
pass
"""
Dataclass fields hinted with this type signals
datalite that the bound column of this
field in the table is NOT NULL and UNIQUE.
"""
Unique = Union[Tuple[T], T]

View File

@@ -2,10 +2,12 @@
Defines the Datalite decorator that can be used to convert a dataclass to
a class bound to a sqlite3 database.
"""
from sqlite3.dbapi2 import IntegrityError
from typing import Dict, Optional, List, Callable
from dataclasses import Field, asdict
import sqlite3 as sql
from constraints import ConstraintFailedError
from .commons import _convert_sql_format, _convert_type, _create_table, type_table
@@ -22,11 +24,14 @@ def _create_entry(self) -> None:
table_name: str = self.__class__.__name__.lower()
kv_pairs = [item for item in asdict(self).items()]
kv_pairs.sort(key=lambda item: item[0]) # Sort by the name of the fields.
cur.execute(f"INSERT INTO {table_name}("
f"{', '.join(item[0] for item in kv_pairs)})"
f" VALUES ({', '.join(_convert_sql_format(item[1]) for item in kv_pairs)});")
self.__setattr__("obj_id", cur.lastrowid)
con.commit()
try:
cur.execute(f"INSERT INTO {table_name}("
f"{', '.join(item[0] for item in kv_pairs)})"
f" VALUES ({', '.join(_convert_sql_format(item[1]) for item in kv_pairs)});")
self.__setattr__("obj_id", cur.lastrowid)
con.commit()
except IntegrityError:
raise ConstraintFailedError("A constraint has failed.")
def _update_entry(self) -> None: