aury-boot 0.0.2__py3-none-any.whl → 0.0.3__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 (138) hide show
  1. aury/boot/__init__.py +66 -0
  2. aury/boot/_version.py +2 -2
  3. aury/boot/application/__init__.py +120 -0
  4. aury/boot/application/app/__init__.py +39 -0
  5. aury/boot/application/app/base.py +511 -0
  6. aury/boot/application/app/components.py +434 -0
  7. aury/boot/application/app/middlewares.py +101 -0
  8. aury/boot/application/config/__init__.py +44 -0
  9. aury/boot/application/config/settings.py +663 -0
  10. aury/boot/application/constants/__init__.py +19 -0
  11. aury/boot/application/constants/components.py +50 -0
  12. aury/boot/application/constants/scheduler.py +28 -0
  13. aury/boot/application/constants/service.py +29 -0
  14. aury/boot/application/errors/__init__.py +55 -0
  15. aury/boot/application/errors/chain.py +80 -0
  16. aury/boot/application/errors/codes.py +67 -0
  17. aury/boot/application/errors/exceptions.py +238 -0
  18. aury/boot/application/errors/handlers.py +320 -0
  19. aury/boot/application/errors/response.py +120 -0
  20. aury/boot/application/interfaces/__init__.py +76 -0
  21. aury/boot/application/interfaces/egress.py +224 -0
  22. aury/boot/application/interfaces/ingress.py +98 -0
  23. aury/boot/application/middleware/__init__.py +22 -0
  24. aury/boot/application/middleware/logging.py +451 -0
  25. aury/boot/application/migrations/__init__.py +13 -0
  26. aury/boot/application/migrations/manager.py +685 -0
  27. aury/boot/application/migrations/setup.py +237 -0
  28. aury/boot/application/rpc/__init__.py +63 -0
  29. aury/boot/application/rpc/base.py +108 -0
  30. aury/boot/application/rpc/client.py +294 -0
  31. aury/boot/application/rpc/discovery.py +218 -0
  32. aury/boot/application/scheduler/__init__.py +13 -0
  33. aury/boot/application/scheduler/runner.py +123 -0
  34. aury/boot/application/server/__init__.py +296 -0
  35. aury/boot/commands/__init__.py +30 -0
  36. aury/boot/commands/add.py +76 -0
  37. aury/boot/commands/app.py +105 -0
  38. aury/boot/commands/config.py +177 -0
  39. aury/boot/commands/docker.py +367 -0
  40. aury/boot/commands/docs.py +284 -0
  41. aury/boot/commands/generate.py +1277 -0
  42. aury/boot/commands/init.py +890 -0
  43. aury/boot/commands/migrate/__init__.py +37 -0
  44. aury/boot/commands/migrate/app.py +54 -0
  45. aury/boot/commands/migrate/commands.py +303 -0
  46. aury/boot/commands/scheduler.py +124 -0
  47. aury/boot/commands/server/__init__.py +21 -0
  48. aury/boot/commands/server/app.py +541 -0
  49. aury/boot/commands/templates/generate/api.py.tpl +105 -0
  50. aury/boot/commands/templates/generate/model.py.tpl +17 -0
  51. aury/boot/commands/templates/generate/repository.py.tpl +19 -0
  52. aury/boot/commands/templates/generate/schema.py.tpl +29 -0
  53. aury/boot/commands/templates/generate/service.py.tpl +48 -0
  54. aury/boot/commands/templates/project/CLI.md.tpl +92 -0
  55. aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +1397 -0
  56. aury/boot/commands/templates/project/README.md.tpl +111 -0
  57. aury/boot/commands/templates/project/admin_console_init.py.tpl +50 -0
  58. aury/boot/commands/templates/project/config.py.tpl +30 -0
  59. aury/boot/commands/templates/project/conftest.py.tpl +26 -0
  60. aury/boot/commands/templates/project/env.example.tpl +213 -0
  61. aury/boot/commands/templates/project/gitignore.tpl +128 -0
  62. aury/boot/commands/templates/project/main.py.tpl +41 -0
  63. aury/boot/commands/templates/project/modules/api.py.tpl +19 -0
  64. aury/boot/commands/templates/project/modules/exceptions.py.tpl +84 -0
  65. aury/boot/commands/templates/project/modules/schedules.py.tpl +18 -0
  66. aury/boot/commands/templates/project/modules/tasks.py.tpl +20 -0
  67. aury/boot/commands/worker.py +143 -0
  68. aury/boot/common/__init__.py +35 -0
  69. aury/boot/common/exceptions/__init__.py +114 -0
  70. aury/boot/common/i18n/__init__.py +16 -0
  71. aury/boot/common/i18n/translator.py +272 -0
  72. aury/boot/common/logging/__init__.py +716 -0
  73. aury/boot/contrib/__init__.py +10 -0
  74. aury/boot/contrib/admin_console/__init__.py +18 -0
  75. aury/boot/contrib/admin_console/auth.py +137 -0
  76. aury/boot/contrib/admin_console/discovery.py +69 -0
  77. aury/boot/contrib/admin_console/install.py +172 -0
  78. aury/boot/contrib/admin_console/utils.py +44 -0
  79. aury/boot/domain/__init__.py +79 -0
  80. aury/boot/domain/exceptions/__init__.py +132 -0
  81. aury/boot/domain/models/__init__.py +51 -0
  82. aury/boot/domain/models/base.py +69 -0
  83. aury/boot/domain/models/mixins.py +135 -0
  84. aury/boot/domain/models/models.py +96 -0
  85. aury/boot/domain/pagination/__init__.py +279 -0
  86. aury/boot/domain/repository/__init__.py +23 -0
  87. aury/boot/domain/repository/impl.py +423 -0
  88. aury/boot/domain/repository/interceptors.py +47 -0
  89. aury/boot/domain/repository/interface.py +106 -0
  90. aury/boot/domain/repository/query_builder.py +348 -0
  91. aury/boot/domain/service/__init__.py +11 -0
  92. aury/boot/domain/service/base.py +73 -0
  93. aury/boot/domain/transaction/__init__.py +404 -0
  94. aury/boot/infrastructure/__init__.py +104 -0
  95. aury/boot/infrastructure/cache/__init__.py +31 -0
  96. aury/boot/infrastructure/cache/backends.py +348 -0
  97. aury/boot/infrastructure/cache/base.py +68 -0
  98. aury/boot/infrastructure/cache/exceptions.py +37 -0
  99. aury/boot/infrastructure/cache/factory.py +94 -0
  100. aury/boot/infrastructure/cache/manager.py +274 -0
  101. aury/boot/infrastructure/database/__init__.py +39 -0
  102. aury/boot/infrastructure/database/config.py +71 -0
  103. aury/boot/infrastructure/database/exceptions.py +44 -0
  104. aury/boot/infrastructure/database/manager.py +317 -0
  105. aury/boot/infrastructure/database/query_tools/__init__.py +164 -0
  106. aury/boot/infrastructure/database/strategies/__init__.py +198 -0
  107. aury/boot/infrastructure/di/__init__.py +15 -0
  108. aury/boot/infrastructure/di/container.py +393 -0
  109. aury/boot/infrastructure/events/__init__.py +33 -0
  110. aury/boot/infrastructure/events/bus.py +362 -0
  111. aury/boot/infrastructure/events/config.py +52 -0
  112. aury/boot/infrastructure/events/consumer.py +134 -0
  113. aury/boot/infrastructure/events/middleware.py +51 -0
  114. aury/boot/infrastructure/events/models.py +63 -0
  115. aury/boot/infrastructure/monitoring/__init__.py +529 -0
  116. aury/boot/infrastructure/scheduler/__init__.py +19 -0
  117. aury/boot/infrastructure/scheduler/exceptions.py +37 -0
  118. aury/boot/infrastructure/scheduler/manager.py +478 -0
  119. aury/boot/infrastructure/storage/__init__.py +38 -0
  120. aury/boot/infrastructure/storage/base.py +164 -0
  121. aury/boot/infrastructure/storage/exceptions.py +37 -0
  122. aury/boot/infrastructure/storage/factory.py +88 -0
  123. aury/boot/infrastructure/tasks/__init__.py +24 -0
  124. aury/boot/infrastructure/tasks/config.py +45 -0
  125. aury/boot/infrastructure/tasks/constants.py +37 -0
  126. aury/boot/infrastructure/tasks/exceptions.py +37 -0
  127. aury/boot/infrastructure/tasks/manager.py +490 -0
  128. aury/boot/testing/__init__.py +24 -0
  129. aury/boot/testing/base.py +122 -0
  130. aury/boot/testing/client.py +163 -0
  131. aury/boot/testing/factory.py +154 -0
  132. aury/boot/toolkit/__init__.py +21 -0
  133. aury/boot/toolkit/http/__init__.py +367 -0
  134. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/METADATA +3 -2
  135. aury_boot-0.0.3.dist-info/RECORD +137 -0
  136. aury_boot-0.0.2.dist-info/RECORD +0 -5
  137. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/WHEEL +0 -0
  138. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,50 @@
1
+ """中间件和组件名称常量。
2
+
3
+ 定义所有内置中间件和组件的标准命名。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class MiddlewareName(str, Enum):
12
+ """中间件名称常量。
13
+
14
+ 所有内置 HTTP 中间件的标准命名。
15
+ """
16
+
17
+ # HTTP 中间件
18
+ REQUEST_LOGGING = "request_logging"
19
+ WEBSOCKET_LOGGING = "websocket_logging"
20
+ CORS = "cors"
21
+
22
+
23
+ class ComponentName(str, Enum):
24
+ """组件名称常量。
25
+
26
+ 所有内置基础设施组件的标准命名。
27
+ """
28
+
29
+ # 基础设施组件
30
+ DATABASE = "database"
31
+ CACHE = "cache"
32
+ TASK_QUEUE = "task_queue"
33
+ SCHEDULER = "scheduler"
34
+
35
+ # 存储组件
36
+ STORAGE = "storage"
37
+
38
+ # 迁移组件
39
+ MIGRATIONS = "migrations"
40
+
41
+ # 管理后台(可选扩展)
42
+ ADMIN_CONSOLE = "admin_console"
43
+
44
+
45
+ __all__ = [
46
+ "ComponentName",
47
+ "MiddlewareName",
48
+ ]
49
+
50
+
@@ -0,0 +1,28 @@
1
+ """调度器运行模式常量。
2
+
3
+ 定义调度器运行模式的枚举。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class SchedulerMode(str, Enum):
12
+ """调度器运行模式枚举(应用层配置)。
13
+
14
+ - EMBEDDED: 伴随 API 运行(默认)
15
+ - STANDALONE: 独立运行
16
+ - DISABLED: 禁用调度器
17
+ """
18
+
19
+ EMBEDDED = "embedded"
20
+ STANDALONE = "standalone"
21
+ DISABLED = "disabled"
22
+
23
+
24
+ __all__ = [
25
+ "SchedulerMode",
26
+ ]
27
+
28
+
@@ -0,0 +1,29 @@
1
+ """服务类型常量。
2
+
3
+ 定义服务运行模式的枚举。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class ServiceType(str, Enum):
12
+ """服务类型枚举(应用层配置)。
13
+
14
+ 用于区分不同的服务运行模式:
15
+ - API: 运行 API 服务(可伴随调度器)
16
+ - WORKER: 运行任务队列 Worker
17
+ - SCHEDULER: 仅运行调度器(独立 pod)
18
+ """
19
+
20
+ API = "api"
21
+ WORKER = "worker"
22
+ SCHEDULER = "scheduler"
23
+
24
+
25
+ __all__ = [
26
+ "ServiceType",
27
+ ]
28
+
29
+
@@ -0,0 +1,55 @@
1
+ """错误处理系统 - 责任链模式 + Pydantic。
2
+
3
+ 提供统一的异常类和错误处理链。
4
+ """
5
+
6
+ from .chain import ErrorHandlerChain, error_handler_chain, global_exception_handler
7
+ from .codes import ErrorCode
8
+ from .exceptions import (
9
+ AlreadyExistsError,
10
+ BaseError,
11
+ BusinessError,
12
+ DatabaseError,
13
+ ForbiddenError,
14
+ NotFoundError,
15
+ UnauthorizedError,
16
+ ValidationError,
17
+ VersionConflictError,
18
+ )
19
+ from .handlers import (
20
+ BaseErrorHandler,
21
+ DatabaseErrorHandler,
22
+ ErrorHandler,
23
+ HTTPExceptionHandler,
24
+ ServiceErrorHandler,
25
+ ValidationErrorHandler,
26
+ )
27
+ from .response import ErrorDetail
28
+
29
+ __all__ = [
30
+ "AlreadyExistsError",
31
+ "BaseError",
32
+ "BaseErrorHandler",
33
+ "BusinessError",
34
+ "DatabaseError",
35
+ "DatabaseErrorHandler",
36
+ # 错误代码
37
+ "ErrorCode",
38
+ # 错误模型
39
+ "ErrorDetail",
40
+ # 错误处理器
41
+ "ErrorHandler",
42
+ # 错误处理链
43
+ "ErrorHandlerChain",
44
+ "ForbiddenError",
45
+ "HTTPExceptionHandler",
46
+ "NotFoundError",
47
+ "ServiceErrorHandler",
48
+ "UnauthorizedError",
49
+ "ValidationError",
50
+ "ValidationErrorHandler",
51
+ "VersionConflictError",
52
+ "error_handler_chain",
53
+ "global_exception_handler",
54
+ ]
55
+
@@ -0,0 +1,80 @@
1
+ """错误处理链管理器。
2
+
3
+ 提供错误处理链的构建和管理。
4
+ """
5
+
6
+ from fastapi import Request
7
+ from fastapi.responses import JSONResponse
8
+
9
+ from .handlers import (
10
+ BaseErrorHandler,
11
+ DatabaseErrorHandler,
12
+ ErrorHandler,
13
+ HTTPExceptionHandler,
14
+ ServiceErrorHandler,
15
+ ValidationErrorHandler,
16
+ )
17
+
18
+
19
+ class ErrorHandlerChain:
20
+ """错误处理链管理器。"""
21
+
22
+ def __init__(self) -> None:
23
+ """初始化处理链。"""
24
+ self._chain = self._build_chain()
25
+
26
+ def _build_chain(self) -> ErrorHandler:
27
+ """构建处理链。
28
+
29
+ Returns:
30
+ ErrorHandler: 处理链头部
31
+ """
32
+ # 按优先级顺序构建处理链
33
+ # 1. BaseErrorHandler - 处理应用层自定义异常
34
+ # 2. ServiceErrorHandler - 处理 Domain 层 ServiceException(业务异常)
35
+ # 3. HTTPExceptionHandler - 处理 FastAPI HTTP 异常
36
+ # 4. ValidationErrorHandler - 处理 Pydantic 验证异常
37
+ # 5. DatabaseErrorHandler - 处理数据库异常(包括 Domain 层其他异常)
38
+ base_handler = BaseErrorHandler()
39
+ service_handler = ServiceErrorHandler()
40
+ http_handler = HTTPExceptionHandler()
41
+ validation_handler = ValidationErrorHandler()
42
+ db_handler = DatabaseErrorHandler()
43
+
44
+ base_handler.set_next(service_handler).set_next(http_handler).set_next(validation_handler).set_next(db_handler)
45
+
46
+ return base_handler
47
+
48
+ async def handle(self, exception: Exception, request: Request) -> JSONResponse:
49
+ """处理异常。
50
+
51
+ Args:
52
+ exception: 异常对象
53
+ request: 请求对象
54
+
55
+ Returns:
56
+ JSONResponse: 响应对象
57
+ """
58
+ return await self._chain.process(exception, request)
59
+
60
+
61
+ # 全局异常处理器实例
62
+ error_handler_chain = ErrorHandlerChain()
63
+
64
+
65
+ async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
66
+ """全局异常处理器(FastAPI集成)。
67
+
68
+ 使用方式:
69
+ app.add_exception_handler(Exception, global_exception_handler)
70
+ """
71
+ return await error_handler_chain.handle(exc, request)
72
+
73
+
74
+ __all__ = [
75
+ "ErrorHandlerChain",
76
+ "error_handler_chain",
77
+ "global_exception_handler",
78
+ ]
79
+
80
+
@@ -0,0 +1,67 @@
1
+ """错误代码定义。
2
+
3
+ 提供统一的错误代码枚举。
4
+
5
+ **重要提示**:
6
+ Python 的 Enum 不支持继承已有成员的枚举。
7
+ 如果你需要扩展错误代码,请使用以下方式之一:
8
+
9
+ 方式 1(推荐):创建独立的枚举类
10
+ ```python
11
+ class ServiceErrorCode(str, Enum):
12
+ # 服务特定错误代码(5xxx)
13
+ CUSTOM_ERROR = "5000"
14
+ ```
15
+
16
+ 方式 2:使用联合类型
17
+ ```python
18
+ ErrorCodeType = ErrorCode | ServiceErrorCode
19
+ ```
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from enum import Enum
25
+
26
+
27
+ class ErrorCode(str, Enum):
28
+ """Foundation Kit 基础错误代码。
29
+
30
+ 预留范围:
31
+ - 1xxx: 通用错误
32
+ - 2xxx: 数据库错误
33
+ - 3xxx: 业务错误
34
+ - 4xxx: 外部服务错误
35
+ - 5xxx+: 留给各个服务自定义
36
+ """
37
+
38
+ # 通用错误 (1xxx)
39
+ UNKNOWN_ERROR = "1000"
40
+ VALIDATION_ERROR = "1001"
41
+ NOT_FOUND = "1002"
42
+ ALREADY_EXISTS = "1003"
43
+ UNAUTHORIZED = "1004"
44
+ FORBIDDEN = "1005"
45
+
46
+ # 数据库错误 (2xxx)
47
+ DATABASE_ERROR = "2000"
48
+ DUPLICATE_KEY = "2001"
49
+ CONSTRAINT_VIOLATION = "2002"
50
+ VERSION_CONFLICT = "2003" # 乐观锁冲突
51
+
52
+ # 业务错误 (3xxx)
53
+ BUSINESS_ERROR = "3000"
54
+ INVALID_OPERATION = "3001"
55
+ INSUFFICIENT_PERMISSION = "3002"
56
+
57
+ # 外部服务错误 (4xxx)
58
+ EXTERNAL_SERVICE_ERROR = "4000"
59
+ TIMEOUT_ERROR = "4001"
60
+ NETWORK_ERROR = "4002"
61
+
62
+
63
+ __all__ = [
64
+ "ErrorCode",
65
+ ]
66
+
67
+
@@ -0,0 +1,238 @@
1
+ """应用层异常类定义。
2
+
3
+ 提供应用层业务异常类,用于业务逻辑中抛出异常。
4
+ 这些异常会被错误处理器转换为 HTTP 响应。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from fastapi import status
12
+
13
+ from aury.boot.common.exceptions import FoundationError
14
+
15
+ from .codes import ErrorCode
16
+ from .response import ErrorDetail
17
+
18
+ if TYPE_CHECKING:
19
+ from aury.boot.domain.exceptions import VersionConflictError as DomainVersionConflictError
20
+
21
+
22
+ class BaseError(FoundationError):
23
+ """应用层异常基类(用于 HTTP 响应)。
24
+
25
+ 所有应用层的异常应继承此类。
26
+ 用于 HTTP API 响应,包含错误代码和状态码。
27
+
28
+ 继承示例:
29
+ class OrderError(BaseError):
30
+ default_message = "订单错误"
31
+ default_code = "5001" # 自定义错误码
32
+ default_status_code = 400
33
+
34
+ class OrderNotPaidError(OrderError):
35
+ default_message = "订单未支付"
36
+ default_code = "5002"
37
+
38
+ Attributes:
39
+ message: 错误消息
40
+ code: 错误代码(字符串或 ErrorCode 枚举)
41
+ status_code: HTTP状态码
42
+ details: 错误详情列表
43
+ metadata: 元数据
44
+ """
45
+
46
+ # 类级别默认值,子类可覆盖
47
+ default_message: str = "未知错误"
48
+ default_code: str | ErrorCode = ErrorCode.UNKNOWN_ERROR
49
+ default_status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
50
+
51
+ def __init__(
52
+ self,
53
+ message: str | None = None,
54
+ code: str | ErrorCode | None = None,
55
+ status_code: int | None = None,
56
+ details: list[ErrorDetail] | None = None,
57
+ metadata: dict[str, Any] | None = None,
58
+ ) -> None:
59
+ """初始化异常。
60
+
61
+ Args:
62
+ message: 错误消息(默认使用类的 default_message)
63
+ code: 错误代码(默认使用类的 default_code)
64
+ status_code: HTTP状态码(默认使用类的 default_status_code)
65
+ details: 错误详情
66
+ metadata: 元数据
67
+ """
68
+ self.message = message or self.default_message
69
+ self.code = code or self.default_code
70
+ self.status_code = status_code or self.default_status_code
71
+ self.details = details or []
72
+ self.metadata = metadata or {}
73
+ super().__init__(self.message)
74
+
75
+ def to_dict(self) -> dict[str, Any]:
76
+ """转换为字典。"""
77
+ code_value = self.code.value if isinstance(self.code, ErrorCode) else self.code
78
+ return {
79
+ "message": self.message,
80
+ "code": code_value,
81
+ "status_code": self.status_code,
82
+ "details": [detail.model_dump() for detail in self.details],
83
+ "metadata": self.metadata,
84
+ }
85
+
86
+ def __repr__(self) -> str:
87
+ """字符串表示。"""
88
+ code_value = self.code.value if isinstance(self.code, ErrorCode) else self.code
89
+ return f"<{self.__class__.__name__} code={code_value} message={self.message}>"
90
+
91
+
92
+ class ValidationError(BaseError):
93
+ """验证异常。"""
94
+
95
+ default_message = "数据验证失败"
96
+ default_code = ErrorCode.VALIDATION_ERROR
97
+ default_status_code = status.HTTP_400_BAD_REQUEST
98
+
99
+
100
+ class NotFoundError(BaseError):
101
+ """资源不存在异常。"""
102
+
103
+ default_message = "资源不存在"
104
+ default_code = ErrorCode.NOT_FOUND
105
+ default_status_code = status.HTTP_404_NOT_FOUND
106
+
107
+ def __init__(
108
+ self,
109
+ message: str | None = None,
110
+ resource: Any = None,
111
+ **kwargs
112
+ ) -> None:
113
+ if resource:
114
+ metadata = kwargs.get("metadata", {})
115
+ metadata["resource"] = str(resource)
116
+ kwargs["metadata"] = metadata
117
+ super().__init__(message=message, **kwargs)
118
+
119
+
120
+ class AlreadyExistsError(BaseError):
121
+ """资源已存在异常。"""
122
+
123
+ default_message = "资源已存在"
124
+ default_code = ErrorCode.ALREADY_EXISTS
125
+ default_status_code = status.HTTP_409_CONFLICT
126
+
127
+ def __init__(
128
+ self,
129
+ message: str | None = None,
130
+ resource: Any = None,
131
+ **kwargs
132
+ ) -> None:
133
+ if resource:
134
+ metadata = kwargs.get("metadata", {})
135
+ metadata["resource"] = str(resource)
136
+ kwargs["metadata"] = metadata
137
+ super().__init__(message=message, **kwargs)
138
+
139
+
140
+ class VersionConflictError(BaseError):
141
+ """版本冲突异常(乐观锁)。
142
+
143
+ 当使用 VersionedModel 时,如果更新时版本号不匹配,抛出此异常。
144
+
145
+ 注意:此异常继承自 BaseError,用于应用层(HTTP 响应)。
146
+ Domain 层的 VersionConflictError 在 domain.exceptions 中定义。
147
+ """
148
+
149
+ def __init__(
150
+ self,
151
+ message: str = "数据已被其他操作修改,请刷新后重试",
152
+ current_version: int | None = None,
153
+ expected_version: int | None = None,
154
+ **kwargs
155
+ ) -> None:
156
+ metadata = kwargs.pop("metadata", {})
157
+ if current_version is not None:
158
+ metadata["current_version"] = current_version
159
+ if expected_version is not None:
160
+ metadata["expected_version"] = expected_version
161
+
162
+ super().__init__(
163
+ message=message,
164
+ code=ErrorCode.VERSION_CONFLICT,
165
+ status_code=status.HTTP_409_CONFLICT,
166
+ metadata=metadata,
167
+ **kwargs
168
+ )
169
+
170
+ @classmethod
171
+ def from_domain_exception(
172
+ cls,
173
+ exc: DomainVersionConflictError,
174
+ ) -> VersionConflictError:
175
+ """从 Domain 层的 VersionConflictError 创建应用层异常。
176
+
177
+ Args:
178
+ exc: Domain 层的 VersionConflictError 异常
179
+
180
+ Returns:
181
+ VersionConflictError: 应用层的异常对象
182
+ """
183
+ from aury.boot.domain.exceptions import VersionConflictError as DomainVersionConflictError
184
+
185
+ if isinstance(exc, DomainVersionConflictError):
186
+ return cls(
187
+ message=exc.message,
188
+ current_version=exc.current_version,
189
+ expected_version=exc.expected_version,
190
+ )
191
+ # 不应该到达这里
192
+ return cls(message=str(exc))
193
+
194
+
195
+ class UnauthorizedError(BaseError):
196
+ """未授权异常。"""
197
+
198
+ default_message = "未授权访问"
199
+ default_code = ErrorCode.UNAUTHORIZED
200
+ default_status_code = status.HTTP_401_UNAUTHORIZED
201
+
202
+
203
+ class ForbiddenError(BaseError):
204
+ """禁止访问异常。"""
205
+
206
+ default_message = "禁止访问"
207
+ default_code = ErrorCode.FORBIDDEN
208
+ default_status_code = status.HTTP_403_FORBIDDEN
209
+
210
+
211
+ class DatabaseError(BaseError):
212
+ """数据库异常。"""
213
+
214
+ default_message = "数据库错误"
215
+ default_code = ErrorCode.DATABASE_ERROR
216
+ default_status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
217
+
218
+
219
+ class BusinessError(BaseError):
220
+ """业务逻辑异常。"""
221
+
222
+ default_message = "业务错误"
223
+ default_code = ErrorCode.BUSINESS_ERROR
224
+ default_status_code = status.HTTP_400_BAD_REQUEST
225
+
226
+
227
+ __all__ = [
228
+ "AlreadyExistsError",
229
+ "BaseError",
230
+ "BusinessError",
231
+ "DatabaseError",
232
+ "ForbiddenError",
233
+ "NotFoundError",
234
+ "UnauthorizedError",
235
+ "ValidationError",
236
+ "VersionConflictError",
237
+ ]
238
+