Skip to content

Commit

Permalink
abc and docummentation
Browse files Browse the repository at this point in the history
  • Loading branch information
CrispenGari committed Feb 11, 2024
1 parent 1b302be commit 2695378
Show file tree
Hide file tree
Showing 14 changed files with 438 additions and 134 deletions.
Empty file added Changelog.md
Empty file.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
- [Utilities](#utilities)
- [`inspect`](#inspect)
- [What is coming next?](#what-is-coming-next)
- [Contributing](#contributing)
- [License](#license)

### Key Features:

Expand Down Expand Up @@ -1159,3 +1161,13 @@ The `inspect` function take the following arguments.
### What is coming next?

1. Associations
2. Grouping
3. Altering tables

### Contributing

Contributions to `dataloom` are welcome! Feel free to submit bug reports, feature requests, or pull requests on [GitHub](https://github.com/CrispenGari/dataloom).

### License

This project is licensed under the MIT License - see the [LICENSE](/LISENSE) file for details.
147 changes: 36 additions & 111 deletions dataloom/loom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@
from dataloom.loom.delete import delete
from dataloom.loom.query import query
from dataloom.loom.insert import insert

from dataloom.exceptions import (
UnsupportedDialectException,
)

from dataloom.loom.sql import sql as SQL
from dataloom.exceptions import UnsupportedDialectException
from dataloom.model import Model
from dataloom.statements import GetStatement
from dataloom.conn import ConnectionOptionsFactory
from dataloom.utils import (
file_logger,
console_logger,
)
from typing import Optional
from typing import Optional, Any
from mysql.connector.pooling import PooledMySQLConnection
from sqlite3 import Connection
from mysql.connector.connection import MySQLConnectionAbstract
from dataloom.types import (
Order,
Include,
Expand All @@ -28,9 +24,10 @@
ColumnValue,
SQL_LOGGER_LITERAL,
)
from dataloom.loom.interfaces import IDataloom


class Dataloom:
class Dataloom(IDataloom):
def __init__(
self,
database: str,
Expand All @@ -48,6 +45,7 @@ def __init__(
self.sql_logger = sql_logger
self.dialect = dialect
self.logs_filename = logs_filename

try:
config = instances[dialect]
except KeyError:
Expand Down Expand Up @@ -246,7 +244,7 @@ def inspect(
).inspect(instance=instance, fields=fields, print_table=print_table)

@property
def tables(self):
def tables(self) -> list[str]:
sql = GetStatement(self.dialect)._get_tables_command
res = self._execute_sql(sql, fetchall=True)
if self.dialect == "sqlite":
Expand All @@ -264,104 +262,27 @@ def _execute_sql(
bulk: bool = False,
affected_rows: bool = False,
operation: Optional[str] = None,
):
# do we need to log the executed SQL?
if self.sql_logger is not None:
if self.sql_logger == "console":
index = console_logger(
index=self.logger_index,
sql_statement=sql.strip(),
dialect=self.dialect,
)
self.logger_index = index + 1
else:
file_logger(
dialect=self.dialect,
file_name=self.logs_filename,
sql_statement=sql.strip(),
)
if self.dialect == "postgres":
with self.conn.cursor() as cursor:
if args is None:
cursor.execute(sql)
else:
if bulk:
cursor.executemany(sql, vars_list=args)
else:
cursor.execute(sql, vars=args)
# options
if bulk or affected_rows:
result = cursor.rowcount
else:
if fetchmany:
result = [res for res in cursor.fetchmany()]
elif fetchall:
result = [res for res in cursor.fetchall()]
elif fetchone:
result = cursor.fetchone()
else:
result = None
if mutation:
self.conn.commit()
elif self.dialect == "mysql":
with self.conn.cursor(buffered=True) as cursor:
if args is None:
cursor.execute(sql)
else:
if bulk:
cursor.executemany(sql, args)
else:
cursor.execute(sql, args)
# options
if bulk or affected_rows:
result = cursor.rowcount
else:
if fetchmany:
result = cursor.fetchmany()
elif fetchall:
result = cursor.fetchall()
elif fetchone:
result = cursor.fetchone()
else:
result = None
if mutation:
self.conn.commit()

if operation is not None:
result = cursor.lastrowid
elif self.dialect == "sqlite":
cursor = self.conn.cursor()
if args is None:
cursor.execute(sql)
else:
if bulk:
cursor.executemany(sql, args)
else:
cursor.execute(sql, args)
# options
if bulk or affected_rows:
result = cursor.rowcount
else:
if fetchmany:
result = cursor.fetchmany()
elif fetchall:
result = cursor.fetchall()
elif fetchone:
result = cursor.fetchone()
else:
result = None
if mutation:
self.conn.commit()
if operation is not None:
result = cursor.lastrowid
else:
raise UnsupportedDialectException(
"The dialect passed is not supported the supported dialects are: {'postgres', 'mysql', 'sqlite'}"
)

return result
) -> Any:
return SQL(
conn=self.conn,
dialect=self.dialect,
sql_logger=self.sql_logger,
logs_filename=self.logs_filename,
).execute_sql(
sql=sql,
args=args,
operation=operation,
mutation=mutation,
fetchall=fetchall,
bulk=bulk,
fetchone=fetchone,
fetchmany=fetchmany,
affected_rows=affected_rows,
)

def connect(self):
def connect(
self,
) -> Any | PooledMySQLConnection | MySQLConnectionAbstract | Connection:
if self.dialect == "postgres":
options = ConnectionOptionsFactory.get_connection_options(
**self.connection_options
Expand Down Expand Up @@ -393,7 +314,9 @@ def connect(self):

def connect_and_sync(
self, models: list[Model], drop=False, force=False, alter=False
):
) -> tuple[
Any | PooledMySQLConnection | MySQLConnectionAbstract | Connection, list[str]
]:
try:
if self.dialect == "postgres":
options = ConnectionOptionsFactory.get_connection_options(
Expand Down Expand Up @@ -437,7 +360,9 @@ def connect_and_sync(
except Exception as e:
raise Exception(e)

def sync(self, models: list[Model], drop=False, force=False, alter=False):
def sync(
self, models: list[Model], drop=False, force=False, alter=False
) -> list[str]:
try:
for model in models:
if drop or force:
Expand Down
36 changes: 32 additions & 4 deletions dataloom/loom/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,44 @@
from typing import Optional, Callable, Any
from dataloom.types import Filter, DIALECT_LITERAL, Order
from dataloom.utils import get_args
from abc import ABC, abstractclassmethod


class delete:
class Delete(ABC):
@abstractclassmethod
def delete_by_pk(self, instance: Model, pk) -> int:
raise NotImplementedError("The delete_by_pk function not implemented.")

@abstractclassmethod
def delete_one(
self,
instance: Model,
filters: Optional[Filter | list[Filter]] = [],
offset: Optional[int] = None,
order: Optional[list[Order]] = [],
) -> int:
raise NotImplementedError("The delete_one function not implemented.")

@abstractclassmethod
def delete_bulk(
self,
instance: Model,
filters: Optional[Filter | list[Filter]] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
order: Optional[list[Order]] = [],
) -> int:
raise NotImplementedError("The delete_one function not implemented.")


class delete(Delete):
def __init__(
self, dialect: DIALECT_LITERAL, _execute_sql: Callable[..., Any]
) -> None:
self._execute_sql = _execute_sql
self.dialect = dialect

def delete_by_pk(self, instance: Model, pk):
def delete_by_pk(self, instance: Model, pk) -> int:
sql = instance._get_delete_by_pk_stm(dialect=self.dialect)
affected_rows = self._execute_sql(
sql, args=(pk,), affected_rows=True, fetchall=True
Expand All @@ -25,7 +53,7 @@ def delete_one(
filters: Optional[Filter | list[Filter]] = [],
offset: Optional[int] = None,
order: Optional[list[Order]] = [],
):
) -> int:
sql, params = instance._get_delete_where_stm(
dialect=self.dialect, filters=filters, offset=offset, order=order
)
Expand All @@ -44,7 +72,7 @@ def delete_bulk(
limit: Optional[int] = None,
offset: Optional[int] = None,
order: Optional[list[Order]] = [],
):
) -> int:
if offset is not None and limit is None and self.dialect == "mysql":
raise InvalidArgumentsException(
f"You can not apply offset without limit on dialect '{self.dialect}'."
Expand Down
21 changes: 18 additions & 3 deletions dataloom/loom/insert.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,31 @@
from typing import Callable, Any
from dataloom.exceptions import InvalidColumnValuesException
from dataloom.utils import get_insert_bulk_attrs
from abc import ABC, abstractclassmethod


class insert:
class Insert(ABC):
@abstractclassmethod
def insert_one(
self, instance: Model, values: ColumnValue | list[ColumnValue]
) -> Any:
raise NotImplementedError("The insert_one method was not implemented.")

@abstractclassmethod
def insert_bulk(self, instance: Model, values: list[list[ColumnValue]]) -> int:
raise NotImplementedError("The insert_bulk method was not implemented.")


class insert(Insert):
def __init__(
self, dialect: DIALECT_LITERAL, _execute_sql: Callable[..., Any]
) -> None:
self._execute_sql = _execute_sql
self.dialect = dialect

def insert_one(self, instance: Model, values: ColumnValue | list[ColumnValue]):
def insert_one(
self, instance: Model, values: ColumnValue | list[ColumnValue]
) -> Any:
sql, values = instance._get_insert_one_stm(dialect=self.dialect, values=values)
row = self._execute_sql(
sql,
Expand All @@ -23,7 +38,7 @@ def insert_one(self, instance: Model, values: ColumnValue | list[ColumnValue]):
)
return row[0] if type(row) in [list, tuple] else row

def insert_bulk(self, instance: Model, values: list[list[ColumnValue]]):
def insert_bulk(self, instance: Model, values: list[list[ColumnValue]]) -> int:
# ? ensure that the values that are passed is a list of a list and they inner list have the same length
if not isinstance(values, list):
raise InvalidColumnValuesException(
Expand Down
16 changes: 14 additions & 2 deletions dataloom/loom/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,21 @@
from dataloom.utils import print_pretty_table
from dataloom.types import DIALECT_LITERAL
from typing import Callable, Any
from abc import ABC, abstractclassmethod


class inspect:
class Inspect(ABC):
@abstractclassmethod
def inspect(
self,
instance: Model,
fields: list[str] = ["name", "type", "nullable", "default"],
print_table: bool = True,
) -> list[dict] | None:
raise NotImplementedError("The inspect method was not implemented.")


class inspect(Inspect):
def __init__(
self, dialect: DIALECT_LITERAL, database: str, _execute_sql: Callable[..., Any]
) -> None:
Expand All @@ -18,7 +30,7 @@ def inspect(
instance: Model,
fields: list[str] = ["name", "type", "nullable", "default"],
print_table: bool = True,
):
) -> list[dict] | None:
# The column name should be first and required.
allowed = {
"name": "column_name",
Expand Down
Loading

0 comments on commit 2695378

Please sign in to comment.