tina4-python 3.10.54__tar.gz → 3.10.55__tar.gz
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.
- {tina4_python-3.10.54 → tina4_python-3.10.55}/PKG-INFO +1 -1
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/__init__.py +2 -2
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/router.py +55 -6
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/crud/__init__.py +27 -8
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/adapter.py +11 -8
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/connection.py +8 -0
- tina4_python-3.10.55/tina4_python/database/mongodb.py +751 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/.gitignore +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/README.md +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/pyproject.toml +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/Testing.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/events.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/request.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/response.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/core/server.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/dev_reload.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.10.54 → tina4_python-3.10.55}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -8,13 +8,13 @@ Tina4 Python v3.0 — Zero-dependency, lightweight web framework.
|
|
|
8
8
|
|
|
9
9
|
One import, everything works.
|
|
10
10
|
"""
|
|
11
|
-
__version__ = "3.10.
|
|
11
|
+
__version__ = "3.10.55"
|
|
12
12
|
|
|
13
13
|
# ── Route decorators ──
|
|
14
14
|
from tina4_python.core.router import ( # noqa: E402, F401
|
|
15
15
|
get, post, put, patch, delete, any_method,
|
|
16
16
|
noauth, secured, cached, middleware, template,
|
|
17
|
-
Router,
|
|
17
|
+
Router, RouteGroup,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
# ── HTTP Constants ──
|
|
@@ -57,6 +57,51 @@ class RouteRef:
|
|
|
57
57
|
return self
|
|
58
58
|
|
|
59
59
|
|
|
60
|
+
class RouteGroup:
|
|
61
|
+
"""A group of routes sharing a common prefix and middleware.
|
|
62
|
+
|
|
63
|
+
Passed to the callback in Router.group(). Supports nesting.
|
|
64
|
+
|
|
65
|
+
Usage::
|
|
66
|
+
|
|
67
|
+
Router.group("/api", lambda group: [
|
|
68
|
+
group.get("/users", list_handler),
|
|
69
|
+
group.post("/users", create_handler),
|
|
70
|
+
group.group("/admin", lambda admin: [
|
|
71
|
+
admin.get("/stats", stats_handler),
|
|
72
|
+
], middleware=[admin_check]),
|
|
73
|
+
], middleware=[auth_check])
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(self, router_cls, prefix: str, middleware: list = None):
|
|
77
|
+
self._router = router_cls
|
|
78
|
+
self._prefix = prefix
|
|
79
|
+
self._middleware = middleware or []
|
|
80
|
+
|
|
81
|
+
def get(self, path: str, handler, **options) -> RouteRef:
|
|
82
|
+
return self._router.add("GET", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
83
|
+
|
|
84
|
+
def post(self, path: str, handler, **options) -> RouteRef:
|
|
85
|
+
return self._router.add("POST", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
86
|
+
|
|
87
|
+
def put(self, path: str, handler, **options) -> RouteRef:
|
|
88
|
+
return self._router.add("PUT", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
89
|
+
|
|
90
|
+
def patch(self, path: str, handler, **options) -> RouteRef:
|
|
91
|
+
return self._router.add("PATCH", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
92
|
+
|
|
93
|
+
def delete(self, path: str, handler, **options) -> RouteRef:
|
|
94
|
+
return self._router.add("DELETE", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
95
|
+
|
|
96
|
+
def any(self, path: str, handler, **options) -> RouteRef:
|
|
97
|
+
return self._router.add("ANY", self._prefix + path, handler, middleware=self._middleware, **options)
|
|
98
|
+
|
|
99
|
+
def group(self, prefix: str, callback, middleware=None):
|
|
100
|
+
merged = list(self._middleware) + (middleware or [])
|
|
101
|
+
nested = RouteGroup(self._router, self._prefix + prefix.rstrip("/"), merged)
|
|
102
|
+
callback(nested)
|
|
103
|
+
|
|
104
|
+
|
|
60
105
|
class Router:
|
|
61
106
|
"""Route registry and matcher."""
|
|
62
107
|
|
|
@@ -68,14 +113,17 @@ class Router:
|
|
|
68
113
|
def group(cls, prefix: str, callback, middleware=None):
|
|
69
114
|
"""Register routes with a shared prefix and optional middleware.
|
|
70
115
|
|
|
71
|
-
|
|
72
|
-
|
|
116
|
+
The callback receives a RouteGroup object with get/post/put/patch/
|
|
117
|
+
delete/any/group methods for registering routes under the prefix.
|
|
73
118
|
|
|
74
119
|
Usage::
|
|
75
120
|
|
|
76
|
-
Router.group("/api", lambda: [
|
|
77
|
-
|
|
78
|
-
|
|
121
|
+
Router.group("/api", lambda group: [
|
|
122
|
+
group.get("/users", list_handler),
|
|
123
|
+
group.post("/users", create_handler),
|
|
124
|
+
group.group("/admin", lambda admin: [
|
|
125
|
+
admin.get("/stats", stats_handler),
|
|
126
|
+
], middleware=[admin_check]),
|
|
79
127
|
], middleware=[auth_check])
|
|
80
128
|
"""
|
|
81
129
|
prev_prefix = cls._group_prefix
|
|
@@ -85,7 +133,8 @@ class Router:
|
|
|
85
133
|
cls._group_middleware = prev_middleware + (middleware or [])
|
|
86
134
|
|
|
87
135
|
try:
|
|
88
|
-
|
|
136
|
+
group = RouteGroup(cls, cls._group_prefix, list(cls._group_middleware))
|
|
137
|
+
callback(group)
|
|
89
138
|
finally:
|
|
90
139
|
cls._group_prefix = prev_prefix
|
|
91
140
|
cls._group_middleware = prev_middleware
|
|
@@ -15,7 +15,7 @@ Discovers ORM models and registers CRUD routes automatically.
|
|
|
15
15
|
|
|
16
16
|
Generated endpoints per model:
|
|
17
17
|
|
|
18
|
-
GET /api/{table_name} — list with pagination (limit,
|
|
18
|
+
GET /api/{table_name} — list with pagination (limit, offset; also accepts page, per_page)
|
|
19
19
|
GET /api/{table_name}/{id} — get single record by primary key
|
|
20
20
|
POST /api/{table_name} — create new record
|
|
21
21
|
PUT /api/{table_name}/{id} — update record by primary key
|
|
@@ -94,18 +94,37 @@ class AutoCrud:
|
|
|
94
94
|
# ── GET /api/{table} — list with pagination ──────────────
|
|
95
95
|
async def list_handler(request, response, _cls=model_class):
|
|
96
96
|
try:
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
# Primary names: limit / offset
|
|
98
|
+
# Compat names: per_page / page (PHP/Ruby/Node style)
|
|
99
|
+
limit = int(request.params.get("limit", request.params.get("per_page", 10)))
|
|
100
|
+
offset = int(request.params.get("offset", 0))
|
|
101
|
+
# page/per_page compat: if page is provided, derive offset from it
|
|
102
|
+
if "page" in request.params and "offset" not in request.params:
|
|
103
|
+
page = int(request.params.get("page", 1))
|
|
104
|
+
per_page = int(request.params.get("per_page", limit))
|
|
105
|
+
offset = (page - 1) * per_page
|
|
106
|
+
limit = per_page
|
|
107
|
+
else:
|
|
108
|
+
page = (offset // limit) + 1 if limit else 1
|
|
99
109
|
except (ValueError, TypeError):
|
|
100
110
|
limit = 10
|
|
101
|
-
|
|
111
|
+
offset = 0
|
|
112
|
+
page = 1
|
|
102
113
|
|
|
103
|
-
records, total = _cls.all(limit=limit, skip=
|
|
114
|
+
records, total = _cls.all(limit=limit, skip=offset)
|
|
115
|
+
total_pages = max(1, -(-total // limit)) if limit else 1
|
|
116
|
+
data = [r.to_dict() for r in records]
|
|
104
117
|
return response({
|
|
105
|
-
"
|
|
106
|
-
"
|
|
118
|
+
"records": data, # standard name
|
|
119
|
+
"data": data, # backwards compat
|
|
120
|
+
"count": total, # standard name
|
|
121
|
+
"total": total, # backwards compat
|
|
107
122
|
"limit": limit,
|
|
108
|
-
"
|
|
123
|
+
"offset": offset,
|
|
124
|
+
"page": page,
|
|
125
|
+
"per_page": limit, # backwards compat
|
|
126
|
+
"totalPages": total_pages, # camelCase standard
|
|
127
|
+
"total_pages": total_pages, # backwards compat
|
|
109
128
|
})
|
|
110
129
|
|
|
111
130
|
list_handler.__name__ = f"autocrud_list_{table}"
|
|
@@ -33,16 +33,19 @@ class DatabaseResult:
|
|
|
33
33
|
|
|
34
34
|
def to_paginate(self, page: int = 1, per_page: int = 20) -> dict:
|
|
35
35
|
total_pages = max(1, -(-self.count // per_page)) # ceil division
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
offset = (page - 1) * per_page
|
|
37
|
+
data = self.records[offset:offset + per_page]
|
|
38
38
|
return {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
39
|
+
"records": data, # standard name
|
|
40
|
+
"data": data, # backwards compat (PHP/Ruby/Node)
|
|
41
|
+
"count": self.count, # standard name
|
|
42
|
+
"total": self.count, # backwards compat
|
|
43
|
+
"limit": per_page, # standard name
|
|
44
|
+
"offset": offset, # standard name
|
|
41
45
|
"page": page,
|
|
42
|
-
"per_page": per_page,
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"has_prev": page > 1,
|
|
46
|
+
"per_page": per_page, # backwards compat
|
|
47
|
+
"totalPages": total_pages, # camelCase standard
|
|
48
|
+
"total_pages": total_pages, # backwards compat
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
def column_info(self) -> list[dict]:
|
|
@@ -123,6 +123,14 @@ register_driver("sqlserver", MSSQLAdapter)
|
|
|
123
123
|
from tina4_python.database.firebird import FirebirdAdapter
|
|
124
124
|
register_driver("firebird", FirebirdAdapter)
|
|
125
125
|
|
|
126
|
+
# Register MongoDB (pymongo — optional)
|
|
127
|
+
try:
|
|
128
|
+
from tina4_python.database.mongodb import MongoDBAdapter
|
|
129
|
+
register_driver("mongodb", MongoDBAdapter)
|
|
130
|
+
register_driver("pymongo", MongoDBAdapter)
|
|
131
|
+
except ImportError:
|
|
132
|
+
pass
|
|
133
|
+
|
|
126
134
|
|
|
127
135
|
class Database:
|
|
128
136
|
"""Database connection manager.
|