zrb 1.0.0a10__py3-none-any.whl → 1.0.0a14__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.
Files changed (79) hide show
  1. zrb/builtin/__init__.py +15 -5
  2. zrb/builtin/project/add/fastapp.py +32 -17
  3. zrb/builtin/project/add/fastapp_template/_zrb/column/create_column_task.py +11 -0
  4. zrb/builtin/project/add/fastapp_template/_zrb/config.py +4 -4
  5. zrb/builtin/project/add/fastapp_template/_zrb/entity/create_entity_task.py +196 -0
  6. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/my_entity_usecase.py +66 -0
  7. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/factory.py +13 -0
  8. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/my_entity_db_repository.py +33 -0
  9. zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/my_entity_repository.py +39 -0
  10. zrb/builtin/project/add/fastapp_template/_zrb/entity/schema.template.py +29 -0
  11. zrb/builtin/project/add/fastapp_template/_zrb/group.py +9 -5
  12. zrb/builtin/project/add/fastapp_template/_zrb/helper.py +25 -11
  13. zrb/builtin/project/add/fastapp_template/_zrb/input.py +43 -0
  14. zrb/builtin/project/add/fastapp_template/_zrb/main.py +30 -21
  15. zrb/builtin/project/add/fastapp_template/_zrb/module/create_module_task.py +136 -0
  16. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/alembic.ini +117 -0
  17. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/api_client.py +6 -0
  18. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/direct_client.py +6 -0
  19. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/factory.py +9 -0
  20. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/README +1 -0
  21. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/env.py +108 -0
  22. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/script.py.mako +26 -0
  23. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration/versions/3093c7336477_add_user_table.py +37 -0
  24. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/migration_metadata.py +3 -0
  25. zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/route.py +19 -0
  26. zrb/builtin/project/add/fastapp_template/_zrb/module/run_module.template.py +26 -0
  27. zrb/builtin/project/add/fastapp_template/_zrb/venv_task.py +2 -5
  28. zrb/builtin/project/add/fastapp_template/common/app.py +3 -1
  29. zrb/builtin/project/add/fastapp_template/config.py +7 -7
  30. zrb/builtin/project/add/fastapp_template/module/auth/client/any_client.py +27 -0
  31. zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +2 -2
  32. zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +2 -2
  33. zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +1 -1
  34. zrb/builtin/project/add/fastapp_template/module/auth/route.py +1 -1
  35. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +2 -2
  36. zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/{db_repository.py → user_db_repository.py} +2 -2
  37. zrb/builtin/project/add/fastapp_template/module/auth/service/user/{usecase.py → user_usecase.py} +15 -8
  38. zrb/builtin/project/add/fastapp_template/requirements.txt +5 -6
  39. zrb/builtin/project/add/fastapp_template/schema/permission.py +31 -0
  40. zrb/builtin/project/add/fastapp_template/template.env +2 -2
  41. zrb/builtin/project/create/create.py +2 -2
  42. zrb/builtin/project/create/project-template/zrb_init.py +0 -4
  43. zrb/builtin/setup/{dev → asdf}/asdf.py +6 -6
  44. zrb/builtin/setup/{system/latex → latex}/ubuntu.py +1 -1
  45. zrb/builtin/setup/{dev → tmux}/tmux.py +1 -1
  46. zrb/builtin/setup/tmux/tmux_config.sh +12 -0
  47. zrb/builtin/todo.py +101 -15
  48. zrb/config.py +2 -2
  49. zrb/content_transformer/content_transformer.py +14 -2
  50. zrb/context/context.py +13 -10
  51. zrb/input/base_input.py +3 -2
  52. zrb/input/bool_input.py +1 -1
  53. zrb/input/float_input.py +1 -1
  54. zrb/input/int_input.py +1 -1
  55. zrb/input/option_input.py +1 -1
  56. zrb/input/password_input.py +1 -1
  57. zrb/input/text_input.py +1 -1
  58. zrb/runner/cli.py +16 -5
  59. zrb/runner/web_app.py +30 -18
  60. zrb/runner/web_controller/task_ui/controller.py +8 -6
  61. zrb/session/session.py +4 -1
  62. zrb/task/scaffolder.py +7 -9
  63. zrb/util/cli/style.py +7 -0
  64. zrb/util/codemod/add_code_to_module.py +12 -0
  65. zrb/util/load.py +9 -7
  66. zrb/util/string/conversion.py +52 -0
  67. zrb/util/todo.py +152 -34
  68. {zrb-1.0.0a10.dist-info → zrb-1.0.0a14.dist-info}/METADATA +1 -2
  69. {zrb-1.0.0a10.dist-info → zrb-1.0.0a14.dist-info}/RECORD +79 -55
  70. {zrb-1.0.0a10.dist-info → zrb-1.0.0a14.dist-info}/WHEEL +1 -1
  71. /zrb/builtin/project/add/fastapp_template/{module/auth/client/base_client.py → _zrb/module/module_template/client/any_client.py} +0 -0
  72. /zrb/builtin/{setup/dev/tmux_config.sh → project/add/fastapp_template/_zrb/module/module_template/service/__init__.py} +0 -0
  73. /zrb/builtin/project/add/fastapp_template/common/{db_repository.py → base_db_repository.py} +0 -0
  74. /zrb/builtin/project/add/fastapp_template/common/{usecase.py → base_usecase.py} +0 -0
  75. /zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/{repository.py → user_repository.py} +0 -0
  76. /zrb/builtin/setup/{dev → asdf}/asdf_helper.py +0 -0
  77. /zrb/builtin/setup/{dev → tmux}/tmux_helper.py +0 -0
  78. /zrb/builtin/setup/{system/ubuntu.py → ubuntu.py} +0 -0
  79. {zrb-1.0.0a10.dist-info → zrb-1.0.0a14.dist-info}/entry_points.txt +0 -0
zrb/builtin/__init__.py CHANGED
@@ -12,14 +12,22 @@ from zrb.builtin.md5 import hash_md5, sum_md5
12
12
  from zrb.builtin.project.add.fastapp import add_fastapp_to_project
13
13
  from zrb.builtin.project.create.create import create_project
14
14
  from zrb.builtin.python import format_python_code
15
- from zrb.builtin.setup.dev.asdf import setup_asdf
16
- from zrb.builtin.setup.dev.tmux import setup_tmux
17
- from zrb.builtin.setup.system.latex.ubuntu import setup_latex_on_ubuntu
18
- from zrb.builtin.setup.system.ubuntu import setup_ubuntu
15
+ from zrb.builtin.setup.asdf.asdf import setup_asdf
16
+ from zrb.builtin.setup.latex.ubuntu import setup_latex_on_ubuntu
17
+ from zrb.builtin.setup.tmux.tmux import setup_tmux
18
+ from zrb.builtin.setup.ubuntu import setup_ubuntu
19
19
  from zrb.builtin.shell.autocomplete.bash import make_bash_autocomplete
20
20
  from zrb.builtin.shell.autocomplete.subcmd import get_shell_subcommands
21
21
  from zrb.builtin.shell.autocomplete.zsh import make_zsh_autocomplete
22
- from zrb.builtin.todo import add_todo, complete_todo, edit_todo, list_todo, log_todo
22
+ from zrb.builtin.todo import (
23
+ add_todo,
24
+ archive_todo,
25
+ complete_todo,
26
+ edit_todo,
27
+ list_todo,
28
+ log_todo,
29
+ show_todo,
30
+ )
23
31
 
24
32
  assert create_project
25
33
  assert add_fastapp_to_project
@@ -42,9 +50,11 @@ assert git_pull_subtree
42
50
  assert git_push_subtree
43
51
  assert list_todo
44
52
  assert add_todo
53
+ assert archive_todo
45
54
  assert edit_todo
46
55
  assert complete_todo
47
56
  assert log_todo
57
+ assert show_todo
48
58
  assert setup_ubuntu
49
59
  assert setup_latex_on_ubuntu
50
60
  assert setup_asdf
@@ -6,7 +6,7 @@ from zrb.input.str_input import StrInput
6
6
  from zrb.task.make_task import make_task
7
7
  from zrb.task.scaffolder import Scaffolder
8
8
  from zrb.task.task import Task
9
- from zrb.util.string.conversion import double_quote
9
+ from zrb.util.string.conversion import double_quote, to_snake_case
10
10
  from zrb.util.string.name import get_random_name
11
11
 
12
12
  _DIR = os.path.dirname(__file__)
@@ -22,25 +22,21 @@ scaffold_fastapp = Scaffolder(
22
22
  default_str=lambda _: os.getcwd(),
23
23
  ),
24
24
  StrInput(
25
- name="app-name",
25
+ name="app",
26
26
  description="App name",
27
27
  prompt="App name",
28
- default_str=lambda _: get_random_name(separator="_"),
29
28
  ),
30
29
  ],
31
30
  source_path=os.path.join(_DIR, "fastapp_template"),
32
31
  render_source_path=False,
33
- destination_path=lambda ctx: os.path.join(
34
- ctx.input["project-dir"], ctx.input["app-name"]
35
- ),
32
+ destination_path=lambda ctx: os.path.join(ctx.input["project-dir"], ctx.input.app),
36
33
  transform_content={
37
- "fastapp_template": "{to_snake_case(ctx.input['app-name'])}",
38
- "App Name": "{ctx.input['app-name'].title()}",
39
- "App name": "{ctx.input['app-name'].capitalize()}",
40
- "app-name": "{to_kebab_case(ctx.input['app-name'])}",
41
- "app_name": "{to_snake_case(ctx.input['app-name'])}",
42
- "APP_NAME": "{to_snake_case(ctx.input['app-name']).upper()}",
43
- "secure-password": lambda _: get_random_name(),
34
+ "fastapp_template": "{to_snake_case(ctx.input.app)}",
35
+ "My App Name": "{ctx.input.app.title()}",
36
+ "my-app-name": "{to_kebab_case(ctx.input.app)}",
37
+ "my_app_name": "{to_snake_case(ctx.input.app)}",
38
+ "MY_APP_NAME": "{to_snake_case(ctx.input.app).upper()}",
39
+ "my-secure-password": lambda _: get_random_name(),
44
40
  },
45
41
  retries=0,
46
42
  )
@@ -48,16 +44,34 @@ scaffold_fastapp = Scaffolder(
48
44
 
49
45
  @make_task(
50
46
  name="register-fastapp-automation",
47
+ retries=0,
51
48
  )
52
49
  def register_fastapp_automation(ctx: AnyContext):
53
50
  project_dir_path = ctx.input["project-dir"]
54
51
  zrb_init_path = os.path.join(project_dir_path, "zrb_init.py")
55
- app_dir_path = ctx.input["app-name"]
56
- app_automation_file_part = ", ".join(
52
+ app_dir_path = ctx.input.app
53
+ app_name = to_snake_case(ctx.input.app)
54
+ with open(zrb_init_path, "r") as f:
55
+ file_content = f.read().strip()
56
+ # Assemble new content
57
+ new_content_list = [file_content]
58
+ # Check if import load_file is exists, if not exists, add
59
+ import_load_file_script = "from zrb import load_file"
60
+ if import_load_file_script not in file_content:
61
+ new_content_list = [import_load_file_script] + new_content_list
62
+ # Add fastapp-automation script
63
+ automation_file_part = ", ".join(
57
64
  [double_quote(part) for part in [app_dir_path, "_zrb", "main.py"]]
58
65
  )
59
- with open(zrb_init_path, "+a") as f:
60
- f.write(f"load_file(os.path.join(_DIR, {app_automation_file_part}))\n")
66
+ new_content_list = new_content_list + [
67
+ f"{app_name} = load_file(os.path.join(_DIR, {automation_file_part}))",
68
+ f"assert {app_name}",
69
+ "",
70
+ ]
71
+ new_content = "\n".join(new_content_list)
72
+ # Write new content
73
+ with open(zrb_init_path, "w") as f:
74
+ f.write(new_content)
61
75
 
62
76
 
63
77
  scaffold_fastapp >> register_fastapp_automation
@@ -66,6 +80,7 @@ add_fastapp_to_project = add_to_project_group.add_task(
66
80
  Task(
67
81
  name="add-fastapp",
68
82
  description="🚀 Add FastApp to project",
83
+ retries=0,
69
84
  ),
70
85
  alias="fastapp",
71
86
  )
@@ -0,0 +1,11 @@
1
+ from fastapp_template._zrb.group import app_create_group
2
+
3
+ from zrb import Task
4
+
5
+ create_my_app_name_column = app_create_group.add_task(
6
+ Task(
7
+ name="create-my-app-name-column",
8
+ description="📊 Create new column on an entity",
9
+ ),
10
+ alias="column",
11
+ )
@@ -6,12 +6,12 @@ APP_DIR = os.path.dirname(DIR)
6
6
  APP_MODULE_NAME = os.path.basename(APP_DIR)
7
7
 
8
8
  MICROSERVICES_ENV_VARS = {
9
- "APP_NAME_MODE": "microservices",
10
- "APP_NAME_AUTH_BASE_URL": "http://localhost:3002",
9
+ "MY_APP_NAME_MODE": "microservices",
10
+ "MY_APP_NAME_AUTH_BASE_URL": "http://localhost:3002",
11
11
  }
12
- MONOLITH_ENV_VARS = {"APP_NAME_MODE": "monolith"}
12
+ MONOLITH_ENV_VARS = {"MY_APP_NAME_MODE": "monolith"}
13
13
 
14
14
  if platform.system() == "Windows":
15
- ACTIVATE_VENV_SCRIPT = "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; . .venv\Scripts\Activate" # noqa
15
+ ACTIVATE_VENV_SCRIPT = "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser; . .venv\\Scripts\\Activate" # noqa
16
16
  else:
17
17
  ACTIVATE_VENV_SCRIPT = "source .venv/bin/activate"
@@ -0,0 +1,196 @@
1
+ import os
2
+
3
+ from fastapp_template._zrb.config import APP_DIR
4
+ from fastapp_template._zrb.group import app_create_group
5
+ from fastapp_template._zrb.helper import (
6
+ get_existing_module_names,
7
+ get_existing_schema_names,
8
+ )
9
+ from fastapp_template._zrb.input import (
10
+ existing_module_input,
11
+ new_entity_column_input,
12
+ new_entity_input,
13
+ plural_entity_input,
14
+ )
15
+
16
+ from zrb import AnyContext, Scaffolder, Task, make_task
17
+ from zrb.util.codemod.add_code_to_module import add_code_to_module
18
+ from zrb.util.codemod.add_parent_to_class import add_parent_to_class
19
+ from zrb.util.string.conversion import to_pascal_case, to_snake_case
20
+
21
+
22
+ @make_task(
23
+ name="validate-create-my-app-name-entity",
24
+ input=[
25
+ existing_module_input,
26
+ new_entity_input,
27
+ plural_entity_input,
28
+ new_entity_column_input,
29
+ ],
30
+ retries=0,
31
+ )
32
+ async def validate_create_my_app_name_entity(ctx: AnyContext):
33
+ module_name = to_snake_case(ctx.input.module)
34
+ if module_name not in get_existing_module_names():
35
+ raise ValueError(f"Module not exist: {module_name}")
36
+ schema_name = to_snake_case(ctx.input.entity)
37
+ if schema_name in get_existing_schema_names():
38
+ raise ValueError(f"Schema already exists: {schema_name}")
39
+
40
+
41
+ scaffold_my_app_name_schema = Scaffolder(
42
+ name="scaffold-my-app-name-schema",
43
+ input=[
44
+ existing_module_input,
45
+ new_entity_input,
46
+ new_entity_column_input,
47
+ ],
48
+ source_path=os.path.join(os.path.dirname(__file__), "schema.template.py"),
49
+ render_source_path=False,
50
+ destination_path=lambda ctx: os.path.join(
51
+ APP_DIR,
52
+ "schema",
53
+ f"{to_snake_case(ctx.input.entity)}.py",
54
+ ),
55
+ transform_content={
56
+ "MyEntity": "{to_pascal_case(ctx.input.entity)}",
57
+ "my_column": "{to_snake_case(ctx.input.column)}",
58
+ },
59
+ retries=0,
60
+ upstream=validate_create_my_app_name_entity,
61
+ )
62
+
63
+ scaffold_my_app_name_module_entity = Scaffolder(
64
+ name="scaffold-my-app-name-schema",
65
+ input=[
66
+ existing_module_input,
67
+ new_entity_input,
68
+ plural_entity_input,
69
+ ],
70
+ source_path=os.path.join(os.path.dirname(__file__), "module_template"),
71
+ render_source_path=False,
72
+ destination_path=lambda ctx: os.path.join(
73
+ APP_DIR,
74
+ "module",
75
+ f"{to_snake_case(ctx.input.module)}",
76
+ ),
77
+ transform_content={
78
+ "my_module": "{to_snake_case(ctx.input.module)}",
79
+ "MyEntity": "{to_pascal_case(ctx.input.entity)}",
80
+ "my_entity": "{to_snake_case(ctx.input.entity)}",
81
+ "my_entities": "{to_snake_case(ctx.input.plural)}",
82
+ "my-entities": "{to_kebab_case(ctx.input.plural)}",
83
+ },
84
+ retries=0,
85
+ upstream=validate_create_my_app_name_entity,
86
+ )
87
+
88
+
89
+ @make_task(
90
+ name="register-my-app-name-migration",
91
+ input=[existing_module_input, new_entity_input],
92
+ retries=0,
93
+ upstream=validate_create_my_app_name_entity,
94
+ )
95
+ async def register_my_app_name_migration(ctx: AnyContext):
96
+ migration_metadata_file_path = os.path.join(
97
+ APP_DIR, "module", to_snake_case(ctx.input.module), "migration_metadata.py"
98
+ )
99
+ app_name = os.path.basename(APP_DIR)
100
+ with open(migration_metadata_file_path, "r") as f:
101
+ file_content = f.read()
102
+ entity_name = to_snake_case(ctx.input.entity)
103
+ entity_class = to_pascal_case(ctx.input.entity)
104
+ new_file_content_list = (
105
+ [f"from {app_name}.schema.{entity_name} import {entity_class}"]
106
+ + file_content.strip()
107
+ + [
108
+ f"{entity_class}.metadata = metadata",
109
+ f"{entity_class}.__table__.tometadata(metadata)",
110
+ "",
111
+ ]
112
+ )
113
+ with open(migration_metadata_file_path, "w") as f:
114
+ f.write("\n".join(new_file_content_list))
115
+
116
+
117
+ @make_task(
118
+ name="register-my-app-name-api-client",
119
+ input=[existing_module_input, new_entity_input],
120
+ retries=0,
121
+ upstream=validate_create_my_app_name_entity,
122
+ )
123
+ async def register_my_app_name_api_client(ctx: AnyContext):
124
+ api_client_file_path = os.path.join(
125
+ APP_DIR, "module", to_snake_case(ctx.input.module), "client", "api_client.py"
126
+ )
127
+ with open(api_client_file_path, "r") as f:
128
+ file_content = f.read()
129
+ module_config_name = to_snake_case(ctx.input.module).upper()
130
+ new_code = add_code_to_module(
131
+ file_content,
132
+ f"user_api_client = user_usecase.as_api_client(base_url=APP_{module_config_name}_BASE_URL)", # noqa
133
+ )
134
+ new_code = add_parent_to_class(
135
+ original_code=new_code,
136
+ class_name="APIClient",
137
+ parent_class_name="user_api_client",
138
+ )
139
+ app_name = os.path.basename(APP_DIR)
140
+ entity_name = to_snake_case(ctx.input.entity)
141
+ module_name = to_snake_case(ctx.input.module)
142
+ new_file_content_list = [
143
+ f"from {app_name}.module.{module_name}.service.{entity_name} import {entity_name}_usecase", # noqa
144
+ new_code.strip(),
145
+ "",
146
+ ]
147
+ with open(api_client_file_path, "w") as f:
148
+ f.write("\n".join(new_file_content_list))
149
+
150
+
151
+ @make_task(
152
+ name="register-my-app-name-direct-client",
153
+ input=[existing_module_input, new_entity_input],
154
+ retries=0,
155
+ upstream=validate_create_my_app_name_entity,
156
+ )
157
+ async def register_my_app_name_direct_client(ctx: AnyContext):
158
+ direct_client_file_path = os.path.join(
159
+ APP_DIR, "module", to_snake_case(ctx.input.module), "client", "direct_client.py"
160
+ )
161
+ with open(direct_client_file_path, "r") as f:
162
+ file_content = f.read()
163
+ new_code = add_code_to_module(
164
+ file_content, "user_direct_client = user_usecase.as_direct_client()"
165
+ )
166
+ new_code = add_parent_to_class(
167
+ original_code=new_code,
168
+ class_name="DirectClient",
169
+ parent_class_name="user_direct_client",
170
+ )
171
+ app_name = os.path.basename(APP_DIR)
172
+ entity_name = to_snake_case(ctx.input.entity)
173
+ module_name = to_snake_case(ctx.input.module)
174
+ new_file_content_list = [
175
+ f"from {app_name}.module.{module_name}.service.{entity_name} import {entity_name}_usecase", # noqa
176
+ new_code.strip(),
177
+ "",
178
+ ]
179
+ with open(direct_client_file_path, "w") as f:
180
+ f.write("\n".join(new_file_content_list))
181
+
182
+
183
+ create_my_app_name_entity = app_create_group.add_task(
184
+ Task(
185
+ name="create-my-app-name-entity",
186
+ description="🏗️ Create new entity on a module",
187
+ successor="",
188
+ ),
189
+ alias="entity",
190
+ )
191
+ create_my_app_name_entity << [
192
+ scaffold_my_app_name_schema,
193
+ scaffold_my_app_name_module_entity,
194
+ register_my_app_name_api_client,
195
+ register_my_app_name_direct_client,
196
+ ]
@@ -0,0 +1,66 @@
1
+ from fastapp_template.common.base_usecase import BaseUsecase
2
+ from fastapp_template.module.my_module.service.my_entity.repository.factory import (
3
+ my_entity_repository,
4
+ )
5
+ from fastapp_template.module.my_module.service.my_entity.repository.repository import (
6
+ MyEntityRepository,
7
+ )
8
+ from fastapp_template.schema.my_entity import (
9
+ MyEntityCreate,
10
+ MyEntityResponse,
11
+ MyEntityUpdate,
12
+ )
13
+
14
+
15
+ class MyEntityUsecase(BaseUsecase):
16
+
17
+ def __init__(self, my_entity_repository: MyEntityRepository):
18
+ super().__init__()
19
+ self.my_entity_repository = my_entity_repository
20
+
21
+ @BaseUsecase.route(
22
+ "/api/v1/my-entities/{my_entity_id}",
23
+ methods=["get"],
24
+ response_model=MyEntityResponse,
25
+ )
26
+ async def get_my_entity_by_id(self, my_entity_id: str) -> MyEntityResponse:
27
+ return await self.my_entity_repository.get_by_id(my_entity_id)
28
+
29
+ @BaseUsecase.route(
30
+ "/api/v1/my-entities", methods=["get"], response_model=list[MyEntityResponse]
31
+ )
32
+ async def get_all_my_entities(self) -> list[MyEntityResponse]:
33
+ return await self.my_entity_repository.get_all()
34
+
35
+ @BaseUsecase.route(
36
+ "/api/v1/my-entities",
37
+ methods=["post"],
38
+ response_model=MyEntityResponse | list[MyEntityResponse],
39
+ )
40
+ async def create_my_entity(
41
+ self, data: MyEntityCreate | list[MyEntityCreate]
42
+ ) -> MyEntityResponse | list[MyEntityResponse]:
43
+ if isinstance(data, MyEntityCreate):
44
+ return await self.my_entity_repository.create(data)
45
+ return await self.my_entity_repository.create_bulk(data)
46
+
47
+ @BaseUsecase.route(
48
+ "/api/v1/my-entities/{my_entity_id}",
49
+ methods=["put"],
50
+ response_model=MyEntityResponse,
51
+ )
52
+ async def update_my_entity(
53
+ self, my_entity_id: str, data: MyEntityUpdate
54
+ ) -> MyEntityResponse:
55
+ return await self.my_entity_repository.update(my_entity_id, data)
56
+
57
+ @BaseUsecase.route(
58
+ "/api/v1/my-entities/{my_entity_id}",
59
+ methods=["delete"],
60
+ response_model=MyEntityResponse,
61
+ )
62
+ async def delete_my_entity(self, my_entity_id: str) -> MyEntityResponse:
63
+ return await self.my_entity_repository.delete(my_entity_id)
64
+
65
+
66
+ my_entity_usecase = MyEntityUsecase(my_entity_repository=my_entity_repository)
@@ -0,0 +1,13 @@
1
+ from fastapp_template.common.db_engine import engine
2
+ from fastapp_template.config import APP_REPOSITORY_TYPE
3
+ from fastapp_template.module.my_module.service.my_entity.repository.my_entity_db_repository import (
4
+ MyEntityDBRepository,
5
+ )
6
+ from fastapp_template.module.my_module.service.my_entity.repository.my_entity_repository import (
7
+ MyEntityRepository,
8
+ )
9
+
10
+ if APP_REPOSITORY_TYPE == "db":
11
+ my_entity_repository: MyEntityRepository = MyEntityDBRepository(engine)
12
+ else:
13
+ my_entity_repository: MyEntityRepository = None
@@ -0,0 +1,33 @@
1
+ from fastapp_template.common.base_db_repository import BaseDBRepository
2
+ from fastapp_template.common.error import NotFoundError
3
+ from fastapp_template.module.my_module.service.my_entity.repository.my_entity_repository import (
4
+ MyEntityRepository,
5
+ )
6
+ from fastapp_template.schema.my_entity import (
7
+ MyEntity,
8
+ MyEntityCreate,
9
+ MyEntityResponse,
10
+ MyEntityUpdate,
11
+ )
12
+ from passlib.context import CryptContext
13
+ from sqlalchemy.ext.asyncio import AsyncSession
14
+ from sqlmodel import Session, select
15
+
16
+ # Password hashing context
17
+ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
18
+
19
+
20
+ def hash_password(password: str) -> str:
21
+ return pwd_context.hash(password)
22
+
23
+
24
+ class MyEntityDBRepository(
25
+ BaseDBRepository[MyEntity, MyEntityResponse, MyEntityCreate, MyEntityUpdate],
26
+ MyEntityRepository,
27
+ ):
28
+ db_model = MyEntity
29
+ response_model = MyEntityResponse
30
+ create_model = MyEntityCreate
31
+ update_model = MyEntityUpdate
32
+ entity_name = "my_entity"
33
+ column_preprocessors = {}
@@ -0,0 +1,39 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from fastapp_template.schema.my_entity import (
4
+ MyEntity,
5
+ MyEntityCreate,
6
+ MyEntityResponse,
7
+ MyEntityUpdate,
8
+ )
9
+
10
+
11
+ class MyEntityRepository(ABC):
12
+
13
+ @abstractmethod
14
+ async def create(self, my_entity_data: MyEntityCreate) -> MyEntityResponse:
15
+ pass
16
+
17
+ @abstractmethod
18
+ async def get_by_id(self, my_entity_id: str) -> MyEntity:
19
+ pass
20
+
21
+ @abstractmethod
22
+ async def get_all(self) -> list[MyEntity]:
23
+ pass
24
+
25
+ @abstractmethod
26
+ async def update(
27
+ self, my_entity_id: str, my_entity_data: MyEntityUpdate
28
+ ) -> MyEntity:
29
+ pass
30
+
31
+ @abstractmethod
32
+ async def delete(self, my_entity_id: str) -> MyEntity:
33
+ pass
34
+
35
+ @abstractmethod
36
+ async def create_bulk(
37
+ self, my_entity_data_list: list[MyEntityCreate]
38
+ ) -> list[MyEntityResponse]:
39
+ pass
@@ -0,0 +1,29 @@
1
+ import datetime
2
+
3
+ import ulid
4
+ from sqlmodel import Field, SQLModel
5
+
6
+
7
+ class MyEntityBase(SQLModel):
8
+ my_column: str
9
+
10
+
11
+ class MyEntityCreate(MyEntityBase):
12
+ pass
13
+
14
+
15
+ class MyEntityUpdate(SQLModel):
16
+ my_column: str | None = None
17
+
18
+
19
+ class MyEntityResponse(MyEntityBase):
20
+ id: str
21
+
22
+
23
+ class MyEntity(SQLModel, table=True):
24
+ id: str = Field(default_factory=lambda: ulid.new().str, primary_key=True)
25
+ created_at: datetime.datetime
26
+ created_by: str
27
+ updated_at: datetime.datetime
28
+ updated_by: str
29
+ my_column: str
@@ -1,16 +1,20 @@
1
1
  from zrb import Group
2
- from zrb.builtin import project_group
2
+ from zrb.builtin.group import project_group
3
3
 
4
4
  app_group = project_group.add_group(
5
- Group(name="app-name", description="🚀 Managing App Name")
5
+ Group(name="my-app-name", description="🚀 Managing My App Name")
6
6
  )
7
7
 
8
- app_run_group = app_group.add_group(Group(name="run", description="🟢 Run App Name"))
8
+ app_run_group = app_group.add_group(Group(name="run", description="🟢 Run My App Name"))
9
9
 
10
10
  app_migrate_group = app_group.add_group(
11
- Group(name="migrate", description="📦 Run App Name DB migration")
11
+ Group(name="migrate", description="📦 Run My App Name DB migration")
12
12
  )
13
13
 
14
14
  app_create_group = app_group.add_group(
15
- Group(name="create", description="✨ Create resources for App Name")
15
+ Group(name="create", description="✨ Create resources for My App Name")
16
+ )
17
+
18
+ app_create_migration_group = app_create_group.add_group(
19
+ Group(name="migration", description="📦 Create My App Name DB migration")
16
20
  )
@@ -12,8 +12,8 @@ from zrb import Cmd, CmdTask, EnvFile, EnvMap, StrInput, Task
12
12
 
13
13
  def create_migration(name: str, module: str) -> Task:
14
14
  return CmdTask(
15
- name=f"create-app-name-{name}-migration",
16
- description=f"🧩 Create App Name {name.capitalize()} DB migration",
15
+ name=f"create-my-app-name-{name}-migration",
16
+ description=f"🧩 Create My App Name {name.capitalize()} DB migration",
17
17
  input=StrInput(
18
18
  name="message",
19
19
  description="Migration message",
@@ -25,7 +25,7 @@ def create_migration(name: str, module: str) -> Task:
25
25
  EnvMap(
26
26
  vars={
27
27
  "APP_DB_URL": f"sqlite:///{APP_DIR}/.migration.{module}.db",
28
- "APP_NAME_MODULES": f"{module}",
28
+ "MY_APP_NAME_MODULES": f"{module}",
29
29
  }
30
30
  ),
31
31
  ],
@@ -48,17 +48,17 @@ def migrate_module(name: str, module: str, as_microservices: bool) -> Task:
48
48
  env_vars = MICROSERVICES_ENV_VARS if as_microservices else MONOLITH_ENV_VARS
49
49
  return CmdTask(
50
50
  name=(
51
- f"migrate-app-name-{name}"
51
+ f"migrate-my-app-name-{name}"
52
52
  if as_microservices
53
53
  else f"migrate-{name}-on-monolith"
54
54
  ),
55
- description=f"🧩 Run App Name {name.capitalize()} DB migration",
55
+ description=f"🧩 Run My App Name {name.capitalize()} DB migration",
56
56
  env=[
57
57
  EnvFile(path=os.path.join(APP_DIR, "template.env")),
58
58
  EnvMap(
59
59
  vars={
60
60
  **env_vars,
61
- "APP_NAME_MODULES": f"{module}",
61
+ "MY_APP_NAME_MODULES": f"{module}",
62
62
  }
63
63
  ),
64
64
  ],
@@ -75,23 +75,37 @@ def migrate_module(name: str, module: str, as_microservices: bool) -> Task:
75
75
 
76
76
  def run_microservice(name: str, port: int, module: str) -> Task:
77
77
  return CmdTask(
78
- name=f"run-app-name-{name}",
79
- description=f"🧩 Run App Name {name.capitalize()}",
78
+ name=f"run-my-app-name-{name}",
79
+ description=f"🧩 Run My App Name {name.capitalize()}",
80
80
  env=[
81
81
  EnvFile(path=os.path.join(APP_DIR, "template.env")),
82
82
  EnvMap(
83
83
  vars={
84
84
  **MICROSERVICES_ENV_VARS,
85
- "APP_NAME_PORT": f"{port}",
86
- "APP_NAME_MODULES": f"{module}",
85
+ "MY_APP_NAME_PORT": f"{port}",
86
+ "MY_APP_NAME_MODULES": f"{module}",
87
87
  }
88
88
  ),
89
89
  ],
90
90
  cwd=APP_DIR,
91
91
  cmd=[
92
92
  ACTIVATE_VENV_SCRIPT,
93
- 'fastapi dev main.py --port "${APP_NAME_PORT}"',
93
+ 'fastapi dev main.py --port "${MY_APP_NAME_PORT}"',
94
94
  ],
95
95
  render_cmd=False,
96
96
  retries=2,
97
97
  )
98
+
99
+
100
+ def get_existing_module_names() -> list[str]:
101
+ module_dir_path = os.path.join(APP_DIR, "module")
102
+ return [entry.name for entry in os.scandir(module_dir_path) if entry.is_dir()]
103
+
104
+
105
+ def get_existing_schema_names() -> list[str]:
106
+ module_dir_path = os.path.join(APP_DIR, "schema")
107
+ return [
108
+ os.path.splitext(entry.name)[0]
109
+ for entry in os.scandir(module_dir_path)
110
+ if entry.is_file() and entry.name.endswith(".py")
111
+ ]