graphddb-runtime 0.7.7__tar.gz → 0.7.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 (48) hide show
  1. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/PKG-INFO +1 -1
  2. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/transactions.py +18 -2
  3. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime.egg-info/PKG-INFO +1 -1
  4. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/pyproject.toml +1 -1
  5. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_unit.py +57 -0
  6. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/README.md +0 -0
  7. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/__init__.py +0 -0
  8. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/async_runtime.py +0 -0
  9. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/batch.py +0 -0
  10. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/concurrency.py +0 -0
  11. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/cursor.py +0 -0
  12. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/errors.py +0 -0
  13. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/filters.py +0 -0
  14. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/hydration.py +0 -0
  15. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/limits.py +0 -0
  16. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/middleware.py +0 -0
  17. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/per_key_cursor.py +0 -0
  18. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/relations.py +0 -0
  19. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/runtime.py +0 -0
  20. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime/templates.py +0 -0
  21. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime.egg-info/SOURCES.txt +0 -0
  22. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime.egg-info/dependency_links.txt +0 -0
  23. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime.egg-info/requires.txt +0 -0
  24. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/graphddb_runtime.egg-info/top_level.txt +0 -0
  25. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/setup.cfg +0 -0
  26. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_concurrency.py +0 -0
  27. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_contract_runtime.py +0 -0
  28. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_crosslang_python_cells.py +0 -0
  29. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_description.py +0 -0
  30. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_description_followups.py +0 -0
  31. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_description_jsdoc.py +0 -0
  32. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration.py +0 -0
  33. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_command.py +0 -0
  34. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_compose.py +0 -0
  35. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_contract.py +0 -0
  36. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_edge_derive.py +0 -0
  37. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_edge_write.py +0 -0
  38. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_events.py +0 -0
  39. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_maintain.py +0 -0
  40. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_middleware.py +0 -0
  41. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_referential.py +0 -0
  42. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_relations.py +0 -0
  43. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_integration_unique.py +0 -0
  44. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_maintain.py +0 -0
  45. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_middleware.py +0 -0
  46. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_relations.py +0 -0
  47. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_spec_version_guard.py +0 -0
  48. {graphddb_runtime-0.7.7 → graphddb_runtime-0.7.8}/tests/test_ttl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphddb-runtime
3
- Version: 0.7.7
3
+ Version: 0.7.8
4
4
  Summary: Thin DynamoDB executor for GraphDDB-generated Python repositories (single-operation core, issue #44).
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -50,11 +50,27 @@ def _resolve_template(
50
50
 
51
51
 
52
52
  def _resolve_value(
53
- template: str,
53
+ template: Any,
54
54
  params: Mapping[str, Any],
55
55
  element: Optional[Mapping[str, Any]],
56
56
  ) -> Any:
57
- """Resolve a value template, keeping the typed value for a whole placeholder."""
57
+ """Resolve a value leaf, preserving its type (issue #245).
58
+
59
+ A non-string leaf (an ``int`` / ``bool`` typed literal, from the #245
60
+ serializer) passes through verbatim, so it lands in DynamoDB as ``N`` /
61
+ ``BOOL``. A string leaf is a template: a whole placeholder keeps the bound
62
+ param's type; a composite / plain string resolves to a string.
63
+
64
+ Scope note (#245): only integer / boolean literals keep their type in this
65
+ runtime. A ``float`` literal (e.g. ``rate: 0.5``) passes through here but then
66
+ fails LOUD at serialize time — boto3's ``TypeSerializer`` raises
67
+ ``TypeError: Float types are not supported`` (the same pre-existing constraint
68
+ that applies to ``float`` *params*), so a float is never silently corrupted.
69
+ Making floats round-trip requires a ``Decimal`` conversion pass — a broader
70
+ change deliberately OUT of #245 scope (a follow-up).
71
+ """
72
+ if not isinstance(template, str):
73
+ return template
58
74
  if _WHOLE_PLACEHOLDER_RE.match(template):
59
75
  name = template[1:-1]
60
76
  if name.startswith("item."):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphddb-runtime
3
- Version: 0.7.7
3
+ Version: 0.7.8
4
4
  Summary: Thin DynamoDB executor for GraphDDB-generated Python repositories (single-operation core, issue #44).
5
5
  License: MIT
6
6
  Requires-Python: >=3.9
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "graphddb-runtime"
7
- version = "0.7.7"
7
+ version = "0.7.8"
8
8
  description = "Thin DynamoDB executor for GraphDDB-generated Python repositories (single-operation core, issue #44)."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -634,6 +634,63 @@ def test_transaction_exceeding_25_after_expansion_raises():
634
634
  )
635
635
 
636
636
 
637
+ # ── issue #245: value-position literals keep their type (N / BOOL, not S) ─────
638
+ def test_resolve_value_passes_typed_literal_through():
639
+ """A non-string leaf (number / boolean typed literal, #245) is returned
640
+ verbatim, while a string leaf is resolved as a template."""
641
+ from graphddb_runtime.transactions import _resolve_value
642
+
643
+ assert _resolve_value(0, {}, None) == 0
644
+ assert isinstance(_resolve_value(0, {}, None), int)
645
+ assert _resolve_value(True, {}, None) is True
646
+ # A whole-placeholder string still keeps the bound param's type.
647
+ assert _resolve_value("{v}", {"v": 42}, None) == 42
648
+ # A composite string resolves to a string.
649
+ assert _resolve_value("V#{v}", {"v": 42}, None) == "V#42"
650
+
651
+
652
+ def test_transaction_put_serializes_numeric_literal_as_N():
653
+ """End-to-end through ``TransactionExpander._build_item``: a ``version: 0``
654
+ numeric literal in a put item is serialized as an ``N`` attribute (not ``"0"``
655
+ as an ``S``), the #245 regression the whole fix targets."""
656
+ from graphddb_runtime.transactions import TransactionExpander
657
+
658
+ rt = make_runtime(FakeClient())
659
+ # Register a chunk-like modeled entity (mirrors the TS ChunkModel).
660
+ rt._entities["ChunkModel"] = {
661
+ "table": "UserPermissions",
662
+ "physicalName": "UserPermissions",
663
+ "prefix": "CHUNK",
664
+ "fields": {
665
+ "id": {"type": "string"},
666
+ "version": {"type": "number"},
667
+ "active": {"type": "boolean"},
668
+ },
669
+ "key": {
670
+ "inputFields": ["id"],
671
+ "pkTemplate": "CHUNK#{id}",
672
+ "skTemplate": "META",
673
+ },
674
+ "gsis": [],
675
+ "relations": {},
676
+ }
677
+ expander = TransactionExpander(rt)
678
+ spec = {
679
+ "type": "Put",
680
+ "tableName": "UserPermissions",
681
+ "entity": "ChunkModel",
682
+ # The #245 serializer emits number / boolean literals verbatim (native JSON).
683
+ "item": {"id": "{id}", "version": 0, "active": True},
684
+ }
685
+ built = expander._build_item(spec, {"id": "c1"}, None)
686
+ item = built["Put"]["Item"]
687
+ # DynamoDB attribute-value form: N for the number, BOOL for the boolean, S for id.
688
+ assert item["version"] == {"N": "0"}
689
+ assert item["active"] == {"BOOL": True}
690
+ assert item["id"] == {"S": "c1"}
691
+ assert item["PK"] == {"S": "CHUNK#c1"}
692
+
693
+
637
694
  def test_transaction_validates_array_param():
638
695
  rt = make_runtime(FakeClient())
639
696
  with pytest.raises(ParameterValidationError):