sqlobjects 1.2.5__tar.gz → 1.3.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.
Files changed (77) hide show
  1. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/CHANGELOG.md +6 -0
  2. {sqlobjects-1.2.5/sqlobjects.egg-info → sqlobjects-1.3.0}/PKG-INFO +1 -1
  3. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/pyproject.toml +1 -1
  4. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/functions.py +34 -5
  5. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/metadata.py +37 -0
  6. {sqlobjects-1.2.5 → sqlobjects-1.3.0/sqlobjects.egg-info}/PKG-INFO +1 -1
  7. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/LICENSE +0 -0
  8. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/README.md +0 -0
  9. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/01-database-session-guide.md +0 -0
  10. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/02-model-definition-guide.md +0 -0
  11. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/03-query-operations-guide.md +0 -0
  12. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/04-crud-operations-guide.md +0 -0
  13. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/05-relationships-guide.md +0 -0
  14. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/06-validation-signals-guide.md +0 -0
  15. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/07-performance-guide.md +0 -0
  16. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/README.md +0 -0
  17. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/setup.cfg +0 -0
  18. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/__init__.py +0 -0
  19. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/_install_rules.py +0 -0
  20. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/cascade.py +0 -0
  21. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/__init__.py +0 -0
  22. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/config.py +0 -0
  23. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/manager.py +0 -0
  24. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/exceptions.py +0 -0
  25. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/__init__.py +0 -0
  26. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/aggregate.py +0 -0
  27. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/base.py +0 -0
  28. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/cte.py +0 -0
  29. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/explain.py +0 -0
  30. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/function.py +0 -0
  31. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/mixins.py +0 -0
  32. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/scalar.py +0 -0
  33. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/subquery.py +0 -0
  34. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/terminal.py +0 -0
  35. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/window.py +0 -0
  36. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/__init__.py +0 -0
  37. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/core.py +0 -0
  38. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/proxies.py +0 -0
  39. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/__init__.py +0 -0
  40. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/descriptors.py +0 -0
  41. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/managers.py +0 -0
  42. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/prefetch.py +0 -0
  43. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/strategies.py +0 -0
  44. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/utils.py +0 -0
  45. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/shortcuts.py +0 -0
  46. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/__init__.py +0 -0
  47. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/base.py +0 -0
  48. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/comparators.py +0 -0
  49. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/registry.py +0 -0
  50. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/utils.py +0 -0
  51. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/__init__.py +0 -0
  52. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/operations.py +0 -0
  53. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/results.py +0 -0
  54. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/mixins.py +0 -0
  55. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/model.py +0 -0
  56. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/__init__.py +0 -0
  57. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/bulk.py +0 -0
  58. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/core.py +0 -0
  59. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/upsert.py +0 -0
  60. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/__init__.py +0 -0
  61. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/builder.py +0 -0
  62. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/dialect.py +0 -0
  63. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/executor.py +0 -0
  64. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queryset.py +0 -0
  65. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/session.py +0 -0
  66. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/signals.py +0 -0
  67. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/__init__.py +0 -0
  68. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/inspect.py +0 -0
  69. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/naming.py +0 -0
  70. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/pattern.py +0 -0
  71. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/validators.py +0 -0
  72. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/SOURCES.txt +0 -0
  73. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/dependency_links.txt +0 -0
  74. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/entry_points.txt +0 -0
  75. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/requires.txt +0 -0
  76. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/top_level.txt +0 -0
  77. {sqlobjects-1.2.5 → sqlobjects-1.3.0}/tests/test_config.py +0 -0
@@ -1,3 +1,9 @@
1
+ ## 1.3.0 (2026-03-10)
2
+
3
+ ### Feat
4
+
5
+ - **fields**: support class name reference in foreign_key() with delayed matching
6
+
1
7
  ## 1.2.5 (2026-03-06)
2
8
 
3
9
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlobjects
3
- Version: 1.2.5
3
+ Version: 1.3.0
4
4
  Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
5
5
  Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
6
6
  Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sqlobjects"
3
- version = "1.2.5"
3
+ version = "1.3.0"
4
4
  description = "Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -8,6 +8,22 @@ from .core import Column, column
8
8
  from .shortcuts import ComputedColumn, IdentityColumn
9
9
 
10
10
 
11
+ def _extract_table_or_class_name(reference: str) -> str | None:
12
+ """从 'X.col' 或 'schema.X.col' 中提取 X(可能是表名或类名)。
13
+
14
+ Returns:
15
+ X 部分,用于后续延迟匹配;格式不合法时返回 None
16
+ """
17
+ parts = reference.split(".")
18
+ if len(parts) == 2:
19
+ # "X.col"
20
+ return parts[0]
21
+ if len(parts) == 3:
22
+ # "schema.X.col"
23
+ return parts[1]
24
+ return None
25
+
26
+
11
27
  def identity(
12
28
  *,
13
29
  start: int = 1,
@@ -76,7 +92,10 @@ def foreign_key(
76
92
  """Create foreign key column with database constraint behavior.
77
93
 
78
94
  Args:
79
- reference: Foreign key reference in format "table.column"
95
+ reference: Foreign key reference in format "X.column" where X can be either
96
+ a model class name (e.g. "User.id", "UserProfile.id") or a database table
97
+ name (e.g. "users.id"). Class names are automatically resolved to table
98
+ names via delayed matching. Schema is also supported: "schema.X.column".
80
99
  type: Column type, "auto" for automatic type inference
81
100
  nullable: Whether column can be null
82
101
  ondelete: Database constraint behavior when referenced object is deleted
@@ -89,12 +108,15 @@ def foreign_key(
89
108
  Column descriptor with foreign key constraint
90
109
 
91
110
  Examples:
92
- # Basic usage with auto type inference
111
+ # Using class name (resolved automatically)
112
+ author_id: Column[int] = foreign_key("User.id")
113
+
114
+ # Using table name directly (also works)
93
115
  author_id: Column[int] = foreign_key("users.id")
94
116
 
95
117
  # Complete constraint configuration
96
118
  author_id: Column[int] = foreign_key(
97
- "users.id",
119
+ "User.id",
98
120
  ondelete="CASCADE",
99
121
  onupdate="CASCADE",
100
122
  nullable=False
@@ -102,7 +124,7 @@ def foreign_key(
102
124
 
103
125
  # Deferred constraint for circular references
104
126
  parent_id: Column[int] = foreign_key(
105
- "categories.id",
127
+ "Category.id",
106
128
  deferrable=True,
107
129
  initially="DEFERRED"
108
130
  )
@@ -122,9 +144,16 @@ def foreign_key(
122
144
  fk_kwargs["deferrable"] = True
123
145
  fk_kwargs["initially"] = initially
124
146
 
125
- # Create ForeignKey constraint
147
+ # Reference is passed directly to SQLAlchemy; delayed matching in
148
+ # ModelProcessor._resolve_class_foreign_keys will correct the table
149
+ # name if the first segment turns out to be a class name.
126
150
  fk_constraint = ForeignKey(reference, **fk_kwargs)
127
151
 
152
+ # Store the table-or-class segment for delayed resolution
153
+ table_or_class = _extract_table_or_class_name(reference)
154
+ if table_or_class:
155
+ fk_constraint.info["_fk_ref"] = table_or_class
156
+
128
157
  # Use existing column() function with foreign key
129
158
  return column(
130
159
  type=type,
@@ -368,6 +368,9 @@ class ModelProcessor(type):
368
368
  # Auto-register model to ModelRegistry
369
369
  registry.register_model(cast(type["ObjectModel"], cls))
370
370
 
371
+ # Resolve class name foreign key references to actual table names
372
+ mcs._resolve_class_foreign_keys(registry)
373
+
371
374
  # Process pending M2M tables
372
375
  registry.process_pending_m2m()
373
376
 
@@ -851,6 +854,40 @@ class ModelProcessor(type):
851
854
 
852
855
  cls.__eq__ = __eq__
853
856
 
857
+ @classmethod
858
+ def _resolve_class_foreign_keys(mcs, registry):
859
+ """延迟解析外键引用:优先按类名匹配,匹配不到则视为表名。
860
+
861
+ foreign_key("User.id") 传入时原样交给 SQLAlchemy(_colspec="User.id")。
862
+ 每次新模型注册后,此方法遍历所有 FK:
863
+ 1. 取出 info["_fk_ref"](即 "." 前的那段,如 "User")
864
+ 2. 尝试在 registry 中按类名查找模型
865
+ 3. 找到 → 替换 _colspec 为实际表名,标记 _resolved
866
+ 4. 找不到 → 保留原样(视为已经是表名)
867
+ """
868
+ for table in registry.tables.values():
869
+ for col in table.columns:
870
+ for fk in col.foreign_keys:
871
+ fk_info = fk.info
872
+ if fk_info.get("_fk_resolved"):
873
+ continue
874
+ ref_name = fk_info.get("_fk_ref")
875
+ if not ref_name:
876
+ continue
877
+ model = registry.get_model(ref_name)
878
+ if not model or not hasattr(model, "__table__"):
879
+ continue
880
+ # Found matching model — rewrite _colspec to actual table name
881
+ actual_table = model.__table__.name
882
+ schema, tname, colname = fk._column_tokens
883
+ if tname != actual_table:
884
+ if schema:
885
+ fk._colspec = f"{schema}.{actual_table}.{colname}"
886
+ else:
887
+ fk._colspec = f"{actual_table}.{colname}"
888
+ fk.__dict__.pop("_column_tokens", None)
889
+ fk_info["_fk_resolved"] = True
890
+
854
891
  @classmethod
855
892
  def _bind_column_attributes_to_table(mcs, cls: Any, table) -> None:
856
893
  """Bind ColumnAttribute instances to their corresponding table columns.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlobjects
3
- Version: 1.2.5
3
+ Version: 1.3.0
4
4
  Summary: Django-style async ORM library based on SQLAlchemy with chainable queries, Q objects, and relationship loading
5
5
  Author-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
6
6
  Maintainer-email: XtraVisions <gitadmin@xtravisions.com>, Chen Hao <chenhao@xtravisions.com>
File without changes
File without changes
File without changes