tai-sql 0.8.2__tar.gz → 0.8.3__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 (229) hide show
  1. {tai_sql-0.8.2 → tai_sql-0.8.3}/PKG-INFO +1 -1
  2. {tai_sql-0.8.2 → tai_sql-0.8.3}/pyproject.toml +1 -1
  3. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/schemas/chatbot.py +69 -14
  4. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/README.md +11 -6
  5. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/plan/planner.py +19 -11
  6. {tai_sql-0.8.2 → tai_sql-0.8.3}/LICENSE +0 -0
  7. {tai_sql-0.8.2 → tai_sql-0.8.3}/README.md +0 -0
  8. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/__init__.py +0 -0
  9. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/__init__.py +0 -0
  10. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_backup/__init__.py +0 -0
  11. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_backup/main.py +0 -0
  12. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_deploy/__init__.py +0 -0
  13. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_deploy/config.py +0 -0
  14. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_deploy/local.py +0 -0
  15. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_deploy/main.py +0 -0
  16. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_deploy/workflow.py +0 -0
  17. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_feed/__init__.py +0 -0
  18. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_feed/main.py +0 -0
  19. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_generate/__init__.py +0 -0
  20. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_generate/funcs.py +0 -0
  21. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_generate/main.py +0 -0
  22. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_hash_migrate/__init__.py +0 -0
  23. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_hash_migrate/main.py +0 -0
  24. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_info/__init__.py +0 -0
  25. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_info/main.py +0 -0
  26. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_info/status.py +0 -0
  27. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_init/__init__.py +0 -0
  28. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_init/main.py +0 -0
  29. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_init/model.py +0 -0
  30. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_install/__init__.py +0 -0
  31. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_install/main.py +0 -0
  32. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_ping/__init__.py +0 -0
  33. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_ping/main.py +0 -0
  34. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_pull/__init__.py +0 -0
  35. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_pull/funcs.py +0 -0
  36. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_pull/main.py +0 -0
  37. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_restore/__init__.py +0 -0
  38. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_restore/main.py +0 -0
  39. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_rules/__init__.py +0 -0
  40. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_rules/main.py +0 -0
  41. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/__init__.py +0 -0
  42. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/model.py +0 -0
  43. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/new.py +0 -0
  44. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/schemas/__init__.py +0 -0
  45. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/schemas/auth.py +0 -0
  46. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/schemas/base.py +0 -0
  47. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/schemas/default.py +0 -0
  48. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/cmd_schema/set_default.py +0 -0
  49. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/prompts.py +0 -0
  50. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/__init__.py +0 -0
  51. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/connectivity.py +0 -0
  52. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/create.py +0 -0
  53. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/github/__init__.py +0 -0
  54. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/github/auth.py +0 -0
  55. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/github/client.py +0 -0
  56. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/commands/utils/github/models.py +0 -0
  57. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/errors.py +0 -0
  58. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/main.py +0 -0
  59. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/preamble.py +0 -0
  60. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/services/__init__.py +0 -0
  61. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/cli/services/backup.py +0 -0
  62. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/README.md +0 -0
  63. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/__init__.py +0 -0
  64. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/provider.py +0 -0
  65. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/recipe.py +0 -0
  66. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/session.py +0 -0
  67. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/connection/sources.py +0 -0
  68. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/crypto.py +0 -0
  69. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/__init__.py +0 -0
  70. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/base.py +0 -0
  71. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/bigquery.py +0 -0
  72. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/capabilities.py +0 -0
  73. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/mysql.py +0 -0
  74. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/postgresql.py +0 -0
  75. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/drivers/sqlserver.py +0 -0
  76. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/errors/README.md +0 -0
  77. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/errors/__init__.py +0 -0
  78. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/errors/collector.py +0 -0
  79. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/errors/render.py +0 -0
  80. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/errors/types.py +0 -0
  81. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/README.md +0 -0
  82. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/__init__.py +0 -0
  83. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/collect.py +0 -0
  84. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/executor.py +0 -0
  85. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/feeder.py +0 -0
  86. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/plan.py +0 -0
  87. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/presenter.py +0 -0
  88. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/records.py +0 -0
  89. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/feed/transform.py +0 -0
  90. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/__init__.py +0 -0
  91. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/base.py +0 -0
  92. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/README.md +0 -0
  93. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/__init__.py +0 -0
  94. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/assets/README.md +0 -0
  95. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/assets/cytoscape.min.js +0 -0
  96. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/builder.py +0 -0
  97. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/generator.py +0 -0
  98. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/graphviz_render.py +0 -0
  99. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/html_render.py +0 -0
  100. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/layout.py +0 -0
  101. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/model.py +0 -0
  102. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/templates/er.html.jinja2 +0 -0
  103. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/diagram/themes.py +0 -0
  104. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/__init__.py +0 -0
  105. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/calculated.py +0 -0
  106. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/context.py +0 -0
  107. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/base.py.jinja2 +0 -0
  108. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/domain/__init__.py.jinja2 +0 -0
  109. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/domain/dao.py.jinja2 +0 -0
  110. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/domain/dtos.py.jinja2 +0 -0
  111. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/domain/model.py.jinja2 +0 -0
  112. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/facade.py.jinja2 +0 -0
  113. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/aggregation.jinja2 +0 -0
  114. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/dataframe.jinja2 +0 -0
  115. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/filters.jinja2 +0 -0
  116. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/hierarchy.jinja2 +0 -0
  117. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/read.jinja2 +0 -0
  118. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/triggers.jinja2 +0 -0
  119. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/upsert.jinja2 +0 -0
  120. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/vector.jinja2 +0 -0
  121. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/macros/write.jinja2 +0 -0
  122. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/session.py.jinja2 +0 -0
  123. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/__init__.py.jinja2 +0 -0
  124. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/aggregation.py.jinja2 +0 -0
  125. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/binary.py.jinja2 +0 -0
  126. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/context.py.jinja2 +0 -0
  127. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/utils/__init__.py.jinja2 +0 -0
  128. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/utils/encoders.py.jinja2 +0 -0
  129. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/utils/funcs.py.jinja2 +0 -0
  130. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/utils/hierarchy.py.jinja2 +0 -0
  131. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/utils/rls.py.jinja2 +0 -0
  132. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/templates/shared/vector.py.jinja2 +0 -0
  133. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/__init__.py +0 -0
  134. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/analyzer.py +0 -0
  135. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/renderer.py +0 -0
  136. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/scopes.py +0 -0
  137. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/steps.py +0 -0
  138. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/python_client/triggers/transformer.py +0 -0
  139. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/rules/__init__.py +0 -0
  140. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/generators/rules/templates/schema.md.jinja2 +0 -0
  141. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/README.md +0 -0
  142. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/__init__.py +0 -0
  143. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/blueprint.py +0 -0
  144. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/build.py +0 -0
  145. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/defaults.py +0 -0
  146. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/naming.py +0 -0
  147. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/reader.py +0 -0
  148. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/templates/schema.py.jinja2 +0 -0
  149. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/types.py +0 -0
  150. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/introspect/writer.py +0 -0
  151. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/README.md +0 -0
  152. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/__init__.py +0 -0
  153. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/README.md +0 -0
  154. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/__init__.py +0 -0
  155. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/calculated.py +0 -0
  156. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/collector.py +0 -0
  157. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/column_analyzer.py +0 -0
  158. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/constraints.py +0 -0
  159. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/hints.py +0 -0
  160. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/relation_analyzer.py +0 -0
  161. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/analysis/schema_analyzer.py +0 -0
  162. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/README.md +0 -0
  163. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/__init__.py +0 -0
  164. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/annotations.py +0 -0
  165. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/base.py +0 -0
  166. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/calculated.py +0 -0
  167. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/columns.py +0 -0
  168. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/constraints.py +0 -0
  169. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/datasource.py +0 -0
  170. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/descriptors.py +0 -0
  171. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/encoders.py +0 -0
  172. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/enumerations.py +0 -0
  173. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/relations.py +0 -0
  174. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/table.py +0 -0
  175. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/trigger_api.py +0 -0
  176. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/triggers.py +0 -0
  177. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/declarative/view.py +0 -0
  178. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/mapping/README.md +0 -0
  179. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/mapping/__init__.py +0 -0
  180. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/mapping/sqlalchemy_mapper.py +0 -0
  181. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/README.md +0 -0
  182. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/__init__.py +0 -0
  183. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/column.py +0 -0
  184. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/constraints.py +0 -0
  185. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/entity.py +0 -0
  186. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/enumeration.py +0 -0
  187. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/relation.py +0 -0
  188. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/schema.py +0 -0
  189. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/model/trigger.py +0 -0
  190. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/naming.py +0 -0
  191. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/ordering.py +0 -0
  192. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/registry.py +0 -0
  193. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/orm/types.py +0 -0
  194. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/README.md +0 -0
  195. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/__init__.py +0 -0
  196. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/config.py +0 -0
  197. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/context.py +0 -0
  198. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/manager.py +0 -0
  199. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/project/paths.py +0 -0
  200. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/README.md +0 -0
  201. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/__init__.py +0 -0
  202. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/catalog.py +0 -0
  203. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/installer.py +0 -0
  204. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/meta.py +0 -0
  205. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/service.py +0 -0
  206. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/staleness.py +0 -0
  207. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/static/comandos.md +0 -0
  208. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/static/errores.md +0 -0
  209. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/rules/static/modelo.md +0 -0
  210. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/schema.py +0 -0
  211. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/__init__.py +0 -0
  212. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/diff/__init__.py +0 -0
  213. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/diff/constraints.py +0 -0
  214. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/diff/indexes.py +0 -0
  215. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/diff/tables.py +0 -0
  216. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/diff/views.py +0 -0
  217. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/executor.py +0 -0
  218. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/ownership.py +0 -0
  219. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/plan/__init__.py +0 -0
  220. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/plan/statements.py +0 -0
  221. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/presenter.py +0 -0
  222. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/report.py +0 -0
  223. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/safety.py +0 -0
  224. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/state/__init__.py +0 -0
  225. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/state/local.py +0 -0
  226. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/state/model.py +0 -0
  227. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/state/normalize.py +0 -0
  228. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/state/remote.py +0 -0
  229. {tai_sql-0.8.2 → tai_sql-0.8.3}/tai_sql/sync/synchronizer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tai-sql
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: SQL database management and code generation tool
5
5
  License-Expression: LicenseRef-Proprietary
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tai-sql"
3
- version = "0.8.2"
3
+ version = "0.8.3"
4
4
  description = "SQL database management and code generation tool"
5
5
  license = "LicenseRef-Proprietary"
6
6
  license-files = ["LICENSE"]
@@ -6,8 +6,8 @@ from .base import SchemaTemplate
6
6
 
7
7
 
8
8
  class ChatbotSchema(SchemaTemplate):
9
- """Plantilla chatbot: Chat, Mensaje, TokenUsage, TokenUsageParte, ToolCall, Sugerencia, Modelo, Tarifa, Bolsa,
10
- LimitePresupuesto y vistas"""
9
+ """Plantilla chatbot: Chat, Mensaje, TokenUsage, TokenUsageParte, ToolCall, Sugerencia, InformeConversacion, Modelo,
10
+ Tarifa, Bolsa, LimitePresupuesto y vistas"""
11
11
 
12
12
  def get_content(self) -> str:
13
13
  return dedent(f'''
@@ -57,7 +57,7 @@ class ChatbotSchema(SchemaTemplate):
57
57
 
58
58
  id: col[bigint] = column(primary_key=True, autoincrement=True, description='UUID del chat')
59
59
  title: col[str] = column(description='Título de la conversación')
60
- username: col[str] = column(description='ID del usuario propietario del chat')
60
+ username: col[str] = column(index=True, description='ID del usuario propietario del chat')
61
61
  is_active: col[bool] = column(default=True, description='Estado activo del chat')
62
62
 
63
63
  visible: col[bool] = column(default=True, index=True, description='Si no, la conversación no se lista')
@@ -70,6 +70,7 @@ class ChatbotSchema(SchemaTemplate):
70
70
 
71
71
  messages: onetomany[Mensaje] # Relación one-to-many con la tabla Mensaje
72
72
  token_usage: onetomany[TokenUsage] # El consumo de la conversación, tenga mensaje o no
73
+ informes: onetomany[InformeConversacion] # Sus informes: los resúmenes que se pidieron de ella
73
74
 
74
75
 
75
76
  class Feedback(Enum):
@@ -93,7 +94,7 @@ class ChatbotSchema(SchemaTemplate):
93
94
  content: col[str] = column(description='Contenido del mensaje')
94
95
  role: col[MessageRole] = column(description='Rol del mensaje (user, assistant, system)')
95
96
  timestamp: col[datetime] = column(default=datetime.now, description='Timestamp del mensaje')
96
- feedback: col[Feedback] = column(default=Feedback.GOOD, description='Feedback del mensaje')
97
+ feedback: col[Feedback | None] = column(description='La valoración del usuario (good o bad); vacía si no la valoró')
97
98
  feedback_comment: col[str | None] = column(description='Comentario adicional del feedback')
98
99
  reasoning: col[str | None] = column(description='Texto de razonamiento del agente antes de usar herramientas')
99
100
  agent_iterations: col[int] = column(default=0, description='Número de iteraciones del agente')
@@ -101,11 +102,12 @@ class ChatbotSchema(SchemaTemplate):
101
102
  model_name: col[str | None] = column(description='Modelo con el que se respondió')
102
103
  provider: col[str | None] = column(description='Proveedor del modelo con el que se respondió')
103
104
 
104
- chat_id: col[bigint] = column(description='ID del chat al que pertenece el mensaje')
105
+ chat_id: col[bigint] = column(index=True, description='ID del chat al que pertenece el mensaje')
105
106
 
106
107
  token_usage: onetomany[TokenUsage] # Relación one-to-many con la tabla TokenUsage
107
108
  tool_calls: onetomany[ToolCall] # Relación one-to-many con la tabla ToolCall
108
109
  sugerencias: onetomany[Sugerencia] # Lo que se sugiere preguntar tras esta respuesta
110
+ informes: onetomany[InformeConversacion] # El informe que entrega este mensaje de sistema
109
111
 
110
112
  chat: manytoone[Chat] = relation(fields=['chat_id'], references=['id'], backref='messages') # Relación many-to-one con Chat
111
113
 
@@ -123,10 +125,10 @@ class ChatbotSchema(SchemaTemplate):
123
125
  prompt_tokens: col[int] = column(default=0, description='Tokens consumidos en el prompt')
124
126
  completion_tokens: col[int] = column(default=0, description='Tokens consumidos en la respuesta')
125
127
  total_tokens: col[int] = column(default=0, description='Total de tokens consumidos')
126
- timestamp: col[datetime] = column(default=datetime.now, description='Timestamp del consumo')
128
+ timestamp: col[datetime] = column(default=datetime.now, index=True, description='Timestamp del consumo')
127
129
 
128
130
  username: col[str] = column(index=True, description='Usuario que consumió')
129
- message_id: col[bigint | None] = column(description='Mensaje que lo generó; vacío si se borró la conversación')
131
+ message_id: col[bigint | None] = column(index=True, description='Mensaje que lo generó; vacío si se borró la conversación')
130
132
  chat_id: col[bigint | None] = column(index=True, description='Conversación en la que se consumió; vacío si no es de ninguna')
131
133
 
132
134
  tarifa_id: col[bigint | None] = column(index=True, description='Tarifa con la que se valora')
@@ -150,6 +152,10 @@ class ChatbotSchema(SchemaTemplate):
150
152
  class ToolCall(Table):
151
153
  """Tabla que almacena las llamadas a herramientas realizadas por el agente durante la generación de respuestas"""
152
154
  __tablename__ = "tool_call"
155
+ # El call_id es único dentro de su mensaje (el del modelo, no el de la fila): así una llamada de
156
+ # un sub-agente puede apuntar a la que lo creó. El índice de esta restricción sirve también para
157
+ # buscar las llamadas de un mensaje, que empieza por message_id
158
+ __constraints__ = unique_constraint("message_id", "call_id")
153
159
 
154
160
  id: col[bigint] = column(primary_key=True, autoincrement=True, description='ID de la llamada a herramienta')
155
161
  tool_name: col[str] = column(description='Nombre de la herramienta invocada')
@@ -157,10 +163,18 @@ class ChatbotSchema(SchemaTemplate):
157
163
  tool_result: col[dict | None] = column(description='Resultado de la herramienta en formato JSON')
158
164
  duration_ms: col[int | None] = column(description='Duración de la ejecución en milisegundos')
159
165
  success: col[bool] = column(default=True, description='Si la llamada fue exitosa')
166
+ call_id: col[str | None] = column(description='El id de la llamada que hizo el modelo')
167
+ padre: col[str | None] = column(description='El call_id de la herramienta que creó el sub-agente que hizo esta llamada; vacío en las del agente principal')
160
168
  timestamp: col[datetime] = column(default=datetime.now, description='Timestamp de la llamada')
161
169
  message_id: col[bigint] = column(description='ID del mensaje asociado')
162
170
 
163
171
  message: manytoone[Mensaje] = relation(fields=['message_id'], references=['id'], backref='tool_calls') # Relación many-to-one con Mensaje
172
+ # La llamada que creó el sub-agente que hizo esta: del mismo mensaje, por la clave compuesta
173
+ # (message_id, padre) → (message_id, call_id). Por el id del modelo y no por el de la fila: las
174
+ # filas se crean anidadas en el mensaje, y el id de la del padre todavía no existe. Con padre
175
+ # vacío (las del agente principal) la clave no se comprueba. Borrar una se lleva sus hijas
176
+ llamada_padre: manytoone[ToolCall] = relation(fields=['message_id', 'padre'], references=['message_id', 'call_id'], backref='hijas', onDelete='cascade')
177
+ hijas: onetomany[ToolCall]
164
178
 
165
179
 
166
180
  class TokenUsageParte(Table):
@@ -191,6 +205,33 @@ class ChatbotSchema(SchemaTemplate):
191
205
  message: manytoone[Mensaje] = relation(fields=['message_id'], references=['id'], backref='sugerencias', onDelete='cascade')
192
206
 
193
207
 
208
+ class InformeConversacion(Table):
209
+ """Tabla con los informes de una conversación: su resumen, redactado por el modelo; se descarga en DOCX o en PDF"""
210
+ __tablename__ = "informe_conversacion"
211
+
212
+ id: col[bigint] = column(primary_key=True, autoincrement=True)
213
+ extension: col[str] = column(description="'corto', 'medio' o 'largo'")
214
+ indicaciones: col[str | None] = column(description='Lo que pidió quien lo pidió (centrarse en algo, las tablas…); vacío si nada. No sale en el documento')
215
+ estado: col[str] = column(index=True, description="'preparando', 'listo' o 'error'")
216
+ error: col[str | None] = column(description='Por qué no se pudo preparar')
217
+ titulo: col[str | None] = column(description='El título que le puso el modelo')
218
+ contenido: col[str | None] = column(description='El informe, en markdown: el documento se pinta al descargarlo')
219
+ hasta_mensaje_id: col[bigint | None] = column(description='El último mensaje que resume: con el mismo, se reutiliza sin llamar al modelo')
220
+ mensajes: col[int] = column(default=0, description='Cuántos mensajes resume')
221
+ compactado: col[bool] = column(default=False, description='Si la conversación no cabía y se resumió por tandas antes de redactarlo')
222
+ reutilizado_de: col[bigint | None] = column(description='El informe del que se copió el contenido, sin llamar al modelo')
223
+ model_name: col[str | None] = column(description='Modelo con el que se redactó')
224
+ provider: col[str | None] = column(description='Proveedor del modelo con el que se redactó')
225
+ timestamp: col[datetime] = column(default=datetime.now, description='Cuándo se pidió')
226
+ chat_id: col[bigint] = column(index=True, description='La conversación que resume')
227
+ message_id: col[bigint | None] = column(index=True, description='El mensaje de sistema que lo entrega; vacío mientras se prepara')
228
+
229
+ # `chat` y `message`, como en TokenUsage: los triggers en cascada comparan las relaciones
230
+ # por su nombre, y estos no repiten el de ningún padre
231
+ chat: manytoone[Chat] = relation(fields=['chat_id'], references=['id'], backref='informes', onDelete='cascade')
232
+ message: manytoone[Mensaje] = relation(fields=['message_id'], references=['id'], backref='informes', onDelete='set null')
233
+
234
+
194
235
  class Modelo(Table):
195
236
  """Tabla que almacena los modelos con los que puede responder el agente"""
196
237
  __tablename__ = "modelo"
@@ -278,6 +319,8 @@ class ChatbotSchema(SchemaTemplate):
278
319
  total_completion_tokens: col[int]
279
320
  total_tokens: col[int]
280
321
  total_cost_eur: col[float]
322
+ total_cache_read: col[int | None]
323
+ total_cache_write: col[int | None]
281
324
  chat_count: col[int]
282
325
  message_count: col[int]
283
326
 
@@ -295,6 +338,8 @@ class ChatbotSchema(SchemaTemplate):
295
338
  total_completion_tokens: col[int]
296
339
  total_tokens: col[int]
297
340
  coste_eur: col[float]
341
+ total_cache_read: col[int | None]
342
+ total_cache_write: col[int | None]
298
343
  message_count: col[int]
299
344
 
300
345
 
@@ -379,7 +424,7 @@ class ChatbotSchema(SchemaTemplate):
379
424
  content: col[str]
380
425
  # 'good' o 'bad'
381
426
  feedback: col[str]
382
- feedback_comment: col[str]
427
+ feedback_comment: col[str | None]
383
428
  total_duration_ms: col[int | None]
384
429
  model_name: col[str | None]
385
430
  chat_id: col[bigint]
@@ -517,6 +562,10 @@ class ChatbotSchema(SchemaTemplate):
517
562
  + COALESCE(tu.cache_write, 0) * (COALESCE(t.precio_cache_write_eur_millon, t.precio_input_eur_millon) - t.precio_input_eur_millon)
518
563
  + tu.completion_tokens * t.precio_output_eur_millon)
519
564
  * t.margen / 1000000)::numeric, 8))::double precision as total_cost_eur,
565
+ -- Lo leído de la caché del proveedor y lo escrito en ella: parte de la entrada. Sin COALESCE: un
566
+ -- día o un mes sin ningún apunte que lo diga (anteriores a apuntarlo) queda vacío, no a 0
567
+ SUM(tu.cache_read) as total_cache_read,
568
+ SUM(tu.cache_write) as total_cache_write,
520
569
  COUNT(DISTINCT COALESCE(tu.chat_id, me.chat_id)) as chat_count
521
570
  FROM token_usage tu
522
571
  JOIN tarifa t ON t.id = tu.tarifa_id
@@ -557,6 +606,8 @@ class ChatbotSchema(SchemaTemplate):
557
606
  COALESCE(co.total_completion_tokens, 0) as total_completion_tokens,
558
607
  COALESCE(co.total_tokens, 0) as total_tokens,
559
608
  COALESCE(co.total_cost_eur, 0) as total_cost_eur,
609
+ co.total_cache_read,
610
+ co.total_cache_write,
560
611
  COALESCE(co.chat_count, 0) as chat_count,
561
612
  COALESCE(e.message_count, 0) as message_count
562
613
  FROM consumo co
@@ -586,7 +637,11 @@ class ChatbotSchema(SchemaTemplate):
586
637
  + COALESCE(tu.cache_read, 0) * (COALESCE(t.precio_cache_input_eur_millon, t.precio_input_eur_millon) - t.precio_input_eur_millon)
587
638
  + COALESCE(tu.cache_write, 0) * (COALESCE(t.precio_cache_write_eur_millon, t.precio_input_eur_millon) - t.precio_input_eur_millon)
588
639
  + tu.completion_tokens * t.precio_output_eur_millon)
589
- * t.margen / 1000000)::numeric, 8))::double precision as coste_eur
640
+ * t.margen / 1000000)::numeric, 8))::double precision as coste_eur,
641
+ -- Lo leído de la caché del proveedor y lo escrito en ella: parte de la entrada. Sin COALESCE: un
642
+ -- día o un mes sin ningún apunte que lo diga (anteriores a apuntarlo) queda vacío, no a 0
643
+ SUM(tu.cache_read) as total_cache_read,
644
+ SUM(tu.cache_write) as total_cache_write
590
645
  FROM token_usage tu
591
646
  JOIN tarifa t ON t.id = tu.tarifa_id
592
647
  JOIN modelo m ON m.id = t.modelo_id
@@ -625,6 +680,8 @@ class ChatbotSchema(SchemaTemplate):
625
680
  COALESCE(co.total_completion_tokens, 0) as total_completion_tokens,
626
681
  COALESCE(co.total_tokens, 0) as total_tokens,
627
682
  COALESCE(co.coste_eur, 0) as coste_eur,
683
+ co.total_cache_read,
684
+ co.total_cache_write,
628
685
  COALESCE(e.message_count, 0) as message_count
629
686
  FROM consumo co
630
687
  FULL JOIN enviados e
@@ -716,9 +773,8 @@ class ChatbotSchema(SchemaTemplate):
716
773
  ''').rstrip()
717
774
 
718
775
  valoracion_sql = dedent('''\
719
- -- Vista con las respuestas que el usuario valoró con un comentario, con su conversación
720
- -- y lo que se apuntó con ellas. Solo las que tienen comentario: la columna feedback nace
721
- -- 'good', así que una valoración sin texto no se distingue de un mensaje sin valorar
776
+ -- Vista con las respuestas que el usuario valoró (con comentario o sin él), con su
777
+ -- conversación y lo que se apuntó con ellas. Un mensaje sin valorar tiene feedback vacío
722
778
  SELECT
723
779
  m.id as message_id,
724
780
  m.timestamp,
@@ -734,8 +790,7 @@ class ChatbotSchema(SchemaTemplate):
734
790
  FROM mensaje m
735
791
  JOIN chat c ON c.id = m.chat_id
736
792
  WHERE m.role = 'asistente'
737
- AND m.feedback_comment IS NOT NULL
738
- AND trim(m.feedback_comment) <> ''
793
+ AND m.feedback IS NOT NULL
739
794
  ORDER BY m.timestamp DESC;
740
795
  ''').rstrip()
741
796
 
@@ -94,18 +94,23 @@ En [plan/planner.py](tai_sql/sync/plan/planner.py), y es:
94
94
  4. DROP FK .............. las que el schema ya no declara
95
95
  5. DROP FK .............. las que rompe un cambio de tipo
96
96
  6. columnas ............. ADD / DROP / ALTER
97
- 7. ADD FK ............... de tablas nuevas y de tablas existentes
98
- 8. ALTER FK ............. cambio de acción en cascada
99
- 9. ADD FK ............... recreación tras el cambio de tipo
100
- 10. DROP CONSTRAINT UNIQUE antes del cambio de PK, que puede necesitar sus columnas
101
- 11. ALTER PRIMARY KEY .... DROP de la vieja + ADD de la nueva
102
- 12. ADD CONSTRAINT UNIQUE
97
+ 7. DROP CONSTRAINT UNIQUE antes del cambio de PK, que puede necesitar sus columnas
98
+ 8. ALTER PRIMARY KEY .... DROP de la vieja + ADD de la nueva
99
+ 9. ADD CONSTRAINT UNIQUE
100
+ 10. ADD FK ............... de tablas nuevas y de tablas existentes
101
+ 11. ALTER FK ............. cambio de acción en cascada
102
+ 12. ADD FK ............... recreación tras el cambio de tipo
103
103
  13. DROP INDEX ........... solo los que creó tai-sql
104
104
  14. CREATE INDEX ......... de tablas nuevas y de tablas existentes
105
105
  15. redefinir vista ...... en orden de dependencias
106
106
  16. CREATE VIEW .......... en orden de dependencias
107
107
  ```
108
108
 
109
+ La unicidad y la clave primaria van antes de las FKs: una FK solo se crea hacia columnas con una
110
+ restricción única o la clave primaria, y una FK hacia una restricción nueva del mismo push (una FK
111
+ compuesta a la propia tabla) fallaba por llegar antes. En una tabla nueva no pasaba, porque la
112
+ UNIQUE va dentro del `CREATE TABLE`.
113
+
109
114
  Antes el orden real no era el documentado: la generación del `CREATE TABLE` invocaba a la de
110
115
  claves foráneas en su última línea, así que las FKs de las tablas nuevas quedaban antes de los
111
116
  DROP y de los ALTER.
@@ -19,17 +19,24 @@ El orden es:
19
19
  4. DROP FK ...................... las que el schema ya no declara
20
20
  5. DROP FK ...................... las que rompe un cambio de tipo
21
21
  6. columnas ..................... ADD / DROP / ALTER
22
- 7. ADD FK ....................... de tablas nuevas y de tablas existentes
23
- 8. ALTER FK ..................... cambio de acción en cascada
24
- 9. ADD FK ....................... recreación tras el cambio de tipo
25
- 10. DROP CONSTRAINT UNIQUE ....... antes del cambio de PK, que puede necesitar sus columnas
26
- 11. ALTER PRIMARY KEY ............ DROP de la vieja + ADD de la nueva
27
- 12. ADD CONSTRAINT UNIQUE
22
+ 7. DROP CONSTRAINT UNIQUE ....... antes del cambio de PK, que puede necesitar sus columnas
23
+ 8. ALTER PRIMARY KEY ............ DROP de la vieja + ADD de la nueva
24
+ 9. ADD CONSTRAINT UNIQUE
25
+ 10. ADD FK ....................... de tablas nuevas y de tablas existentes
26
+ 11. ALTER FK ..................... cambio de acción en cascada
27
+ 12. ADD FK ....................... recreación tras el cambio de tipo
28
28
  13. DROP INDEX ................... solo los que creó tai-sql
29
29
  14. CREATE INDEX ................. de tablas nuevas y de tablas existentes
30
30
  15. redefinir vista ............. en orden de dependencias
31
31
  16. CREATE VIEW ................. en orden de dependencias
32
32
 
33
+ La unicidad y la clave primaria van **antes** de las FKs: una FK solo se puede crear hacia
34
+ columnas con una restricción única o la clave primaria, y si esa restricción es nueva en el
35
+ mismo push —una FK compuesta a la propia tabla, como `(message_id, padre)` →
36
+ `(message_id, call_id)`— la FK fallaba por llegar antes («there is no unique constraint
37
+ matching given keys»). En una tabla nueva no pasaba: la UNIQUE va dentro del CREATE TABLE.
38
+ Lo que esos pasos quitan ya no tiene FKs que lo usen: las sueltan los pasos 4 y 5.
39
+
33
40
  El planner **no toca la base de datos**. Lo único que hace es pedirle al driver el texto de
34
41
  cada sentencia; las vistas dependientes que hay que soltar se las dan ya leídas.
35
42
  """
@@ -104,12 +111,13 @@ class DDLPlanner:
104
111
  statements.extend(self._drop_foreign_keys(report))
105
112
  statements.extend(self._drop_foreign_keys_for_type_change(report))
106
113
  statements.extend(self._column_changes(report))
107
- statements.extend(self._add_foreign_keys(report))
108
- statements.extend(self._alter_foreign_keys(report))
109
- statements.extend(self._recreate_foreign_keys_for_type_change(report))
114
+ # Lo que una FK puede necesitar: la unicidad y la clave primaria, antes que ellas
110
115
  statements.extend(self._drop_unique_constraints(report))
111
116
  statements.extend(self._alter_primary_keys(report))
112
117
  statements.extend(self._add_unique_constraints(report))
118
+ statements.extend(self._add_foreign_keys(report))
119
+ statements.extend(self._alter_foreign_keys(report))
120
+ statements.extend(self._recreate_foreign_keys_for_type_change(report))
113
121
  statements.extend(self._drop_indexes(report))
114
122
  statements.extend(self._create_indexes(report))
115
123
  statements.extend(self._alter_views(report))
@@ -222,7 +230,7 @@ class DDLPlanner:
222
230
 
223
231
  return statements
224
232
 
225
- # ── 7, 8 y 9. ADD y ALTER de claves foráneas ─────────────────────────
233
+ # ── 10, 11 y 12. ADD y ALTER de claves foráneas ──────────────────────
226
234
 
227
235
  def _add_foreign_keys(self, report: DriftReport) -> list[Statement]:
228
236
  """
@@ -282,7 +290,7 @@ class DDLPlanner:
282
290
  no_defer=no_defer,
283
291
  )
284
292
 
285
- # ── 10, 11 y 12. Unicidad y clave primaria ───────────────────────────
293
+ # ── 7, 8 y 9. Unicidad y clave primaria ──────────────────────────────
286
294
 
287
295
  def _drop_unique_constraints(self, report: DriftReport) -> list[Statement]:
288
296
  """
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes