sqlobjects 1.2.4__py3-none-any.whl → 1.3.0__py3-none-any.whl

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 (20) hide show
  1. sqlobjects/expressions/function.py +2 -0
  2. sqlobjects/expressions/mixins.py +19 -3
  3. sqlobjects/fields/functions.py +34 -5
  4. sqlobjects/fields/types/comparators.py +54 -5
  5. sqlobjects/fields/types/registry.py +6 -4
  6. sqlobjects/metadata.py +37 -0
  7. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/METADATA +1 -1
  8. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/RECORD +20 -20
  9. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/WHEEL +1 -1
  10. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/01-database-session-guide.md +0 -0
  11. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/02-model-definition-guide.md +0 -0
  12. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/03-query-operations-guide.md +0 -0
  13. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/04-crud-operations-guide.md +0 -0
  14. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/05-relationships-guide.md +0 -0
  15. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/06-validation-signals-guide.md +0 -0
  16. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/07-performance-guide.md +0 -0
  17. {sqlobjects-1.2.4.data → sqlobjects-1.3.0.data}/data/share/sqlobjects/rules/README.md +0 -0
  18. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/entry_points.txt +0 -0
  19. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/licenses/LICENSE +0 -0
  20. {sqlobjects-1.2.4.dist-info → sqlobjects-1.3.0.dist-info}/top_level.txt +0 -0
@@ -147,6 +147,8 @@ class FunctionExpression:
147
147
  for building complex database expressions.
148
148
  """
149
149
 
150
+ is_clause_element = False # prevent __getattr__ from proxying this to expression.is_clause_element
151
+
150
152
  if TYPE_CHECKING:
151
153
  # Inherit all method hints for IDE support
152
154
  def __new__(cls, *args, **kwargs) -> "FunctionExpression & _FunctionMethods": ... # type: ignore
@@ -247,9 +247,25 @@ class ColumnAttributeFunctionMixin(FunctionMixin):
247
247
  def extract(self, field: str) -> "FunctionExpression": ...
248
248
  def date_trunc(self, precision: str) -> "FunctionExpression": ...
249
249
 
250
- # JSON methods
251
- def extract_path(self, path) -> "FunctionExpression": ...
252
- def extract_text(self, path) -> "FunctionExpression": ...
250
+ # JSON methods (MySQL json type)
251
+ def json_extract(self, path: str) -> "FunctionExpression": ...
252
+ def json_unquote(self, path: str) -> "FunctionExpression": ...
253
+ def json_contains(self, other, path: str | None = None) -> "FunctionExpression": ...
254
+ def json_contains_path(self, *paths: str, match: str = "one") -> "FunctionExpression": ...
255
+ def json_length(self, path: str | None = None) -> "FunctionExpression": ...
256
+ def json_keys(self, path: str | None = None) -> "FunctionExpression": ...
257
+ def json_overlaps(self, other) -> "FunctionExpression": ...
258
+ def json_search(self, value: str, match: str = "one", path: str | None = None) -> "FunctionExpression": ...
259
+ def json_type(self) -> "FunctionExpression": ...
260
+
261
+ # JSONB methods (PostgreSQL jsonb type)
262
+ def contained_by(self, other) -> "FunctionExpression": ...
263
+ def has_key(self, other) -> "FunctionExpression": ...
264
+ def has_all(self, other) -> "FunctionExpression": ...
265
+ def has_any(self, other) -> "FunctionExpression": ...
266
+ def path_exists(self, other) -> "FunctionExpression": ...
267
+ def path_match(self, other) -> "FunctionExpression": ...
268
+ def delete_path(self, array) -> "FunctionExpression": ...
253
269
 
254
270
  # Common methods (all types)
255
271
  def sum(self) -> "FunctionExpression": ...
@@ -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,
@@ -323,13 +323,62 @@ class DateTimeComparator(ComparatorMixin, DateTime.Comparator): # type: ignore[
323
323
 
324
324
 
325
325
  class JSONComparator(ComparatorMixin, JSON.Comparator): # type: ignore[reportIncompatibleMethodOverride]
326
- """JSON type comparator with JSON extraction and manipulation methods."""
326
+ """MySQL JSON type comparator. For PostgreSQL, use jsonb type instead."""
327
327
 
328
- def extract_path(self, path) -> FunctionExpression:
329
- return FunctionExpression(func.json_extract_path(self, path))
328
+ def json_extract(self, path: str) -> FunctionExpression:
329
+ """JSON_EXTRACT(col, path) - e.g. json_extract('$.name')"""
330
+ return FunctionExpression(func.json_extract(self, path))
330
331
 
331
- def extract_text(self, path) -> FunctionExpression:
332
- return FunctionExpression(func.json_extract_path_text(self, path))
332
+ def json_unquote(self, path: str) -> FunctionExpression:
333
+ """JSON_UNQUOTE(JSON_EXTRACT(col, path)) - returns unquoted string value"""
334
+ return FunctionExpression(func.json_unquote(func.json_extract(self, path)))
335
+
336
+ def json_contains(self, other, path: str | None = None) -> FunctionExpression:
337
+ """JSON_CONTAINS(col, val[, path]) - check if JSON contains value"""
338
+ import json
339
+
340
+ from sqlalchemy import literal
341
+
342
+ value = [other] if not isinstance(other, (list, dict)) else other
343
+ json_val = literal(json.dumps(value))
344
+ if path is not None:
345
+ return FunctionExpression(func.json_contains(self, json_val, path))
346
+ return FunctionExpression(func.json_contains(self, json_val))
347
+
348
+ def json_contains_path(self, *paths: str, match: str = "one") -> FunctionExpression:
349
+ """JSON_CONTAINS_PATH(col, 'one'|'all', path, ...) - check if path(s) exist"""
350
+ return FunctionExpression(func.json_contains_path(self, match, *paths))
351
+
352
+ def json_length(self, path: str | None = None) -> FunctionExpression:
353
+ """JSON_LENGTH(col[, path]) - array/object length"""
354
+ if path is not None:
355
+ return FunctionExpression(func.json_length(self, path))
356
+ return FunctionExpression(func.json_length(self))
357
+
358
+ def json_keys(self, path: str | None = None) -> FunctionExpression:
359
+ """JSON_KEYS(col[, path]) - return all keys as JSON array"""
360
+ if path is not None:
361
+ return FunctionExpression(func.json_keys(self, path))
362
+ return FunctionExpression(func.json_keys(self))
363
+
364
+ def json_overlaps(self, other) -> FunctionExpression:
365
+ """JSON_OVERLAPS(col, val) - check if two JSON documents share any key-value pairs (MySQL 8.0+)"""
366
+ import json
367
+
368
+ from sqlalchemy import literal
369
+
370
+ value = other if isinstance(other, str) else json.dumps(other)
371
+ return FunctionExpression(func.json_overlaps(self, literal(value)))
372
+
373
+ def json_search(self, value: str, match: str = "one", path: str | None = None) -> FunctionExpression:
374
+ """JSON_SEARCH(col, 'one'|'all', val[, path]) - find path of value"""
375
+ if path is not None:
376
+ return FunctionExpression(func.json_search(self, match, value, None, path))
377
+ return FunctionExpression(func.json_search(self, match, value))
378
+
379
+ def json_type(self) -> FunctionExpression:
380
+ """JSON_TYPE(col) - return JSON value type as string"""
381
+ return FunctionExpression(func.json_type(self))
333
382
 
334
383
 
335
384
  class BooleanComparator(ComparatorMixin, Boolean.Comparator): # type: ignore[reportIncompatibleMethodOverride]
@@ -1,9 +1,10 @@
1
1
  import inspect
2
2
  from typing import Any, Callable, NotRequired, TypedDict
3
3
 
4
+ from sqlalchemy.dialects.mysql import JSON
5
+ from sqlalchemy.dialects.postgresql import JSONB
4
6
  from sqlalchemy.sql.sqltypes import (
5
7
  ARRAY,
6
- JSON,
7
8
  BigInteger,
8
9
  Boolean,
9
10
  Date,
@@ -344,14 +345,15 @@ class TypeRegistry:
344
345
  (Interval, "interval", DateTimeComparator, [], {}),
345
346
  (LargeBinary, "binary", DefaultComparator, ["bytes"], {}),
346
347
  (Uuid, "uuid", StringComparator, [], {}),
347
- (JSON, "json", JSONComparator, ["dict"], {}),
348
348
  ]
349
349
 
350
- # Special types
350
+ # Special types: dialect-specific or non-standard types
351
351
  special_types = [
352
- (ARRAY, "array", DefaultComparator, [], {}),
352
+ (ARRAY, "array", DefaultComparator, [], {}), # PostgreSQL only
353
353
  (Enum, "enum", DefaultComparator, [], {}),
354
354
  (Auto, "auto", DefaultComparator, [], {}),
355
+ (JSON, "json", JSONComparator, ["dict"], {}), # MySQL: contains -> JSON_CONTAINS
356
+ (JSONB, "jsonb", JSONB.Comparator, [], {}), # PostgreSQL: contains -> @>
355
357
  ]
356
358
 
357
359
  for field_type, name, comparator, aliases, defaults in builtin_types + special_types:
sqlobjects/metadata.py CHANGED
@@ -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.4
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>
@@ -2,7 +2,7 @@ sqlobjects/__init__.py,sha256=AiZiXBEjvrSItmhnlgyvMDCipU49XmvQPAujg-EoEDg,977
2
2
  sqlobjects/_install_rules.py,sha256=ndw9815-60WY_ORGUefijUBnoUHPd0NBzUkCL8mQLKc,4053
3
3
  sqlobjects/cascade.py,sha256=HLHB4TEoqK7m2i4X9JM0oX3nbltuTntaX3tMX1B1ym4,38389
4
4
  sqlobjects/exceptions.py,sha256=IEp5XV6N3hc3SAU-C3F-5D6jEZU_p72mufvwVhaStHo,16592
5
- sqlobjects/metadata.py,sha256=ftumbrSTJGN73jtg0e88vPwGURQAxRkho6B41YOMU-Q,41481
5
+ sqlobjects/metadata.py,sha256=5f76PnUJ7YFr4JMZJHWqrf2Cr4Mjm-rmLF6FyrNNO2Y,43324
6
6
  sqlobjects/mixins.py,sha256=TBZFYAfa9RKF0UpxloBwREoWRPrWFHQE8MjOu7Aepu0,25501
7
7
  sqlobjects/model.py,sha256=PwP-0XhlVktICRCEye0gYlXrkVQG13yErjOwwf2ssJ0,19273
8
8
  sqlobjects/queryset.py,sha256=nIouDo4oL6a3fdrNNAeicFHeYYIx0fpdOpFND5wugAg,50079
@@ -17,15 +17,15 @@ sqlobjects/expressions/aggregate.py,sha256=Gh4HekOaUmYDkS8O4QnmEhuf73QD44dBuAgUL
17
17
  sqlobjects/expressions/base.py,sha256=L9zHa9gb9M88sA9JmUSpR9k5tr-9Pgknbajo1ZmhOpk,5177
18
18
  sqlobjects/expressions/cte.py,sha256=9NAPpvBpxIoWmhc7eL3MyI3pmw65b9Hz6WzdNr2iVzc,4440
19
19
  sqlobjects/expressions/explain.py,sha256=GpfJq_JPgBfkNa9xlPi1wvkqYR6hlgT4V6lq5y6ftCE,1210
20
- sqlobjects/expressions/function.py,sha256=Dk5e_26ZKVdOqWdpQkC_XZWndUmYoq_iAMRFiK1O448,15113
21
- sqlobjects/expressions/mixins.py,sha256=pwqFXl7csdcou-O3ztfZ760XLdREqr4br0S475v2BSc,10469
20
+ sqlobjects/expressions/function.py,sha256=vCDbZR2aSxwXPGn_S2d93pm4yc3Xd2N83Fgpu6HTyr4,15218
21
+ sqlobjects/expressions/mixins.py,sha256=y430mXrJoz9dn7BNO74ZCtFvP1P5IDJAC3c5t4-Ex3s,11595
22
22
  sqlobjects/expressions/scalar.py,sha256=TRg1cg70m5kLKK2d-IOCHk0hPD2WWtXYErlMYSz6zio,6034
23
23
  sqlobjects/expressions/subquery.py,sha256=Jhhcl-EJbCvZmC91f7mZI4yeJqYVEyWtODHgB0_tNjk,15065
24
24
  sqlobjects/expressions/terminal.py,sha256=3R3LsRMoUazpd3EVNYi_m1LXwx6l42kyv4zlosgsrN0,15024
25
25
  sqlobjects/expressions/window.py,sha256=0Olsi422n04SuemGjhIB_WwA9vTGJvMqOjHPWBFjHOo,7871
26
26
  sqlobjects/fields/__init__.py,sha256=SXYpmfS3l0CqKTIJsOD68wiQIE_x2ORYk2D7gb_E7Qc,1459
27
27
  sqlobjects/fields/core.py,sha256=IUGofZ-BlPuMzQBsqH25Ri9eGvLkenur7969u_wMniU,38712
28
- sqlobjects/fields/functions.py,sha256=KuCdtjTdfXo_1c2MNSlcPhyQmjPo8xFIt4CNUZnvU88,4281
28
+ sqlobjects/fields/functions.py,sha256=5a5I9pwzhz01HTbLw1M-AX_3StROfwwJzinqiFUFEfc,5468
29
29
  sqlobjects/fields/proxies.py,sha256=nUSKYWDdmv91--0TzWh5-YK-fauW-piVVAiLZtMWjqM,17541
30
30
  sqlobjects/fields/shortcuts.py,sha256=euYyW0DliR77jLZDRQLNSsCpIHJBoRc7kzTBOIvHQFo,22794
31
31
  sqlobjects/fields/utils.py,sha256=HokUdlkyrUT85U468_ngWH7wbGj-VSjSet1AYG64tqI,3549
@@ -37,8 +37,8 @@ sqlobjects/fields/relations/strategies.py,sha256=X4KkeBxwpCcBHWhcL9EGH2WTQ2NdZWB
37
37
  sqlobjects/fields/relations/utils.py,sha256=G1PbW1heCShUSfjaDIbqj4I0yODdy4j3udf0Ex70cOg,12487
38
38
  sqlobjects/fields/types/__init__.py,sha256=PaEslOWuQVZVUoVnUFtqF-sNHOvF9AEVhuDseqRr-GA,651
39
39
  sqlobjects/fields/types/base.py,sha256=aK-8UDYtUcqJtwxw_emR-WefKDhrQyp0BK7s-UKx4yw,463
40
- sqlobjects/fields/types/comparators.py,sha256=d9azQGpUGg7eNF_aR0wWjZDzL3sFClHNh-fyObQudgY,15556
41
- sqlobjects/fields/types/registry.py,sha256=52niJnXdpqRewFKyOyiU-EhygR7SSZ1RQsflZ4u7evI,14529
40
+ sqlobjects/fields/types/comparators.py,sha256=Q0w1O_b1nh7_47s2xV9PLZtZdStNc3hVk87LCcKgHD8,18000
41
+ sqlobjects/fields/types/registry.py,sha256=6wNs-Fa18QA6o9u57eJ2yZyojOi4SdIu6Xd9ROsvM7I,14792
42
42
  sqlobjects/internal/__init__.py,sha256=Vam4blEYmPIgxMJY5YI32btY6Q2SD49OaGduwnaSDsM,447
43
43
  sqlobjects/internal/operations.py,sha256=IDB6XiIDZUFBfm_uub6Jr77hgOAEpCQbLNLBAcHeflA,3561
44
44
  sqlobjects/internal/results.py,sha256=rTX4sIG9Eo9Ik3eTWKV116MPtNzGjdLAJIy8FdVGWBA,2216
@@ -54,17 +54,17 @@ sqlobjects/utils/__init__.py,sha256=NsJ52Fl_PaB-2WlOIJVGNPmgOnqPmvYRmp7uaq5zfYs,
54
54
  sqlobjects/utils/inspect.py,sha256=u-Q9VBoSGYCE_3Soy8jMuCAdM-P7IkSzTxqrJop_Ilk,2612
55
55
  sqlobjects/utils/naming.py,sha256=PmfNuEz-Twly2qREjKfMNulJt8TmOUJaxzFTuts3COg,1411
56
56
  sqlobjects/utils/pattern.py,sha256=FGCgobTpnmKjdAtQidHIg4Xa2CQLeP35F0VuX_1T1dk,14740
57
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/01-database-session-guide.md,sha256=lnqRpcDhYKdH-f0avW1jXcWt3qi7XBwkMt7clTs9Zvg,7601
58
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/02-model-definition-guide.md,sha256=i5gNJM-0bIJ2xSUu3mij8uB9kJC9EAc_439sCBqRph8,10977
59
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/03-query-operations-guide.md,sha256=BEZE_WUUhY6sEZDiDtrbInlV_UVIhbYETABJTNhu2JQ,10550
60
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/04-crud-operations-guide.md,sha256=abUEvRPSiSjX8enclXO5Uryox9Rt0WFeRcFkvHXfPf8,10085
61
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/05-relationships-guide.md,sha256=MJ23fYOTWqrLd54ENZLu3S3QRqbLf7joq-YhF6-V8OQ,12204
62
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/06-validation-signals-guide.md,sha256=i9WLLhyCDoWGkIYqH2D_XLn98oMbF1pB3-L-b5gRbT4,14294
63
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/07-performance-guide.md,sha256=rjR0DjT39poEBVaUxAzJBEaMaBrZKLVer1zXaNNYfxg,12851
64
- sqlobjects-1.2.4.data/data/share/sqlobjects/rules/README.md,sha256=d2n5ZZT8LGvjL60u_HlzXn2uA8FwoCgqG3fuAhvMFvM,2280
65
- sqlobjects-1.2.4.dist-info/licenses/LICENSE,sha256=ScFR7nvWIhar0d32Y-LA4vqp9zNmy1HSJia7UX7jU6c,1068
66
- sqlobjects-1.2.4.dist-info/METADATA,sha256=Wql2U7dUxjC3mK9nGp7iF7YoVpHJBbynF798QO4Kc0c,13740
67
- sqlobjects-1.2.4.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
68
- sqlobjects-1.2.4.dist-info/entry_points.txt,sha256=9Q3Ci55MawxkQhMlR_eLJui00_rYYIVO_Aq_Dm0u5MQ,76
69
- sqlobjects-1.2.4.dist-info/top_level.txt,sha256=brO5vDtCpn4L9dpX0EHpehbu4kcHaK_2Bbnwze35YKc,11
70
- sqlobjects-1.2.4.dist-info/RECORD,,
57
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/01-database-session-guide.md,sha256=lnqRpcDhYKdH-f0avW1jXcWt3qi7XBwkMt7clTs9Zvg,7601
58
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/02-model-definition-guide.md,sha256=i5gNJM-0bIJ2xSUu3mij8uB9kJC9EAc_439sCBqRph8,10977
59
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/03-query-operations-guide.md,sha256=BEZE_WUUhY6sEZDiDtrbInlV_UVIhbYETABJTNhu2JQ,10550
60
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/04-crud-operations-guide.md,sha256=abUEvRPSiSjX8enclXO5Uryox9Rt0WFeRcFkvHXfPf8,10085
61
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/05-relationships-guide.md,sha256=MJ23fYOTWqrLd54ENZLu3S3QRqbLf7joq-YhF6-V8OQ,12204
62
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/06-validation-signals-guide.md,sha256=i9WLLhyCDoWGkIYqH2D_XLn98oMbF1pB3-L-b5gRbT4,14294
63
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/07-performance-guide.md,sha256=rjR0DjT39poEBVaUxAzJBEaMaBrZKLVer1zXaNNYfxg,12851
64
+ sqlobjects-1.3.0.data/data/share/sqlobjects/rules/README.md,sha256=d2n5ZZT8LGvjL60u_HlzXn2uA8FwoCgqG3fuAhvMFvM,2280
65
+ sqlobjects-1.3.0.dist-info/licenses/LICENSE,sha256=ScFR7nvWIhar0d32Y-LA4vqp9zNmy1HSJia7UX7jU6c,1068
66
+ sqlobjects-1.3.0.dist-info/METADATA,sha256=AFzNAzdZPIzZ5P0INZP6UK586XBRlaETnYKPl6lH5lc,13740
67
+ sqlobjects-1.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
68
+ sqlobjects-1.3.0.dist-info/entry_points.txt,sha256=9Q3Ci55MawxkQhMlR_eLJui00_rYYIVO_Aq_Dm0u5MQ,76
69
+ sqlobjects-1.3.0.dist-info/top_level.txt,sha256=brO5vDtCpn4L9dpX0EHpehbu4kcHaK_2Bbnwze35YKc,11
70
+ sqlobjects-1.3.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (82.0.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5