From 39f0d06e81b72ecf953862441a6de46d6c809cd1 Mon Sep 17 00:00:00 2001 From: Crispen Gari Date: Sat, 3 Feb 2024 08:33:37 +0200 Subject: [PATCH] some-docs --- README.md | 482 ++++++++++++++++++++++++++++-------------------- hi.db | Bin 28672 -> 28672 bytes playground.py | 67 +++++-- sqlite-logs.sql | 10 + 4 files changed, 336 insertions(+), 223 deletions(-) create mode 100644 sqlite-logs.sql diff --git a/README.md b/README.md index 1fd9f53..b709bb4 100644 --- a/README.md +++ b/README.md @@ -20,286 +20,362 @@ In this section we are going to go through how you can use our `orm` package in ### Connection -A database connection is required. In this example a connection will be set on a `postgres` database instance that have a database name `hi. +To use Dataloom, you need to establish a connection with a specific database dialect. The available dialect options are `mysql`, `postgres`, and `sqlite`. In this example, we'll demonstrate how to set up a connection to a PostgreSQL database named "hi" using the `postgres` dialect. The following is an example of how you can establish a connection with postgres database. -```py -from dataloom import ( - Dataloom -) -from typing import Optional +```python +from dataloom import Dataloom +# Create a Dataloom instance with PostgreSQL configuration pg_loom = Dataloom( - dialect="postgres", database="hi", password="root", user="postgres", logging=True + dialect="postgres", + database="hi", + password="root", + user="postgres", + host="localhost", + logging=True, + logs_filename="logs.sql", + port=5432, ) -mysql_loom = Dataloom(dialect="mysql", database="hi", password="root", user="root") -sqlite_loom = Dataloom(dialect="sqlite", database="hi.db") +# Connect to the PostgreSQL database conn = pg_loom.connect() -if __name__ == "main": +# Close the connection when the script completes +if __name__ == "__main__": + conn.close() +``` + +To establish a connection with a `MySQL` database using Dataloom, you can use the following example: + +```python +from dataloom import Dataloom + +# Create a Dataloom instance with MySQL configuration +mysql_loom = Dataloom( + dialect="mysql", + database="hi", + password="root", + user="root", + host="localhost", + logging=True, + logs_filename="logs.sql", + port=3306, +) + +# Connect to the MySQL database +conn = mysql_loom.connect() + +# Close the connection when the script completes +if __name__ == "__main__": conn.close() ``` -The database class takes in the following options: +To establish a connection with an `SQLite` database using Dataloom, you can use the following example: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OptionValue TypeDescriptionDefault
databasestrThis is the name of the database. It is required upon connection creation.
dialectstr|NoneThe user to connect to the database instance.postgres
passwordstr|NoneThe password to connect to the database instance of the specified user.postgres
hoststr|NoneThe database host. localhost|127.0.0.1
portint|NoneThe database port number. 4532
logsboolSpecify wether you want to see sql statements as you perform operations on the database in the logs or not.True
+```python +from dataloom import Dataloom + +# Create a Dataloom instance with SQLite configuration +sqlite_loom = Dataloom( + dialect="sqlite", + database="hi.db", + logs_filename="sqlite-logs.sql", + logging=True +) + +# Connect to the SQLite database +conn = sqlite_loom.connect() + +# Close the connection when the script completes +if __name__ == "__main__": + conn.close() +``` + +The `Dataloom` class takes in the following options: +| Parameter | Description | Value Type | Default Value | Required | +| --------------- | --------------------------------------------------------------------------------- | --------------- | -------------- | -------- | +| `dialect` | Dialect for the database connection. Options are `mysql`, `postgres`, or `sqlite` | `str` or `None` | `None` | `Yes` | +| `database` | Name of the database for `mysql` and `postgres`, filename for `sqlite` | `str` or `None` | `None` | `Yes` | +| `password` | Password for the database user (only for `mysql` and `postgres`) | `str` or `None` | `None` | `No` | +| `user` | Database user (only for `mysql` and `postgres`) | `str` or `None` | `None` | `No` | +| `host` | Database host (only for `mysql` and `postgres`) | `str` or `None` | `localhost` | `No` | +| `logging` | Enable logging for the database queries | `bool` | `True` | `No` | +| `logs_filename` | Filename for the query logs | `str` or `None` | `dataloom.sql` | `No` | +| `port` | Port number for the database connection (only for `mysql` and `postgres`) | `int` or `None` | `None` | `No` | ### `Model` Class -A model is just a top level class that allows you to build some complicated SQL tables from regular python classes. You can define a table `User` as an class that inherits from `Model` class as follows: +A model in Dataloom is a top-level class that facilitates the creation of complex SQL tables using regular Python classes. This example demonstrates how to define two tables, `User` and `Post`, by creating classes that inherit from the `Model` class. ```py +from dataloom import ( + Dataloom, + Model, + PrimaryKeyColumn, + Column, + CreatedAtColumn, + UpdatedAtColumn, + TableColumn, + ForeignKeyColumn, +) +from typing import Optional + class User(Model): - __tablename__ = "users" - id = PrimaryKeyColumn(type="bigint", auto_increment=True) - username = Column(type="text", nullable=False, default="Hello there!!") - name = Column(type="varchar", unique=True, length=255) + __tablename__: Optional[TableColumn] = TableColumn(name="users") + id = PrimaryKeyColumn(type="int", auto_increment=True) + name = Column(type="text", nullable=False, default="Bob") + username = Column(type="varchar", unique=True, length=255) - def __str__(self) -> str: - return f"User<{self.id}>" + # timestamps + createdAt = CreatedAtColumn() + updatedAt = UpdatedAtColumn() - def __repr__(self) -> str: - return f"User<{self.id}>" + @property + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "username": self.username, + "createdAt": self.createdAt, + "updatedAt": self.updatedAt, + } + +class Post(Model): + __tablename__: Optional[TableColumn] = TableColumn(name="posts") + id = PrimaryKeyColumn(type="int", auto_increment=True, nullable=False, unique=True) + completed = Column(type="boolean", default=False) + title = Column( + type="varchar", + length=255, + nullable=False, + ) + # timestamps + createdAt = CreatedAtColumn() + updatedAt = UpdatedAtColumn() + + # relations + userId = ForeignKeyColumn( + User, type="int", required=True, onDelete="CASCADE", onUpdate="CASCADE" + ) + + @property def to_dict(self): - return {"id": self.id, "name": self.name, "username": self.username} + return { + "id": self.id, + "completed": self.completed, + "title": self.title, + "userId": self.userId, + "createdAt": self.createdAt, + "updatedAt": self.updatedAt, + } ``` -- We are defining a model called `User` and we are specifying the table name using the property `__tablename__` to `"users"`. This will tell `dataloom` that don't infer the table name from the class use the one that I have provided. If you don't pass the `__tablename__` then the class name will be used as your table name upon syncing tables. +- 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 -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. +In the context of a database table, each property marked as a column in a model is treated as an individual attribute. Here's an example of how to define a column in a table using the `Column` class: -```py +```python 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ArgumentDescriptionTypeDefault
typeRequired datatype of a columnany datatype supported
nullableOptional to specify if the column will allow null values or not.boolFalse
lengthOptional to specify if the length of the type that. eg if this argument is passed as N with a T type, this will yield an sql statement with type T(N).int|NoneNone
auto_incrementOptional to specify if the column will automatically increment or not.boolFalse
defaultOptional to specify if the default value in a column.anyNone
uniqueOptional to specify if the column will contain unique values or not.boolFalse
+Here are some other options that you can pass to the `Column`: +| Argument | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------- | ------- | +| `type` | Required datatype of a column | any `datatype` | | +| `nullable` | Optional to specify if the column will allow null values or not. | `bool` | `False` | +| `length` | Optional to specify the length of the type. If passed as `N` with type `T`, it yields an SQL statement with type `T(N)`. | `int` \| `None` | `None` | +| `auto_increment` | Optional to specify if the column will automatically increment or not. | `bool` | `False` | +| `default` | Optional to specify the default value in a column. | `any` | `None` | +| `unique` | Optional to specify if the column will contain unique values or not. | `bool` | `False` | + +> Talking about data types, each `dialect` has its own accepted values. Here is a list of types supported by each and every `dialect`: + +1. `mysql` + + - `"int"` - Integer data type. + - `"smallint"` - Small integer data type. + - `"bigint"` - Big integer data type. + - `"float"` - Floating-point number data type. + - `"double"` - Double-precision floating-point number data type. + - `"numeric"` - Numeric or decimal data type. + - `"text"` - Text data type. + - `"varchar"` - Variable-length character data type. + - `"char"` - Fixed-length character data type. + - `"boolean"` - Boolean data type. + - `"date"` - Date data type. + - `"time"` - Time data type. + - `"timestamp"` - Timestamp data type. + - `"json"` - JSON (JavaScript Object Notation) data type. + - `"blob"` - Binary Large Object (BLOB) data type. + +2. `postgres` + + - `"int"` - Integer data type (Alias: `"INTEGER"`). + - `"smallint"` - Small integer data type (Alias: `"SMALLINT"`). + - `"bigint"` - Big integer data type (Alias: `"BIGINT"`). + - `"serial"` - Auto-incrementing integer data type (Alias: `"SERIAL"`). + - `"bigserial"` - Auto-incrementing big integer data type (Alias: `"BIGSERIAL"`). + - `"smallserial"` - Auto-incrementing small integer data type (Alias: `"SMALLSERIAL"`). + - `"float"` - Real number data type (Alias: `"REAL"`). + - `"double precision"` - Double-precision floating-point number data type (Alias: `"DOUBLE PRECISION"`). + - `"numeric"` - Numeric data type (Alias: `"NUMERIC"`). + - `"text"` - Text data type. + - `"varchar"` - Variable-length character data type. + - `"char"` - Fixed-length character data type. + - `"boolean"` - Boolean data type. + - `"date"` - Date data type. + - `"time"` - Time data type. + - `"timestamp"` - Timestamp data type. + - `"interval"` - Time interval data type. + - `"uuid"` - UUID (Universally Unique Identifier) data type. + - `"json"` - JSON (JavaScript Object Notation) data type. + - `"jsonb"` - Binary JSON (JavaScript Object Notation) data type. + - `"bytea"` - Binary data type (Array of bytes). + - `"array"` - Array data type. + - `"inet"` - IP network address data type. + - `"cidr"` - Classless Inter-Domain Routing (CIDR) address data type. + - `"macaddr"` - MAC (Media Access Control) address data type. + - `"tsvector"` - Text search vector data type. + - `"point"` - Geometric point data type. + - `"line"` - Geometric line data type. + - `"lseg"` - Geometric line segment data type. + - `"box"` - Geometric box data type. + - `"path"` - Geometric path data type. + - `"polygon"` - Geometric polygon data type. + - `"circle"` - Geometric circle data type. + - `"hstore"` - Key-value pair store data type. + +3. `sqlite` + - `"int"` - Integer data type (Alias: `"INTEGER"`). + - `"smallint"` - Small integer data type (Alias: `"SMALLINT"`). + - `"bigint"` - Big integer data type (Alias: `"BIGINT"`). + - `"float"` - Real number data type (Alias: `"REAL"`). + - `"double precision"` - Double-precision floating-point number data type (Alias: `"DOUBLE"`). + - `"numeric"` - Numeric data type (Alias: `"NUMERIC"`). + - `"text"` - Text data type. + - `"varchar"` - Variable-length character data type. + - `"char"` - Fixed-length character data type. + - `"boolean"` - Boolean data type. + - `"date"` - Date data type. + - `"time"` - Time data type. + - `"timestamp"` - Timestamp data type. + - `"json"` - JSON (JavaScript Object Notation) data type. + - `"blob"` - Binary Large Object (BLOB) data type. > 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 named `Post`: +This class is used to create a unique index in every table you create. In the context of a table that inherits from the `Model` class, exactly one `PrimaryKeyColumn` is required. Below is an example of creating an `id` column as a primary key in a table named `Post`: -```py +```python class Post(Model): - __tablename__ = "posts" - id = PrimaryKeyColumn(type="bigint", auto_increment=True) + __tablename__: Optional[TableColumn] = TableColumn(name="users") + id = PrimaryKeyColumn(type="int", auto_increment=True) #...rest of your columns + ``` -The `PrimaryKeyColumn` takes the following arguments: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ArgumentDescriptionTypeDefault
typeThe datatype of your primary key.str"bigserial"
lengthOptional to specify if the length of the type that. eg if this argument is passed as N with a T type, this will yield an sql statement with type T(N).int|NoneNone
auto_incrementOptional to specify if the column will automatically increment or not.boolFalse
defaultOptional to specify if the default value in a column.anyNone
nullableOptional to specify if the column will allow null values or not.boolFalse
uniqueOptional to specify if the column will contain unique values or not.boolTrue
+The following are the arguments that the `PrimaryKeyColumn` class accepts. +| Argument | Description | Type | Default | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------ | --------------- | ------------- | +| `type` | The datatype of your primary key. | `str` | `"bigserial`" | +| `length` | Optional to specify the length of the type. If passed as `N` with type `T`, it yields an SQL statement with type `T(N)`. | `int` \| `None` | `None` | +| `auto_increment`| Optional to specify if the column will automatically increment or not. |`bool` |`False` | +|`default` | Optional to specify the default value in a column. |`any` |`None` | +|`nullable` | Optional to specify if the column will allow null values or not. |`bool` |`False` | +|`unique` | Optional to specify if the column will contain unique values or not. |`bool` |`True` | ### `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`: +This class is utilized when informing `dataloom` that a column has a relationship with a primary key in another table. Consider the following model definition of a `Post`: ```py class Post(Model): - __tablename__ = "posts" - - id = PrimaryKeyColumn(type="bigint", auto_increment=True) - title = Column(type="text", nullable=False, default="Hello there!!") - createAt = CreatedAtColumn() + __tablename__: Optional[TableColumn] = TableColumn(name="posts") + id = PrimaryKeyColumn(type="int", auto_increment=True, nullable=False, unique=True) + completed = Column(type="boolean", default=False) + title = Column(type="varchar", length=255, nullable=False) + # timestamps + createdAt = CreatedAtColumn() updatedAt = UpdatedAtColumn() - userId = ForeignKeyColumn(User, onDelete="CASCADE", onUpdate="CASCADE") + # relations + userId = ForeignKeyColumn( + User, type="int", required=True, onDelete="CASCADE", onUpdate="CASCADE" + ) + ``` -- `userId` is a foreign key in the table `posts` which means it has a relationship with a primary key in the `users` table. This column takes in some arguments which are: +- `userId` is a foreign key in the table `posts`, indicating it has a relationship with a primary key in the `users` table. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ArgumentDescriptionTypeDefault
tableRequired, this is the table that the current model reference as it's parent. In our toy example this is called `User`.Model
typeYou can specify the type of the foreign key, which is optional as dataloom can infer it from the parent table.str|NoneNone
requiredSpecifying if the foreign key is required or not.boolFalse
onDeleteSpecifying the action that will be performed when the parent table is deletedstr ["NO ACTION", "SET NULL", "CASCADE"]"NO ACTION"
onDeleteSpecifying the action that will be performed when the parent table is updatedstr ["NO ACTION", "SET NULL", "CASCADE"]"NO ACTION"
+This column accepts the following arguments: +| Argument | Description | Type | Default | +| ---------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- | +| `table` | Required. This is the parent table that the current model references. In our example, this is referred to as `User`. | `Model` | | +| `type` | Optional. Specifies the data type of the foreign key. If not provided, dataloom can infer it from the parent table. | `str` \| `None` | `None` | +| `required` | Optional. Indicates whether the foreign key is required or not. | `bool` | `False` | +| `onDelete` | Optional. Specifies the action to be taken when the associated record in the parent table is deleted. | `str` [`"NO ACTION"`, `"SET NULL"`, `"CASCADE"`] | `"NO ACTION"` | +| `onUpdate` | Optional. Specifies the action to be taken when the associated record in the parent table is updated. | str [`"NO ACTION"`, `"SET NULL"`, `"CASCADE"`] | `"NO ACTION"` | -It is very important to specify the actions on `onDelete` and `onUpdate` so that `dataloom` will take care of your models relationships actions as. The actions that are available are: +It is crucial to specify the actions for `onDelete` and `onUpdate` to ensure that `dataloom` manages your model's relationship actions appropriately. The available actions are: -1. `"NO ACTION"` - Meaning if you `delete` or `update` the parent table nothing will happen to the child table. -2. `"SET NULL"` - Meaning if you `delete` or `update` the parent table, then in the child table the value will be set to `null` -3. `"CASCADE"` - Meaning if you `delete` or `update` the table also the same action will happen on the child table. +1. `"NO ACTION"` - If you delete or update the parent table, no changes will occur in the child table. +2. `"SET NULL"` - If you delete or update the parent table, the corresponding value in the child table will be set to `null`. +3. `"CASCADE"` - If you delete or update the table, the same action will also be applied to the child table. ### `CreatedAtColumn` Class -When a column is marked as `CreatedAtColumn` it's value will automatically get generated every time when you `create` a new record in a database as a timestamp. +When a column is designated as `CreatedAtColumn`, its value will be automatically generated each time you create a new record in a database, serving as a timestamp. ### `UpdatedAtColumn` Class -When a column is marked as `UpdatedAtColumn` it's value will automatically get generated every time when you `create` a new record or `update` an existing record in a database table as a timestamp. +When a column is designated as `UpdatedAtColumn`, its value will be automatically generated each time you create a new record or update an existing record in a database table, acting as a timestamp. ### Syncing Tables -This is the process of creating tables from models and save them to a database. -After defining your tables you will need to `sync` your database tables. To Sync a database you call the method called `sync`. This method allows you to create and save tables into the database. Let's say we have two models `User` and `Post` and you want to them to the database you can do it as follows: +Syncing tables involves the process of creating tables from models and saving them to a database. After defining your tables, you will need to synchronize your database tables using the `sync` method. This method enables you to create and save tables into the database. For instance, if you have two models, `User` and `Post`, and you want to synchronize them with the database, you can achieve it as follows: ```py -tables = db.sync([User, Post], drop=True, force=True) +tables = sqlite_loom.sync([Post, User], drop=True, force=True) +print(tables) ``` -The method returns a list of table names that have been created or the table names that are in your database. The `sync` method accepts the following arguments: +The method returns a list of table names that have been created or that exist in your database. The `sync` method accepts the following arguments: - - - - - - - - - - - - - - - - - - - - - - -
ArgumentDescriptionTypeDefault
modelsA list of your table class that are inheriting from the Model class.list[]
dropWeather to drop tables during syncing or not.boolFalse
forceForce to drop tables during syncing or not.boolFalse
alterAlter tables rather than dropping them during syncing or not.boolFalse
+| Argument | Description | Type | Default | +| -------- | --------------------------------------------------------------- | ------ | ------- | +| `models` | A list of your table classes that inherit from the Model class. | `list` | `[]` | +| `drop` | Whether to drop tables during syncing or not. | `bool` | `False` | +| `force` | Forcefully drop tables during syncing or not. | `bool` | `False` | +| `alter` | Alter tables instead of dropping them during syncing or not. | `bool` | `False` | -> We have noticed that there are two steps that we are doing here to start working with our `orm`. First you need to create a connection and then `sync` the tables in another steps. The `connect_and_sync` is very handy as it does the database connection and also does the `sync` of tables. Here is an example on how you can use it: +> We've noticed two steps involved in starting to work with our `orm`. Initially, you need to create a connection and then synchronize the tables in another step. The `connect_and_sync` function proves to be very handy as it handles both the database connection and table synchronization. Here is an example demonstrating its usage: ```py -db = Database("hi", password="root", user="postgres") -conn, tables = db.connect_and_sync([User, Post], drop=True, force=True) +# .... + +sqlite_loom = Dataloom( + dialect="sqlite", database="hi.db", logs_filename="sqlite-logs.sql", logging=True +) +conn, tables = sqlite_loom.connect_and_sync([Post, User], drop=True, force=True) +print(tables) if __name__ == "__main__": conn.close() ``` -Returns a `conn` and `tablenames` that are in the database. The method accepts the same arguments as the `sync` method. +Returns a `conn` and the list of `tablenames` that exist in the database. The method accepts the same arguments as the `sync` method. 1. Creating a Record diff --git a/hi.db b/hi.db index eadd8a9866cff39d1be55821ab389031b43576a6..177c8727504c8bfdd27ca4f149716a29ac631127 100644 GIT binary patch delta 606 zcmZp8z}WDBae}m<9s>gdI}pQw-b5W^Nj(O=tP8w+_6%&?6B+p2d1mr`;hxAR!uxV# zqa-(16RRn^xVSiDbLQlQys48F`NX-M@{`nc6cS2{Q;R0?iPt9=r6!i7rZ|=)D1>9Wk4DWQb^FC+2m^sc0o&JNn%n?YC(Q+NimpU zat?BJ44K@?Usew^mB!A1de}21LBZ26#MRw3NWsrPM8PlA$44Q^&ehEo=uKzWU`VhO zCuk&OrX*-8`1=7v!pAklRl(UY*xAv=6(kZG;Npl7(bP1be2`COvH(9HqZyRN#%~A; z-C{PrnG77D$eQfV7sSFZ&k#L%E}t(CP{0%~+#kYU6 zpuh|suEscZc5!iW#%Afsv$^9Zckl~|HS$4(8mmhZ8+En8(oL2?=~U4$#~^19#~_7J zKhMBWR~?0f(&E&j$-lT|`8`r|a`F{QGE$3D6&2MrC%f|nvGBcOP@6oL&zFnegMkC& zC{5kT2l-?sv-9yW>VR05AnnERhG2>fs6Yv%s#+6lWn*YbVp2|OL4I*bF_>U-ZWPvo QxQ2D|VxI2J|M?jc04Y2`#{d8T diff --git a/playground.py b/playground.py index 1700df3..e15e152 100644 --- a/playground.py +++ b/playground.py @@ -8,51 +8,78 @@ TableColumn, ForeignKeyColumn, ) -from typing import Optional pg_loom = Dataloom( dialect="postgres", database="hi", password="root", user="postgres", logging=True ) -mysql_loom = Dataloom(dialect="mysql", database="hi", password="root", user="root") -sqlite_loom = Dataloom(dialect="sqlite", database="hi.db") +mysql_loom = Dataloom( + dialect="mysql", + database="hi", + password="root", + user="root", + host="localhost", + logging=True, + logs_filename="logs.sql", + port=3306, +) +sqlite_loom = Dataloom( + dialect="sqlite", database="hi.db", logs_filename="sqlite-logs.sql", logging=True +) +from typing import Optional +from dataclasses import dataclass conn = sqlite_loom.connect() -if __name__ == "main": - conn.close() - - class User(Model): __tablename__: Optional[TableColumn] = TableColumn(name="users") - id: Optional[PrimaryKeyColumn] = PrimaryKeyColumn(type="int", auto_increment=True) - username = Column(type="text", unique=True) + id = PrimaryKeyColumn(type="int", auto_increment=True) + name = Column(type="text", nullable=False, default="Bob") + username = Column(type="varchar", unique=True, length=255) + # timestamps 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): __tablename__: Optional[TableColumn] = TableColumn(name="posts") - id: Optional[PrimaryKeyColumn] = PrimaryKeyColumn(type="int", auto_increment=True) - title = Column(type="text", nullable=False) - + id = PrimaryKeyColumn(type="int", auto_increment=True, nullable=False, unique=True) + completed = Column(type="boolean", default=False) + title = Column(type="varchar", length=255, nullable=False) + # timestamps createdAt = CreatedAtColumn() updatedAt = UpdatedAtColumn() - userId: ForeignKeyColumn = ForeignKeyColumn( - User, onDelete="CASCADE", onUpdate="CASCADE", required=False + # relations + 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, + } -conn = sqlite_loom.connect() -tables = sqlite_loom.sync([Post, User], drop=True, force=True) +conn, tables = sqlite_loom.connect_and_sync([Post, User], drop=True, force=True) print(tables) -post = Post( - id=2, -) - # instance = [*db, dataloom.logging] diff --git a/sqlite-logs.sql b/sqlite-logs.sql new file mode 100644 index 0000000..bb8f2cf --- /dev/null +++ b/sqlite-logs.sql @@ -0,0 +1,10 @@ +[2024-02-03 08:21:27.605095] : Dataloom[sqlite]: DROP TABLE IF EXISTS posts; +[2024-02-03 08:21:27.658113] : Dataloom[sqlite]: CREATE TABLE IF NOT EXISTS `posts` (`id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, `title` TEXT NOT NULL, `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updatedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `userId` INTEGER NULL REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE); +[2024-02-03 08:21:27.706106] : Dataloom[sqlite]: DROP TABLE IF EXISTS users; +[2024-02-03 08:21:27.757221] : Dataloom[sqlite]: CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, `username` TEXT UNIQUE, `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updatedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP); +[2024-02-03 08:21:27.817225] : Dataloom[sqlite]: SELECT name FROM sqlite_master WHERE type='table'; +[2024-02-03 08:22:27.432708] : Dataloom[sqlite]: DROP TABLE IF EXISTS posts; +[2024-02-03 08:22:27.459710] : Dataloom[sqlite]: CREATE TABLE IF NOT EXISTS `posts` (`completed` BOOLEAN, `id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, `title` VARCHAR NOT NULL, `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updatedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `userId` INTEGER NOT NULL REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE); +[2024-02-03 08:22:27.483841] : Dataloom[sqlite]: DROP TABLE IF EXISTS users; +[2024-02-03 08:22:27.512489] : Dataloom[sqlite]: CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, `name` TEXT NOT NULL DEFAULT 'Bob', `username` VARCHAR UNIQUE, `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updatedAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP); +[2024-02-03 08:22:27.539478] : Dataloom[sqlite]: SELECT name FROM sqlite_master WHERE type='table';