Skip to content

Commit a50ea41

Browse files
committed
Documentation update
1 parent b064788 commit a50ea41

File tree

9 files changed

+105
-93
lines changed

9 files changed

+105
-93
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ EllarSQL Module adds support for `SQLAlchemy` and `Alembic` package to your Ella
2020
$(venv) pip install ellar-sql
2121
```
2222

23+
This library was inspired by [Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/en/3.1.x/){target="_blank"}
24+
2325
## Features
2426

2527
- Migration

docs/migrations/env.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
In the generated migration template, EllarSQL adopts an async-first approach for handling migration file generation.
44
This approach simplifies the execution of migrations for both `Session`, `Engine`, `AsyncSession`, and `AsyncEngine`,
55
but it also introduces a certain level of complexity.
6+
67
```python
78
from logging.config import fileConfig
89

docs/migrations/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# **Migrations**
2-
EllarSQL also extends Alembic package
3-
to add migration functionality to your application and make database operations available through EllarCLI commandline interface.
2+
EllarSQL also extends **Alembic** package
3+
to add migration functionality and make database operations accessible through **EllarCLI** commandline interface.
44

5-
EllarSQL with Alembic does not override Alembic action rather provide Alembic all the configs/information
6-
it needs to for a proper migration operation in your application.
5+
**EllarSQL** with Alembic does not override Alembic action rather provide Alembic all the configs/information
6+
it needs to for a proper migration/database operations.
77
Its also still possible to use Alembic outside EllarSQL setup when necessary.
88

99
This section is inspired by [`Flask Migrate`](https://flask-migrate.readthedocs.io/en/latest/#)
1010

1111
## **Quick Example**
12-
We assume you have set up `EllarSQLModule` in your application and you have specified `migration_options`.
12+
We assume you have set up `EllarSQLModule` in your application, and you have specified `migration_options`.
1313

1414
Create a simple `User` model as shown below:
1515

docs/models/configuration.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
# **EllarSQLModule Config**
2+
**`EllarSQLModule`** is an Ellar Dynamic Module that offers two ways of configuration:
23

3-
**`EllarSQLModule`** is a versatile module, allowing configuration through the application `Config`.
4-
This configuration can be done either using `EllarSQLModule.register_setup()` within your application setup or directly
5-
during module registration with `EllarSQLModule.setup()`.
4+
- `EllarSQLModule.register_setup()`: This method registers a `ModuleSetup` that depends on the application config.
5+
- `EllarSQLModule.setup()`: This method immediately sets up the module with the provided options.
66

7-
While examples have been provided for using `EllarSQLModule.setup()`, this section will shed light
8-
on the usage of `EllarSQLModule.register_setup()`. Before diving into that, let's first explore
9-
the setup options available for `EllarSQLModule`.
7+
While we've explored many examples using `EllarSQLModule.setup()`, this section will focus on the usage of `EllarSQLModule.register_setup()`.
108

9+
Before delving into that, let's first explore the setup options available for `EllarSQLModule`.
1110
## **EllarSQLModule Configuration Parameters**
1211

1312
- **databases**: _typing.Union[str, typing.Dict[str, typing.Any]]_:
@@ -128,16 +127,17 @@ For more in-depth information
128127
on [dealing with disconnects](https://docs.sqlalchemy.org/core/pooling.html#dealing-with-disconnects){target="_blank"},
129128
refer to SQLAlchemy's documentation on handling connection issues.
130129

131-
## **EllarSQLModule With App Config**
132-
As stated above, **EllarSQLModule** can be configured from application through `EllarSQLModule.register_setup`.
133-
This will register a [ModuleSetup](https://python-ellar.github.io/ellar/basics/dynamic-modules/#modulesetup){target="_blank"} factory that checks for `ELLAR_SQL` in application config.
134-
The value of `ELLAR_SQL` read from the application config will be passed `EllarSQLModule` setup action
135-
which validates and initializes the module.
130+
## **EllarSQLModule RegisterSetup**
131+
As mentioned earlier, **EllarSQLModule** can be configured from the application through `EllarSQLModule.register_setup`.
132+
This process registers a [ModuleSetup](https://python-ellar.github.io/ellar/basics/dynamic-modules/#modulesetup){target="_blank"} factory
133+
that depends on the Application Config object.
134+
The factory retrieves the `ELLAR_SQL` attribute from the config and validates the data before passing it to `EllarSQLModule` for setup.
136135

137-
It's important to note
138-
that `ELLAR_SQL` will be a dictionary object with the above [configuration parameters](#ellarsqlmodule-configuration-parameters) as keys.
136+
It's essential to note
137+
that `ELLAR_SQL` will be a dictionary object with the [configuration parameters](#ellarsqlmodule-configuration-parameters)
138+
mentioned above as keys.
139139

140-
A Quick example:
140+
Here's a quick example:
141141
```python title="db_learning/root_module.py"
142142
from ellar.common import Module, exception_handler, IExecutionContext, JSONResponse, Response, IApplicationStartup
143143
from ellar.app import App
@@ -180,8 +180,10 @@ class DevelopmentConfig(BaseConfig):
180180
'models': []
181181
}
182182
```
183-
We have added config for **EllarSQLModule** through `ELLAR_SQL`. And from there, the rest of the actions
184-
will be the same as to normal registration with `EllarSQLModule.setup()`.
183+
The registered ModuleSetup factory reads the `ELLAR_SQL` value and configures the `EllarSQLModule` appropriately.
185184

186-
But with this approach,
187-
we can seamlessly change **EllarSQLModule** configuration in any environment like CI, Development, Staging or Production.
185+
This approach is particularly useful when dealing with multiple environments.
186+
It allows for seamless modification of the **ELLAR_SQL** values in various environments such as
187+
Continuous Integration (CI), Development, Staging, or Production.
188+
You can easily change the settings for each environment
189+
and export the configurations as a string to be imported into `ELLAR_CONFIG_MODULE`.

docs/models/index.md

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# **Quick Start**
2-
In this section,
3-
we shall go over how to set up **EllarSQL** in your ellar application
4-
and have all necessary service registered and configuration set and ready to use.
2+
In this segment, we will walk through the process of configuring **EllarSQL** within your Ellar application,
3+
ensuring that all essential services are registered, configurations are set, and everything is prepared for immediate use.
54

6-
Before we proceed, we assume you have a clear understanding
7-
of how [Ellar Modules](https://python-ellar.github.io/ellar/basics/dynamic-modules/#module-dynamic-setup){target="_blank"} work.
5+
Before we delve into the setup instructions, it is assumed that you possess a comprehensive
6+
understanding of how [Ellar Modules](https://python-ellar.github.io/ellar/basics/dynamic-modules/#module-dynamic-setup){target="_blank"}
7+
operate.
88

99
## **Installation**
10-
Let's install all necessary packages. Also assuming your python environment has been configured:
10+
Let us install all the required packages, assuming that your Python environment has been properly configured:
1111

1212
#### **For Existing Project:**
1313
```shell
@@ -99,10 +99,10 @@ class UsersController(ecm.ControllerBase):
9999
```
100100

101101
## **EllarSQLModule Setup**
102-
In `root_module.py`, we need to do two things:
102+
In the `root_module.py` file, two main tasks need to be performed:
103103

104-
- Register `UsersController` to have `/users` available when we start the application
105-
- configure `EllarSQLModule` to configure and register all necessary services such as `EllarSQLService`, `Session` and `Engine`
104+
1. Register the `UsersController` to make the `/users` endpoint available when starting the application.
105+
2. Configure the `EllarSQLModule`, which will set up and register essential services such as `EllarSQLService`, `Session`, and `Engine`.
106106

107107
```python title="db_learning/root_module.py"
108108
from ellar.common import Module, exception_handler, IExecutionContext, JSONResponse, Response, IApplicationStartup
@@ -111,7 +111,6 @@ from ellar.core import ModuleBase
111111
from ellar_sql import EllarSQLModule, EllarSQLService
112112
from .controller import UsersController
113113

114-
115114
@Module(
116115
modules=[EllarSQLModule.setup(
117116
databases={
@@ -133,19 +132,19 @@ class ApplicationModule(ModuleBase, IApplicationStartup):
133132
def exception_404_handler(cls, ctx: IExecutionContext, exc: Exception) -> Response:
134133
return JSONResponse(dict(detail="Resource not found."), status_code=404)
135134
```
136-
In the above illustration,
137-
we registered `UserController` and `EllarSQLModule` with some configurations on database and migration options.
138-
See more on `EllarSQLModule` configurations.
139135

140-
Also, on the `on_startup` function, we retrieved `EllarSQLService` registered into the system through `EllarSQLModule`,
141-
and call the `create_all()` function to create the SQLAlchemy tables.
136+
In the provided code snippet:
137+
138+
- We registered `UserController` and `EllarSQLModule` with specific configurations for the database and migration options. For more details on [`EllarSQLModule` configurations](./configuration.md#ellarsqlmodule-config).
139+
140+
- In the `on_startup` method, we obtained the `EllarSQLService` from the Ellar Dependency Injection container using `EllarSQLModule`. Subsequently, we invoked the `create_all()` method to generate the necessary SQLAlchemy tables.
142141

143-
At this point, we are ready to test the application.
142+
With these configurations, the application is now ready for testing.
144143
```shell
145144
ellar runserver --reload
146145
```
147-
Also,
148-
remember to uncomment the `OpenAPIModule` configurations
149-
in `server.py` to be able to visualize and interact with the `/users` the endpoint.
146+
Additionally, please remember to uncomment the configurations for the `OpenAPIModule` in the `server.py`
147+
file to enable visualization and interaction with the `/users` endpoint.
150148

151-
With that said, visit [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs){target="_blank"}
149+
Once done,
150+
you can access the OpenAPI documentation at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs){target="_blank"}.

docs/models/models.md

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,55 @@
11
# **Models and Tables**
2-
`Model` from `ellar_sql.model.Model` package is a factory class for creating `SQLAlchemy` model.
3-
It also manages a model database key and associates it to its Metadata and engine.
2+
The `ellar_sql.model.Model` class acts as a factory for creating `SQLAlchemy` models, and
3+
associating the generated models with the corresponding **Metadata** through their designated **`__database__`** key.
44

5-
`Model` can be by defining `__base_config__` at the class level. This is necessary for a
6-
case where we want to make a `Base` class that will be inherited through the application or change the declarative type
7-
such as [DeclarativeBase](https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBase){target="_blank"} or
8-
[DeclarativeBaseNoMeta](https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBaseNoMeta){target="_blank"}
95

10-
`Model` configuration parameters:
6+
This class can be configured through the `__base_config__` attribute, allowing you to specify how your `SQLAlchemy` model should be created.
7+
The `__base_config__` attribute can be of type `ModelBaseConfig`, which is a dataclass, or a dictionary with keys that
8+
match the attributes of `ModelBaseConfig`.
119

12-
- **as_base**: Indicates if the class should be treated as a Base class for other model definitions. `Default: True`
13-
- **use_base**: Indicates base classes that will be used to create a model base. `Default=[]`
10+
Attributes of `ModelBaseConfig`:
1411

12+
- **as_base**: Indicates whether the class should be treated as a `Base` class for other model definitions, similar to creating a Base from a [DeclarativeBase](https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBase){target="_blank"} or [DeclarativeBaseNoMeta](https://docs.sqlalchemy.org/en/20/orm/mapping_api.html#sqlalchemy.orm.DeclarativeBaseNoMeta){target="_blank"} class. *(Default: False)*
13+
- **use_base**: Specifies the base classes that will be used to create the `SQLAlchemy` model. *(Default: [])*
1514

16-
## **Base Class**
17-
`Model` treats each model as a standalone model. This means each `model.Model` has a separate **declarative** base created for it
18-
and the `__database__` key is used to determine its Metadata reference.
15+
## **Creating a Base Class**
16+
`Model` treats each model as a standalone entity. Each instance of `model.Model` creates a distinct **declarative** base for itself, using the `__database__` key as a reference to determine its associated **Metadata**. Consequently, models sharing the same `__database__` key will utilize the same **Metadata** object.
17+
18+
Let's explore how we can create a `Base` model using `Model`, similar to the approach in traditional `SQLAlchemy`.
1919

20-
Let's create a class with **DeclarativeBase**
2120
```python
2221
from ellar_sql import model, ModelBaseConfig
2322

2423

2524
class Base(model.Model):
2625
__base_config__ = ModelBaseConfig(as_base=True, use_bases=[model.DeclarativeBase])
26+
27+
28+
assert issubclass(Base, model.DeclarativeBase)
2729
```
28-
If desired, you can enable [SQLAlchemy’s native support for data classes](https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#native-support-for-dataclasses-mapped-as-orm-models){target="_blank"}
29-
by adding MappedAsDataclass as an additional parent class.
30+
31+
If you are interested in [SQLAlchemy’s native support for data classes](https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#native-support-for-dataclasses-mapped-as-orm-models){target="_blank"},
32+
then you can add `MappedAsDataclass` to `use_bases` as shown below:
3033

3134
```python
3235
from ellar_sql import model, ModelBaseConfig
3336

3437

3538
class Base(model.Model):
3639
__base_config__ = ModelBaseConfig(as_base=True, use_bases=[model.DeclarativeBase, model.MappedAsDataclass])
40+
41+
assert issubclass(Base, model.MappedAsDataclass)
3742
```
3843

39-
Optionally, you have the flexibility to construct the SQLAlchemy object with a custom [`MetaData`](https://docs.sqlalchemy.org/en/20/core/metadata.html#sqlalchemy.schema.MetaData){target="_blank"} object.
40-
This customization enables you to define a specific **naming convention** for constraints.
41-
This becomes particularly valuable as it ensures consistency and predictability in constraint names.
42-
This predictability proves especially beneficial when utilizing migrations, as detailed by [Alembic](https://alembic.sqlalchemy.org/en/latest/naming.html){target="_blank"}.
44+
In the examples above, `Base` classes are created, all subclassed from the `use_bases` provided, and with the `as_base`
45+
option, the factory creates the `Base` class as a `Base`.
46+
47+
## Create base with MetaData
48+
You can also configure the SQLAlchemy object with a custom [`MetaData`](https://docs.sqlalchemy.org/en/20/core/metadata.html#sqlalchemy.schema.MetaData){target="_blank"} object.
49+
For instance, you can define a specific **naming convention** for constraints, ensuring consistency and predictability in constraint names.
50+
This can be particularly beneficial during migrations, as detailed by [Alembic](https://alembic.sqlalchemy.org/en/latest/naming.html){target="_blank"}.
51+
52+
For example:
4353

4454
```python
4555
from ellar_sql import model, ModelBaseConfig
@@ -55,10 +65,12 @@ class Base(model.Model):
5565
"pk": "pk_%(table_name)s"
5666
})
5767
```
68+
5869
## **Abstract Models and Mixins**
59-
If the desired behavior is applicable only to specific models rather than all models, consider using an abstract model base class to customize only those models.
60-
For instance, if certain models need to track their creation or update timestamps,
61-
this approach allows for targeted customization.
70+
If the desired behavior is only applicable to specific models rather than all models,
71+
you can use an abstract model base class to customize only those models.
72+
For example, if certain models need to track their creation or update **timestamps**, t
73+
his approach allows for targeted customization.
6274

6375
```python
6476
from datetime import datetime, timezone
@@ -98,9 +110,8 @@ class Book(model.Model, TimestampModel):
98110
```
99111

100112
## **Defining Models**
101-
Unlike plain SQLAlchemy, EllarSQL model will automatically generate a table name
102-
if `__tablename__` is not set and a primary key column is defined.
103-
This can be **disabled** by setting a value for `__tablename__` or defining `__tablename__` as a **declarative_attr**
113+
Unlike plain SQLAlchemy, **EllarSQL** models will automatically generate a table name if the `__tablename__` attribute is not set,
114+
provided a primary key column is defined.
104115

105116
```python
106117
from ellar_sql import model
@@ -125,12 +136,12 @@ For a comprehensive guide on defining model classes declaratively, refer to
125136
This resource provides detailed information and insights into the declarative approach for defining model classes.
126137

127138
## **Defining Tables**
128-
The table class is designed to receive a table name, followed by columns and other table components such as constraints.
139+
The table class is designed to receive a table name, followed by **columns** and other table **components** such as constraints.
129140

130-
EllarSQL enhances the functionality of the SQLAlchemy Table by facilitating the creation or
131-
selection of metadata based on the `__database__` argument.
141+
EllarSQL enhances the functionality of the SQLAlchemy Table
142+
by facilitating the selection of **Metadata** based on the `__database__` argument.
132143

133-
Directly creating a table proves particularly valuable when establishing many-to-many relationships.
144+
Directly creating a table proves particularly valuable when establishing **many-to-many** relationships.
134145
In such cases, the association table doesn't need its dedicated model class; rather, it can be conveniently accessed
135146
through the relevant relationship attributes on the associated models.
136147

@@ -145,14 +156,13 @@ author_book_m2m = model.Table(
145156
```
146157

147158
## **Quick Tutorial**
148-
In this section, we'll delve into straightforward CRUD operations using the ORM objects.
159+
In this section, we'll delve into straightforward **CRUD** operations using the ORM objects.
149160
However, if you're not well-acquainted with SQLAlchemy,
150161
feel free to explore their tutorial
151162
on [ORM](https://docs.sqlalchemy.org/tutorial/orm_data_manipulation.html){target="_blank"}
152163
for a more comprehensive understanding.
153164

154-
### **Create a Model**
155-
Having understood, `Model` usage. Let's create a User model
165+
Having understood, `Model` usage. Let's create a `User` model
156166

157167
```python
158168
from ellar_sql import model
@@ -264,6 +274,7 @@ In the process of `EllarSQLModule` setup, three services are registered to the E
264274
- `Session`SQLAlchemy Session of the default database configuration
265275

266276
Although with `EllarSQLService` you can get the `engine` and `session`. It's there for easy of access.
277+
267278
```python
268279
import sqlalchemy as sa
269280
import sqlalchemy.orm as sa_orm

0 commit comments

Comments
 (0)