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.
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/CHANGELOG.md +6 -0
- {sqlobjects-1.2.5/sqlobjects.egg-info → sqlobjects-1.3.0}/PKG-INFO +1 -1
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/pyproject.toml +1 -1
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/functions.py +34 -5
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/metadata.py +37 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0/sqlobjects.egg-info}/PKG-INFO +1 -1
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/LICENSE +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/README.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/01-database-session-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/02-model-definition-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/03-query-operations-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/04-crud-operations-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/05-relationships-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/06-validation-signals-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/07-performance-guide.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/docs/rules/README.md +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/setup.cfg +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/_install_rules.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/cascade.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/config.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/database/manager.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/exceptions.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/aggregate.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/base.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/cte.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/explain.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/function.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/mixins.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/scalar.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/subquery.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/terminal.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/expressions/window.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/core.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/proxies.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/descriptors.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/managers.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/prefetch.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/strategies.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/relations/utils.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/shortcuts.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/base.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/comparators.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/types/registry.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/fields/utils.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/operations.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/internal/results.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/mixins.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/model.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/bulk.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/core.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/objects/upsert.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/builder.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/dialect.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queries/executor.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/queryset.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/session.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/signals.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/__init__.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/inspect.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/naming.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/utils/pattern.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects/validators.py +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/SOURCES.txt +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/dependency_links.txt +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/entry_points.txt +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/requires.txt +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/sqlobjects.egg-info/top_level.txt +0 -0
- {sqlobjects-1.2.5 → sqlobjects-1.3.0}/tests/test_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlobjects
|
|
3
|
-
Version: 1.
|
|
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>
|
|
@@ -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 "
|
|
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
|
-
#
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
#
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|