Skip to content

Commit

Permalink
primary-key-column implemented and the docs
Browse files Browse the repository at this point in the history
  • Loading branch information
CrispenGari committed Jan 31, 2024
1 parent 6f59ec8 commit 188f972
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 116 deletions.
70 changes: 60 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ A model is just a top level class that allows you to build some complicated SQL
```py
class User(Model):
__tablename__ = "users"
id = Column(type="bigint", primary_key=True, nullable=False, auto_increment=True)
id = PrimaryKeyColumn(type="bigint", auto_increment=True)
username = Column(type="text", nullable=False, default="Hello there!!")
name = Column(type="varchar", unique=True, length=255)

Expand All @@ -83,7 +83,7 @@ class User(Model):
Every table has a column. Each property that is set to column in a model is considered 1. Let's have a look at how we can define a column in a table.

```py
id = Column(type="bigint", primary_key=True, nullable=False, auto_increment=True)
username = Column(type="text", nullable=False, default="Hello there!!")
```

We are defining a column that is called `id`. And we are specifying the type of this column and some other options. Here are some other options that can be passed to the
Expand All @@ -100,12 +100,57 @@ We are defining a column that is called `id`. And we are specifying the type of
<td>any datatype supported</td><td></td>
</tr>
<tr>
<td>primary_key</td><td>Optional to specify if the column is a primary key or not.</td>
<td>nullable</td><td>Optional to specify if the column will allow null values or not.</td>
<td>bool</td><td>False</td>
</tr>
<tr>
<td>nullable</td><td>Optional to specify if the column will allow null values or not.</td>
<td>length</td><td>Optional to specify if the length of the type that. eg if this argument is passed as <b>N</b> with a <b>T</b> type, this will yield an sql statement with type <b>T(N)</b>.</td>
<td>int|None</td><td>None</td>
</tr>
<tr>
<td>auto_increment</td><td>Optional to specify if the column will automatically increment or not.</td>
<td>bool</td><td>False</td>
</tr>
<tr>
<td>default</td><td>Optional to specify if the default value in a column.</td>
<td>any</td><td>None</td>
</tr>
<tr>
<td>unique</td><td>Optional to specify if the column will contain unique values or not.</td>
<td>bool</td><td>False</td>
</tr>
</tbody>
</table>

> Note: Every table is required to have a primary key column and this column should be 1. Let's talk about the `PrimaryKeyColumn`
### `PrimaryKeyColumn` Class

This create a unique index in every table that you create. Every table that you create and that inherits from the `Model` class is required to have exactly 1 `PrimaryKeyColumn`. Here is how you can create a `id` column as a primary key in your table:

```py
class Post(Model):
__tablename__ = "posts"
id = PrimaryKeyColumn(type="bigint", auto_increment=True)
#...rest of your tables
```

The `PrimaryKeyColumn` takes the following arguments:

<table border="1">
<thead>
<tr><th>Argument</th><th>Description</th>
<th>Type</th><th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td>type</td><td>The datatype of your primary key.</td>
<td>str</td><td>"bigserial"</td>
</tr>
<tr>
<td>type</td><td>The datatype of your primary key.</td>
<td>str</td><td>"bigserial"</td>
</tr>
<tr>
<td>length</td><td>Optional to specify if the length of the type that. eg if this argument is passed as <b>N</b> with a <b>T</b> type, this will yield an sql statement with type <b>T(N)</b>.</td>
Expand All @@ -119,11 +164,17 @@ We are defining a column that is called `id`. And we are specifying the type of
<td>default</td><td>Optional to specify if the default value in a column.</td>
<td>any</td><td>None</td>
</tr>
<tr>
<td>nullable</td><td>Optional to specify if the column will allow null values or not.</td>
<td>bool</td><td>False</td>
</tr>
<tr>
<td>unique</td><td>Optional to specify if the column will contain unique values or not.</td>
<td>bool</td><td>True</td>
</tr>
</tbody>
</table>

> Note: Every table is required to have a primary key column and this column should be 1.
### `ForeignKeyColumn` Class

This Column is used when we are telling `dataloom` that the column has a relationship with a primary key in another table. Let's consider the following model definition of a `Post`:
Expand All @@ -132,7 +183,7 @@ This Column is used when we are telling `dataloom` that the column has a relatio
class Post(Model):
__tablename__ = "posts"

id = Column(type="bigint", primary_key=True, nullable=False, auto_increment=True)
id = PrimaryKeyColumn(type="bigint", auto_increment=True)
title = Column(type="text", nullable=False, default="Hello there!!")
createAt = CreatedAtColumn()
updatedAt = UpdatedAtColumn()
Expand Down Expand Up @@ -299,7 +350,7 @@ from dataloom import Column, CreatedAtColumn, UpdatedAtColumn, ForeignKeyColumn

class User(Model):
__tablename__ = "users"
id = Column(type="bigint", primary_key=True, nullable=False, auto_increment=True)
id = PrimaryKeyColumn(type="bigint", auto_increment=True)
username = Column(type="text", nullable=False)
name = Column(type="varchar", unique=False, length=255)
createAt = CreatedAtColumn()
Expand All @@ -323,8 +374,7 @@ class User(Model):

class Post(Model):
__tablename__ = "posts"

id = Column(type="bigint", primary_key=True, nullable=False, auto_increment=True)
id = PrimaryKeyColumn(type="bigint", auto_increment=True)
title = Column(type="text", nullable=False, default="Hello there!!")
createAt = CreatedAtColumn()
updatedAt = UpdatedAtColumn()
Expand Down
51 changes: 41 additions & 10 deletions orm/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
from orm.constants import instances
from orm.model.statements import Statements
from orm.model.model import Model
from orm.model.column import Column
from orm.model.column import (
Column,
UpdatedAtColumn,
PrimaryKeyColumn,
CreatedAtColumn,
ForeignKeyColumn,
)
from functools import partial


Expand Down Expand Up @@ -126,13 +132,8 @@ def sync(self, models: list[Model], drop=False, force=False, alter=False):

def commit(self, instance: Model):
sql, values = instance._get_insert_one_stm()
fields = list()
for name, field in inspect.getmembers(instance):
if isinstance(field, Column):
fields.append(name)
# save to the database
row = self._execute_sql(sql, args=tuple(values), fetchone=True)
return dict(zip(fields, row)).get(fields[0])
return row[0]

def commit_bulk(self, instances: list[Model]):
columns = None
Expand Down Expand Up @@ -186,10 +187,18 @@ def find_by_pk(self, instance: Model, pk):
pk_name = "id"
fields = list()
for name, field in inspect.getmembers(instance):
if isinstance(field, Column):
if field.primary_key:
pk_name = name
if (
isinstance(field, Column)
or isinstance(field, ForeignKeyColumn)
or isinstance(field, CreatedAtColumn)
or isinstance(field, UpdatedAtColumn)
):
fields.append(name)
elif isinstance(field, PrimaryKeyColumn):
pk_name = name
fields.append(name)

print(fields)
sql, fields = instance._get_select_by_pk_stm(pk, pk_name, fields=fields)
row = self._execute_sql(sql, fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))
Expand All @@ -202,3 +211,25 @@ def find_one(self, instance: Model, filters: dict = {}):
sql, _, params = instance._get_select_where_stm(fields, filters)
row = self._execute_sql(sql, args=params, fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))

def delete_one(self, instance: Model, filters: dict = {}):
fields = list()
for name, field in inspect.getmembers(instance):
if isinstance(field, Column):
fields.append(name)
sql, _, params = instance._get_select_where_stm(fields, filters)
row = self._execute_sql(sql, args=params, fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))

def delete_by_pk(self, instance: Model, pk):
# what is the name of the primary key column?
pk_name = "id"
fields = list()
for name, field in inspect.getmembers(instance):
if isinstance(field, Column):
if field.primary_key:
pk_name = name
fields.append(name)
sql, fields = instance._get_select_by_pk_stm(pk, pk_name, fields=fields)
row = self._execute_sql(sql, fetchone=True)
return None if row is None else instance(**dict(zip(fields, row)))
2 changes: 1 addition & 1 deletion orm/keys.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
push = True
push = False


if push:
Expand Down
55 changes: 46 additions & 9 deletions orm/model/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,70 @@ def sql_type(self):
raise ValueError(f"Unsupported column type: {self.type}")


class PrimaryKeyColumn:
def __init__(
self,
type: str = "bigserial",
length: int | None = None,
auto_increment: bool = False,
nullable: bool = False,
unique: bool = True,
default=None,
):
self.type = type
self.length = length
self.auto_increment = auto_increment
self.default = default
self.nullable = nullable
self.unique = unique

@property
def default_constraint(self):
return (
"DEFAULT '{default}'".format(default=self.default) if self.default else ""
)

@property
def unique_constraint(self):
return "UNIQUE" if self.unique else ""

@property
def nullable_constraint(self):
return "NOT NULL" if not self.nullable else ""

@property
def sql_type(self):
if self.type in POSTGRES_SQL_TYPES:
if self.auto_increment:
return "BIGSERIAL"
return (
f"{POSTGRES_SQL_TYPES[self.type]}({self.length})"
if self.length
else POSTGRES_SQL_TYPES[self.type]
)
else:
raise ValueError(f"Unsupported column type: {self.type}")


class Column:
def __init__(
self,
type,
primary_key: bool = False,
nullable: bool = True,
unique: bool = False,
length: int | None = None,
auto_increment: bool = False,
default=None,
):
self.type = type
self.primary_key = primary_key
self.nullable = nullable
self.unique = unique
self.length = length
self.auto_increment = (auto_increment,)
self.auto_increment = auto_increment
self.default = default

self._data = {}

@property
def primary_key_constraint(self):
return "PRIMARY KEY" if self.primary_key else ""

@property
def nullable_constraint(self):
return "NOT NULL" if not self.nullable else ""
Expand All @@ -88,8 +127,6 @@ def default_constraint(self):
@property
def sql_type(self):
if self.type in POSTGRES_SQL_TYPES:
if self.auto_increment and self.primary_key:
return "BIGSERIAL"
return (
f"{POSTGRES_SQL_TYPES[self.type]}({self.length})"
if self.length
Expand Down
Loading

0 comments on commit 188f972

Please sign in to comment.