Skip to content

Commit d4f9f83

Browse files
committed
Restored example project
1 parent 7ab9812 commit d4f9f83

24 files changed

+523
-2
lines changed

ellar_sqlalchemy/model/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import sqlalchemy.sql.schema as sa_sql_schema
55

66
from ellar_sqlalchemy.constant import DEFAULT_KEY
7-
from ellar_sqlalchemy.model import make_metadata
7+
from ellar_sqlalchemy.model.utils import make_metadata
88

99

1010
class Table(sa.Table):

ellar_sqlalchemy/services/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import typing as t
33
from threading import get_ident
44
from weakref import WeakKeyDictionary
5-
65
import sqlalchemy as sa
76
import sqlalchemy.exc as sa_exc
87
import sqlalchemy.orm as sa_orm

examples/single-db/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Ellar SQLAlchemy Single Database Example
2+
Project Description
3+
4+
## Requirements
5+
Python >= 3.7
6+
Starlette
7+
Injector
8+
9+
## Project setup
10+
```shell
11+
pip install poetry
12+
```
13+
then,
14+
```shell
15+
poetry install
16+
```
17+
### Apply Migration
18+
```shell
19+
ellar db upgrade
20+
```
21+
22+
### Development Server
23+
```shell
24+
ellar runserver --reload
25+
```
26+
then, visit [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)

examples/single-db/db/__init__.py

Whitespace-only changes.

examples/single-db/db/controllers.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Define endpoints routes in python class-based fashion
3+
example:
4+
5+
@Controller("/dogs", tag="Dogs", description="Dogs Resources")
6+
class MyController(ControllerBase):
7+
@get('/')
8+
def index(self):
9+
return {'detail': "Welcome Dog's Resources"}
10+
"""
11+
12+
from ellar.common import Controller, ControllerBase, get, post, Body
13+
from pydantic import EmailStr
14+
from sqlalchemy import select
15+
16+
from .models.users import User
17+
18+
19+
@Controller
20+
class DbController(ControllerBase):
21+
22+
@get("/")
23+
def index(self):
24+
return {"detail": "Welcome Db Resource"}
25+
26+
@post("/users")
27+
def create_user(self, username: Body[str], email: Body[EmailStr]):
28+
session = User.get_db_session()
29+
user = User(username=username, email=email)
30+
31+
session.add(user)
32+
session.commit()
33+
34+
return user.dict()
35+
36+
@get("/users/{user_id:int}")
37+
def get_user_by_id(self, user_id: int):
38+
session = User.get_db_session()
39+
stmt = select(User).filter(User.id == user_id)
40+
user = session.execute(stmt).scalar()
41+
return user.dict()
42+
43+
@get("/users")
44+
async def get_all_users(self):
45+
session = User.get_db_session()
46+
stmt = select(User)
47+
rows = session.execute(stmt.offset(0).limit(100)).scalars()
48+
return [row.dict() for row in rows]
49+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Multi-database configuration for Flask.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# template used to generate migration files
5+
file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
6+
7+
# set to 'true' to run the environment during
8+
# the 'revision' command, regardless of autogenerate
9+
# revision_environment = false
10+
11+
12+
# Logging configuration
13+
[loggers]
14+
keys = root,sqlalchemy,alembic,flask_migrate
15+
16+
[handlers]
17+
keys = console
18+
19+
[formatters]
20+
keys = generic
21+
22+
[logger_root]
23+
level = WARN
24+
handlers = console
25+
qualname =
26+
27+
[logger_sqlalchemy]
28+
level = WARN
29+
handlers =
30+
qualname = sqlalchemy.engine
31+
32+
[logger_alembic]
33+
level = INFO
34+
handlers =
35+
qualname = alembic
36+
37+
[logger_flask_migrate]
38+
level = INFO
39+
handlers =
40+
qualname = flask_migrate
41+
42+
[handler_console]
43+
class = StreamHandler
44+
args = (sys.stderr,)
45+
level = NOTSET
46+
formatter = generic
47+
48+
[formatter_generic]
49+
format = %(levelname)-5.5s [%(name)s] %(message)s
50+
datefmt = %H:%M:%S
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import asyncio
2+
import typing as t
3+
from logging.config import fileConfig
4+
5+
from alembic import context
6+
from ellar.app import current_injector
7+
8+
from ellar_sqlalchemy.migrations import (
9+
MultipleDatabaseAlembicEnvMigration,
10+
SingleDatabaseAlembicEnvMigration,
11+
)
12+
from ellar_sqlalchemy.services import EllarSQLAlchemyService
13+
14+
db_service: EllarSQLAlchemyService = current_injector.get(EllarSQLAlchemyService)
15+
16+
# this is the Alembic Config object, which provides
17+
# access to the values within the .ini file in use.
18+
config = context.config
19+
20+
# Interpret the config file for Python logging.
21+
# This line sets up loggers basically.
22+
fileConfig(config.config_file_name) # type:ignore[arg-type]
23+
# logger = logging.getLogger("alembic.env")
24+
25+
26+
AlembicEnvMigrationKlass: t.Type[
27+
t.Union[MultipleDatabaseAlembicEnvMigration, SingleDatabaseAlembicEnvMigration]
28+
] = (
29+
MultipleDatabaseAlembicEnvMigration
30+
if len(db_service.engines) > 1
31+
else SingleDatabaseAlembicEnvMigration
32+
)
33+
34+
35+
# other values from the config, defined by the needs of env.py,
36+
# can be acquired:
37+
# my_important_option = config.get_main_option("my_important_option")
38+
# ... etc.
39+
40+
41+
alembic_env_migration = AlembicEnvMigrationKlass(db_service)
42+
43+
if context.is_offline_mode():
44+
alembic_env_migration.run_migrations_offline(context) # type:ignore[arg-type]
45+
else:
46+
asyncio.get_event_loop().run_until_complete(
47+
alembic_env_migration.run_migrations_online(context) # type:ignore[arg-type]
48+
)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<%!
2+
import re
3+
4+
%>"""${message}
5+
6+
Revision ID: ${up_revision}
7+
Revises: ${down_revision | comma,n}
8+
Create Date: ${create_date}
9+
10+
"""
11+
from alembic import op
12+
import sqlalchemy as sa
13+
${imports if imports else ""}
14+
15+
# revision identifiers, used by Alembic.
16+
revision = ${repr(up_revision)}
17+
down_revision = ${repr(down_revision)}
18+
branch_labels = ${repr(branch_labels)}
19+
depends_on = ${repr(depends_on)}
20+
21+
<%!
22+
from ellar.app import current_injector
23+
from ellar_sqlalchemy.services import EllarSQLAlchemyService
24+
25+
db_service = current_injector.get(EllarSQLAlchemyService)
26+
db_names = list(db_service.engines.keys())
27+
%>
28+
29+
% if len(db_names) > 1:
30+
31+
def upgrade(engine_name):
32+
globals()["upgrade_%s" % engine_name]()
33+
34+
35+
def downgrade(engine_name):
36+
globals()["downgrade_%s" % engine_name]()
37+
38+
39+
40+
## generate an "upgrade_<xyz>() / downgrade_<xyz>()" function
41+
## for each database name in the ini file.
42+
43+
% for db_name in db_names:
44+
45+
def upgrade_${db_name}():
46+
${context.get("%s_upgrades" % db_name, "pass")}
47+
48+
49+
def downgrade_${db_name}():
50+
${context.get("%s_downgrades" % db_name, "pass")}
51+
52+
% endfor
53+
54+
% else:
55+
56+
def upgrade():
57+
${upgrades if upgrades else "pass"}
58+
59+
60+
def downgrade():
61+
${downgrades if downgrades else "pass"}
62+
63+
% endif
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""empty message
2+
3+
Revision ID: cce418606c45
4+
Revises:
5+
Create Date: 2024-01-01 10:16:49.511421
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'cce418606c45'
14+
down_revision = None
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
20+
21+
def upgrade():
22+
# ### commands auto generated by Alembic - please adjust! ###
23+
op.create_table('user',
24+
sa.Column('id', sa.Integer(), nullable=False),
25+
sa.Column('username', sa.String(), nullable=False),
26+
sa.Column('email', sa.String(), nullable=False),
27+
sa.Column('created_date', sa.DateTime(), nullable=False),
28+
sa.Column('time_updated', sa.DateTime(), nullable=False),
29+
sa.PrimaryKeyConstraint('id', name=op.f('pk_user')),
30+
sa.UniqueConstraint('username', name=op.f('uq_user_username'))
31+
)
32+
# ### end Alembic commands ###
33+
34+
35+
def downgrade():
36+
# ### commands auto generated by Alembic - please adjust! ###
37+
op.drop_table('user')
38+
# ### end Alembic commands ###
39+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy