tina4-python 3.13.124__tar.gz → 3.13.125__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.
Files changed (170) hide show
  1. {tina4_python-3.13.124 → tina4_python-3.13.125}/PKG-INFO +1 -1
  2. {tina4_python-3.13.124 → tina4_python-3.13.125}/pyproject.toml +1 -1
  3. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/__init__.py +1 -1
  4. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/cli/__init__.py +4 -4
  5. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/firebird.py +1 -0
  6. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/mssql.py +1 -0
  7. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/mysql.py +1 -0
  8. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/sql_translator.py +43 -0
  9. {tina4_python-3.13.124 → tina4_python-3.13.125}/.gitignore +0 -0
  10. {tina4_python-3.13.124 → tina4_python-3.13.125}/README.md +0 -0
  11. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/CLAUDE.md +0 -0
  12. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/HtmlElement.py +0 -0
  13. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/Testing.py +0 -0
  14. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/_import_helper.py +0 -0
  15. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/ai/__init__.py +0 -0
  16. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/ai/client.py +0 -0
  17. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/api/__init__.py +0 -0
  18. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/auth/__init__.py +0 -0
  19. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/cache/__init__.py +0 -0
  20. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/container/__init__.py +0 -0
  21. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/context/__init__.py +0 -0
  22. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/context/chunker.py +0 -0
  23. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/__init__.py +0 -0
  24. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/cache.py +0 -0
  25. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/constants.py +0 -0
  26. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/events.py +0 -0
  27. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/middleware.py +0 -0
  28. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/port_takeover.py +0 -0
  29. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/rate_limiter.py +0 -0
  30. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/request.py +0 -0
  31. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/response.py +0 -0
  32. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/router.py +0 -0
  33. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/core/server.py +0 -0
  34. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/crud/__init__.py +0 -0
  35. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/__init__.py +0 -0
  36. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/adapter.py +0 -0
  37. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/connection.py +0 -0
  38. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/database_url.py +0 -0
  39. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/mongodb.py +0 -0
  40. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/odbc.py +0 -0
  41. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/postgres.py +0 -0
  42. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/database/sqlite.py +0 -0
  43. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/debug/__init__.py +0 -0
  44. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/debug/error_overlay.py +0 -0
  45. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/dev_admin/__init__.py +0 -0
  46. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/dev_admin/metrics.py +0 -0
  47. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/dev_admin/plan.py +0 -0
  48. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/dev_admin/project_index.py +0 -0
  49. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/docs.py +0 -0
  50. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/docstore/__init__.py +0 -0
  51. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/dotenv/__init__.py +0 -0
  52. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/env.py +0 -0
  53. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/frond/FROND.md +0 -0
  54. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/frond/__init__.py +0 -0
  55. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/frond/compiler.py +0 -0
  56. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/frond/engine.py +0 -0
  57. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/frond/parser.py +0 -0
  58. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/auth/meta.json +0 -0
  59. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
  60. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/database/meta.json +0 -0
  61. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
  62. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/error-overlay/meta.json +0 -0
  63. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
  64. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/orm/meta.json +0 -0
  65. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
  66. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
  67. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/queue/meta.json +0 -0
  68. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
  69. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/rest-api/meta.json +0 -0
  70. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
  71. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/templates/meta.json +0 -0
  72. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
  73. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
  74. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/__init__.py +0 -0
  75. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/adapter.py +0 -0
  76. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/adapters/__init__.py +0 -0
  77. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/adapters/arango.py +0 -0
  78. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/adapters/bolt.py +0 -0
  79. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/adapters/ultipa.py +0 -0
  80. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graph/graph_url.py +0 -0
  81. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/graphql/__init__.py +0 -0
  82. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/i18n/__init__.py +0 -0
  83. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/mcp/__init__.py +0 -0
  84. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/mcp/protocol.py +0 -0
  85. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/mcp/tools.py +0 -0
  86. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/messenger/__init__.py +0 -0
  87. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/migration/__init__.py +0 -0
  88. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/migration/runner.py +0 -0
  89. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/mqtt/__init__.py +0 -0
  90. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/mqtt/message.py +0 -0
  91. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/orm/__init__.py +0 -0
  92. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/orm/fields.py +0 -0
  93. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/orm/model.py +0 -0
  94. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/orm/point.py +0 -0
  95. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/__feedback/widget.js +0 -0
  96. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/css/tina4.css +0 -0
  97. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/css/tina4.min.css +0 -0
  98. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/favicon.ico +0 -0
  99. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/images/logo.svg +0 -0
  100. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
  101. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/js/frond.js +0 -0
  102. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/js/frond.min.js +0 -0
  103. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
  104. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/js/tina4.min.js +0 -0
  105. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/js/tina4js.min.js +0 -0
  106. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/swagger/index.html +0 -0
  107. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
  108. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/query_builder/__init__.py +0 -0
  109. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/__init__.py +0 -0
  110. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/amqp_url.py +0 -0
  111. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/job.py +0 -0
  112. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/kafka_backend.py +0 -0
  113. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/lite_backend.py +0 -0
  114. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/mongo_backend.py +0 -0
  115. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue/rabbitmq_backend.py +0 -0
  116. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue_backends/__init__.py +0 -0
  117. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue_backends/kafka_backend.py +0 -0
  118. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue_backends/mongo_backend.py +0 -0
  119. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
  120. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/__init__.py +0 -0
  121. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/Attachment.py +0 -0
  122. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/Channel.py +0 -0
  123. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/ChannelMember.py +0 -0
  124. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/Message.py +0 -0
  125. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/Workspace.py +0 -0
  126. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/models/__init__.py +0 -0
  127. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/realtime/storage.py +0 -0
  128. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/seeder/__init__.py +0 -0
  129. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/service/__init__.py +0 -0
  130. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session/__init__.py +0 -0
  131. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session_handlers/__init__.py +0 -0
  132. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session_handlers/memcached_handler.py +0 -0
  133. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session_handlers/mongodb_handler.py +0 -0
  134. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session_handlers/redis_handler.py +0 -0
  135. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/session_handlers/valkey_handler.py +0 -0
  136. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/sso.py +0 -0
  137. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/swagger/__init__.py +0 -0
  138. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/components/crud.twig +0 -0
  139. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
  140. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
  141. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/docker/python/Dockerfile +0 -0
  142. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/docker/uv/Dockerfile +0 -0
  143. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/302.twig +0 -0
  144. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/401.twig +0 -0
  145. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/403.twig +0 -0
  146. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/404.twig +0 -0
  147. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/500.twig +0 -0
  148. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/502.twig +0 -0
  149. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/503.twig +0 -0
  150. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/errors/base.twig +0 -0
  151. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/frontend/README.md +0 -0
  152. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/templates/readme.md +0 -0
  153. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/test/__init__.py +0 -0
  154. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/test_client/__init__.py +0 -0
  155. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
  156. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
  157. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
  158. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
  159. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
  160. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
  161. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
  162. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
  163. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
  164. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
  165. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
  166. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
  167. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/validator/__init__.py +0 -0
  168. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/websocket/__init__.py +0 -0
  169. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/websocket/backplane.py +0 -0
  170. {tina4_python-3.13.124 → tina4_python-3.13.125}/tina4_python/wsdl/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tina4-python
3
- Version: 3.13.124
3
+ Version: 3.13.125
4
4
  Summary: Tina4 Python v3 — Zero-dependency, lightweight web framework
5
5
  Author-email: Andre van Zuydam <andrevanzuydam@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tina4-python"
3
- version = "3.13.124"
3
+ version = "3.13.125"
4
4
  description = "Tina4 Python v3 — Zero-dependency, lightweight web framework"
5
5
  authors = [
6
6
  {name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"}
@@ -51,7 +51,7 @@ def _resolve_version() -> str:
51
51
  #
52
52
  # test_version_constant.py now asserts this literal equals the pyproject
53
53
  # version, so the release bump cannot leave it behind again.
54
- return "3.13.124"
54
+ return "3.13.125"
55
55
 
56
56
 
57
57
  __version__ = _resolve_version()
@@ -31,8 +31,8 @@ from pathlib import Path
31
31
 
32
32
  # ── Field type mapping ────────────────────────────────────────────────
33
33
  FIELD_TYPE_MAP = {
34
- "string": {"orm": "StringField", "sql": "TEXT", "default": "''"},
35
- "str": {"orm": "StringField", "sql": "TEXT", "default": "''"},
34
+ "string": {"orm": "StringField", "sql": "VARCHAR(255)", "default": "''"},
35
+ "str": {"orm": "StringField", "sql": "VARCHAR(255)", "default": "''"},
36
36
  "int": {"orm": "IntegerField", "sql": "INTEGER", "default": "0"},
37
37
  "integer": {"orm": "IntegerField", "sql": "INTEGER", "default": "0"},
38
38
  "float": {"orm": "NumericField", "sql": "REAL", "default": "0"},
@@ -41,7 +41,7 @@ FIELD_TYPE_MAP = {
41
41
  "bool": {"orm": "BooleanField", "sql": "INTEGER", "default": "0"},
42
42
  "boolean": {"orm": "BooleanField", "sql": "INTEGER", "default": "0"},
43
43
  "text": {"orm": "TextField", "sql": "TEXT", "default": "''"},
44
- "datetime": {"orm": "DateTimeField", "sql": "TEXT", "default": "NULL"},
44
+ "datetime": {"orm": "DateTimeField", "sql": "TIMESTAMP", "default": "NULL"},
45
45
  "blob": {"orm": "BlobField", "sql": "BLOB", "default": "NULL"},
46
46
  }
47
47
 
@@ -1941,7 +1941,7 @@ def _gen_migration(name: str, flags: dict = None, *,
1941
1941
  info = FIELD_TYPE_MAP.get(ftype, FIELD_TYPE_MAP["string"])
1942
1942
  default = f" DEFAULT {info['default']}" if info["default"] != "NULL" else ""
1943
1943
  col_lines.append(f" {fname} {info['sql']}{default}")
1944
- col_lines.append(" created_at TEXT DEFAULT CURRENT_TIMESTAMP")
1944
+ col_lines.append(" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
1945
1945
 
1946
1946
  # ADR-0063: `tina4:edit` marker between the last column and the closing
1947
1947
  # paren, placed OUTSIDE the comma-joined column list so the SQL stays
@@ -646,6 +646,7 @@ class FirebirdAdapter(SqlCrudMixin, DatabaseAdapter):
646
646
  sql = SQLTranslator.ilike_to_like(sql)
647
647
  sql = SQLTranslator.boolean_to_int(sql)
648
648
  sql = SQLTranslator.auto_increment_syntax(sql, "firebird")
649
+ sql = SQLTranslator.ddl_types(sql, "firebird")
649
650
  return sql
650
651
 
651
652
  def _supports_returning(self) -> bool:
@@ -350,6 +350,7 @@ class MSSQLAdapter(SqlCrudMixin, DatabaseAdapter):
350
350
  sql = SQLTranslator.ilike_to_like(sql)
351
351
  sql = SQLTranslator.auto_increment_syntax(sql, "mssql")
352
352
  sql = SQLTranslator.boolean_to_int(sql)
353
+ sql = SQLTranslator.ddl_types(sql, "mssql")
353
354
  return sql
354
355
 
355
356
  def _supports_returning(self) -> bool:
@@ -321,6 +321,7 @@ class MySQLAdapter(SqlCrudMixin, DatabaseAdapter):
321
321
  sql = SQLTranslator.concat_pipes_to_func(sql)
322
322
  sql = SQLTranslator.ilike_to_like(sql)
323
323
  sql = SQLTranslator.auto_increment_syntax(sql, "mysql")
324
+ sql = SQLTranslator.ddl_types(sql, "mysql")
324
325
  return sql
325
326
 
326
327
  def _supports_returning(self) -> bool:
@@ -347,6 +347,49 @@ class SQLTranslator:
347
347
  return re.sub(r"\s*AUTOINCREMENT\b", "", sql, flags=re.IGNORECASE)
348
348
  return sql
349
349
 
350
+ @staticmethod
351
+ def ddl_types(sql: str, engine: str) -> str:
352
+ """Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to
353
+ the target engine.
354
+
355
+ ONLY acts on ``CREATE TABLE`` / ``ALTER TABLE`` statements, so a query or
356
+ INSERT that happens to contain the word ``TEXT`` (a column name, a string
357
+ literal) is never rewritten. Complements ``auto_increment_syntax`` (which
358
+ maps the id keyword) so ONE portable migration — and every
359
+ ``ORM.create_table()`` DDL, which is also SQLite-canonical — applies on
360
+ every engine instead of failing on Firebird/MSSQL.
361
+
362
+ * Firebird has no ``TEXT`` (-607), no ``REAL``, and no
363
+ ``CREATE TABLE IF NOT EXISTS``.
364
+ * MSSQL has no ``CREATE TABLE IF NOT EXISTS`` and its ``TIMESTAMP`` is a
365
+ rowversion, not a datetime — a ``created_at TIMESTAMP`` there is wrong.
366
+ * MySQL's ``TIMESTAMP`` carries auto-update / 2038 surprises, so a
367
+ datetime column maps to ``DATETIME`` (matching ORM.create_table()).
368
+ """
369
+ # Gate to DDL only, tolerating leading `-- ...` comment lines / blank
370
+ # lines that a migration file carries before its CREATE TABLE. A SELECT
371
+ # or INSERT that merely mentions a type keyword is never rewritten.
372
+ head = re.sub(r"^(?:\s*--[^\n]*\n)+", "", sql)
373
+ if not re.match(r"\s*(CREATE\s+TABLE|ALTER\s+TABLE)\b", head, re.IGNORECASE):
374
+ return sql
375
+ e = (engine or "").lower()
376
+ if e == "firebird":
377
+ sql = re.sub(r"\bIF\s+NOT\s+EXISTS\b", "", sql, flags=re.IGNORECASE)
378
+ # Map bare TEXT -> BLOB SUB_TYPE TEXT, but leave an existing
379
+ # "BLOB SUB_TYPE TEXT" intact (it already contains the word TEXT).
380
+ sql = re.sub(
381
+ r"\bBLOB\s+SUB_TYPE\s+TEXT\b", "\x00FBTEXT\x00", sql, flags=re.IGNORECASE
382
+ )
383
+ sql = re.sub(r"\bTEXT\b", "BLOB SUB_TYPE TEXT", sql, flags=re.IGNORECASE)
384
+ sql = sql.replace("\x00FBTEXT\x00", "BLOB SUB_TYPE TEXT")
385
+ sql = re.sub(r"\bREAL\b", "DOUBLE PRECISION", sql, flags=re.IGNORECASE)
386
+ elif e == "mssql":
387
+ sql = re.sub(r"\bIF\s+NOT\s+EXISTS\b", "", sql, flags=re.IGNORECASE)
388
+ sql = re.sub(r"\bTIMESTAMP\b", "DATETIME2", sql, flags=re.IGNORECASE)
389
+ elif e == "mysql":
390
+ sql = re.sub(r"\bTIMESTAMP\b", "DATETIME", sql, flags=re.IGNORECASE)
391
+ return sql
392
+
350
393
  @staticmethod
351
394
  def placeholder_style(sql: str, style: str = "?") -> str:
352
395
  """Convert ? placeholders to engine-specific style.