zrb 1.0.0a2__py3-none-any.whl → 1.0.0a3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zrb/__init__.py +48 -39
- zrb/__main__.py +3 -3
- zrb/attr/type.py +2 -1
- zrb/builtin/__init__.py +40 -2
- zrb/builtin/base64.py +32 -0
- zrb/builtin/git.py +156 -0
- zrb/builtin/git_subtree.py +88 -0
- zrb/builtin/group.py +34 -0
- zrb/builtin/llm.py +31 -0
- zrb/builtin/md5.py +34 -0
- zrb/builtin/project/__init__.py +0 -0
- zrb/builtin/project/add/__init__.py +0 -0
- zrb/builtin/project/add/fastapp.py +72 -0
- zrb/builtin/project/add/fastapp_template/.gitignore +4 -0
- zrb/builtin/project/add/fastapp_template/README.md +7 -0
- zrb/builtin/project/add/fastapp_template/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/_zrb/config.py +17 -0
- zrb/builtin/project/add/fastapp_template/_zrb/group.py +16 -0
- zrb/builtin/project/add/fastapp_template/_zrb/helper.py +97 -0
- zrb/builtin/project/add/fastapp_template/_zrb/main.py +132 -0
- zrb/builtin/project/add/fastapp_template/_zrb/venv_task.py +22 -0
- zrb/builtin/project/add/fastapp_template/common/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/common/app.py +18 -0
- zrb/builtin/project/add/fastapp_template/common/db_engine.py +5 -0
- zrb/builtin/project/add/fastapp_template/common/db_repository.py +134 -0
- zrb/builtin/project/add/fastapp_template/common/error.py +8 -0
- zrb/builtin/project/add/fastapp_template/common/schema.py +5 -0
- zrb/builtin/project/add/fastapp_template/common/usecase.py +232 -0
- zrb/builtin/project/add/fastapp_template/config.py +29 -0
- zrb/builtin/project/add/fastapp_template/main.py +7 -0
- zrb/builtin/project/add/fastapp_template/migrate.py +3 -0
- zrb/builtin/project/add/fastapp_template/module/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/alembic.ini +117 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +7 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/base_client.py +27 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +6 -0
- zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +9 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/README +1 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/env.py +108 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/script.py.mako +26 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +37 -0
- zrb/builtin/project/add/fastapp_template/module/auth/migration_metadata.py +6 -0
- zrb/builtin/project/add/fastapp_template/module/auth/route.py +22 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/db_repository.py +39 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +13 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/repository.py +34 -0
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/usecase.py +45 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/alembic.ini +117 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/README +1 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/env.py +108 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/script.py.mako +26 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration/versions/.gitkeep +0 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/migration_metadata.py +3 -0
- zrb/builtin/project/add/fastapp_template/module/gateway/route.py +27 -0
- zrb/builtin/project/add/fastapp_template/requirements.txt +6 -0
- zrb/builtin/project/add/fastapp_template/schema/__init__.py +0 -0
- zrb/builtin/project/add/fastapp_template/schema/role.py +31 -0
- zrb/builtin/project/add/fastapp_template/schema/user.py +31 -0
- zrb/builtin/project/add/fastapp_template/template.env +2 -0
- zrb/builtin/project/create/__init__.py +0 -0
- zrb/builtin/project/create/create.py +41 -0
- zrb/builtin/project/create/project-template/README.md +3 -0
- zrb/builtin/project/create/project-template/zrb_init.py +7 -0
- zrb/builtin/python.py +11 -0
- zrb/builtin/shell/__init__.py +0 -5
- zrb/builtin/shell/autocomplete/__init__.py +0 -9
- zrb/builtin/shell/autocomplete/bash.py +5 -6
- zrb/builtin/shell/autocomplete/subcmd.py +7 -8
- zrb/builtin/shell/autocomplete/zsh.py +5 -6
- zrb/builtin/todo.py +186 -0
- zrb/callback/any_callback.py +1 -1
- zrb/callback/callback.py +5 -5
- zrb/cmd/cmd_val.py +2 -2
- zrb/config.py +4 -1
- zrb/content_transformer/any_content_transformer.py +1 -1
- zrb/content_transformer/content_transformer.py +2 -2
- zrb/context/any_context.py +1 -1
- zrb/context/any_shared_context.py +3 -3
- zrb/context/context.py +10 -8
- zrb/context/shared_context.py +9 -8
- zrb/env/__init__.py +0 -3
- zrb/env/any_env.py +1 -1
- zrb/env/env.py +3 -4
- zrb/env/env_file.py +4 -4
- zrb/env/env_map.py +2 -2
- zrb/group/__init__.py +0 -3
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +7 -6
- zrb/input/any_input.py +1 -1
- zrb/input/base_input.py +4 -4
- zrb/input/bool_input.py +5 -5
- zrb/input/float_input.py +3 -3
- zrb/input/int_input.py +3 -3
- zrb/input/option_input.py +51 -0
- zrb/input/password_input.py +2 -2
- zrb/input/str_input.py +1 -1
- zrb/input/text_input.py +12 -10
- zrb/runner/cli.py +79 -45
- zrb/runner/web_app/group_info_ui/controller.py +7 -8
- zrb/runner/web_app/group_info_ui/view.html +2 -2
- zrb/runner/web_app/home_page/controller.py +7 -6
- zrb/runner/web_app/home_page/view.html +2 -2
- zrb/runner/web_app/task_ui/controller.py +8 -12
- zrb/runner/web_app/task_ui/view.html +2 -2
- zrb/runner/web_server.py +137 -211
- zrb/runner/web_util.py +5 -35
- zrb/session/any_session.py +13 -7
- zrb/session/session.py +78 -40
- zrb/session_state_log/session_state_log.py +7 -5
- zrb/session_state_logger/any_session_state_logger.py +1 -1
- zrb/session_state_logger/default_session_state_logger.py +2 -2
- zrb/session_state_logger/file_session_state_logger.py +19 -27
- zrb/task/any_task.py +4 -4
- zrb/task/base_task.py +33 -23
- zrb/task/base_trigger.py +11 -12
- zrb/task/cmd_task.py +48 -39
- zrb/task/http_check.py +8 -8
- zrb/task/llm_task.py +160 -0
- zrb/task/make_task.py +9 -9
- zrb/task/rsync_task.py +7 -7
- zrb/task/scaffolder.py +14 -11
- zrb/task/scheduler.py +6 -7
- zrb/task/task.py +1 -1
- zrb/task/tcp_check.py +8 -8
- zrb/util/attr.py +19 -3
- zrb/util/cli/style.py +71 -2
- zrb/util/cli/subcommand.py +2 -2
- zrb/util/codemod/__init__.py +0 -0
- zrb/util/codemod/add_code_to_class.py +35 -0
- zrb/util/codemod/add_code_to_function.py +36 -0
- zrb/util/codemod/add_code_to_method.py +55 -0
- zrb/util/codemod/add_key_to_dict.py +51 -0
- zrb/util/codemod/add_param_to_function_call.py +39 -0
- zrb/util/codemod/add_property_to_class.py +55 -0
- zrb/util/git.py +156 -0
- zrb/util/git_subtree.py +94 -0
- zrb/util/group.py +2 -2
- zrb/util/llm/tool.py +63 -0
- zrb/util/string/conversion.py +7 -0
- zrb/util/todo.py +135 -0
- {zrb-1.0.0a2.dist-info → zrb-1.0.0a3.dist-info}/METADATA +8 -5
- zrb-1.0.0a3.dist-info/RECORD +194 -0
- zrb/builtin/shell/_group.py +0 -9
- zrb/builtin/shell/autocomplete/_group.py +0 -6
- zrb/runner/web_app/any_request_handler.py +0 -24
- zrb-1.0.0a2.dist-info/RECORD +0 -120
- {zrb-1.0.0a2.dist-info → zrb-1.0.0a3.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a2.dist-info → zrb-1.0.0a3.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
import os
|
2
|
+
import platform
|
3
|
+
|
4
|
+
DIR = os.path.dirname(__file__)
|
5
|
+
APP_DIR = os.path.dirname(DIR)
|
6
|
+
APP_MODULE_NAME = os.path.basename(APP_DIR)
|
7
|
+
|
8
|
+
MICROSERVICES_ENV_VARS = {
|
9
|
+
"APP_NAME_MODE": "microservices",
|
10
|
+
"APP_NAME_AUTH_BASE_URL": "http://localhost:3002",
|
11
|
+
}
|
12
|
+
MONOLITH_ENV_VARS = {"APP_NAME_MODE": "monolith"}
|
13
|
+
|
14
|
+
if platform.system() == "Windows":
|
15
|
+
ACTIVATE_VENV_SCRIPT = "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; . .venv\Scripts\Activate" # noqa
|
16
|
+
else:
|
17
|
+
ACTIVATE_VENV_SCRIPT = "source .venv/bin/activate"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from zrb import Group
|
2
|
+
from zrb.builtin import project_group
|
3
|
+
|
4
|
+
app_group = project_group.add_group(
|
5
|
+
Group(name="app-name", description="🚀 Managing App Name")
|
6
|
+
)
|
7
|
+
|
8
|
+
app_run_group = app_group.add_group(Group(name="run", description="🟢 Run App Name"))
|
9
|
+
|
10
|
+
app_migrate_group = app_group.add_group(
|
11
|
+
Group(name="migrate", description="📦 Run App Name DB migration")
|
12
|
+
)
|
13
|
+
|
14
|
+
app_create_group = app_group.add_group(
|
15
|
+
Group(name="create", description="✨ Create resources for App Name")
|
16
|
+
)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from fastapp_template._zrb.config import (
|
4
|
+
ACTIVATE_VENV_SCRIPT,
|
5
|
+
APP_DIR,
|
6
|
+
MICROSERVICES_ENV_VARS,
|
7
|
+
MONOLITH_ENV_VARS,
|
8
|
+
)
|
9
|
+
|
10
|
+
from zrb import Cmd, CmdTask, EnvFile, EnvMap, StrInput, Task
|
11
|
+
|
12
|
+
|
13
|
+
def create_migration(name: str, module: str) -> Task:
|
14
|
+
return CmdTask(
|
15
|
+
name=f"create-app-name-{name}-migration",
|
16
|
+
description=f"🧩 Create App Name {name.capitalize()} DB migration",
|
17
|
+
input=StrInput(
|
18
|
+
name="message",
|
19
|
+
description="Migration message",
|
20
|
+
prompt="Migration message",
|
21
|
+
allow_empty=False,
|
22
|
+
),
|
23
|
+
env=[
|
24
|
+
EnvFile(path=os.path.join(APP_DIR, "template.env")),
|
25
|
+
EnvMap(
|
26
|
+
vars={
|
27
|
+
"APP_DB_URL": f"sqlite:///{APP_DIR}/.migration.{module}.db",
|
28
|
+
"APP_NAME_MODULES": f"{module}",
|
29
|
+
}
|
30
|
+
),
|
31
|
+
],
|
32
|
+
cwd=APP_DIR,
|
33
|
+
cmd=[
|
34
|
+
ACTIVATE_VENV_SCRIPT,
|
35
|
+
f"cd {os.path.join(APP_DIR, 'module', module)}",
|
36
|
+
"alembic upgrade head",
|
37
|
+
Cmd(
|
38
|
+
"alembic revision --autogenerate -m {double_quote(ctx.input.message)}",
|
39
|
+
auto_render=True,
|
40
|
+
),
|
41
|
+
],
|
42
|
+
auto_render_cmd=False,
|
43
|
+
retries=2,
|
44
|
+
)
|
45
|
+
|
46
|
+
|
47
|
+
def migrate_module(name: str, module: str, as_microservices: bool) -> Task:
|
48
|
+
env_vars = MICROSERVICES_ENV_VARS if as_microservices else MONOLITH_ENV_VARS
|
49
|
+
return CmdTask(
|
50
|
+
name=(
|
51
|
+
f"migrate-app-name-{name}"
|
52
|
+
if as_microservices
|
53
|
+
else f"migrate-{name}-on-monolith"
|
54
|
+
),
|
55
|
+
description=f"🧩 Run App Name {name.capitalize()} DB migration",
|
56
|
+
env=[
|
57
|
+
EnvFile(path=os.path.join(APP_DIR, "template.env")),
|
58
|
+
EnvMap(
|
59
|
+
vars={
|
60
|
+
**env_vars,
|
61
|
+
"APP_NAME_MODULES": f"{module}",
|
62
|
+
}
|
63
|
+
),
|
64
|
+
],
|
65
|
+
cwd=APP_DIR,
|
66
|
+
cmd=[
|
67
|
+
ACTIVATE_VENV_SCRIPT,
|
68
|
+
f"cd {os.path.join(APP_DIR, 'module', module)}",
|
69
|
+
"alembic upgrade head",
|
70
|
+
],
|
71
|
+
auto_render_cmd=False,
|
72
|
+
retries=2,
|
73
|
+
)
|
74
|
+
|
75
|
+
|
76
|
+
def run_microservice(name: str, port: int, module: str) -> Task:
|
77
|
+
return CmdTask(
|
78
|
+
name=f"run-app-name-{name}",
|
79
|
+
description=f"🧩 Run App Name {name.capitalize()}",
|
80
|
+
env=[
|
81
|
+
EnvFile(path=os.path.join(APP_DIR, "template.env")),
|
82
|
+
EnvMap(
|
83
|
+
vars={
|
84
|
+
**MICROSERVICES_ENV_VARS,
|
85
|
+
"APP_NAME_PORT": f"{port}",
|
86
|
+
"APP_NAME_MODULES": f"{module}",
|
87
|
+
}
|
88
|
+
),
|
89
|
+
],
|
90
|
+
cwd=APP_DIR,
|
91
|
+
cmd=[
|
92
|
+
ACTIVATE_VENV_SCRIPT,
|
93
|
+
'fastapi dev main.py --port "${APP_NAME_PORT}"',
|
94
|
+
],
|
95
|
+
auto_render_cmd=False,
|
96
|
+
retries=2,
|
97
|
+
)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from fastapp_template._zrb.config import ACTIVATE_VENV_SCRIPT, APP_DIR
|
4
|
+
from fastapp_template._zrb.group import (
|
5
|
+
app_create_group,
|
6
|
+
app_migrate_group,
|
7
|
+
app_run_group,
|
8
|
+
)
|
9
|
+
from fastapp_template._zrb.helper import (
|
10
|
+
create_migration,
|
11
|
+
migrate_module,
|
12
|
+
run_microservice,
|
13
|
+
)
|
14
|
+
from fastapp_template._zrb.venv_task import prepare_venv
|
15
|
+
|
16
|
+
from zrb import CmdTask, Env, EnvFile, Task
|
17
|
+
|
18
|
+
# 🚀 Run/Migrate All ===========================================================
|
19
|
+
|
20
|
+
run_all = app_run_group.add_task(
|
21
|
+
Task(
|
22
|
+
name="run-app-name", description="🟢 Run App Name as monolith and microservices"
|
23
|
+
),
|
24
|
+
alias="all",
|
25
|
+
)
|
26
|
+
|
27
|
+
migrate_all = app_migrate_group.add_task(
|
28
|
+
Task(
|
29
|
+
name="migrate-app-name",
|
30
|
+
description="📦 Run App Name DB migration for monolith and microservices",
|
31
|
+
),
|
32
|
+
alias="all",
|
33
|
+
)
|
34
|
+
|
35
|
+
create_all_migration = app_create_group.add_task(
|
36
|
+
Task(
|
37
|
+
name="create-app-name-migration", description="📦 Create App Name DB migration"
|
38
|
+
),
|
39
|
+
alias="migration",
|
40
|
+
)
|
41
|
+
|
42
|
+
# 🗿 Run/Migrate Monolith =====================================================
|
43
|
+
|
44
|
+
run_monolith = app_run_group.add_task(
|
45
|
+
CmdTask(
|
46
|
+
name="run-monolith-app-name",
|
47
|
+
description="🗿 Run App Name as a monolith",
|
48
|
+
env=[
|
49
|
+
EnvFile(path=os.path.join(APP_DIR, "template.env")),
|
50
|
+
Env(name="APP_NAME_MODE", default="monolith"),
|
51
|
+
],
|
52
|
+
cwd=APP_DIR,
|
53
|
+
cmd=[
|
54
|
+
ACTIVATE_VENV_SCRIPT,
|
55
|
+
'fastapi dev main.py --port "${APP_NAME_PORT}"',
|
56
|
+
],
|
57
|
+
auto_render_cmd=False,
|
58
|
+
retries=2,
|
59
|
+
),
|
60
|
+
alias="monolith",
|
61
|
+
)
|
62
|
+
prepare_venv >> run_monolith >> run_all
|
63
|
+
|
64
|
+
migrate_monolith = app_migrate_group.add_task(
|
65
|
+
Task(
|
66
|
+
name="migrate-monolith-app-name",
|
67
|
+
description="🗿 Run App Name DB migration for monolith",
|
68
|
+
),
|
69
|
+
alias="monolith",
|
70
|
+
)
|
71
|
+
migrate_monolith >> migrate_all
|
72
|
+
|
73
|
+
# 🌐 Run/Migrate Microsevices ==================================================
|
74
|
+
|
75
|
+
run_microservices = app_run_group.add_task(
|
76
|
+
Task(
|
77
|
+
name="run-microservices-app-name",
|
78
|
+
description="🌐 Run App Name as microservices",
|
79
|
+
),
|
80
|
+
alias="microservices",
|
81
|
+
)
|
82
|
+
run_microservices >> run_all
|
83
|
+
|
84
|
+
migrate_microservices = app_migrate_group.add_task(
|
85
|
+
Task(
|
86
|
+
name="migrate-microservices-app-name",
|
87
|
+
description="🌐 Run App Name DB migration for microservices",
|
88
|
+
),
|
89
|
+
alias="microservices",
|
90
|
+
)
|
91
|
+
migrate_microservices >> migrate_all
|
92
|
+
|
93
|
+
# 📡 Run/Migrate Gateway =======================================================
|
94
|
+
|
95
|
+
run_gateway = app_run_group.add_task(
|
96
|
+
run_microservice("gateway", 3001, "gateway"), alias="microservices-gateway"
|
97
|
+
)
|
98
|
+
prepare_venv >> run_gateway >> run_microservices
|
99
|
+
|
100
|
+
create_gateway_migration = app_create_group.add_task(
|
101
|
+
create_migration("gateway", "gateway"), alias="gateway-migration"
|
102
|
+
)
|
103
|
+
prepare_venv >> create_gateway_migration >> create_all_migration
|
104
|
+
|
105
|
+
migrate_monolith_gateway = migrate_module("gateway", "gateway", as_microservices=False)
|
106
|
+
prepare_venv >> migrate_monolith_gateway >> [migrate_monolith, run_monolith]
|
107
|
+
|
108
|
+
migrate_microservices_gateway = app_migrate_group.add_task(
|
109
|
+
migrate_module("gateway", "gateway", as_microservices=True),
|
110
|
+
alias="microservices-gateway",
|
111
|
+
)
|
112
|
+
prepare_venv >> migrate_microservices_gateway >> [migrate_microservices, run_gateway]
|
113
|
+
|
114
|
+
# 🔐 Run/Migrate Auth ==========================================================
|
115
|
+
|
116
|
+
run_auth = app_run_group.add_task(
|
117
|
+
run_microservice("auth", 3002, "auth"), alias="microservices-auth"
|
118
|
+
)
|
119
|
+
prepare_venv >> run_auth >> run_microservices
|
120
|
+
|
121
|
+
create_auth_migration = app_create_group.add_task(
|
122
|
+
create_migration("auth", "auth"), alias="auth-migration"
|
123
|
+
)
|
124
|
+
prepare_venv >> create_auth_migration >> create_all_migration
|
125
|
+
|
126
|
+
migrate_monolith_auth = migrate_module("auth", "auth", as_microservices=False)
|
127
|
+
prepare_venv >> migrate_monolith_auth >> [migrate_monolith, run_monolith]
|
128
|
+
|
129
|
+
migrate_microservices_auth = app_migrate_group.add_task(
|
130
|
+
migrate_module("auth", "auth", as_microservices=True), alias="microservices-auth"
|
131
|
+
)
|
132
|
+
prepare_venv >> migrate_microservices_auth >> [migrate_microservices, run_auth]
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from fastapp_template._zrb.config import ACTIVATE_VENV_SCRIPT, APP_DIR
|
4
|
+
from fastapp_template._zrb.group import app_group
|
5
|
+
|
6
|
+
from zrb import CmdTask
|
7
|
+
|
8
|
+
create_venv = CmdTask(
|
9
|
+
name="create-app-name-venv",
|
10
|
+
cwd=APP_DIR,
|
11
|
+
cmd="python -m venv .venv",
|
12
|
+
execute_condition=lambda _: not os.path.isdir(os.path.join(APP_DIR, ".venv")),
|
13
|
+
)
|
14
|
+
|
15
|
+
prepare_venv = CmdTask(
|
16
|
+
name="prepare-app-name-venv",
|
17
|
+
cmd=[ACTIVATE_VENV_SCRIPT, "pip install -r requirements.txt"],
|
18
|
+
cwd=APP_DIR,
|
19
|
+
)
|
20
|
+
create_venv >> prepare_venv
|
21
|
+
|
22
|
+
app_group.add_task(create_venv, alias="prepare")
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from contextlib import asynccontextmanager
|
2
|
+
|
3
|
+
from fastapi import FastAPI
|
4
|
+
from fastapp_template.common.db_engine import engine
|
5
|
+
from fastapp_template.config import APP_MODE, APP_MODULES
|
6
|
+
from sqlmodel import SQLModel
|
7
|
+
|
8
|
+
|
9
|
+
@asynccontextmanager
|
10
|
+
async def lifespan(app: FastAPI):
|
11
|
+
SQLModel.metadata.create_all(engine)
|
12
|
+
yield
|
13
|
+
|
14
|
+
|
15
|
+
app_title = (
|
16
|
+
"App Name" if APP_MODE == "monolith" else f"App Name - {', '.join(APP_MODULES)}"
|
17
|
+
)
|
18
|
+
app = FastAPI(title=app_title, lifespan=lifespan)
|
@@ -0,0 +1,134 @@
|
|
1
|
+
from typing import Any, Callable, Generic, Type, TypeVar
|
2
|
+
|
3
|
+
from fastapp_template.common.error import NotFoundError
|
4
|
+
from sqlalchemy import Engine
|
5
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
|
6
|
+
from sqlmodel import Session, SQLModel, select
|
7
|
+
|
8
|
+
DBModel = TypeVar("DBModel", bound=SQLModel)
|
9
|
+
ResponseModel = TypeVar("Model", bound=SQLModel)
|
10
|
+
CreateModel = TypeVar("CreateModel", bound=SQLModel)
|
11
|
+
UpdateModel = TypeVar("UpdateModel", bound=SQLModel)
|
12
|
+
|
13
|
+
|
14
|
+
class BaseDBRepository(Generic[DBModel, ResponseModel, CreateModel, UpdateModel]):
|
15
|
+
db_model: Type[DBModel]
|
16
|
+
response_model: Type[ResponseModel]
|
17
|
+
create_model: Type[CreateModel]
|
18
|
+
update_model: Type[UpdateModel]
|
19
|
+
entity_name: str = "entity"
|
20
|
+
column_preprocessors: dict[str, Callable[[Any], Any]] = {}
|
21
|
+
|
22
|
+
def __init__(self, engine: Engine | AsyncEngine):
|
23
|
+
self.engine = engine
|
24
|
+
self.is_async = isinstance(engine, AsyncEngine)
|
25
|
+
|
26
|
+
def _to_response(self, db_instance: DBModel) -> ResponseModel:
|
27
|
+
return self.response_model(**db_instance.model_dump())
|
28
|
+
|
29
|
+
async def create(self, data: CreateModel) -> ResponseModel:
|
30
|
+
data_dict = data.model_dump(exclude_unset=True)
|
31
|
+
for key, preprocessor in self.column_preprocessors.items():
|
32
|
+
if key in data_dict:
|
33
|
+
data_dict[key] = preprocessor(data_dict[key])
|
34
|
+
db_instance = self.db_model(**data_dict)
|
35
|
+
if self.is_async:
|
36
|
+
async with AsyncSession(self.engine) as session:
|
37
|
+
session.add(db_instance)
|
38
|
+
await session.commit()
|
39
|
+
await session.refresh(db_instance)
|
40
|
+
else:
|
41
|
+
with Session(self.engine) as session:
|
42
|
+
session.add(db_instance)
|
43
|
+
session.commit()
|
44
|
+
session.refresh(db_instance)
|
45
|
+
return self._to_response(db_instance)
|
46
|
+
|
47
|
+
async def get_by_id(self, item_id: str) -> ResponseModel:
|
48
|
+
if self.is_async:
|
49
|
+
async with AsyncSession(self.engine) as session:
|
50
|
+
db_instance = await session.get(self.db_model, item_id)
|
51
|
+
else:
|
52
|
+
with Session(self.engine) as session:
|
53
|
+
db_instance = session.get(self.db_model, item_id)
|
54
|
+
if not db_instance:
|
55
|
+
raise NotFoundError(f"{self.entity_name} not found")
|
56
|
+
return self._to_response(db_instance)
|
57
|
+
|
58
|
+
async def get_all(self, page: int = 1, page_size: int = 10) -> list[ResponseModel]:
|
59
|
+
offset = (page - 1) * page_size
|
60
|
+
statement = select(self.db_model).offset(offset).limit(page_size)
|
61
|
+
if self.is_async:
|
62
|
+
async with AsyncSession(self.engine) as session:
|
63
|
+
result = await session.execute(statement)
|
64
|
+
results = result.scalars().all()
|
65
|
+
else:
|
66
|
+
with Session(self.engine) as session:
|
67
|
+
results = session.exec(statement).all()
|
68
|
+
return [self._to_response(instance) for instance in results]
|
69
|
+
|
70
|
+
async def update(self, item_id: str, data: UpdateModel) -> ResponseModel:
|
71
|
+
update_data = data.model_dump(exclude_unset=True)
|
72
|
+
for key, value in update_data.items():
|
73
|
+
if key in self.column_preprocessors:
|
74
|
+
update_data[key] = self.column_preprocessors[key](value)
|
75
|
+
if self.is_async:
|
76
|
+
async with AsyncSession(self.engine) as session:
|
77
|
+
db_instance = await session.get(self.db_model, item_id)
|
78
|
+
if not db_instance:
|
79
|
+
raise NotFoundError(f"{self.entity_name} not found")
|
80
|
+
for key, value in update_data.items():
|
81
|
+
setattr(db_instance, key, value)
|
82
|
+
session.add(db_instance)
|
83
|
+
await session.commit()
|
84
|
+
await session.refresh(db_instance)
|
85
|
+
else:
|
86
|
+
with Session(self.engine) as session:
|
87
|
+
db_instance = session.get(self.db_model, item_id)
|
88
|
+
if not db_instance:
|
89
|
+
raise NotFoundError(f"{self.entity_name} not found")
|
90
|
+
for key, value in update_data.items():
|
91
|
+
setattr(db_instance, key, value)
|
92
|
+
session.add(db_instance)
|
93
|
+
session.commit()
|
94
|
+
session.refresh(db_instance)
|
95
|
+
return self._to_response(db_instance)
|
96
|
+
|
97
|
+
async def delete(self, item_id: str) -> ResponseModel:
|
98
|
+
if self.is_async:
|
99
|
+
async with AsyncSession(self.engine) as session:
|
100
|
+
db_instance = await session.get(self.db_model, item_id)
|
101
|
+
if not db_instance:
|
102
|
+
raise NotFoundError(f"{self.entity_name} not found")
|
103
|
+
await session.delete(db_instance)
|
104
|
+
await session.commit()
|
105
|
+
else:
|
106
|
+
with Session(self.engine) as session:
|
107
|
+
db_instance = session.get(self.db_model, item_id)
|
108
|
+
if not db_instance:
|
109
|
+
raise NotFoundError(f"{self.entity_name} not found")
|
110
|
+
session.delete(db_instance)
|
111
|
+
session.commit()
|
112
|
+
return self._to_response(db_instance)
|
113
|
+
|
114
|
+
async def create_bulk(self, data_list: list[CreateModel]) -> list[ResponseModel]:
|
115
|
+
db_instances = []
|
116
|
+
for data in data_list:
|
117
|
+
data_dict = data.model_dump(exclude_unset=True)
|
118
|
+
for key, preprocessor in self.column_preprocessors.items():
|
119
|
+
if key in data_dict:
|
120
|
+
data_dict[key] = preprocessor(data_dict[key])
|
121
|
+
db_instances.append(self.db_model(**data_dict))
|
122
|
+
if self.is_async:
|
123
|
+
async with AsyncSession(self.engine) as session:
|
124
|
+
session.add_all(db_instances)
|
125
|
+
await session.commit()
|
126
|
+
for instance in db_instances:
|
127
|
+
await session.refresh(instance)
|
128
|
+
else:
|
129
|
+
with Session(self.engine) as session:
|
130
|
+
session.add_all(db_instances)
|
131
|
+
session.commit()
|
132
|
+
for instance in db_instances:
|
133
|
+
session.refresh(instance)
|
134
|
+
return [self._to_response(instance) for instance in db_instances]
|