Skip to content

Commit e81da85

Browse files
committed
Added support for Table, refactored model creation and added tests
1 parent d4f9f83 commit e81da85

39 files changed

+2396
-240
lines changed

.github/workflows/publish.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ jobs:
1818
run: pip install flit
1919
- name: Install Dependencies
2020
run: flit install --symlink
21+
- name: Install build dependencies
22+
run: pip install build
23+
- name: Build distribution
24+
run: python -m build
2125
- name: Publish
22-
env:
23-
FLIT_USERNAME: ${{ secrets.FLIT_USERNAME }}
24-
FLIT_PASSWORD: ${{ secrets.FLIT_PASSWORD }}
25-
run: flit publish
26+
uses: pypa/[email protected]
27+
with:
28+
password: ${{ secrets.FLIT_PASSWORD }}

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,20 @@
99
[![PyPI version](https://img.shields.io/pypi/pyversions/ellar-sqlachemy.svg)](https://pypi.python.org/pypi/ellar-sqlachemy)
1010

1111
## Project Status
12-
- 70% done
13-
- Tests
14-
- Documentation
12+
[] Overall Completion - 80% done
13+
[] Tests - 90% Complete
14+
[x] Model class to create SQLAlchemy Models and Declarative Base
15+
[x] SQLAlchemy model export to dictionary through `model.dict(exclude={'x', 'y', 'z'})`
16+
[x] Support multiple database configuration in Models and in Query
17+
[x] Session to manage Model metadata
18+
[x] Service to manage Engine and Session creation and Migration initialization for async and sync Engines and Sessions
19+
[x] Alembic env.py with async first `run_migrations_online` action
20+
[x] Expose all alembic commands to Ellar CLI
21+
[x] Module to config and setup SQLAlchemy dependencies and migration
22+
[] SQLAlchemy Pagination for both templating and api routes
23+
[x] File and Image SQLAlchemy Columns integrated with ellar storage
24+
[] SQLAlchemy Django Like Query
25+
[] Documentation
1526

1627
## Introduction
1728
Ellar SQLAlchemy Module simplifies the integration of SQLAlchemy and Alembic migration tooling into your ellar application.

ellar_sqlalchemy/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
__version__ = "0.0.1"
44

55
from .module import EllarSQLAlchemyModule
6+
from .schemas import MigrationOption, SQLAlchemyConfig
67
from .services import EllarSQLAlchemyService
78

8-
__all__ = ["EllarSQLAlchemyModule", "EllarSQLAlchemyService"]
9+
__all__ = [
10+
"EllarSQLAlchemyModule",
11+
"EllarSQLAlchemyService",
12+
"SQLAlchemyConfig",
13+
"MigrationOption",
14+
]

ellar_sqlalchemy/cli/commands.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
import click
1+
import ellar_cli.click as click
22
from ellar.app import current_injector
33

44
from ellar_sqlalchemy.services import EllarSQLAlchemyService
55

66
from .handlers import CLICommandHandlers
77

88

9+
def _get_handler_context(ctx: click.Context) -> CLICommandHandlers:
10+
db_service = current_injector.get(EllarSQLAlchemyService)
11+
return CLICommandHandlers(db_service)
12+
13+
914
@click.group()
1015
def db():
1116
"""- Perform Alembic Database Commands -"""
1217
pass
1318

1419

15-
def _get_handler_context(ctx: click.Context) -> CLICommandHandlers:
16-
db_service = current_injector.get(EllarSQLAlchemyService)
17-
return CLICommandHandlers(db_service)
18-
19-
2020
@db.command()
2121
@click.option(
2222
"-d",
@@ -385,7 +385,21 @@ def stamp(ctx: click.Context, directory, sql, tag, revision):
385385
handler.stamp(directory, revision, sql, tag)
386386

387387

388-
@db.command("init-migration")
388+
@db.command()
389+
@click.option(
390+
"-d",
391+
"--directory",
392+
default=None,
393+
help='Migration script directory (default is "migrations")',
394+
)
395+
@click.pass_context
396+
def check(ctx: click.Context, directory):
397+
"""Check if there are any new operations to migrate"""
398+
handler = _get_handler_context(ctx)
399+
handler.check(directory)
400+
401+
402+
@db.command("init")
389403
@click.option(
390404
"-d",
391405
"--directory",

ellar_sqlalchemy/cli/handlers.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
from __future__ import annotations
22

33
import argparse
4-
import logging
54
import os
6-
import sys
75
import typing as t
86
from functools import wraps
97
from pathlib import Path
108

9+
import click
1110
from alembic import command
1211
from alembic.config import Config as AlembicConfig
1312
from alembic.util.exc import CommandError
1413
from ellar.app import App
1514

1615
from ellar_sqlalchemy.services import EllarSQLAlchemyService
1716

18-
log = logging.getLogger(__name__)
1917
RevIdType = t.Union[str, t.List[str], t.Tuple[str, ...]]
2018

2119

@@ -31,8 +29,7 @@ def wrapped(*args: t.Any, **kwargs: t.Any) -> None:
3129
try:
3230
f(*args, **kwargs)
3331
except (CommandError, RuntimeError) as exc:
34-
log.error("Error: " + str(exc))
35-
sys.exit(1)
32+
raise click.ClickException(str(exc)) from exc
3633

3734
return wrapped
3835

ellar_sqlalchemy/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# class NoMatch(Exception):
2+
# pass
3+
#
4+
#
5+
# class MultipleMatches(Exception):
6+
# pass

ellar_sqlalchemy/model/__init__.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,52 @@
1+
import typing as t
2+
3+
import sqlalchemy as sa
4+
import sqlalchemy.event as sa_event
5+
import sqlalchemy.orm as sa_orm
6+
17
from .base import Model
28
from .table import Table
3-
from .typeDecorator import GUID, GenericIP
9+
from .typeDecorator import (
10+
GUID,
11+
CroppingDetails,
12+
FileField,
13+
FileObject,
14+
GenericIP,
15+
ImageFileField,
16+
ImageFileObject,
17+
)
418
from .utils import make_metadata
519

20+
if t.TYPE_CHECKING:
21+
from sqlalchemy import * # type:ignore[assignment]
22+
from sqlalchemy.event import * # noqa
23+
from sqlalchemy.orm import * # noqa
24+
25+
from .table import Table # noqa
26+
627
__all__ = [
728
"Model",
829
"Table",
930
"make_metadata",
1031
"GUID",
1132
"GenericIP",
33+
"FileObject",
34+
"FileField",
35+
"ImageFileField",
36+
"ImageFileObject",
37+
"CroppingDetails",
1238
]
39+
40+
41+
def __getattr__(name: str) -> t.Any:
42+
if name == "event":
43+
return sa_event
44+
45+
if name.startswith("_"):
46+
raise AttributeError(name)
47+
48+
for mod in (sa, sa_orm):
49+
if hasattr(mod, name):
50+
return getattr(mod, name)
51+
52+
raise AttributeError(name)

0 commit comments

Comments
 (0)