matrx-orm 2.0.2__tar.gz → 2.0.4__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 (124) hide show
  1. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/PKG-INFO +2 -1
  2. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/pyproject.toml +2 -1
  3. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/release.sh +7 -2
  4. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/__init__.py +2 -0
  5. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/client/postgres_connection.py +2 -1
  6. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/config.py +82 -0
  7. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/python_sql/db_objects.py +4 -3
  8. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/python_sql/table_detailed_relationships.py +4 -4
  9. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/python_sql/table_typescript_relationship.py +5 -3
  10. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/__init__.py +4 -0
  11. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/common.py +6 -6
  12. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/helpers/__init__.py +2 -5
  13. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/helpers/git_checker.py +15 -11
  14. matrx_orm-2.0.4/src/matrx_orm/schema_builder/runner.py +160 -0
  15. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/schema_manager.py +4 -0
  16. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/sample_project/.env.example +10 -5
  17. matrx_orm-2.0.4/tests/sample_project/generate.py +3 -0
  18. matrx_orm-2.0.4/tests/sample_project/matrx_orm.yaml +57 -0
  19. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/uv.lock +67 -1
  20. matrx_orm-2.0.2/tests/sample_project/database_registry.py +0 -52
  21. matrx_orm-2.0.2/tests/sample_project/run_schema_generation.py +0 -61
  22. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/.arman/pending/versioning/INITIAL.md +0 -0
  23. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/.env.example +0 -0
  24. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/.github/workflows/publish.yml +0 -0
  25. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/.gitignore +0 -0
  26. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/.python-version +0 -0
  27. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/CLAUDE.md +0 -0
  28. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/MIGRATIONS.md +0 -0
  29. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/README.md +0 -0
  30. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/RESERVED_NAMES.md +0 -0
  31. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/docs/migrations.md +0 -0
  32. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/main.py +0 -0
  33. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/adapters/__init__.py +0 -0
  34. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/adapters/base_adapter.py +0 -0
  35. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/adapters/postgresql.py +0 -0
  36. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/client/__init__.py +0 -0
  37. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/__init__.py +0 -0
  38. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/async_db_manager.py +0 -0
  39. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/base.py +0 -0
  40. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/expressions.py +0 -0
  41. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/extended.py +0 -0
  42. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/fields.py +0 -0
  43. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/paginator.py +0 -0
  44. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/registry.py +0 -0
  45. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/relations.py +0 -0
  46. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/signals.py +0 -0
  47. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/core/transaction.py +0 -0
  48. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/error_handling.py +0 -0
  49. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/exceptions.py +0 -0
  50. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/extended/__init__.py +0 -0
  51. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/extended/app_error_handler.py +0 -0
  52. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/middleware/__init__.py +0 -0
  53. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/middleware/base.py +0 -0
  54. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/__init__.py +0 -0
  55. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/cli.py +0 -0
  56. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/ddl.py +0 -0
  57. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/diff.py +0 -0
  58. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/executor.py +0 -0
  59. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/integration.py +0 -0
  60. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/loader.py +0 -0
  61. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/operations.py +0 -0
  62. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/state.py +0 -0
  63. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/migrations/table_filter.py +0 -0
  64. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/operations/__init__.py +0 -0
  65. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/operations/create.py +0 -0
  66. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/operations/delete.py +0 -0
  67. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/operations/read.py +0 -0
  68. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/operations/update.py +0 -0
  69. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/python_sql/__init__.py +0 -0
  70. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/query/__init__.py +0 -0
  71. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/query/builder.py +0 -0
  72. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/query/executor.py +0 -0
  73. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/columns.py +0 -0
  74. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/generator.py +0 -0
  75. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  76. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  77. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/relationships.py +0 -0
  78. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/schema.py +0 -0
  79. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/tables.py +0 -0
  80. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/schema_builder/views.py +0 -0
  81. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/__init__.py +0 -0
  82. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/executor.py +0 -0
  83. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/queries.py +0 -0
  84. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/registry.py +0 -0
  85. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/types.py +0 -0
  86. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/sql_executor/utils.py +0 -0
  87. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/state.py +0 -0
  88. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/utils/__init__.py +0 -0
  89. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/utils/sql_utils.py +0 -0
  90. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/src/matrx_orm/utils/type_converters.py +0 -0
  91. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/__init__.py +0 -0
  92. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/conftest.py +0 -0
  93. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/__init__.py +0 -0
  94. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_config.py +0 -0
  95. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_ddl_generator.py +0 -0
  96. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_exceptions.py +0 -0
  97. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_fields.py +0 -0
  98. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_migration_diff_types.py +0 -0
  99. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_migration_loader.py +0 -0
  100. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_model_instance.py +0 -0
  101. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_model_meta.py +0 -0
  102. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_query_builder.py +0 -0
  103. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_query_executor_sql.py +0 -0
  104. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_registry.py +0 -0
  105. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_relations.py +0 -0
  106. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level1/test_state_cache.py +0 -0
  107. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/__init__.py +0 -0
  108. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/conftest.py +0 -0
  109. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_bulk_ops.py +0 -0
  110. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_cache_integration.py +0 -0
  111. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_crud.py +0 -0
  112. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_foreign_keys.py +0 -0
  113. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_m2m.py +0 -0
  114. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_manager.py +0 -0
  115. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_migrations_live.py +0 -0
  116. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_query_execution.py +0 -0
  117. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/level2/test_schema_diff.py +0 -0
  118. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/sample_project/README.md +0 -0
  119. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/sample_project/generated/.gitkeep +0 -0
  120. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/sample_project/test_schema_generation.py +0 -0
  121. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/schema/entity_tests.py +0 -0
  122. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/schema/test_base_generation.py +0 -0
  123. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/schema/test_generate_schema.py +0 -0
  124. {matrx_orm-2.0.2 → matrx_orm-2.0.4}/tests/test_model_cls_refactor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matrx-orm
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching. Works with any PostgreSQL database.
5
5
  Project-URL: Homepage, https://github.com/armanisadeghi/matrx-orm
6
6
  Project-URL: Repository, https://github.com/armanisadeghi/matrx-orm
@@ -31,6 +31,7 @@ Requires-Dist: gitpython>=3.1.40
31
31
  Requires-Dist: matrx-utils>=1.0.4
32
32
  Requires-Dist: psycopg-pool>=3.2.5
33
33
  Requires-Dist: psycopg[binary]>=3.2.5
34
+ Requires-Dist: pyyaml>=6.0.3
34
35
  Provides-Extra: dev
35
36
  Requires-Dist: pytest-asyncio>=1.0; extra == 'dev'
36
37
  Requires-Dist: pytest>=9.0; extra == 'dev'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "2.0.2"
3
+ version = "2.0.4"
4
4
  description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching. Works with any PostgreSQL database."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -45,6 +45,7 @@ dependencies = [
45
45
  "psycopg[binary]>=3.2.5",
46
46
  "psycopg-pool>=3.2.5",
47
47
  "matrx-utils>=1.0.4",
48
+ "pyyaml>=6.0.3",
48
49
  ]
49
50
 
50
51
  [project.optional-dependencies]
@@ -67,7 +67,7 @@ echo ""
67
67
  # ── Update pyproject.toml and amend the commit ─────────────────────────────
68
68
 
69
69
  info "Updating $PYPROJECT to version $NEW_VERSION..."
70
- sed -i "s/^version = \"$CURRENT_VERSION\"/version = \"$NEW_VERSION\"/" "$PYPROJECT"
70
+ sed -i '' "s/^version = \"$CURRENT_VERSION\"/version = \"$NEW_VERSION\"/" "$PYPROJECT"
71
71
  ok "Version updated in $PYPROJECT"
72
72
 
73
73
  info "Amending last commit to include version bump..."
@@ -99,6 +99,11 @@ echo -e "${GREEN} Released matrx-orm $NEW_VERSION${NC}"
99
99
  echo -e "${GREEN} GitHub Actions will now build and publish to PyPI.${NC}"
100
100
  echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
101
101
  echo ""
102
+ echo ""
103
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
102
104
  echo -e " Monitor: ${CYAN}https://github.com/armanisadeghi/matrx-orm/actions${NC}"
103
- echo -e " Update: ${CYAN}uv add matrx-orm@${NEW_VERSION}${NC}"
105
+ echo -e " Update: ${CYAN}uv add matrx-orm==${NEW_VERSION}${NC}"
106
+ echo ""
107
+ echo -e " --> Not Available Yet? Speed up indexing: ${CYAN}pip index versions matrx-orm${NC}"
108
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
104
109
  echo ""
@@ -1,6 +1,7 @@
1
1
  from .core.config import (
2
2
  DatabaseProjectConfig,
3
3
  register_database,
4
+ register_database_from_env,
4
5
  get_database_config,
5
6
  get_connection_string,
6
7
  get_manager_config,
@@ -131,6 +132,7 @@ from .migrations import (
131
132
  __all__ = [
132
133
  "DatabaseProjectConfig",
133
134
  "register_database",
135
+ "register_database_from_env",
134
136
  "get_database_config",
135
137
  "get_connection_string",
136
138
  "get_manager_config",
@@ -31,8 +31,9 @@ def init_connection_details(config_name):
31
31
  f"Incomplete database configuration for '{config_name}'. " "Please check your environment variables or settings.")
32
32
 
33
33
  connection_string = f"{db_protocol}://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"
34
+ redacted = f"{db_protocol}://{db_user}:****@{db_host}:{db_port}/{db_name}"
34
35
 
35
- vcprint(f"\n[Matrx ORM] Connection String:\n{connection_string}\n", color="yellow")
36
+ vcprint(f"\n[Matrx ORM] Connection String:\n{redacted}\n", color="yellow")
36
37
 
37
38
  connection_pools[config_name] = ConnectionPool(
38
39
  connection_string,
@@ -161,6 +161,88 @@ def register_database(config: DatabaseProjectConfig) -> None:
161
161
  registry.register(config)
162
162
 
163
163
 
164
+ def register_database_from_env(
165
+ name: str,
166
+ env_prefix: str,
167
+ alias: str = "",
168
+ additional_schemas: list = None,
169
+ entity_overrides: Dict = None,
170
+ field_overrides: Dict = None,
171
+ manager_config_overrides: Dict = None,
172
+ ) -> bool:
173
+ """
174
+ Read database connection details from environment variables, validate them,
175
+ and register the database. Prints colored diagnostics for missing or defaulted vars.
176
+
177
+ Required env vars (using env_prefix, e.g. "PRIMARY_DB"):
178
+ {env_prefix}_HOST, {env_prefix}_PORT, {env_prefix}_NAME,
179
+ {env_prefix}_USER, {env_prefix}_PASSWORD
180
+
181
+ Optional env vars:
182
+ {env_prefix}_PROTOCOL — defaults to "postgresql"
183
+
184
+ Returns True if registration succeeded, False otherwise.
185
+ """
186
+ _REQUIRED = ["HOST", "PORT", "NAME", "USER", "PASSWORD"]
187
+ _OPTIONAL = {"PROTOCOL": "postgresql"}
188
+
189
+ vcprint(f"[matrx-orm] Registering database '{name}'...", color="cyan")
190
+
191
+ missing: list[str] = []
192
+ resolved: dict[str, str] = {}
193
+
194
+ for key in _REQUIRED:
195
+ env_var = f"{env_prefix}_{key}"
196
+ val = os.environ.get(env_var, "").strip()
197
+ if val:
198
+ resolved[key] = val
199
+ else:
200
+ missing.append(env_var)
201
+
202
+ for key, default in _OPTIONAL.items():
203
+ env_var = f"{env_prefix}_{key}"
204
+ val = os.environ.get(env_var, "").strip()
205
+ if val:
206
+ resolved[key] = val
207
+ else:
208
+ resolved[key] = default
209
+ vcprint(
210
+ f" '{env_var}' not set — using default: '{default}'",
211
+ color="yellow",
212
+ )
213
+
214
+ if missing:
215
+ vcprint(
216
+ f" Database '{name}' NOT registered — missing required env vars:",
217
+ color="red",
218
+ )
219
+ for var in missing:
220
+ vcprint(f" • {var}", color="red")
221
+ return False
222
+
223
+ try:
224
+ config = DatabaseProjectConfig(
225
+ name=name,
226
+ alias=alias or name,
227
+ host=resolved["HOST"],
228
+ port=resolved["PORT"],
229
+ protocol=resolved["PROTOCOL"],
230
+ database_name=resolved["NAME"],
231
+ user=resolved["USER"],
232
+ password=resolved["PASSWORD"],
233
+ additional_schemas=additional_schemas or [],
234
+ entity_overrides=entity_overrides or {},
235
+ field_overrides=field_overrides or {},
236
+ manager_config_overrides=manager_config_overrides or {},
237
+ )
238
+ registry.register(config)
239
+ vcprint(f" Database '{name}' registered successfully.", color="green")
240
+ return True
241
+ except DatabaseConfigError as e:
242
+ vcprint(f" Database '{name}' registration failed: {e}", color="red")
243
+ return False
244
+
245
+
164
246
  def get_connection_string(config_name: str) -> str:
165
247
  config = get_database_config(config_name)
166
248
  connection_string = f"{config['protocol']}://{config['user']}:{redact_string(config['password'])}@{config['host']}:{config['port']}/{config['database_name']}"
@@ -1,10 +1,11 @@
1
1
  from matrx_orm.client.postgres_connection import execute_sql_query
2
2
  from collections import defaultdict
3
3
  from matrx_orm.python_sql.table_typescript_relationship import get_ts_object
4
+ from matrx_orm.schema_builder.common import DEBUG_CONFIG
4
5
 
5
- verbose = False
6
- debug = False
7
- info = True
6
+ verbose = DEBUG_CONFIG["verbose"]
7
+ debug = DEBUG_CONFIG["debug"]
8
+ info = DEBUG_CONFIG["info"]
8
9
 
9
10
 
10
11
  def get_full_db_objects(schema, database_project):
@@ -1,9 +1,9 @@
1
1
  from matrx_orm.client.postgres_connection import execute_sql_query
2
+ from matrx_orm.schema_builder.common import DEBUG_CONFIG
2
3
 
3
-
4
- verbose = False
5
- debug = False
6
- info = True
4
+ verbose = DEBUG_CONFIG["verbose"]
5
+ debug = DEBUG_CONFIG["debug"]
6
+ info = DEBUG_CONFIG["info"]
7
7
 
8
8
 
9
9
  def get_table_relationships(schema, database_project):
@@ -4,9 +4,11 @@ from matrx_orm.python_sql.table_detailed_relationships import (
4
4
  analyze_relationships,
5
5
  )
6
6
 
7
- verbose = False
8
- debug = False
9
- info = True
7
+ from matrx_orm.schema_builder.common import DEBUG_CONFIG
8
+
9
+ verbose = DEBUG_CONFIG["verbose"]
10
+ debug = DEBUG_CONFIG["debug"]
11
+ info = DEBUG_CONFIG["info"]
10
12
 
11
13
 
12
14
  def transform_relationships_for_typescript(relationships_data, junction_analysis):
@@ -16,6 +16,9 @@ from matrx_orm.schema_builder.helpers import (
16
16
  from matrx_orm.schema_builder.schema_manager import (
17
17
  SchemaManager,
18
18
  )
19
+ from matrx_orm.schema_builder.runner import (
20
+ run_schema_generation,
21
+ )
19
22
 
20
23
 
21
24
  __all__ = [
@@ -24,6 +27,7 @@ __all__ = [
24
27
  "DEBUG_CONFIG",
25
28
  "schema_builder_verbose",
26
29
  "SchemaManager",
30
+ "run_schema_generation",
27
31
  "check_git_status",
28
32
  "get_schema_structure",
29
33
  "generate_dto_and_manager",
@@ -13,14 +13,14 @@ ADMIN_TS_ROOT = os.getenv("ADMIN_TS_ROOT", "")
13
13
 
14
14
  dt_utils = DataTransformer()
15
15
 
16
- schema_builder_save_direct = True
17
-
18
-
16
+ # Central debug configuration for the entire schema builder.
17
+ # Values can be overridden at runtime by run_schema_generation() from the yaml
18
+ # debug section, or by setting env vars MATRX_DEBUG, MATRX_VERBOSE, MATRX_INFO.
19
19
  DEBUG_CONFIG = {
20
20
  "tables": [],
21
21
  "columns": [],
22
22
  "base_type": [],
23
- "info": True,
24
- "debug": False,
25
- "verbose": False,
23
+ "info": os.getenv("MATRX_INFO", "").lower() in ("1", "true"),
24
+ "debug": os.getenv("MATRX_DEBUG", "").lower() in ("1", "true"),
25
+ "verbose": os.getenv("MATRX_VERBOSE", "").lower() in ("1", "true"),
26
26
  }
@@ -15,11 +15,8 @@ from matrx_orm.schema_builder.helpers.entity_generators import (
15
15
  generate_typescript_entity,
16
16
  )
17
17
 
18
- from matrx_orm.schema_builder.helpers.git_checker import (
19
- ADMIN_PYTHON_ROOT,
20
- ADMIN_TS_ROOT,
21
- check_git_status,
22
- )
18
+ from matrx_orm.schema_builder.common import ADMIN_PYTHON_ROOT, ADMIN_TS_ROOT
19
+ from matrx_orm.schema_builder.helpers.git_checker import check_git_status
23
20
  from matrx_orm.schema_builder.helpers.base_generators import (
24
21
  generate_active_methods,
25
22
  generate_active_relation_methods,
@@ -2,18 +2,24 @@ import os
2
2
  import sys
3
3
  from git import Repo, GitCommandError, InvalidGitRepositoryError
4
4
  from matrx_utils import vcprint
5
- from matrx_orm.schema_builder.common import ADMIN_PYTHON_ROOT, ADMIN_TS_ROOT
6
5
 
7
6
 
8
- def check_git_status(save_direct):
7
+ def check_git_status(save_direct: bool, python_root: str = "", ts_root: str = "") -> bool:
9
8
  """
10
- Check if ADMIN_PYTHON_ROOT and ADMIN_TS_ROOT are git repositories
11
- and verify if there are any uncommitted changes.
12
- Returns True if it's safe to proceed (no changes), False otherwise.
9
+ Check if python_root and ts_root are git repositories with no uncommitted
10
+ changes before allowing a save_direct write that could overwrite live files.
11
+
12
+ Falls back to ADMIN_PYTHON_ROOT / ADMIN_TS_ROOT env vars when the caller
13
+ doesn't supply explicit paths (backward-compat).
14
+
15
+ Returns True if safe to proceed, exits with code 1 if not.
13
16
  """
17
+ python_root = python_root or os.getenv("ADMIN_PYTHON_ROOT", "")
18
+ ts_root = ts_root or os.getenv("ADMIN_TS_ROOT", "")
19
+
14
20
  roots_to_check = [
15
- ("Admin Python Root", ADMIN_PYTHON_ROOT),
16
- ("Admin TypeScript Root", ADMIN_TS_ROOT),
21
+ ("Python root", python_root),
22
+ ("TypeScript root", ts_root),
17
23
  ]
18
24
  has_issues = False
19
25
 
@@ -25,10 +31,8 @@ def check_git_status(save_direct):
25
31
  return True
26
32
 
27
33
  vcprint("\n[MATRX GIT CHECKER] Checking git repository status...", color="yellow")
28
- vcprint(
29
- f"[MATRX GIT CHECKER] ADMIN_PYTHON_ROOT: {ADMIN_PYTHON_ROOT}", color="green"
30
- )
31
- vcprint(f"[MATRX GIT CHECKER] ADMIN_TS_ROOT: {ADMIN_TS_ROOT}", color="green")
34
+ vcprint(f"[MATRX GIT CHECKER] Python root: {python_root}", color="green")
35
+ vcprint(f"[MATRX GIT CHECKER] TypeScript root: {ts_root}", color="green")
32
36
  print()
33
37
 
34
38
  for root_name, root_path in roots_to_check:
@@ -0,0 +1,160 @@
1
+ """
2
+ run_schema_generation() — the single entry point for yaml-driven reverse migrations.
3
+
4
+ Usage:
5
+ from matrx_orm.schema_builder import run_schema_generation
6
+ run_schema_generation("matrx_orm.yaml")
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from dotenv import load_dotenv
17
+ from matrx_utils import vcprint
18
+
19
+ from matrx_orm.core.config import register_database_from_env, DatabaseConfigError
20
+ from matrx_orm.schema_builder.common import DEBUG_CONFIG
21
+ from matrx_orm.schema_builder.helpers.git_checker import check_git_status
22
+ from matrx_orm.schema_builder.schema_manager import SchemaManager
23
+
24
+
25
+ def _load_yaml(path: Path) -> dict[str, Any]:
26
+ try:
27
+ import yaml
28
+ except ImportError:
29
+ raise ImportError(
30
+ "PyYAML is required for yaml-based configuration. "
31
+ "Install it with: pip install pyyaml"
32
+ )
33
+ with open(path) as f:
34
+ return yaml.safe_load(f) or {}
35
+
36
+
37
+ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
38
+ """
39
+ Read a matrx_orm.yaml config file, register all databases, apply debug
40
+ settings, then run reverse-migration schema generation for each entry in
41
+ the ``generate`` list.
42
+
43
+ The config file is looked up relative to the calling script's directory
44
+ (i.e. the directory that contains generate.py), so users never need to
45
+ think about working-directory quirks.
46
+ """
47
+ # Resolve config path relative to the caller's file location
48
+ caller_dir = Path(sys.argv[0]).parent.resolve()
49
+ config_path = (caller_dir / config_path).resolve()
50
+
51
+ if not config_path.exists():
52
+ raise FileNotFoundError(
53
+ f"matrx-orm config not found: {config_path}\n"
54
+ f"Create a matrx_orm.yaml file next to your generate.py script."
55
+ )
56
+
57
+ vcprint(f"[matrx-orm] Loading config: {config_path}", color="cyan")
58
+
59
+ # Load .env from the same directory as the config file
60
+ env_file = config_path.parent / ".env"
61
+ if env_file.exists():
62
+ load_dotenv(env_file)
63
+ else:
64
+ load_dotenv() # fallback to default search
65
+
66
+ cfg = _load_yaml(config_path)
67
+
68
+ # -------------------------------------------------------------------------
69
+ # Debug settings
70
+ # -------------------------------------------------------------------------
71
+ debug_cfg = cfg.get("debug", {})
72
+ DEBUG_CONFIG["info"] = bool(debug_cfg.get("info", False))
73
+ DEBUG_CONFIG["debug"] = bool(debug_cfg.get("debug", False))
74
+ DEBUG_CONFIG["verbose"] = bool(debug_cfg.get("verbose", False))
75
+
76
+ # -------------------------------------------------------------------------
77
+ # Output directories + save_direct
78
+ # -------------------------------------------------------------------------
79
+ output_cfg = cfg.get("output", {})
80
+ base = config_path.parent
81
+ save_direct = bool(output_cfg.get("save_direct", False))
82
+
83
+ python_root = ""
84
+ ts_root = ""
85
+
86
+ if "python_root" in output_cfg:
87
+ python_root = str((base / output_cfg["python_root"]).resolve())
88
+ os.environ["ADMIN_PYTHON_ROOT"] = python_root
89
+
90
+ if "typescript_root" in output_cfg:
91
+ ts_root = str((base / output_cfg["typescript_root"]).resolve())
92
+ os.environ["ADMIN_TS_ROOT"] = ts_root
93
+
94
+ # -------------------------------------------------------------------------
95
+ # Git safety check — must run before any generation when save_direct=True
96
+ # -------------------------------------------------------------------------
97
+ check_git_status(save_direct, python_root=python_root, ts_root=ts_root)
98
+
99
+ # -------------------------------------------------------------------------
100
+ # Register databases
101
+ # -------------------------------------------------------------------------
102
+ databases = cfg.get("databases", [])
103
+ if not databases:
104
+ vcprint("[matrx-orm] No databases defined in matrx_orm.yaml — nothing to do.", color="yellow")
105
+ return
106
+
107
+ for db in databases:
108
+ name = db.get("name")
109
+ prefix = db.get("env_prefix")
110
+ if not name or not prefix:
111
+ vcprint(f"[matrx-orm] Skipping database entry missing 'name' or 'env_prefix': {db}", color="yellow")
112
+ continue
113
+
114
+ register_database_from_env(
115
+ name=name,
116
+ env_prefix=prefix,
117
+ additional_schemas=db.get("additional_schemas", []),
118
+ )
119
+
120
+ # -------------------------------------------------------------------------
121
+ # Run generation for each configured target
122
+ # -------------------------------------------------------------------------
123
+ generate_list = cfg.get("generate", [])
124
+ if not generate_list:
125
+ vcprint("[matrx-orm] No entries in 'generate' — databases registered but nothing generated.", color="yellow")
126
+ return
127
+
128
+ for entry in generate_list:
129
+ db_name = entry.get("database")
130
+ schema = entry.get("schema", "public")
131
+
132
+ vcprint(
133
+ f"[matrx-orm] Generating schema for database='{db_name}' schema='{schema}'",
134
+ color="cyan",
135
+ )
136
+
137
+ try:
138
+ manager = SchemaManager(
139
+ schema=schema,
140
+ database_project=db_name,
141
+ save_direct=save_direct,
142
+ )
143
+ manager.initialize()
144
+ manager.schema.generate_schema_files()
145
+ manager.schema.generate_models()
146
+ vcprint(
147
+ f"[matrx-orm] Done — database='{db_name}' schema='{schema}'",
148
+ color="green",
149
+ )
150
+ except DatabaseConfigError as e:
151
+ vcprint(
152
+ f"[matrx-orm] Skipping '{db_name}': {e}",
153
+ color="red",
154
+ )
155
+ except Exception as e:
156
+ vcprint(
157
+ f"[matrx-orm] Error generating '{db_name}': {e}",
158
+ color="red",
159
+ )
160
+ raise
@@ -66,6 +66,10 @@ class SchemaManager:
66
66
  set(exclude_tables) if exclude_tables is not None else None
67
67
  )
68
68
 
69
+ vcprint(self.schema, title=f"SCHEMA MANAGER] with schema", verbose=self.verbose, color="blue")
70
+ vcprint(self.database_project, title=f"SCHEMA MANAGER] with database project", verbose=self.verbose, color="blue")
71
+ vcprint(self.additional_schemas, title=f"SCHEMA MANAGER] with additional schemas", verbose=self.verbose, color="blue")
72
+
69
73
  # Propagate filter to the Schema so generate_models() can apply it at
70
74
  # write-time without touching any loading or relationship logic.
71
75
  self.schema._include_tables = self._include_tables
@@ -1,19 +1,24 @@
1
1
  # ============================================================
2
- # matrx-orm Sample Project — Environment Variable Template
2
+ # matrx-orm Sample Project — Environment Variables
3
3
  # ============================================================
4
- # Copy this file to .env and fill in your real credentials.
5
- # The .env file is gitignored and will never be committed.
4
+
5
+ BASE_DIR=enter_your_base_directory_here
6
+ ADMIN_PYTHON_ROOT=enter_your_python_root_here
7
+ ADMIN_TS_ROOT=enter_your_typescript_root_here
8
+
6
9
 
7
10
  # --- Primary database (e.g. your main Supabase project) ---
8
- PRIMARY_DB_HOST=db.<project-ref>.supabase.co
11
+ PRIMARY_DB_HOST=enter_your_primary_db_host_here
9
12
  PRIMARY_DB_PORT=5432
13
+ PRIMARY_DB_PROTOCOL=postgresql
10
14
  PRIMARY_DB_NAME=postgres
11
15
  PRIMARY_DB_USER=postgres
12
16
  PRIMARY_DB_PASSWORD=your-database-password-here
13
17
 
14
18
  # --- Secondary database (e.g. a second Supabase project or remote Postgres) ---
15
- SECONDARY_DB_HOST=db.<project-ref>.supabase.co
19
+ SECONDARY_DB_HOST=enter_your_secondary_db_host_here
16
20
  SECONDARY_DB_PORT=5432
21
+ SECONDARY_DB_PROTOCOL=postgresql
17
22
  SECONDARY_DB_NAME=postgres
18
23
  SECONDARY_DB_USER=postgres
19
24
  SECONDARY_DB_PASSWORD=your-database-password-here
@@ -0,0 +1,3 @@
1
+ from matrx_orm.schema_builder import run_schema_generation
2
+
3
+ run_schema_generation("matrx_orm.yaml")
@@ -0,0 +1,57 @@
1
+ # =============================================================================
2
+ # matrx-orm configuration
3
+ # =============================================================================
4
+ #
5
+ # This file drives reverse-migration schema generation.
6
+ # Run: python generate.py
7
+ #
8
+ # Output directories for generated files.
9
+ # Use absolute paths or paths relative to this config file.
10
+ output:
11
+ python_root: generated/python
12
+ typescript_root: generated/typescript
13
+ # save_direct: false — set to true to write directly to the roots above.
14
+ # When true, matrx-orm will refuse to run if either
15
+ # root has uncommitted git changes (safety guard).
16
+ save_direct: false
17
+
18
+ # =============================================================================
19
+ # Databases
20
+ # =============================================================================
21
+ # Add as many databases as you need. Each entry needs a unique name.
22
+ # The env_prefix tells matrx-orm which environment variables hold the
23
+ # connection details. For a prefix of "PRIMARY_DB" it reads:
24
+ # PRIMARY_DB_HOST, PRIMARY_DB_PORT, PRIMARY_DB_NAME,
25
+ # PRIMARY_DB_USER, PRIMARY_DB_PASSWORD
26
+ # PRIMARY_DB_PROTOCOL (optional, defaults to "postgresql")
27
+ #
28
+ databases:
29
+ - name: primary
30
+ env_prefix: PRIMARY_DB
31
+ additional_schemas:
32
+ - auth
33
+
34
+ - name: secondary
35
+ env_prefix: SECONDARY_DB
36
+
37
+ # =============================================================================
38
+ # Schema generation
39
+ # =============================================================================
40
+ # Each entry below triggers one reverse-migration run.
41
+ # database must match a name defined in the databases section above.
42
+ #
43
+ generate:
44
+ - database: primary
45
+ schema: public
46
+
47
+ # Uncomment to also generate from the secondary database:
48
+ # - database: secondary
49
+ # schema: public
50
+
51
+ # =============================================================================
52
+ # Debug
53
+ # =============================================================================
54
+ debug:
55
+ info: false
56
+ verbose: false
57
+ debug: false