tai-sql 0.6.37__tar.gz → 0.7.0__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.
- tai_sql-0.7.0/PKG-INFO +254 -0
- tai_sql-0.7.0/README.md +193 -0
- tai_sql-0.7.0/pyproject.toml +171 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/__init__.py +17 -4
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/__init__.py +4 -2
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_backup/main.py +28 -11
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_deploy/config.py +1 -1
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_deploy/local.py +193 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_feed/main.py +152 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_generate/funcs.py +70 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_generate/main.py +21 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_info/main.py +18 -7
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_init/main.py +12 -2
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_init/model.py +53 -8
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_install/main.py +104 -52
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_ping/main.py +63 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_pull/__init__.py +3 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_pull/funcs.py +232 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_pull/main.py +157 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_restore/main.py +59 -21
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_rules/__init__.py +3 -0
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_rules/main.py +250 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/model.py +10 -2
- tai_sql-0.7.0/tai_sql/cli/commands/cmd_schema/new.py +37 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/schemas/auth.py +9 -6
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/schemas/chatbot.py +1 -1
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/schemas/default.py +1 -1
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/set_default.py +32 -28
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/connectivity.py +25 -17
- tai_sql-0.7.0/tai_sql/cli/commands/utils/create.py +125 -0
- tai_sql-0.7.0/tai_sql/cli/errors.py +131 -0
- tai_sql-0.7.0/tai_sql/cli/main.py +66 -0
- tai_sql-0.7.0/tai_sql/cli/preamble.py +121 -0
- tai_sql-0.7.0/tai_sql/cli/services/__init__.py +20 -0
- tai_sql-0.7.0/tai_sql/connection/README.md +125 -0
- tai_sql-0.7.0/tai_sql/connection/__init__.py +39 -0
- {tai_sql-0.6.37/tai_sql/core → tai_sql-0.7.0/tai_sql/connection}/provider.py +175 -118
- tai_sql-0.7.0/tai_sql/connection/recipe.py +153 -0
- tai_sql-0.7.0/tai_sql/connection/session.py +101 -0
- tai_sql-0.7.0/tai_sql/connection/sources.py +110 -0
- tai_sql-0.7.0/tai_sql/crypto.py +61 -0
- tai_sql-0.7.0/tai_sql/drivers/__init__.py +35 -0
- tai_sql-0.7.0/tai_sql/drivers/base.py +1518 -0
- tai_sql-0.7.0/tai_sql/drivers/bigquery.py +703 -0
- tai_sql-0.7.0/tai_sql/drivers/capabilities.py +52 -0
- tai_sql-0.7.0/tai_sql/drivers/mysql.py +435 -0
- tai_sql-0.7.0/tai_sql/drivers/postgresql.py +672 -0
- tai_sql-0.7.0/tai_sql/drivers/sqlserver.py +467 -0
- tai_sql-0.7.0/tai_sql/errors/README.md +139 -0
- tai_sql-0.7.0/tai_sql/errors/__init__.py +45 -0
- tai_sql-0.7.0/tai_sql/errors/collector.py +131 -0
- tai_sql-0.7.0/tai_sql/errors/render.py +245 -0
- tai_sql-0.7.0/tai_sql/errors/types.py +192 -0
- tai_sql-0.7.0/tai_sql/feed/README.md +138 -0
- tai_sql-0.7.0/tai_sql/feed/__init__.py +34 -0
- tai_sql-0.7.0/tai_sql/feed/collect.py +289 -0
- tai_sql-0.7.0/tai_sql/feed/executor.py +402 -0
- tai_sql-0.7.0/tai_sql/feed/feeder.py +208 -0
- tai_sql-0.7.0/tai_sql/feed/plan.py +127 -0
- tai_sql-0.7.0/tai_sql/feed/presenter.py +103 -0
- tai_sql-0.7.0/tai_sql/feed/records.py +145 -0
- tai_sql-0.7.0/tai_sql/feed/transform.py +162 -0
- tai_sql-0.7.0/tai_sql/generators/base.py +181 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/README.md +120 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/__init__.py +93 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/assets/README.md +26 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/assets/cytoscape.min.js +32 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/builder.py +306 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/generator.py +361 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/graphviz_render.py +545 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/html_render.py +221 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/layout.py +150 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/model.py +251 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/templates/er.html.jinja2 +1356 -0
- tai_sql-0.7.0/tai_sql/generators/diagram/themes.py +191 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/__init__.py +109 -72
- tai_sql-0.7.0/tai_sql/generators/python_client/calculated.py +197 -0
- tai_sql-0.7.0/tai_sql/generators/python_client/context.py +499 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/domain/dao.py.jinja2 +13 -9
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/domain/dtos.py.jinja2 +28 -13
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/domain/model.py.jinja2 +33 -4
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/facade.py.jinja2 +2 -2
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/dataframe.jinja2 +9 -47
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/read.jinja2 +15 -6
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/upsert.jinja2 +54 -22
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/vector.jinja2 +20 -11
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/write.jinja2 +45 -11
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/session.py.jinja2 +69 -58
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/utils/rls.py.jinja2 +32 -8
- tai_sql-0.7.0/tai_sql/generators/python_client/triggers/__init__.py +32 -0
- tai_sql-0.7.0/tai_sql/generators/python_client/triggers/analyzer.py +236 -0
- tai_sql-0.7.0/tai_sql/generators/python_client/triggers/renderer.py +204 -0
- tai_sql-0.7.0/tai_sql/generators/python_client/triggers/steps.py +76 -0
- tai_sql-0.7.0/tai_sql/generators/python_client/triggers/transformer.py +688 -0
- tai_sql-0.7.0/tai_sql/generators/rules/__init__.py +389 -0
- tai_sql-0.7.0/tai_sql/generators/rules/templates/schema.md.jinja2 +154 -0
- tai_sql-0.7.0/tai_sql/introspect/README.md +116 -0
- tai_sql-0.7.0/tai_sql/introspect/__init__.py +60 -0
- tai_sql-0.7.0/tai_sql/introspect/blueprint.py +265 -0
- tai_sql-0.7.0/tai_sql/introspect/build.py +712 -0
- tai_sql-0.7.0/tai_sql/introspect/defaults.py +142 -0
- tai_sql-0.7.0/tai_sql/introspect/naming.py +187 -0
- tai_sql-0.7.0/tai_sql/introspect/reader.py +107 -0
- tai_sql-0.7.0/tai_sql/introspect/templates/schema.py.jinja2 +97 -0
- tai_sql-0.7.0/tai_sql/introspect/types.py +143 -0
- tai_sql-0.7.0/tai_sql/introspect/writer.py +259 -0
- tai_sql-0.7.0/tai_sql/orm/README.md +88 -0
- tai_sql-0.7.0/tai_sql/orm/__init__.py +85 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/README.md +118 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/__init__.py +35 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/calculated.py +152 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/collector.py +27 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/column_analyzer.py +296 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/constraints.py +232 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/hints.py +159 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/relation_analyzer.py +315 -0
- tai_sql-0.7.0/tai_sql/orm/analysis/schema_analyzer.py +420 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/README.md +135 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/__init__.py +87 -0
- {tai_sql-0.6.37/tai_sql/orm → tai_sql-0.7.0/tai_sql/orm/declarative}/annotations.py +0 -56
- tai_sql-0.7.0/tai_sql/orm/declarative/base.py +139 -0
- {tai_sql-0.6.37/tai_sql/orm → tai_sql-0.7.0/tai_sql/orm/declarative}/calculated.py +55 -231
- {tai_sql-0.6.37/tai_sql/orm → tai_sql-0.7.0/tai_sql/orm/declarative}/columns.py +54 -169
- tai_sql-0.7.0/tai_sql/orm/declarative/constraints.py +163 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/datasource.py +333 -0
- {tai_sql-0.6.37/tai_sql/orm → tai_sql-0.7.0/tai_sql/orm/declarative}/descriptors.py +6 -58
- tai_sql-0.7.0/tai_sql/orm/declarative/enumerations.py +107 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/relations.py +108 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/table.py +92 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/trigger_api.py +505 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/triggers.py +482 -0
- tai_sql-0.7.0/tai_sql/orm/declarative/view.py +77 -0
- tai_sql-0.7.0/tai_sql/orm/mapping/README.md +67 -0
- tai_sql-0.7.0/tai_sql/orm/mapping/__init__.py +23 -0
- tai_sql-0.7.0/tai_sql/orm/mapping/sqlalchemy_mapper.py +296 -0
- tai_sql-0.7.0/tai_sql/orm/model/README.md +97 -0
- tai_sql-0.7.0/tai_sql/orm/model/__init__.py +55 -0
- tai_sql-0.7.0/tai_sql/orm/model/column.py +158 -0
- tai_sql-0.7.0/tai_sql/orm/model/constraints.py +70 -0
- tai_sql-0.7.0/tai_sql/orm/model/entity.py +218 -0
- tai_sql-0.7.0/tai_sql/orm/model/enumeration.py +32 -0
- tai_sql-0.7.0/tai_sql/orm/model/relation.py +123 -0
- tai_sql-0.7.0/tai_sql/orm/model/schema.py +110 -0
- tai_sql-0.7.0/tai_sql/orm/model/trigger.py +59 -0
- tai_sql-0.7.0/tai_sql/orm/naming.py +88 -0
- tai_sql-0.7.0/tai_sql/orm/ordering.py +81 -0
- tai_sql-0.7.0/tai_sql/orm/registry.py +158 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/orm/types.py +15 -0
- tai_sql-0.7.0/tai_sql/project/README.md +71 -0
- tai_sql-0.7.0/tai_sql/project/__init__.py +30 -0
- tai_sql-0.7.0/tai_sql/project/config.py +75 -0
- tai_sql-0.7.0/tai_sql/project/context.py +68 -0
- tai_sql-0.7.0/tai_sql/project/manager.py +219 -0
- tai_sql-0.7.0/tai_sql/project/paths.py +149 -0
- tai_sql-0.7.0/tai_sql/rules/README.md +94 -0
- tai_sql-0.7.0/tai_sql/rules/__init__.py +91 -0
- tai_sql-0.7.0/tai_sql/rules/catalog.py +155 -0
- tai_sql-0.7.0/tai_sql/rules/installer.py +485 -0
- tai_sql-0.7.0/tai_sql/rules/meta.py +111 -0
- tai_sql-0.7.0/tai_sql/rules/service.py +129 -0
- tai_sql-0.7.0/tai_sql/rules/staleness.py +102 -0
- tai_sql-0.7.0/tai_sql/rules/static/comandos.md +277 -0
- tai_sql-0.7.0/tai_sql/rules/static/errores.md +189 -0
- tai_sql-0.7.0/tai_sql/rules/static/modelo.md +334 -0
- tai_sql-0.7.0/tai_sql/schema.py +437 -0
- tai_sql-0.7.0/tai_sql/sync/README.md +269 -0
- tai_sql-0.7.0/tai_sql/sync/__init__.py +136 -0
- tai_sql-0.7.0/tai_sql/sync/diff/__init__.py +139 -0
- tai_sql-0.7.0/tai_sql/sync/diff/constraints.py +263 -0
- tai_sql-0.7.0/tai_sql/sync/diff/indexes.py +60 -0
- tai_sql-0.7.0/tai_sql/sync/diff/tables.py +152 -0
- tai_sql-0.7.0/tai_sql/sync/diff/views.py +118 -0
- tai_sql-0.7.0/tai_sql/sync/executor.py +284 -0
- tai_sql-0.7.0/tai_sql/sync/plan/__init__.py +66 -0
- tai_sql-0.7.0/tai_sql/sync/plan/planner.py +555 -0
- tai_sql-0.7.0/tai_sql/sync/plan/statements.py +216 -0
- tai_sql-0.7.0/tai_sql/sync/presenter.py +263 -0
- tai_sql-0.7.0/tai_sql/sync/report.py +415 -0
- tai_sql-0.7.0/tai_sql/sync/safety.py +514 -0
- tai_sql-0.7.0/tai_sql/sync/state/__init__.py +53 -0
- tai_sql-0.7.0/tai_sql/sync/state/local.py +204 -0
- tai_sql-0.7.0/tai_sql/sync/state/model.py +297 -0
- tai_sql-0.7.0/tai_sql/sync/state/normalize.py +271 -0
- tai_sql-0.7.0/tai_sql/sync/state/remote.py +449 -0
- tai_sql-0.7.0/tai_sql/sync/synchronizer.py +211 -0
- tai_sql-0.6.37/PKG-INFO +0 -2484
- tai_sql-0.6.37/README.md +0 -2427
- tai_sql-0.6.37/pyproject.toml +0 -70
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_deploy/local.py +0 -174
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_feed/main.py +0 -103
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_generate/funcs.py +0 -29
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_generate/main.py +0 -24
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_ping/main.py +0 -65
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_roles/__init__.py +0 -1
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_roles/main.py +0 -53
- tai_sql-0.6.37/tai_sql/cli/commands/cmd_schema/new.py +0 -26
- tai_sql-0.6.37/tai_sql/cli/commands/utils/create.py +0 -102
- tai_sql-0.6.37/tai_sql/cli/main.py +0 -47
- tai_sql-0.6.37/tai_sql/cli/services/__init__.py +0 -13
- tai_sql-0.6.37/tai_sql/cli/services/ddl.py +0 -961
- tai_sql-0.6.37/tai_sql/cli/services/drift.py +0 -674
- tai_sql-0.6.37/tai_sql/cli/services/feed.py +0 -849
- tai_sql-0.6.37/tai_sql/cli/services/keycloak.py +0 -333
- tai_sql-0.6.37/tai_sql/cli/services/safety.py +0 -364
- tai_sql-0.6.37/tai_sql/core/__init__.py +0 -12
- tai_sql-0.6.37/tai_sql/core/funcs.py +0 -352
- tai_sql-0.6.37/tai_sql/drivers/__init__.py +0 -15
- tai_sql-0.6.37/tai_sql/drivers/base.py +0 -422
- tai_sql-0.6.37/tai_sql/drivers/mysql.py +0 -328
- tai_sql-0.6.37/tai_sql/drivers/postgresql.py +0 -509
- tai_sql-0.6.37/tai_sql/drivers/sqlserver.py +0 -402
- tai_sql-0.6.37/tai_sql/generators/base.py +0 -136
- tai_sql-0.6.37/tai_sql/generators/diagram/__init__.py +0 -997
- tai_sql-0.6.37/tai_sql/orm/__init__.py +0 -46
- tai_sql-0.6.37/tai_sql/orm/base.py +0 -373
- tai_sql-0.6.37/tai_sql/orm/enumerations.py +0 -101
- tai_sql-0.6.37/tai_sql/orm/relations.py +0 -334
- tai_sql-0.6.37/tai_sql/orm/table.py +0 -390
- tai_sql-0.6.37/tai_sql/orm/triggers.py +0 -2092
- tai_sql-0.6.37/tai_sql/orm/view.py +0 -135
- tai_sql-0.6.37/tai_sql/project.py +0 -288
- tai_sql-0.6.37/tai_sql/schema.py +0 -304
- {tai_sql-0.6.37 → tai_sql-0.7.0}/LICENSE +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_backup/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_deploy/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_deploy/main.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_deploy/workflow.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_feed/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_generate/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_info/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_info/status.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_init/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_install/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_ping/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_restore/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/schemas/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/cmd_schema/schemas/base.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/prompts.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/github/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/github/auth.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/github/client.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/commands/utils/github/models.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/cli/services/backup.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/__init__.py +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/base.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/domain/__init__.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/aggregation.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/filters.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/hierarchy.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/macros/triggers.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/__init__.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/aggregation.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/context.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/utils/__init__.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/utils/encoders.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/utils/funcs.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/utils/hierarchy.py.jinja2 +0 -0
- {tai_sql-0.6.37 → tai_sql-0.7.0}/tai_sql/generators/python_client/templates/shared/vector.py.jinja2 +0 -0
- {tai_sql-0.6.37/tai_sql/orm → tai_sql-0.7.0/tai_sql/orm/declarative}/encoders.py +0 -0
tai_sql-0.7.0/PKG-INFO
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tai-sql
|
|
3
|
+
Version: 0.7.0
|
|
4
|
+
Summary: SQL database management and code generation tool
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: sql,database,code-generation,orm,sqlalchemy
|
|
8
|
+
Author: MateoSaezMata
|
|
9
|
+
Author-email: msaez@triplealpha.in
|
|
10
|
+
Requires-Python: >=3.10,<4.0
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Database
|
|
18
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
19
|
+
Provides-Extra: all
|
|
20
|
+
Provides-Extra: backup
|
|
21
|
+
Provides-Extra: bigquery
|
|
22
|
+
Provides-Extra: deploy
|
|
23
|
+
Provides-Extra: diagrams
|
|
24
|
+
Provides-Extra: encryption
|
|
25
|
+
Provides-Extra: mysql
|
|
26
|
+
Provides-Extra: sqlserver
|
|
27
|
+
Provides-Extra: vectors
|
|
28
|
+
Requires-Dist: click (>=8.2.1,<9.0)
|
|
29
|
+
Requires-Dist: cryptography (>=45.0.4,<46.0) ; extra == "all"
|
|
30
|
+
Requires-Dist: cryptography (>=45.0.4,<46.0) ; extra == "encryption"
|
|
31
|
+
Requires-Dist: graphviz (>=0.20.3,<1.0) ; extra == "all"
|
|
32
|
+
Requires-Dist: graphviz (>=0.20.3,<1.0) ; extra == "diagrams"
|
|
33
|
+
Requires-Dist: inquirerpy (>=0.3.4,<0.4.0)
|
|
34
|
+
Requires-Dist: jinja2 (>=3.1.6,<4.0)
|
|
35
|
+
Requires-Dist: pgvector (>=0.3.0,<1.0) ; extra == "all"
|
|
36
|
+
Requires-Dist: pgvector (>=0.3.0,<1.0) ; extra == "vectors"
|
|
37
|
+
Requires-Dist: psycopg2-binary (>=2.9.10,<3.0)
|
|
38
|
+
Requires-Dist: pydantic (>=2.11.7,<3.0)
|
|
39
|
+
Requires-Dist: pymysql (>=1.1.1,<2.0) ; extra == "all"
|
|
40
|
+
Requires-Dist: pymysql (>=1.1.1,<2.0) ; extra == "mysql"
|
|
41
|
+
Requires-Dist: pynacl (>=1.5.0,<2.0) ; extra == "all"
|
|
42
|
+
Requires-Dist: pynacl (>=1.5.0,<2.0) ; extra == "deploy"
|
|
43
|
+
Requires-Dist: pyodbc (>=5.2.0,<6.0) ; extra == "all"
|
|
44
|
+
Requires-Dist: pyodbc (>=5.2.0,<6.0) ; extra == "sqlserver"
|
|
45
|
+
Requires-Dist: requests (>=2.32.4,<3.0) ; extra == "all"
|
|
46
|
+
Requires-Dist: requests (>=2.32.4,<3.0) ; extra == "deploy"
|
|
47
|
+
Requires-Dist: rich (>=15.0.0,<16.0.0)
|
|
48
|
+
Requires-Dist: sqlalchemy (>=2.0.42,<3.0)
|
|
49
|
+
Requires-Dist: sqlalchemy-bigquery (>=1.11.0,<2.0) ; extra == "all"
|
|
50
|
+
Requires-Dist: sqlalchemy-bigquery (>=1.11.0,<2.0) ; extra == "bigquery"
|
|
51
|
+
Requires-Dist: tai-alphi (>=2.0.1,<3.0) ; extra == "all"
|
|
52
|
+
Requires-Dist: tai-alphi (>=2.0.1,<3.0) ; extra == "backup"
|
|
53
|
+
Requires-Dist: tai-storage (>=0.1.0) ; extra == "all"
|
|
54
|
+
Requires-Dist: tai-storage (>=0.1.0) ; extra == "backup"
|
|
55
|
+
Project-URL: Documentation, https://triplealpha-innovation.github.io/tai-sql/
|
|
56
|
+
Project-URL: Homepage, https://www.triplealpha.in/es/
|
|
57
|
+
Project-URL: Issues, https://github.com/triplealpha-innovation/tai-sql/issues
|
|
58
|
+
Project-URL: Repository, https://github.com/triplealpha-innovation/tai-sql
|
|
59
|
+
Description-Content-Type: text/markdown
|
|
60
|
+
|
|
61
|
+
# tai-sql
|
|
62
|
+
|
|
63
|
+
[](https://pypi.org/project/tai-sql/)
|
|
64
|
+
[](https://pypi.org/project/tai-sql/)
|
|
65
|
+
[](LICENSE)
|
|
66
|
+
[](https://triplealpha-innovation.github.io/tai-sql/)
|
|
67
|
+
|
|
68
|
+
**Framework declarativo de Python, sobre SQLAlchemy, que gestiona el ciclo de vida completo de
|
|
69
|
+
una base de datos.** Declaras el modelo una vez, en un fichero Python, y a partir de ahí tai-sql
|
|
70
|
+
sincroniza la estructura de la base de datos, genera un cliente Python completo —modelos, DTOs y
|
|
71
|
+
DAOs síncronos y asíncronos— y dibuja el diagrama entidad-relación.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
schemas/public.py ──▶ tai-sql push ──▶ la base de datos se parece al schema
|
|
75
|
+
──▶ tai-sql generate ──▶ cliente Python + diagrama ER
|
|
76
|
+
──▶ tai-sql feed ──▶ datos iniciales
|
|
77
|
+
◀── tai-sql pull ◀── una base de datos que ya existe
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Motores soportados: **PostgreSQL**, **MySQL**, **SQL Server** y **BigQuery**.
|
|
81
|
+
|
|
82
|
+
📖 **[El manual completo está en triplealpha-innovation.github.io/tai-sql](https://triplealpha-innovation.github.io/tai-sql/)**
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Quickstart
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pip install tai-sql # PostgreSQL funciona sin extras
|
|
90
|
+
tai-sql init -n mi_proyecto -s public # crea el proyecto
|
|
91
|
+
cd mi_proyecto
|
|
92
|
+
export MAIN_DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
|
93
|
+
tai-sql install # instala lo que el cliente generado necesitará
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Edita `schemas/public.py`:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
# -*- coding: utf-8 -*-
|
|
100
|
+
from __future__ import annotations
|
|
101
|
+
from tai_sql import *
|
|
102
|
+
from tai_sql.generators import *
|
|
103
|
+
|
|
104
|
+
datasource(provider=env('MAIN_DATABASE_URL'), schema='public', syntax='v2')
|
|
105
|
+
|
|
106
|
+
generate(
|
|
107
|
+
PythonClientGenerator(output_dir='database'),
|
|
108
|
+
ERDiagramGenerator(output_dir='diagrams', format='html'),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Usuario(Table):
|
|
113
|
+
"""Usuarios del sistema."""
|
|
114
|
+
__tablename__ = 'usuario'
|
|
115
|
+
|
|
116
|
+
id: col[int] = column(primary_key=True, autoincrement=True)
|
|
117
|
+
nombre: col[str]
|
|
118
|
+
email: col[str] = column(unique=True)
|
|
119
|
+
creado_en: col[datetime] = column(server_now=True)
|
|
120
|
+
|
|
121
|
+
posts: onetomany[Post]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class Post(Table):
|
|
125
|
+
"""Posts publicados."""
|
|
126
|
+
__tablename__ = 'post'
|
|
127
|
+
|
|
128
|
+
id: col[bigint] = column(primary_key=True, autoincrement=True)
|
|
129
|
+
titulo: col[str]
|
|
130
|
+
contenido: col[text]
|
|
131
|
+
autor_id: col[int]
|
|
132
|
+
|
|
133
|
+
autor: manytoone[Usuario] = relation(fields=['autor_id'], references=['id'], backref='posts')
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
tai-sql push --dry-run --verbose # enseña el DDL sin ejecutar nada
|
|
138
|
+
tai-sql push # lo aplica y regenera el cliente
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Y a usarlo:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from database.public import public_sync_api, UsuarioCreate
|
|
145
|
+
|
|
146
|
+
usuario = public_sync_api.usuario.create(UsuarioCreate(nombre='Ana', email='ana@example.com'))
|
|
147
|
+
usuarios = public_sync_api.usuario.find_many(limit=10, includes=['posts'])
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Los cinco principios que explican el resto
|
|
153
|
+
|
|
154
|
+
1. **El schema es la única fuente de verdad.** Todo lo demás —DDL, cliente, diagramas— es
|
|
155
|
+
derivado y desechable. Si el cliente generado no hace lo que necesitas, no se edita el
|
|
156
|
+
cliente: se arregla el schema y se regenera.
|
|
157
|
+
2. **Mapear y después actuar.** Todo comando importa el schema, lo analiza y actúa sobre ese
|
|
158
|
+
mapeo. Ningún comando parsea el fichero por su cuenta.
|
|
159
|
+
3. **El código generado nunca importa `tai_sql`.** tai-sql es una herramienta de desarrollo, no
|
|
160
|
+
una dependencia de producción: el cliente se despliega donde tai-sql no está instalado.
|
|
161
|
+
4. **Modelo declarativo, sin migraciones versionadas.** No hay ficheros de migración: `push`
|
|
162
|
+
compara el estado declarado con el real y genera el DDL que hace falta.
|
|
163
|
+
5. **Definición ≠ runtime.** El ORM de tai-sql *describe*; el comportamiento en producción vive
|
|
164
|
+
en el código generado.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Qué trae
|
|
169
|
+
|
|
170
|
+
| | |
|
|
171
|
+
|---|---|
|
|
172
|
+
| **Schema declarativo** | Tablas, relaciones, vistas, enumerados, constraints e índices de varias columnas, columnas calculadas y jerarquías. Dos sintaxis, v1 y v2, y las dos se soportan |
|
|
173
|
+
| **Sincronización sin migraciones** | `push` compara y genera el DDL, clasificando cada operación en SAFE / WARNING / BLOCKED antes de tocar nada |
|
|
174
|
+
| **Cliente Python generado** | CRUD completo, filtros por tipo de columna, relaciones anidadas, agregaciones con GROUP BY, DataFrames, RLS, auditoría y transacciones, en síncrono y asíncrono |
|
|
175
|
+
| **Triggers transpilados** | Lógica de negocio declarada en el schema que se *inlinea* en los DAOs: sin coste en runtime |
|
|
176
|
+
| **Cifrado y vectores** | Columnas cifradas con Fernet, transparentes al leer, y columnas vectoriales con pgvector y búsqueda por similitud |
|
|
177
|
+
| **Diagrama ER** | Una página HTML interactiva, o una imagen con Graphviz |
|
|
178
|
+
| **Introspección** | `pull` escribe el schema de una base de datos que ya existe |
|
|
179
|
+
| **Reglas para asistentes de IA** | `rules install` deja en tu proyecto la documentación que un asistente necesita, incluida la derivada de tu schema |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## El manual
|
|
184
|
+
|
|
185
|
+
| Sección | Qué responde |
|
|
186
|
+
|---|---|
|
|
187
|
+
| [Instalación](https://triplealpha-innovation.github.io/tai-sql/empezar/instalacion/) | Qué instalar, y por qué son dos instalaciones y no una |
|
|
188
|
+
| [Tu primer proyecto](https://triplealpha-innovation.github.io/tai-sql/empezar/primer-proyecto/) | De cero a un cliente generado funcionando |
|
|
189
|
+
| [El schema](https://triplealpha-innovation.github.io/tai-sql/schema/) | Todo lo que se puede declarar, y cómo |
|
|
190
|
+
| [El CLI](https://triplealpha-innovation.github.io/tai-sql/cli/) | Qué hace cada comando, y qué puede destruir `push` |
|
|
191
|
+
| [El cliente generado](https://triplealpha-innovation.github.io/tai-sql/cliente/) | La API que vas a usar desde tu aplicación |
|
|
192
|
+
| [Referencia](https://triplealpha-innovation.github.io/tai-sql/referencia/dsl/) | Firmas del DSL, motores, extensión y catálogo de errores |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Desarrollo
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
git clone https://github.com/triplealpha-innovation/tai-sql
|
|
200
|
+
cd tai-sql
|
|
201
|
+
poetry install --all-extras # los extras no son opcionales para la suite
|
|
202
|
+
|
|
203
|
+
poetry run pytest # todo lo que el entorno permita
|
|
204
|
+
poetry run pytest -m "not db and not mysql" # lo que corre sin ninguna base de datos
|
|
205
|
+
poetry run pytest -m mysql # el ciclo completo contra MySQL
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Los tests marcados `db` necesitan un PostgreSQL alcanzable y se **saltan** si no lo hay; los
|
|
209
|
+
marcados `mysql`, un MySQL en `TAI_SQL_MYSQL_URL`. Sus schemas salen de `tests/fixtures/project/`.
|
|
210
|
+
|
|
211
|
+
El CI tiene tres workflows: `tests.yaml` ejecuta la suite en cada push y PR a `main` y `dev` —un
|
|
212
|
+
trabajo con PostgreSQL y otro con MySQL—, `docs.yaml` publica el manual y `publish.yaml` publica
|
|
213
|
+
a PyPI en push a `main`. La rama de trabajo habitual es `dev`, y la versión se bumpea a mano en
|
|
214
|
+
`pyproject.toml`.
|
|
215
|
+
|
|
216
|
+
### El manual, en local
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
pip install -r docs/requirements.txt
|
|
220
|
+
mkdocs serve # http://127.0.0.1:8000, con recarga en caliente
|
|
221
|
+
mkdocs build --strict # lo mismo que valida el CI
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
El manual vive en `docs/` y es para quien **usa** tai-sql. Las reglas de diseño internas
|
|
225
|
+
(`.claude/rules/`) y el `README.md` de cada paquete son para quien trabaja **en** tai-sql, y no
|
|
226
|
+
se publican: son dos audiencias con preguntas distintas.
|
|
227
|
+
|
|
228
|
+
### El mapa del código
|
|
229
|
+
|
|
230
|
+
| Ruta | Qué es |
|
|
231
|
+
|---|---|
|
|
232
|
+
| `tai_sql/orm/` | El mapeo, en cuatro capas: `declarative/` → `analysis/` → `model/` → `mapping/` |
|
|
233
|
+
| `tai_sql/sync/` | Sincronización schema ↔ BD: `state/` → `diff/` → `report.py` → `plan/` → `safety.py` → `executor.py` |
|
|
234
|
+
| `tai_sql/feed/` | Poblar la base de datos: recoger → planificar → aplicar en una transacción |
|
|
235
|
+
| `tai_sql/introspect/` | La dirección contraria: BD existente → fichero de schema |
|
|
236
|
+
| `tai_sql/drivers/` | Todo el SQL dialectal, más las capacidades de cada motor |
|
|
237
|
+
| `tai_sql/generators/` | Cliente Python, diagrama ER y reglas |
|
|
238
|
+
| `tai_sql/connection/` | Con qué se conecta tai-sql y cómo se conectará el cliente generado |
|
|
239
|
+
| `tai_sql/cli/` | El CLI de Click |
|
|
240
|
+
| `tai_sql/errors/` | `TaiSqlError` (mensaje + **solución** obligatoria) y su presentador |
|
|
241
|
+
|
|
242
|
+
Cada uno de esos paquetes tiene su propio `README.md` con el detalle.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Licencia
|
|
247
|
+
|
|
248
|
+
MIT. Ver [LICENSE](LICENSE).
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
<sub>Desarrollado por [Triple Alpha Innovation](https://www.triplealpha.in/es/) ·
|
|
253
|
+
[Issues](https://github.com/triplealpha-innovation/tai-sql/issues)</sub>
|
|
254
|
+
|
tai_sql-0.7.0/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# tai-sql
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/tai-sql/)
|
|
4
|
+
[](https://pypi.org/project/tai-sql/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://triplealpha-innovation.github.io/tai-sql/)
|
|
7
|
+
|
|
8
|
+
**Framework declarativo de Python, sobre SQLAlchemy, que gestiona el ciclo de vida completo de
|
|
9
|
+
una base de datos.** Declaras el modelo una vez, en un fichero Python, y a partir de ahí tai-sql
|
|
10
|
+
sincroniza la estructura de la base de datos, genera un cliente Python completo —modelos, DTOs y
|
|
11
|
+
DAOs síncronos y asíncronos— y dibuja el diagrama entidad-relación.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
schemas/public.py ──▶ tai-sql push ──▶ la base de datos se parece al schema
|
|
15
|
+
──▶ tai-sql generate ──▶ cliente Python + diagrama ER
|
|
16
|
+
──▶ tai-sql feed ──▶ datos iniciales
|
|
17
|
+
◀── tai-sql pull ◀── una base de datos que ya existe
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Motores soportados: **PostgreSQL**, **MySQL**, **SQL Server** y **BigQuery**.
|
|
21
|
+
|
|
22
|
+
📖 **[El manual completo está en triplealpha-innovation.github.io/tai-sql](https://triplealpha-innovation.github.io/tai-sql/)**
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install tai-sql # PostgreSQL funciona sin extras
|
|
30
|
+
tai-sql init -n mi_proyecto -s public # crea el proyecto
|
|
31
|
+
cd mi_proyecto
|
|
32
|
+
export MAIN_DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"
|
|
33
|
+
tai-sql install # instala lo que el cliente generado necesitará
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Edita `schemas/public.py`:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
# -*- coding: utf-8 -*-
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
from tai_sql import *
|
|
42
|
+
from tai_sql.generators import *
|
|
43
|
+
|
|
44
|
+
datasource(provider=env('MAIN_DATABASE_URL'), schema='public', syntax='v2')
|
|
45
|
+
|
|
46
|
+
generate(
|
|
47
|
+
PythonClientGenerator(output_dir='database'),
|
|
48
|
+
ERDiagramGenerator(output_dir='diagrams', format='html'),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Usuario(Table):
|
|
53
|
+
"""Usuarios del sistema."""
|
|
54
|
+
__tablename__ = 'usuario'
|
|
55
|
+
|
|
56
|
+
id: col[int] = column(primary_key=True, autoincrement=True)
|
|
57
|
+
nombre: col[str]
|
|
58
|
+
email: col[str] = column(unique=True)
|
|
59
|
+
creado_en: col[datetime] = column(server_now=True)
|
|
60
|
+
|
|
61
|
+
posts: onetomany[Post]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Post(Table):
|
|
65
|
+
"""Posts publicados."""
|
|
66
|
+
__tablename__ = 'post'
|
|
67
|
+
|
|
68
|
+
id: col[bigint] = column(primary_key=True, autoincrement=True)
|
|
69
|
+
titulo: col[str]
|
|
70
|
+
contenido: col[text]
|
|
71
|
+
autor_id: col[int]
|
|
72
|
+
|
|
73
|
+
autor: manytoone[Usuario] = relation(fields=['autor_id'], references=['id'], backref='posts')
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
tai-sql push --dry-run --verbose # enseña el DDL sin ejecutar nada
|
|
78
|
+
tai-sql push # lo aplica y regenera el cliente
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Y a usarlo:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from database.public import public_sync_api, UsuarioCreate
|
|
85
|
+
|
|
86
|
+
usuario = public_sync_api.usuario.create(UsuarioCreate(nombre='Ana', email='ana@example.com'))
|
|
87
|
+
usuarios = public_sync_api.usuario.find_many(limit=10, includes=['posts'])
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Los cinco principios que explican el resto
|
|
93
|
+
|
|
94
|
+
1. **El schema es la única fuente de verdad.** Todo lo demás —DDL, cliente, diagramas— es
|
|
95
|
+
derivado y desechable. Si el cliente generado no hace lo que necesitas, no se edita el
|
|
96
|
+
cliente: se arregla el schema y se regenera.
|
|
97
|
+
2. **Mapear y después actuar.** Todo comando importa el schema, lo analiza y actúa sobre ese
|
|
98
|
+
mapeo. Ningún comando parsea el fichero por su cuenta.
|
|
99
|
+
3. **El código generado nunca importa `tai_sql`.** tai-sql es una herramienta de desarrollo, no
|
|
100
|
+
una dependencia de producción: el cliente se despliega donde tai-sql no está instalado.
|
|
101
|
+
4. **Modelo declarativo, sin migraciones versionadas.** No hay ficheros de migración: `push`
|
|
102
|
+
compara el estado declarado con el real y genera el DDL que hace falta.
|
|
103
|
+
5. **Definición ≠ runtime.** El ORM de tai-sql *describe*; el comportamiento en producción vive
|
|
104
|
+
en el código generado.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Qué trae
|
|
109
|
+
|
|
110
|
+
| | |
|
|
111
|
+
|---|---|
|
|
112
|
+
| **Schema declarativo** | Tablas, relaciones, vistas, enumerados, constraints e índices de varias columnas, columnas calculadas y jerarquías. Dos sintaxis, v1 y v2, y las dos se soportan |
|
|
113
|
+
| **Sincronización sin migraciones** | `push` compara y genera el DDL, clasificando cada operación en SAFE / WARNING / BLOCKED antes de tocar nada |
|
|
114
|
+
| **Cliente Python generado** | CRUD completo, filtros por tipo de columna, relaciones anidadas, agregaciones con GROUP BY, DataFrames, RLS, auditoría y transacciones, en síncrono y asíncrono |
|
|
115
|
+
| **Triggers transpilados** | Lógica de negocio declarada en el schema que se *inlinea* en los DAOs: sin coste en runtime |
|
|
116
|
+
| **Cifrado y vectores** | Columnas cifradas con Fernet, transparentes al leer, y columnas vectoriales con pgvector y búsqueda por similitud |
|
|
117
|
+
| **Diagrama ER** | Una página HTML interactiva, o una imagen con Graphviz |
|
|
118
|
+
| **Introspección** | `pull` escribe el schema de una base de datos que ya existe |
|
|
119
|
+
| **Reglas para asistentes de IA** | `rules install` deja en tu proyecto la documentación que un asistente necesita, incluida la derivada de tu schema |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## El manual
|
|
124
|
+
|
|
125
|
+
| Sección | Qué responde |
|
|
126
|
+
|---|---|
|
|
127
|
+
| [Instalación](https://triplealpha-innovation.github.io/tai-sql/empezar/instalacion/) | Qué instalar, y por qué son dos instalaciones y no una |
|
|
128
|
+
| [Tu primer proyecto](https://triplealpha-innovation.github.io/tai-sql/empezar/primer-proyecto/) | De cero a un cliente generado funcionando |
|
|
129
|
+
| [El schema](https://triplealpha-innovation.github.io/tai-sql/schema/) | Todo lo que se puede declarar, y cómo |
|
|
130
|
+
| [El CLI](https://triplealpha-innovation.github.io/tai-sql/cli/) | Qué hace cada comando, y qué puede destruir `push` |
|
|
131
|
+
| [El cliente generado](https://triplealpha-innovation.github.io/tai-sql/cliente/) | La API que vas a usar desde tu aplicación |
|
|
132
|
+
| [Referencia](https://triplealpha-innovation.github.io/tai-sql/referencia/dsl/) | Firmas del DSL, motores, extensión y catálogo de errores |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Desarrollo
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone https://github.com/triplealpha-innovation/tai-sql
|
|
140
|
+
cd tai-sql
|
|
141
|
+
poetry install --all-extras # los extras no son opcionales para la suite
|
|
142
|
+
|
|
143
|
+
poetry run pytest # todo lo que el entorno permita
|
|
144
|
+
poetry run pytest -m "not db and not mysql" # lo que corre sin ninguna base de datos
|
|
145
|
+
poetry run pytest -m mysql # el ciclo completo contra MySQL
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Los tests marcados `db` necesitan un PostgreSQL alcanzable y se **saltan** si no lo hay; los
|
|
149
|
+
marcados `mysql`, un MySQL en `TAI_SQL_MYSQL_URL`. Sus schemas salen de `tests/fixtures/project/`.
|
|
150
|
+
|
|
151
|
+
El CI tiene tres workflows: `tests.yaml` ejecuta la suite en cada push y PR a `main` y `dev` —un
|
|
152
|
+
trabajo con PostgreSQL y otro con MySQL—, `docs.yaml` publica el manual y `publish.yaml` publica
|
|
153
|
+
a PyPI en push a `main`. La rama de trabajo habitual es `dev`, y la versión se bumpea a mano en
|
|
154
|
+
`pyproject.toml`.
|
|
155
|
+
|
|
156
|
+
### El manual, en local
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pip install -r docs/requirements.txt
|
|
160
|
+
mkdocs serve # http://127.0.0.1:8000, con recarga en caliente
|
|
161
|
+
mkdocs build --strict # lo mismo que valida el CI
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
El manual vive en `docs/` y es para quien **usa** tai-sql. Las reglas de diseño internas
|
|
165
|
+
(`.claude/rules/`) y el `README.md` de cada paquete son para quien trabaja **en** tai-sql, y no
|
|
166
|
+
se publican: son dos audiencias con preguntas distintas.
|
|
167
|
+
|
|
168
|
+
### El mapa del código
|
|
169
|
+
|
|
170
|
+
| Ruta | Qué es |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `tai_sql/orm/` | El mapeo, en cuatro capas: `declarative/` → `analysis/` → `model/` → `mapping/` |
|
|
173
|
+
| `tai_sql/sync/` | Sincronización schema ↔ BD: `state/` → `diff/` → `report.py` → `plan/` → `safety.py` → `executor.py` |
|
|
174
|
+
| `tai_sql/feed/` | Poblar la base de datos: recoger → planificar → aplicar en una transacción |
|
|
175
|
+
| `tai_sql/introspect/` | La dirección contraria: BD existente → fichero de schema |
|
|
176
|
+
| `tai_sql/drivers/` | Todo el SQL dialectal, más las capacidades de cada motor |
|
|
177
|
+
| `tai_sql/generators/` | Cliente Python, diagrama ER y reglas |
|
|
178
|
+
| `tai_sql/connection/` | Con qué se conecta tai-sql y cómo se conectará el cliente generado |
|
|
179
|
+
| `tai_sql/cli/` | El CLI de Click |
|
|
180
|
+
| `tai_sql/errors/` | `TaiSqlError` (mensaje + **solución** obligatoria) y su presentador |
|
|
181
|
+
|
|
182
|
+
Cada uno de esos paquetes tiene su propio `README.md` con el detalle.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Licencia
|
|
187
|
+
|
|
188
|
+
MIT. Ver [LICENSE](LICENSE).
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
<sub>Desarrollado por [Triple Alpha Innovation](https://www.triplealpha.in/es/) ·
|
|
193
|
+
[Issues](https://github.com/triplealpha-innovation/tai-sql/issues)</sub>
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tai-sql"
|
|
3
|
+
version = "0.7.0"
|
|
4
|
+
description = "SQL database management and code generation tool"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = ["LICENSE"]
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "MateoSaezMata", email = "msaez@triplealpha.in"},
|
|
9
|
+
{name = "PabloFernandezLamas", email = "pablo.fernandezlamas@triplealpha.in"}
|
|
10
|
+
]
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.10,<4.0"
|
|
13
|
+
keywords = ["sql", "database", "code-generation", "orm", "sqlalchemy"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Database",
|
|
22
|
+
"Topic :: Software Development :: Code Generators",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
# Lo mínimo para declarar un schema y ejecutar el CLI contra PostgreSQL.
|
|
26
|
+
#
|
|
27
|
+
# `psycopg2-binary` está aquí y no en un extra, y es la única asimetría entre motores:
|
|
28
|
+
# moverlo rompería `pip install tai-sql` para quien ya lo usa contra PostgreSQL, que es
|
|
29
|
+
# el caso mayoritario. Los demás motores traen su DBAPI en su extra.
|
|
30
|
+
dependencies = [
|
|
31
|
+
"sqlalchemy>=2.0.42,<3.0",
|
|
32
|
+
"psycopg2-binary>=2.9.10,<3.0",
|
|
33
|
+
"click>=8.2.1,<9.0",
|
|
34
|
+
"jinja2>=3.1.6,<4.0",
|
|
35
|
+
"pydantic>=2.11.7,<3.0",
|
|
36
|
+
"inquirerpy>=0.3.4,<0.4.0",
|
|
37
|
+
"rich (>=15.0.0,<16.0.0)",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://www.triplealpha.in/es/"
|
|
42
|
+
Documentation = "https://triplealpha-innovation.github.io/tai-sql/"
|
|
43
|
+
Repository = "https://github.com/triplealpha-innovation/tai-sql"
|
|
44
|
+
Issues = "https://github.com/triplealpha-innovation/tai-sql/issues"
|
|
45
|
+
|
|
46
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
47
|
+
# Extras
|
|
48
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
49
|
+
#
|
|
50
|
+
# ESTOS EXTRAS SON DE LA HERRAMIENTA, NO DEL CÓDIGO GENERADO.
|
|
51
|
+
#
|
|
52
|
+
# Hay dos `pyproject.toml` en juego y confundirlos es de donde salen las instalaciones
|
|
53
|
+
# que no arreglan nada:
|
|
54
|
+
#
|
|
55
|
+
# 1. **este** — lo que necesita tai-sql en la máquina de quien desarrolla, para
|
|
56
|
+
# conectarse, comparar el schema con la base de datos, generar y dibujar. Se instala
|
|
57
|
+
# con `pip install 'tai-sql[...]'`.
|
|
58
|
+
# 2. **el del proyecto del usuario** — lo que necesita el **cliente generado** en
|
|
59
|
+
# tiempo de ejecución. Lo escribe `tai-sql init` y lo resuelve `tai-sql install`
|
|
60
|
+
# (que analiza el schema y dice qué extras hacen falta). tai-sql **no** está
|
|
61
|
+
# instalado donde ese cliente se despliega: es una herramienta de desarrollo, no una
|
|
62
|
+
# dependencia de producción (principio 3 de `.claude/rules/00-filosofia.md`).
|
|
63
|
+
#
|
|
64
|
+
# Por eso aquí no hay ni `langchain-*` ni `sentence-transformers` ni drivers asíncronos:
|
|
65
|
+
# tai-sql no importa ninguno. Son del cliente generado, y viven en el otro pyproject.
|
|
66
|
+
#
|
|
67
|
+
# Cada extra dice **cuándo** hace falta. El detalle está en el README, sección
|
|
68
|
+
# "Instalación".
|
|
69
|
+
[project.optional-dependencies]
|
|
70
|
+
|
|
71
|
+
# ── Motores: el DBAPI con el que tai-sql se conecta ──────────────────────────
|
|
72
|
+
# Hace falta el del motor al que apunte tu `datasource(provider=...)`. Sin él, el fallo
|
|
73
|
+
# aparece en el primer comando que abra conexión (`tai-sql ping`) como un
|
|
74
|
+
# ModuleNotFoundError de SQLAlchemy que no dice qué instalar.
|
|
75
|
+
# PostgreSQL no necesita nada: su DBAPI es dependencia dura (ver arriba).
|
|
76
|
+
mysql = ["pymysql>=1.1.1,<2.0"]
|
|
77
|
+
sqlserver = ["pyodbc>=5.2.0,<6.0"]
|
|
78
|
+
# BigQuery solo lo necesita para **conectarse**: escribir el DDL y generar el cliente no,
|
|
79
|
+
# porque el driver renderiza los tipos de GoogleSQL él mismo.
|
|
80
|
+
bigquery = ["sqlalchemy-bigquery>=1.11.0,<2.0"]
|
|
81
|
+
|
|
82
|
+
# ── Features del schema: lo pide lo que declares ──────────────────────────────
|
|
83
|
+
# `vectors`: alguna columna `vector_column()`. Lo necesitan `push` y `feed`, que
|
|
84
|
+
# construyen el `MetaData` y ahí hace falta el tipo `Vector`. `generate` **no**: el
|
|
85
|
+
# cliente que produce define su propio tipo.
|
|
86
|
+
# `encryption`: alguna `column(encrypt=True)`. Lo necesitan `generate` —valida la clave
|
|
87
|
+
# secreta antes de emitir el cliente— y `feed`, que cifra los valores que inserta.
|
|
88
|
+
# `diagrams`: el schema declara `ERDiagramGenerator`. Necesita además el **binario** de
|
|
89
|
+
# Graphviz en el sistema (`apt install graphviz`), que pip no instala.
|
|
90
|
+
vectors = ["pgvector>=0.3.0,<1.0"]
|
|
91
|
+
encryption = ["cryptography>=45.0.4,<46.0"]
|
|
92
|
+
diagrams = ["graphviz>=0.20.3,<1.0"]
|
|
93
|
+
|
|
94
|
+
# ── Comandos concretos del CLI ────────────────────────────────────────────────
|
|
95
|
+
# `backup`: `tai-sql backup` y `tai-sql restore`.
|
|
96
|
+
# `deploy`: nada hoy — el comando está **desactivado a propósito** (comentado en
|
|
97
|
+
# `cli/main.py`). El extra se conserva para no romper a quien lo tenga instalado, pero
|
|
98
|
+
# instalarlo no habilita ningún comando.
|
|
99
|
+
backup = ["tai-storage>=0.1.0", "tai-alphi>=2.0.1,<3.0"]
|
|
100
|
+
deploy = ["requests>=2.32.4,<3.0", "pynacl>=1.5.0,<2.0"]
|
|
101
|
+
|
|
102
|
+
# ── Todo ──────────────────────────────────────────────────────────────────────
|
|
103
|
+
# La lista está duplicada porque Poetry rechaza que un extra se referencie a sí mismo
|
|
104
|
+
# (`tai-sql[diagrams,...]` → "listed as a dependency of itself"). Que no se
|
|
105
|
+
# desincronice lo comprueba `tests/test_packaging.py`, que asevera que `all` es la unión
|
|
106
|
+
# exacta de los extras de arriba — ya se había quedado atrás una vez.
|
|
107
|
+
all = [
|
|
108
|
+
"pymysql>=1.1.1,<2.0",
|
|
109
|
+
"pyodbc>=5.2.0,<6.0",
|
|
110
|
+
"sqlalchemy-bigquery>=1.11.0,<2.0",
|
|
111
|
+
"pgvector>=0.3.0,<1.0",
|
|
112
|
+
"cryptography>=45.0.4,<46.0",
|
|
113
|
+
"graphviz>=0.20.3,<1.0",
|
|
114
|
+
"tai-storage>=0.1.0",
|
|
115
|
+
"tai-alphi>=2.0.1,<3.0",
|
|
116
|
+
"requests>=2.32.4,<3.0",
|
|
117
|
+
"pynacl>=1.5.0,<2.0",
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
[project.scripts]
|
|
121
|
+
tai-sql = "tai_sql.cli.main:cli"
|
|
122
|
+
|
|
123
|
+
[build-system]
|
|
124
|
+
# poetry-core 2 hace falta para `license = "MIT"` como expresión SPDX (PEP 639).
|
|
125
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
126
|
+
build-backend = "poetry.core.masonry.api"
|
|
127
|
+
|
|
128
|
+
# Para trabajar **en** tai-sql:
|
|
129
|
+
#
|
|
130
|
+
# poetry install --all-extras
|
|
131
|
+
#
|
|
132
|
+
# Los extras no son opcionales para la suite, y no se saltan: **fallan**. Sin `vectors`,
|
|
133
|
+
# el schema de fixtures que declara una columna vectorial no puede construir su
|
|
134
|
+
# `MetaData` y se cae todo lo que compare o planifique sobre él.
|
|
135
|
+
#
|
|
136
|
+
# Lo que sí se salta con elegancia es la base de datos: 111 de los 993 tests necesitan un
|
|
137
|
+
# PostgreSQL alcanzable y sin él se marcan como saltados. Ver `.claude/rules/tests.md`.
|
|
138
|
+
[dependency-groups]
|
|
139
|
+
dev = [
|
|
140
|
+
"pytest (>=8.0)",
|
|
141
|
+
"pytest-asyncio (>=0.24)",
|
|
142
|
+
# Mide qué parte del **cliente generado** ejecutan los tests. No cubre a tai-sql:
|
|
143
|
+
# lo que hay que poder afirmar es que el código que se despliega está probado.
|
|
144
|
+
# Ver `tests/_client_coverage.py`.
|
|
145
|
+
"coverage (>=7.0)",
|
|
146
|
+
# No lo importa tai-sql: lo importan el cliente generado (`as_dataframe`,
|
|
147
|
+
# `from_dataframe`) y `tai_storage`, que carga su submódulo `data` al importarse y
|
|
148
|
+
# ahí exige pandas y numpy. Sin declararlo, el CI instalaba tai-storage por el extra
|
|
149
|
+
# `backup` y **la colección de toda la suite se rompía** al importarlo, mientras en
|
|
150
|
+
# local pasaba porque pandas estaba instalado sin que nadie lo hubiera pedido.
|
|
151
|
+
"pandas (>=2.0,<3.0)",
|
|
152
|
+
# Lo mismo por el otro lado: `test_generated_runtime.py` ejercita el cliente async
|
|
153
|
+
# contra PostgreSQL, y su dialecto es asyncpg. Sin declararlo, esos 22 tests pasaban
|
|
154
|
+
# en local —donde estaba instalado— y en el CI fallaban todos con ModuleNotFoundError.
|
|
155
|
+
"asyncpg (>=0.30,<1.0)"
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
[tool.pytest.ini_options]
|
|
159
|
+
testpaths = ["tests"]
|
|
160
|
+
# Sin esto, un `async def test_*` se recoge pero no se ejecuta: pytest lo marca como
|
|
161
|
+
# fallo con un aviso de plugin ausente.
|
|
162
|
+
asyncio_mode = "auto"
|
|
163
|
+
# Un solo event loop por sesión. El cliente generado expone su session manager async
|
|
164
|
+
# como singleton de módulo, así que su pool queda atado al loop del primer test: con un
|
|
165
|
+
# loop por test, el segundo falla con "Event loop is closed".
|
|
166
|
+
asyncio_default_fixture_loop_scope = "session"
|
|
167
|
+
asyncio_default_test_loop_scope = "session"
|
|
168
|
+
markers = [
|
|
169
|
+
"db: requiere una base de datos PostgreSQL real; se salta si no hay conexión",
|
|
170
|
+
"mysql: requiere un MySQL real en TAI_SQL_MYSQL_URL; se salta si no hay conexión",
|
|
171
|
+
]
|
|
@@ -14,19 +14,30 @@ from sqlalchemy.types import (
|
|
|
14
14
|
from datetime import datetime, date, time
|
|
15
15
|
from typing import List, Optional
|
|
16
16
|
|
|
17
|
-
from .project import ProjectManager
|
|
18
|
-
from .
|
|
17
|
+
from .project import ProjectManager
|
|
18
|
+
from .connection import env, connection_string, params
|
|
19
|
+
|
|
20
|
+
# La instancia por defecto: el proyecto sobre el que trabaja el CLI. Antes `pm` era la
|
|
21
|
+
# propia clase, usada como espacio de nombres global; ahora es un objeto, y se puede
|
|
22
|
+
# construir otro para otro proyecto sin que se pisen.
|
|
23
|
+
pm = ProjectManager()
|
|
19
24
|
from .orm import (
|
|
25
|
+
# DSL de cabecera del schema
|
|
26
|
+
datasource, generate, query,
|
|
20
27
|
# Core ORM components
|
|
21
28
|
Table, View, Enum, column, vector, vector_column, VectorColumn,
|
|
22
|
-
relation,
|
|
29
|
+
relation, unique_constraint, index_constraint,
|
|
30
|
+
TriggerAPI, on_create, on_update, on_delete,
|
|
23
31
|
trigger_api, col, onetomany, manytoone, onetoone, get_type_registry,
|
|
24
32
|
register_type, TypeDescriptor, BaseEncoder, SentenceTransformerEncoder,
|
|
25
33
|
OpenAIEncoder, AzureOpenAIEncoder, GoogleEncoder,
|
|
26
34
|
calculated_column,
|
|
27
35
|
)
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
# Importar el paquete registra los cuatro drivers: cada módulo se inscribe en el
|
|
38
|
+
# `DriverRegistry` al final. Antes esta línea los enumeraba uno a uno y era **la única**
|
|
39
|
+
# que los registraba, así que entrar por `tai_sql.drivers` daba "driver no soportado".
|
|
40
|
+
from . import drivers as drivers
|
|
30
41
|
|
|
31
42
|
# Exportar los elementos principales
|
|
32
43
|
__all__ = [
|
|
@@ -38,6 +49,8 @@ __all__ = [
|
|
|
38
49
|
'Table',
|
|
39
50
|
'column',
|
|
40
51
|
'relation',
|
|
52
|
+
'unique_constraint',
|
|
53
|
+
'index_constraint',
|
|
41
54
|
'List',
|
|
42
55
|
'Optional',
|
|
43
56
|
'datetime',
|