matrx-orm 2.0.7__tar.gz → 2.0.8__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 (125) hide show
  1. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/PKG-INFO +1 -1
  2. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/pyproject.toml +1 -1
  3. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/config.py +9 -6
  4. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/helpers/git_checker.py +18 -10
  5. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/runner.py +66 -9
  6. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/schema.py +15 -2
  7. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/schema_manager.py +2 -0
  8. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/tables.py +12 -2
  9. matrx_orm-2.0.8/tests/sample_project/.env.example +45 -0
  10. matrx_orm-2.0.8/tests/sample_project/matrx_orm.yaml +122 -0
  11. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/uv.lock +1 -1
  12. matrx_orm-2.0.7/tests/sample_project/.env.example +0 -24
  13. matrx_orm-2.0.7/tests/sample_project/matrx_orm.yaml +0 -67
  14. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/.arman/pending/versioning/INITIAL.md +0 -0
  15. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/.env.example +0 -0
  16. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/.github/workflows/publish.yml +0 -0
  17. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/.gitignore +0 -0
  18. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/.python-version +0 -0
  19. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/CLAUDE.md +0 -0
  20. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/MIGRATIONS.md +0 -0
  21. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/README.md +0 -0
  22. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/RESERVED_NAMES.md +0 -0
  23. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/docs/migrations.md +0 -0
  24. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/main.py +0 -0
  25. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/release.sh +0 -0
  26. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/__init__.py +0 -0
  27. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/adapters/__init__.py +0 -0
  28. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/adapters/base_adapter.py +0 -0
  29. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/adapters/postgresql.py +0 -0
  30. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/client/__init__.py +0 -0
  31. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/client/postgres_connection.py +0 -0
  32. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/__init__.py +0 -0
  33. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/async_db_manager.py +0 -0
  34. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/base.py +0 -0
  35. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/expressions.py +0 -0
  36. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/extended.py +0 -0
  37. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/fields.py +0 -0
  38. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/paginator.py +0 -0
  39. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/registry.py +0 -0
  40. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/relations.py +0 -0
  41. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/signals.py +0 -0
  42. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/core/transaction.py +0 -0
  43. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/error_handling.py +0 -0
  44. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/exceptions.py +0 -0
  45. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/extended/__init__.py +0 -0
  46. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/extended/app_error_handler.py +0 -0
  47. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/middleware/__init__.py +0 -0
  48. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/middleware/base.py +0 -0
  49. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/__init__.py +0 -0
  50. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/cli.py +0 -0
  51. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/ddl.py +0 -0
  52. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/diff.py +0 -0
  53. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/executor.py +0 -0
  54. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/integration.py +0 -0
  55. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/loader.py +0 -0
  56. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/operations.py +0 -0
  57. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/state.py +0 -0
  58. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/migrations/table_filter.py +0 -0
  59. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/operations/__init__.py +0 -0
  60. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/operations/create.py +0 -0
  61. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/operations/delete.py +0 -0
  62. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/operations/read.py +0 -0
  63. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/operations/update.py +0 -0
  64. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/python_sql/__init__.py +0 -0
  65. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/python_sql/db_objects.py +0 -0
  66. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  67. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  68. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/query/__init__.py +0 -0
  69. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/query/builder.py +0 -0
  70. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/query/executor.py +0 -0
  71. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/__init__.py +0 -0
  72. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/code_handler.py +0 -0
  73. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/columns.py +0 -0
  74. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/common.py +0 -0
  75. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/generator.py +0 -0
  76. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  77. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  78. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  79. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/relationships.py +0 -0
  80. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/schema_builder/views.py +0 -0
  81. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/__init__.py +0 -0
  82. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/executor.py +0 -0
  83. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/queries.py +0 -0
  84. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/registry.py +0 -0
  85. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/types.py +0 -0
  86. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/sql_executor/utils.py +0 -0
  87. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/state.py +0 -0
  88. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/utils/__init__.py +0 -0
  89. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/utils/sql_utils.py +0 -0
  90. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/src/matrx_orm/utils/type_converters.py +0 -0
  91. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/__init__.py +0 -0
  92. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/conftest.py +0 -0
  93. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/__init__.py +0 -0
  94. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_config.py +0 -0
  95. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_ddl_generator.py +0 -0
  96. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_exceptions.py +0 -0
  97. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_fields.py +0 -0
  98. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_migration_diff_types.py +0 -0
  99. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_migration_loader.py +0 -0
  100. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_model_instance.py +0 -0
  101. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_model_meta.py +0 -0
  102. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_query_builder.py +0 -0
  103. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_query_executor_sql.py +0 -0
  104. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_registry.py +0 -0
  105. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_relations.py +0 -0
  106. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level1/test_state_cache.py +0 -0
  107. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/__init__.py +0 -0
  108. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/conftest.py +0 -0
  109. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_bulk_ops.py +0 -0
  110. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_cache_integration.py +0 -0
  111. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_crud.py +0 -0
  112. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_foreign_keys.py +0 -0
  113. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_m2m.py +0 -0
  114. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_manager.py +0 -0
  115. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_migrations_live.py +0 -0
  116. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_query_execution.py +0 -0
  117. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/level2/test_schema_diff.py +0 -0
  118. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/sample_project/README.md +0 -0
  119. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/sample_project/generate.py +0 -0
  120. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/sample_project/generated/.gitkeep +0 -0
  121. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/sample_project/test_schema_generation.py +0 -0
  122. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/schema/entity_tests.py +0 -0
  123. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/schema/test_base_generation.py +0 -0
  124. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/tests/schema/test_generate_schema.py +0 -0
  125. {matrx_orm-2.0.7 → matrx_orm-2.0.8}/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.7
3
+ Version: 2.0.8
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "2.0.7"
3
+ version = "2.0.8"
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" }
@@ -169,22 +169,26 @@ def register_database_from_env(
169
169
  entity_overrides: Dict = None,
170
170
  field_overrides: Dict = None,
171
171
  manager_config_overrides: Dict = None,
172
+ env_var_overrides: Dict = None,
172
173
  ) -> bool:
173
174
  """
174
175
  Read database connection details from environment variables, validate them,
175
176
  and register the database. Prints colored diagnostics for missing or defaulted vars.
176
177
 
177
- Required env vars (using env_prefix, e.g. "PRIMARY_DB"):
178
+ Default env var names (using env_prefix, e.g. "PRIMARY_DB"):
178
179
  {env_prefix}_HOST, {env_prefix}_PORT, {env_prefix}_NAME,
179
180
  {env_prefix}_USER, {env_prefix}_PASSWORD
181
+ {env_prefix}_PROTOCOL (optional, defaults to "postgresql")
180
182
 
181
- Optional env vars:
182
- {env_prefix}_PROTOCOL — defaults to "postgresql"
183
+ env_var_overrides lets you remap any key to a different env var name.
184
+ Example: {"NAME": "SUPABASE_MATRIX_DATABASE_NAME"} reads that env var
185
+ instead of constructing {env_prefix}_NAME.
183
186
 
184
187
  Returns True if registration succeeded, False otherwise.
185
188
  """
186
189
  _REQUIRED = ["HOST", "PORT", "NAME", "USER", "PASSWORD"]
187
190
  _OPTIONAL = {"PROTOCOL": "postgresql"}
191
+ _overrides = env_var_overrides or {}
188
192
 
189
193
  vcprint(name, f"\n[MATRX ORM] Registering database", color="cyan")
190
194
 
@@ -192,7 +196,7 @@ def register_database_from_env(
192
196
  resolved: dict[str, str] = {}
193
197
 
194
198
  for key in _REQUIRED:
195
- env_var = f"{env_prefix}_{key}"
199
+ env_var = _overrides.get(key, f"{env_prefix}_{key}")
196
200
  val = os.environ.get(env_var, "").strip()
197
201
  if val:
198
202
  resolved[key] = val
@@ -200,7 +204,7 @@ def register_database_from_env(
200
204
  missing.append(env_var)
201
205
 
202
206
  for key, default in _OPTIONAL.items():
203
- env_var = f"{env_prefix}_{key}"
207
+ env_var = _overrides.get(key, f"{env_prefix}_{key}")
204
208
  val = os.environ.get(env_var, "").strip()
205
209
  if val:
206
210
  resolved[key] = val
@@ -287,7 +291,6 @@ def get_code_config(db_project):
287
291
  # Note: import_lines are dynamically replaced by generate_models() in schema.py
288
292
  # based on the actual field types used. This is a fallback default only.
289
293
  "import_lines": [
290
- "import database_registry",
291
294
  "from matrx_orm import Model, model_registry, BaseDTO, BaseManager",
292
295
  "from enum import Enum",
293
296
  "from dataclasses import dataclass"
@@ -56,17 +56,25 @@ def check_git_status(save_direct: bool, python_root: str = "", ts_root: str = ""
56
56
 
57
57
  # Check if there are uncommitted changes
58
58
  if repo.is_dirty(untracked_files=True):
59
- vcprint("- Uncommitted changes detected! Details:\n", color="red")
60
-
61
- # Show modified files
62
- modified = repo.git.status("--porcelain").split("\n")
63
- if any(line.strip() for line in modified):
59
+ modified_lines = [
60
+ line.strip()
61
+ for line in repo.git.status("--porcelain").split("\n")
62
+ if line.strip()
63
+ ]
64
+ changed_files = [line[3:].strip() for line in modified_lines]
65
+
66
+ # Allow the sole change to be matrx_orm.yaml (config sync artifact)
67
+ if len(changed_files) == 1 and os.path.basename(changed_files[0]) == "matrx_orm.yaml":
68
+ vcprint(
69
+ f"- Only 'matrx_orm.yaml' has changes — treating as clean ✓",
70
+ color="green",
71
+ )
72
+ else:
73
+ vcprint("- Uncommitted changes detected! Details:\n", color="red")
64
74
  vcprint(" Modified files:", color="red")
65
- for line in modified:
66
- if line.strip():
67
- vcprint(f" {line.strip()}", color="red")
68
-
69
- has_issues = True
75
+ for line in modified_lines:
76
+ vcprint(f" {line}", color="red")
77
+ has_issues = True
70
78
  else:
71
79
  vcprint("- No uncommitted changes found ✓", color="green")
72
80
 
@@ -56,12 +56,25 @@ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
56
56
 
57
57
  vcprint(config_path, f"[MATRX ORM] Loading config", color="cyan")
58
58
 
59
- # Load .env from the same directory as the config file
60
- env_file = config_path.parent / ".env"
61
- if env_file.exists():
59
+ # Load .env — search from the config file's directory upward, stopping at
60
+ # the filesystem root. This mirrors how git, Node, and most tooling work:
61
+ # the .env lives at the project root, not necessarily next to generate.py.
62
+ env_file = None
63
+ search = config_path.parent
64
+ while True:
65
+ candidate = search / ".env"
66
+ if candidate.exists():
67
+ env_file = candidate
68
+ break
69
+ parent = search.parent
70
+ if parent == search:
71
+ break
72
+ search = parent
73
+
74
+ if env_file:
62
75
  load_dotenv(env_file)
63
76
  else:
64
- load_dotenv() # fallback to default search
77
+ load_dotenv() # last-resort: let python-dotenv search from cwd
65
78
 
66
79
  cfg = _load_yaml(config_path)
67
80
 
@@ -75,21 +88,49 @@ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
75
88
 
76
89
  # -------------------------------------------------------------------------
77
90
  # Output config — resolves paths, type flags, and save_direct
91
+ #
92
+ # Priority (highest wins):
93
+ # 1. .env MATRX_PYTHON_ROOT / MATRX_TS_ROOT / MATRX_SAVE_DIRECT
94
+ # 2. matrx_orm.yaml output.python_root / output.typescript_root / output.save_direct
95
+ #
96
+ # This lets developers keep machine-specific absolute paths (e.g. paths
97
+ # outside the project, or different per server) in their local .env without
98
+ # touching the yaml that gets committed to git.
78
99
  # -------------------------------------------------------------------------
79
100
  output_cfg = cfg.get("output", {})
80
101
  base = config_path.parent
81
102
 
82
- python_root = ""
83
- ts_root = ""
84
-
85
- if "python_root" in output_cfg:
103
+ # Resolve python_root: .env wins over yaml
104
+ env_python_root = os.environ.get("MATRX_PYTHON_ROOT", "").strip()
105
+ if env_python_root:
106
+ python_root = env_python_root
107
+ elif "python_root" in output_cfg:
86
108
  python_root = str((base / output_cfg["python_root"]).resolve())
109
+ else:
110
+ python_root = ""
111
+
112
+ if python_root:
87
113
  os.environ["ADMIN_PYTHON_ROOT"] = python_root
88
114
 
89
- if "typescript_root" in output_cfg:
115
+ # Resolve typescript_root: .env wins over yaml
116
+ env_ts_root = os.environ.get("MATRX_TS_ROOT", "").strip()
117
+ if env_ts_root:
118
+ ts_root = env_ts_root
119
+ elif "typescript_root" in output_cfg:
90
120
  ts_root = str((base / output_cfg["typescript_root"]).resolve())
121
+ else:
122
+ ts_root = ""
123
+
124
+ if ts_root:
91
125
  os.environ["ADMIN_TS_ROOT"] = ts_root
92
126
 
127
+ # Resolve save_direct: .env wins over yaml (yaml default is False)
128
+ env_save_direct = os.environ.get("MATRX_SAVE_DIRECT", "").strip().lower()
129
+ if env_save_direct in ("1", "true"):
130
+ output_cfg = {**output_cfg, "save_direct": True}
131
+ elif env_save_direct in ("0", "false"):
132
+ output_cfg = {**output_cfg, "save_direct": False}
133
+
93
134
  output_config = OutputConfig.from_dict(output_cfg)
94
135
 
95
136
  # -------------------------------------------------------------------------
@@ -115,7 +156,12 @@ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
115
156
  register_database_from_env(
116
157
  name=name,
117
158
  env_prefix=prefix,
159
+ alias=db.get("alias", ""),
118
160
  additional_schemas=db.get("additional_schemas", []),
161
+ entity_overrides=db.get("entity_overrides") or {},
162
+ field_overrides=db.get("field_overrides") or {},
163
+ manager_config_overrides=db.get("manager_config_overrides") or {},
164
+ env_var_overrides=db.get("env_var_overrides") or {},
119
165
  )
120
166
 
121
167
  # -------------------------------------------------------------------------
@@ -130,6 +176,14 @@ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
130
176
  db_name = entry.get("database")
131
177
  schema = entry.get("schema", "public")
132
178
 
179
+ # Table filters — mutually exclusive
180
+ include_tables = entry.get("include_tables") or None
181
+ exclude_tables = entry.get("exclude_tables") or None
182
+
183
+ # manager_flags: yaml-level defaults for all tables in this generation run.
184
+ # Per-table manager_config_overrides (from the databases section) stack on top.
185
+ manager_flags = entry.get("manager_flags") or None
186
+
133
187
  vcprint(f"[MATRX ORM] Generating schema... \n\n- Database: '{db_name}'\n- Schema: '{schema}'", verbose=DEBUG_CONFIG["verbose"], color="cyan")
134
188
 
135
189
  try:
@@ -137,6 +191,9 @@ def run_schema_generation(config_path: str | Path = "matrx_orm.yaml") -> None:
137
191
  schema=schema,
138
192
  database_project=db_name,
139
193
  output_config=output_config,
194
+ include_tables=include_tables,
195
+ exclude_tables=exclude_tables,
196
+ manager_flags=manager_flags,
140
197
  )
141
198
  manager.initialize()
142
199
  manager.schema.generate_schema_files()
@@ -20,12 +20,24 @@ def format_ts_object(ts_object_str):
20
20
  return re.sub(r'"(\w+)"\s*:', r"\1:", ts_object_str)
21
21
 
22
22
 
23
+ _MANAGER_FLAG_DEFAULTS: dict = {
24
+ "include_core_relations": True,
25
+ "include_filter_fields": True,
26
+ "include_active_relations": False,
27
+ "include_active_methods": False,
28
+ "include_or_not_methods": False,
29
+ "include_to_dict_methods": False,
30
+ "include_to_dict_relations": False,
31
+ }
32
+
33
+
23
34
  class Schema:
24
35
  def __init__(
25
36
  self,
26
37
  name="public",
27
38
  database_project=None,
28
39
  output_config: OutputConfig = None,
40
+ manager_flags: dict | None = None,
29
41
  ):
30
42
  if output_config is None:
31
43
  output_config = OutputConfig()
@@ -44,6 +56,8 @@ class Schema:
44
56
  self.initialized = False
45
57
  self._include_tables: set[str] | None = None
46
58
  self._exclude_tables: set[str] | None = None
59
+ # Global manager flags — yaml-level defaults, per-table overrides stack on top
60
+ self.manager_flags: dict = {**_MANAGER_FLAG_DEFAULTS, **(manager_flags or {})}
47
61
 
48
62
  vcprint(
49
63
  self.to_dict(),
@@ -796,7 +810,7 @@ class Schema:
796
810
 
797
811
  for table_name in sorted_tables:
798
812
  table = self.tables[table_name]
799
- py_manager_entry = table.to_python_manager_string()
813
+ py_manager_entry = table.to_python_manager_string(self.manager_flags)
800
814
  py_manager_structure.append(py_manager_entry)
801
815
 
802
816
  py_auto_config_entry = table.base_class_auto_config
@@ -835,7 +849,6 @@ class Schema:
835
849
  sorted_field_types = sorted(all_field_types)
836
850
  field_imports = ", ".join(sorted_field_types)
837
851
  dynamic_import_lines = [
838
- "import database_registry",
839
852
  f"from matrx_orm import {field_imports}, model_registry, BaseDTO, BaseManager",
840
853
  ]
841
854
  if has_enums:
@@ -21,6 +21,7 @@ class SchemaManager:
21
21
  save_direct=False,
22
22
  include_tables=None,
23
23
  exclude_tables=None,
24
+ manager_flags: dict | None = None,
24
25
  ):
25
26
  if additional_schemas is None:
26
27
  # Read from the registered database config if a project name is provided;
@@ -53,6 +54,7 @@ class SchemaManager:
53
54
  name=schema,
54
55
  database_project=database_project,
55
56
  output_config=output_config,
57
+ manager_flags=manager_flags,
56
58
  )
57
59
  self.additional_schemas = additional_schemas
58
60
  self.database_project = database_project
@@ -1138,7 +1138,7 @@ class Table:
1138
1138
 
1139
1139
  return py_structure
1140
1140
 
1141
- def to_python_manager_string(self):
1141
+ def to_python_manager_string(self, global_manager_flags: dict | None = None):
1142
1142
  MANAGER_CONFIG_OVERRIDES = get_manager_config(self.database_project)
1143
1143
 
1144
1144
  relations = self.get_all_relations_list()
@@ -1150,6 +1150,12 @@ class Table:
1150
1150
  m2m_relations = list(m2m_config.keys()) if m2m_config else None
1151
1151
 
1152
1152
  alias = get_database_alias(self.database_project)
1153
+
1154
+ # Start with system defaults, apply yaml-level global flags, then per-table overrides.
1155
+ # This gives three layers of control:
1156
+ # 1. System defaults (hardcoded here — safe baseline)
1157
+ # 2. global_manager_flags from matrx_orm.yaml generate[].manager_flags
1158
+ # 3. manager_config_overrides from databases[].manager_config_overrides (per-table)
1153
1159
  base_config = {
1154
1160
  "models_module_path": f"database.{alias}.models",
1155
1161
  "model_pascal": self.python_model_name,
@@ -1168,7 +1174,11 @@ class Table:
1168
1174
  "m2m_relations": m2m_relations,
1169
1175
  }
1170
1176
 
1171
- # Apply overrides if they exist
1177
+ # Layer 2: yaml generate[].manager_flags (all-table defaults for this run)
1178
+ if global_manager_flags:
1179
+ base_config.update(global_manager_flags)
1180
+
1181
+ # Layer 3: per-table manager_config_overrides from the database registration
1172
1182
  if self.name in MANAGER_CONFIG_OVERRIDES:
1173
1183
  model_overrides = MANAGER_CONFIG_OVERRIDES[self.name]
1174
1184
  base_config.update(model_overrides)
@@ -0,0 +1,45 @@
1
+ # ============================================================
2
+ # matrx-orm Sample Project — Environment Variables
3
+ # ============================================================
4
+ #
5
+ # Copy this file to .env and fill in your values.
6
+ # The .env file is never committed to git.
7
+ #
8
+ # ============================================================
9
+ # Output path overrides (optional)
10
+ # ============================================================
11
+ #
12
+ # These override the python_root / typescript_root / save_direct
13
+ # values in matrx_orm.yaml. Use them to keep machine-specific
14
+ # absolute paths (e.g. paths outside the project, or paths that
15
+ # differ per developer / server) out of the yaml file that gets
16
+ # committed to git.
17
+ #
18
+ # If these are not set, matrx-orm uses whatever is in matrx_orm.yaml.
19
+ #
20
+ # MATRX_PYTHON_ROOT=/absolute/path/to/python/output
21
+ # MATRX_TS_ROOT=/absolute/path/to/typescript/output
22
+ #
23
+ # Override save_direct from .env (true = write directly to roots,
24
+ # false = write to temp staging directory).
25
+ # MATRX_SAVE_DIRECT=true
26
+
27
+ # ============================================================
28
+ # Primary database (e.g. your main Supabase project)
29
+ # ============================================================
30
+ PRIMARY_DB_HOST=enter_your_primary_db_host_here
31
+ PRIMARY_DB_PORT=5432
32
+ PRIMARY_DB_PROTOCOL=postgresql
33
+ PRIMARY_DB_NAME=postgres
34
+ PRIMARY_DB_USER=postgres
35
+ PRIMARY_DB_PASSWORD=your-database-password-here
36
+
37
+ # ============================================================
38
+ # Secondary database (e.g. a second Supabase project or remote Postgres)
39
+ # ============================================================
40
+ SECONDARY_DB_HOST=enter_your_secondary_db_host_here
41
+ SECONDARY_DB_PORT=5432
42
+ SECONDARY_DB_PROTOCOL=postgresql
43
+ SECONDARY_DB_NAME=postgres
44
+ SECONDARY_DB_USER=postgres
45
+ SECONDARY_DB_PASSWORD=your-database-password-here
@@ -0,0 +1,122 @@
1
+ # =============================================================================
2
+ # matrx-orm configuration
3
+ # =============================================================================
4
+ #
5
+ # This file drives reverse-migration schema generation.
6
+ # Run: python generate.py
7
+ #
8
+ # =============================================================================
9
+ # Output
10
+ # =============================================================================
11
+ #
12
+ # python_root and typescript_root set where generated files land.
13
+ # Use absolute paths or paths relative to this config file.
14
+ #
15
+ # These can also be overridden per-environment using .env variables:
16
+ # MATRX_PYTHON_ROOT=/absolute/path/to/python/output
17
+ # MATRX_TS_ROOT=/absolute/path/to/typescript/output
18
+ #
19
+ # .env wins over yaml — use it to keep machine-specific paths out of git.
20
+ #
21
+ output:
22
+ python_root: generated/python
23
+ typescript_root: generated/typescript
24
+
25
+ # save_direct: controls whether generated files overwrite your live source
26
+ # files or are written to a temporary staging directory instead.
27
+ #
28
+ # false (default) — safe mode. Files go to a temp dir so you can review
29
+ # them before committing. Nothing in your project is
30
+ # touched.
31
+ #
32
+ # true — live mode. Files are written directly to python_root
33
+ # and typescript_root. matrx-orm will refuse to run if
34
+ # either root has uncommitted git changes (safety guard
35
+ # so you never lose hand-written work).
36
+ #
37
+ # Can also be set via .env: MATRX_SAVE_DIRECT=true
38
+ #
39
+ save_direct: true
40
+
41
+ # Set any of these to false to skip generating that file type entirely.
42
+ python: true
43
+ typescript: true
44
+ json: true
45
+
46
+ # =============================================================================
47
+ # Databases
48
+ # =============================================================================
49
+ # Add as many databases as you need. Each entry needs a unique name.
50
+ # The env_prefix tells matrx-orm which environment variables hold the
51
+ # connection details. For a prefix of "PRIMARY_DB" it reads:
52
+ # PRIMARY_DB_HOST, PRIMARY_DB_PORT, PRIMARY_DB_NAME,
53
+ # PRIMARY_DB_USER, PRIMARY_DB_PASSWORD
54
+ # PRIMARY_DB_PROTOCOL (optional, defaults to "postgresql")
55
+ #
56
+ databases:
57
+ - name: primary
58
+ env_prefix: PRIMARY_DB
59
+ additional_schemas:
60
+ - auth
61
+
62
+ - name: secondary
63
+ env_prefix: SECONDARY_DB
64
+ additional_schemas:
65
+ - auth
66
+
67
+ # =============================================================================
68
+ # Schema generation
69
+ # =============================================================================
70
+ # Each entry below triggers one reverse-migration run.
71
+ # database must match a name defined in the databases section above.
72
+ #
73
+ # Table filtering (mutually exclusive — use one or neither):
74
+ # include_tables: [table_a, table_b] — only generate these tables
75
+ # exclude_tables: [table_x, table_y] — generate everything except these
76
+ #
77
+ # manager_flags controls which methods are included in each generated manager
78
+ # class. These map directly to the code-generation layer — changing them
79
+ # affects what methods every developer gets in their generated managers.
80
+ #
81
+ # Defaults shown below exactly match the built-in system defaults.
82
+ # Only override what you need to change.
83
+ #
84
+ generate:
85
+ - database: primary
86
+ schema: public
87
+ # include_tables:
88
+ # - my_table
89
+ # - other_table
90
+ # exclude_tables:
91
+ # - internal_table
92
+ manager_flags:
93
+ include_core_relations: true # FK/IFK fetch methods (load_by_*, fetch_fk, fetch_ifk)
94
+ include_filter_fields: true # filter_by_* methods for indexed/common lookup fields
95
+ include_active_relations: false # active-record style relation traversal
96
+ include_active_methods: false # active-record create/update/delete on instance
97
+ include_or_not_methods: false # load_or_create, update_or_create helpers
98
+ include_to_dict_methods: false # to_dict() / to_json() serializers
99
+ include_to_dict_relations: false # include related objects in to_dict() output
100
+
101
+ # Uncomment to also generate from the secondary database:
102
+ # - database: secondary
103
+ # schema: public
104
+ # manager_flags:
105
+ # include_core_relations: true
106
+ # include_filter_fields: true
107
+ # include_active_relations: false
108
+ # include_active_methods: false
109
+ # include_or_not_methods: false
110
+ # include_to_dict_methods: false
111
+ # include_to_dict_relations: false
112
+
113
+ # =============================================================================
114
+ # Debug
115
+ # =============================================================================
116
+ # Controls console output during generation.
117
+ # Can also be set per-run via env vars: MATRX_INFO, MATRX_DEBUG, MATRX_VERBOSE
118
+ #
119
+ debug:
120
+ info: true
121
+ debug: false
122
+ verbose: false
@@ -266,7 +266,7 @@ wheels = [
266
266
 
267
267
  [[package]]
268
268
  name = "matrx-orm"
269
- version = "2.0.6"
269
+ version = "2.0.7"
270
270
  source = { editable = "." }
271
271
  dependencies = [
272
272
  { name = "asyncpg" },
@@ -1,24 +0,0 @@
1
- # ============================================================
2
- # matrx-orm Sample Project — Environment Variables
3
- # ============================================================
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
-
9
-
10
- # --- Primary database (e.g. your main Supabase project) ---
11
- PRIMARY_DB_HOST=enter_your_primary_db_host_here
12
- PRIMARY_DB_PORT=5432
13
- PRIMARY_DB_PROTOCOL=postgresql
14
- PRIMARY_DB_NAME=postgres
15
- PRIMARY_DB_USER=postgres
16
- PRIMARY_DB_PASSWORD=your-database-password-here
17
-
18
- # --- Secondary database (e.g. a second Supabase project or remote Postgres) ---
19
- SECONDARY_DB_HOST=enter_your_secondary_db_host_here
20
- SECONDARY_DB_PORT=5432
21
- SECONDARY_DB_PROTOCOL=postgresql
22
- SECONDARY_DB_NAME=postgres
23
- SECONDARY_DB_USER=postgres
24
- SECONDARY_DB_PASSWORD=your-database-password-here
@@ -1,67 +0,0 @@
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
-
14
- # save_direct: write directly to the roots above instead of the temp dir.
15
- # When true, matrx-orm will refuse to run if either root has uncommitted
16
- # git changes (safety guard).
17
- save_direct: true
18
-
19
- # Set any of these to false to skip generating that file type entirely.
20
- python: true
21
- typescript: true
22
- json: true
23
-
24
- # =============================================================================
25
- # Databases
26
- # =============================================================================
27
- # Add as many databases as you need. Each entry needs a unique name.
28
- # The env_prefix tells matrx-orm which environment variables hold the
29
- # connection details. For a prefix of "PRIMARY_DB" it reads:
30
- # PRIMARY_DB_HOST, PRIMARY_DB_PORT, PRIMARY_DB_NAME,
31
- # PRIMARY_DB_USER, PRIMARY_DB_PASSWORD
32
- # PRIMARY_DB_PROTOCOL (optional, defaults to "postgresql")
33
- #
34
- databases:
35
- - name: primary
36
- env_prefix: PRIMARY_DB
37
- additional_schemas:
38
- - auth
39
-
40
- - name: secondary
41
- env_prefix: SECONDARY_DB
42
- additional_schemas:
43
- - auth
44
-
45
- # =============================================================================
46
- # Schema generation
47
- # =============================================================================
48
- # Each entry below triggers one reverse-migration run.
49
- # database must match a name defined in the databases section above.
50
- #
51
- generate:
52
- - database: primary
53
- schema: public
54
-
55
-
56
- # Uncomment to also generate from the secondary database:
57
- - database: secondary
58
- schema: public
59
-
60
- # =============================================================================
61
- # Debug
62
- # =============================================================================
63
- debug:
64
- info: true
65
- debug: true
66
- verbose: true
67
-
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