Skip to content

Commit

Permalink
selecting fields and limit-offset
Browse files Browse the repository at this point in the history
  • Loading branch information
CrispenGari committed Feb 4, 2024
1 parent ec4f0f3 commit 2d774d5
Show file tree
Hide file tree
Showing 16 changed files with 10,962 additions and 254 deletions.
49 changes: 6 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,7 @@ class User(Model):
createdAt = CreatedAtColumn()
updatedAt = UpdatedAtColumn()

@property
def to_dict(self):
return {
"id": self.id,
"name": self.name,
"username": self.username,
"createdAt": self.createdAt,
"updatedAt": self.updatedAt,
}



class Post(Model):
Expand All @@ -220,26 +212,13 @@ class Post(Model):
userId = ForeignKeyColumn(
User, type="int", required=True, onDelete="CASCADE", onUpdate="CASCADE"
)

@property
def to_dict(self):
return {
"id": self.id,
"completed": self.completed,
"title": self.title,
"userId": self.userId,
"createdAt": self.createdAt,
"updatedAt": self.updatedAt,
}

```

- Within the `User` model definition, the table name is explicitly specified using the `__tablename__` property, set to `"users"`. This informs `dataloom` to use the provided name instead of automatically deriving it from the class name. If `__tablename__` is not specified, the class name becomes the default table name during the synchronization of tables. To achieve this, the `TableColumn` class is used, accepting the specified table name as an argument.
- Every table must include exactly one primary key column. To define this, the `PrimaryKeyColumn` class is employed, signaling to `dataloom` that the specified field is a primary key.
- The `Column` class represents a regular column, allowing the inclusion of various options such as type and whether it is required.
- The `CreatedAtColumn` and `UpdatedAt` column types are automatically generated by the database as timestamps. If timestamps are unnecessary or only one of them is needed, they can be omitted.
- The `ForeignKeyColumn` establishes a relationship between the current (child) table and a referenced (parent) table.
- A `to_dict` property has been created, providing a convenient way to retrieve the data in the form of a Python dictionary when invoked.

#### `Column` Class

Expand Down Expand Up @@ -479,14 +458,14 @@ To retrieve records from the database, you can utilize the `find_all()` and `fin

```py
users = sqlite_loom.find_all(User)
print([u.to_dict for u in users])
print([u for u in users])
```

Here is an example demonstrating the usage of the `find_many()` function with specific filters.

```py
many = sqlite_loom.find_many(Post, {"userId": 5})
print([u.to_dict for u in many])
print([u for u in many])
```

The distinction between the `find_all()` and `find_many()` methods lies in the fact that `find_many()` enables you to apply specific filters, whereas `find_all()` retrieves all the documents within the specified model.
Expand All @@ -498,15 +477,15 @@ The `find_by_pk()` and `find_one()` methods are employed to locate a single reco
```py
user = User(name="Crispen", username="heyy")
me = sqlite_loom.find_by_pk(User, 1)
print(me.to_dict)
print(me)

```

With the `find_one()` method, you can specify the filters of your query as follows:

```py
him = sqlite_loom.find_one(User, filters={"id": 1})
print(him.to_dict)
print(him)
```

#### 4. Deleting a record
Expand Down Expand Up @@ -594,15 +573,6 @@ class User(Model):
def __repr__(self) -> str:
return f"User<{self.id}>"

def to_dict(self):
return {
"id": self.id,
"name": self.name,
"username": self.username,
"createdAt": self.createAt,
"updatedAt": self.updatedAt,
}


class Post(Model):
__tablename__ = "posts"
Expand All @@ -612,14 +582,7 @@ class Post(Model):
updatedAt = UpdatedAtColumn()

userId = ForeignKeyColumn(User, onDelete="CASCADE", onUpdate="CASCADE")
def to_dict(self):
return {
"id": self.id,
"title": self.title,
"userId": self.userId,
"createdAt": self.createAt,
"updatedAt": self.updatedAt,
}


```

Expand Down
10,596 changes: 10,596 additions & 0 deletions dataloom.sql

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions dataloom/columns/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def default_constraint(self):
"DEFAULT {default}".format(
default=(
self.default
if type(self.default) == type(True)
if isinstance(self.default, bool)
else f"'{self.default}'"
)
)
Expand Down Expand Up @@ -195,6 +195,9 @@ def __init__(

self._data = {}

def __str__(self) -> str:
return ""

@property
def nullable_constraint(self):
return "NOT NULL" if not self.nullable else ""
Expand All @@ -209,7 +212,7 @@ def default_constraint(self):
"DEFAULT {default}".format(
default=(
self.default
if type(self.default) == type(True)
if isinstance(self.default, bool)
else f"'{self.default}'"
)
)
Expand Down
74 changes: 60 additions & 14 deletions dataloom/loom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,38 +285,84 @@ def insert_bulk(self, instances: list[Model]):
row_count = self._execute_sql(sql, args=tuple(values), fetchall=True, bulk=True)
return row_count

def find_many(self, instance: Model, filters: dict = {}) -> list:
def find_many(
self,
instance: Model,
filters: dict = {},
select: list[str] = [],
include: list[Model] = [],
return_dict: bool = True,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> list:
sql, params, fields = instance._get_select_where_stm(
dialect=self.dialect, args=filters
dialect=self.dialect,
args=filters,
select=select,
limit=limit,
offset=offset,
)
data = list()
rows = self._execute_sql(sql, fetchall=True, args=params)
for row in rows:
res = dict(zip(fields, row))
data.append(instance(**res))
json = dict(zip(fields, row))
data.append(json if return_dict else instance(**json))
return data

def find_all(self, instance: Model) -> list:
sql, fields, params = instance._get_select_where_stm(dialect=self.dialect)
def find_all(
self,
instance: Model,
select: list[str] = [],
include: list[Model] = [],
return_dict: bool = True,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> list:
sql, params, fields = instance._get_select_where_stm(
dialect=self.dialect, select=select, limit=limit, offset=offset
)
data = list()
rows = self._execute_sql(sql, fetchall=True)
for row in rows:
res = dict(zip(fields, row))
data.append(instance(**res))
json = dict(zip(fields, row))
data.append(json if return_dict else instance(**json))
return data

def find_by_pk(self, instance: Model, pk, options: dict = {}):
def find_by_pk(
self,
instance: Model,
pk,
select: list[str] = [],
include: list[Model] = [],
return_dict: bool = True,
):
# what is the name of the primary key column? well we will find out
sql, fields = instance._get_select_by_pk_stm(dialect=self.dialect)
sql, fields = instance._get_select_by_pk_stm(
dialect=self.dialect, select=select
)
row = self._execute_sql(sql, args=(pk,), fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))
if row is None:
return None
json = dict(zip(fields, row))
return json if return_dict else instance(**json)

def find_one(self, instance: Model, filters: dict = {}):
def find_one(
self,
instance: Model,
filters: dict = {},
select: list[str] = [],
include: list[Model] = [],
return_dict: bool = True,
offset: Optional[int] = None,
):
sql, params, fields = instance._get_select_where_stm(
dialect=self.dialect, args=filters
dialect=self.dialect, args=filters, select=select, offset=offset
)
row = self._execute_sql(sql, args=params, fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))
if row is None:
return None
json = dict(zip(fields, row))
return json if return_dict else instance(**json)

def update_by_pk(self, instance: Model, pk, values: dict = {}):
sql, args = instance._get_update_by_pk_stm(dialect=self.dialect, args=values)
Expand Down
46 changes: 39 additions & 7 deletions dataloom/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
UpdatedAtColumn,
)
from dataloom.statements import GetStatement
from typing import Optional


class Model:
Expand Down Expand Up @@ -147,7 +148,14 @@ def _get_insert_bulk_smt(cls, dialect: str, placeholders, columns, data):
return sql, values

@classmethod
def _get_select_where_stm(cls, dialect: str, args: dict = {}):
def _get_select_where_stm(
cls,
dialect: str,
args: dict = {},
select: list[str] = [],
limit: Optional[int] = None,
offset: Optional[int] = None,
):
fields = []
filters = []
params = []
Expand All @@ -162,6 +170,11 @@ def _get_select_where_stm(cls, dialect: str, args: dict = {}):
fields.append(name)
elif isinstance(field, UpdatedAtColumn):
fields.append(name)
for column in select:
if column not in fields:
raise UnknownColumnException(
f'The table "{cls._get_table_name()}" does not have a column "{column}".'
)
for key, value in args.items():
_key = (
f'"{key}" = %s'
Expand All @@ -176,23 +189,33 @@ def _get_select_where_stm(cls, dialect: str, args: dict = {}):
else:
filters.append(_key)
params.append(value)

if dialect == "postgres" or "mysql" or "sqlite":
if len(filters) == 0:
sql = GetStatement(
dialect=dialect, model=cls, table_name=cls._get_table_name()
)._get_select_command(fields=fields)
)._get_select_command(
fields=fields if len(select) == 0 else select,
limit=limit,
offset=offset,
)
else:
sql = GetStatement(
dialect=dialect, model=cls, table_name=cls._get_table_name()
)._get_select_where_command(filters=filters, fields=fields)
)._get_select_where_command(
filters=filters,
fields=fields if len(select) == 0 else select,
limit=limit,
offset=offset,
)
else:
raise UnsupportedDialectException(
"The dialect passed is not supported the supported dialects are: {'postgres', 'mysql', 'sqlite'}"
)
return sql, params, fields
return sql, params, fields if len(select) == 0 else select

@classmethod
def _get_select_by_pk_stm(cls, dialect: str):
def _get_select_by_pk_stm(cls, dialect: str, select: list[str] = []):
fields = []
pk_name = None
# what is the pk name?
Expand All @@ -208,15 +231,24 @@ def _get_select_by_pk_stm(cls, dialect: str):
fields.append(name)
elif isinstance(field, UpdatedAtColumn):
fields.append(name)

for column in select:
if column not in fields:
raise UnknownColumnException(
f'The table "{cls._get_table_name()}" does not have a column "{column}".'
)

if dialect == "postgres" or "mysql" or "sqlite":
sql = GetStatement(
dialect=dialect, model=cls, table_name=cls._get_table_name()
)._get_select_by_pk_command(fields=fields, pk_name=pk_name)
)._get_select_by_pk_command(
fields=select if len(select) != 0 else fields, pk_name=pk_name
)
else:
raise UnsupportedDialectException(
"The dialect passed is not supported the supported dialects are: {'postgres', 'mysql', 'sqlite'}"
)
return sql, fields
return sql, fields if len(select) == 0 else select

@classmethod
def _get_update_by_pk_stm(cls, dialect: str, args: dict = {}):
Expand Down
Loading

0 comments on commit 2d774d5

Please sign in to comment.