macss-modular-api-sqlserver 0.4.7__tar.gz → 0.6.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.
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/PKG-INFO +5 -3
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/README.md +4 -2
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/pyproject.toml +1 -1
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/macss_modular_api_sqlserver.egg-info/PKG-INFO +5 -3
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/modular_api_sqlserver/__init__.py +6 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/modular_api_sqlserver/db_client.py +42 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/tests/test_db_client.py +98 -1
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/tests/test_db_conformance.py +52 -2
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/setup.cfg +0 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/macss_modular_api_sqlserver.egg-info/SOURCES.txt +0 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/macss_modular_api_sqlserver.egg-info/dependency_links.txt +0 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/macss_modular_api_sqlserver.egg-info/requires.txt +0 -0
- {macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/src/macss_modular_api_sqlserver.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: macss-modular-api-sqlserver
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Official MACSS SQL Server integration package for Python.
|
|
5
5
|
Author: ccisne.dev
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,10 +56,12 @@ else:
|
|
|
56
56
|
|
|
57
57
|
See [example/example.py](example/example.py) for a complete in-memory wiring sample.
|
|
58
58
|
|
|
59
|
-
##
|
|
59
|
+
## What this package provides
|
|
60
60
|
|
|
61
61
|
- normalized SQL Server connection defaults and redacted summaries
|
|
62
62
|
- engine-agnostic `DbClient`, `DbRepository`, and transaction contracts
|
|
63
63
|
- explicit lease ownership semantics for package-owned and application-owned sessions
|
|
64
64
|
- health contributor and GraphQL support bundle for higher-level integrations
|
|
65
|
-
-
|
|
65
|
+
- the application supplies the driver binding (adapter) for its chosen engine and driver
|
|
66
|
+
|
|
67
|
+
This package is **contracts-only by design** and will never ship a driver binding; you choose your engine and driver and provide the adapter. See [ADR-0004](../../../docs/adr/0004-contracts-only-database-packages.md).
|
|
@@ -32,10 +32,12 @@ else:
|
|
|
32
32
|
|
|
33
33
|
See [example/example.py](example/example.py) for a complete in-memory wiring sample.
|
|
34
34
|
|
|
35
|
-
##
|
|
35
|
+
## What this package provides
|
|
36
36
|
|
|
37
37
|
- normalized SQL Server connection defaults and redacted summaries
|
|
38
38
|
- engine-agnostic `DbClient`, `DbRepository`, and transaction contracts
|
|
39
39
|
- explicit lease ownership semantics for package-owned and application-owned sessions
|
|
40
40
|
- health contributor and GraphQL support bundle for higher-level integrations
|
|
41
|
-
-
|
|
41
|
+
- the application supplies the driver binding (adapter) for its chosen engine and driver
|
|
42
|
+
|
|
43
|
+
This package is **contracts-only by design** and will never ship a driver binding; you choose your engine and driver and provide the adapter. See [ADR-0004](../../../docs/adr/0004-contracts-only-database-packages.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: macss-modular-api-sqlserver
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Official MACSS SQL Server integration package for Python.
|
|
5
5
|
Author: ccisne.dev
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,10 +56,12 @@ else:
|
|
|
56
56
|
|
|
57
57
|
See [example/example.py](example/example.py) for a complete in-memory wiring sample.
|
|
58
58
|
|
|
59
|
-
##
|
|
59
|
+
## What this package provides
|
|
60
60
|
|
|
61
61
|
- normalized SQL Server connection defaults and redacted summaries
|
|
62
62
|
- engine-agnostic `DbClient`, `DbRepository`, and transaction contracts
|
|
63
63
|
- explicit lease ownership semantics for package-owned and application-owned sessions
|
|
64
64
|
- health contributor and GraphQL support bundle for higher-level integrations
|
|
65
|
-
-
|
|
65
|
+
- the application supplies the driver binding (adapter) for its chosen engine and driver
|
|
66
|
+
|
|
67
|
+
This package is **contracts-only by design** and will never ship a driver binding; you choose your engine and driver and provide the adapter. See [ADR-0004](../../../docs/adr/0004-contracts-only-database-packages.md).
|
|
@@ -14,6 +14,9 @@ from .db_client import (
|
|
|
14
14
|
DbHealthContributor,
|
|
15
15
|
DbHealthReport,
|
|
16
16
|
DbHealthStatus,
|
|
17
|
+
DbParameter,
|
|
18
|
+
DbParameterDirection,
|
|
19
|
+
DbProcedureOutcome,
|
|
17
20
|
DbProviderDescription,
|
|
18
21
|
DbRepository,
|
|
19
22
|
DbRepositoryContext,
|
|
@@ -40,6 +43,9 @@ __all__ = [
|
|
|
40
43
|
"DbHealthContributor",
|
|
41
44
|
"DbHealthReport",
|
|
42
45
|
"DbHealthStatus",
|
|
46
|
+
"DbParameter",
|
|
47
|
+
"DbParameterDirection",
|
|
48
|
+
"DbProcedureOutcome",
|
|
43
49
|
"DbProviderDescription",
|
|
44
50
|
"DbRepository",
|
|
45
51
|
"DbRepositoryContext",
|
|
@@ -17,6 +17,13 @@ class DbCommandKind(str, Enum):
|
|
|
17
17
|
EXECUTE = "execute"
|
|
18
18
|
BATCH = "batch"
|
|
19
19
|
SCALAR = "scalar"
|
|
20
|
+
PROCEDURE = "procedure"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DbParameterDirection(str, Enum):
|
|
24
|
+
INPUT = "input"
|
|
25
|
+
OUTPUT = "output"
|
|
26
|
+
INPUT_OUTPUT = "inputOutput"
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
class DbFailureKind(str, Enum):
|
|
@@ -84,6 +91,39 @@ class DbConnectionSettings:
|
|
|
84
91
|
)
|
|
85
92
|
|
|
86
93
|
|
|
94
|
+
@dataclass(frozen=True, slots=True)
|
|
95
|
+
class DbParameter:
|
|
96
|
+
name: str
|
|
97
|
+
value: object | None = None
|
|
98
|
+
direction: DbParameterDirection = DbParameterDirection.INPUT
|
|
99
|
+
type_hint: str | None = None
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def input(cls, name: str, value: object | None, type_hint: str | None = None) -> DbParameter:
|
|
103
|
+
return cls(name=name, value=value, direction=DbParameterDirection.INPUT, type_hint=type_hint)
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def output(cls, name: str, type_hint: str | None = None) -> DbParameter:
|
|
107
|
+
return cls(name=name, direction=DbParameterDirection.OUTPUT, type_hint=type_hint)
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def input_output(
|
|
111
|
+
cls, name: str, value: object | None, type_hint: str | None = None
|
|
112
|
+
) -> DbParameter:
|
|
113
|
+
return cls(
|
|
114
|
+
name=name,
|
|
115
|
+
value=value,
|
|
116
|
+
direction=DbParameterDirection.INPUT_OUTPUT,
|
|
117
|
+
type_hint=type_hint,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass(frozen=True, slots=True)
|
|
122
|
+
class DbProcedureOutcome:
|
|
123
|
+
return_value: object | None = None
|
|
124
|
+
output_parameters: Mapping[str, object] | None = None
|
|
125
|
+
|
|
126
|
+
|
|
87
127
|
@dataclass(frozen=True, slots=True)
|
|
88
128
|
class DbCommand:
|
|
89
129
|
kind: DbCommandKind
|
|
@@ -104,12 +144,14 @@ class DbExecutionMetadata:
|
|
|
104
144
|
class DbRowSet:
|
|
105
145
|
rows: list[Mapping[str, object]]
|
|
106
146
|
metadata: DbExecutionMetadata
|
|
147
|
+
procedure: DbProcedureOutcome | None = None
|
|
107
148
|
|
|
108
149
|
|
|
109
150
|
@dataclass(frozen=True, slots=True)
|
|
110
151
|
class DbExecutionSummary:
|
|
111
152
|
affected_count: int
|
|
112
153
|
metadata: DbExecutionMetadata
|
|
154
|
+
procedure: DbProcedureOutcome | None = None
|
|
113
155
|
|
|
114
156
|
|
|
115
157
|
@dataclass(frozen=True, slots=True)
|
{macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/tests/test_db_client.py
RENAMED
|
@@ -16,6 +16,9 @@ from modular_api_sqlserver import (
|
|
|
16
16
|
DbGraphqlSupport,
|
|
17
17
|
DbHealthContributor,
|
|
18
18
|
DbHealthStatus,
|
|
19
|
+
DbParameter,
|
|
20
|
+
DbParameterDirection,
|
|
21
|
+
DbProcedureOutcome,
|
|
19
22
|
DbProviderDescription,
|
|
20
23
|
DbRepository,
|
|
21
24
|
DbRepositoryContext,
|
|
@@ -473,4 +476,98 @@ class _UserStatsRepository(DbRepository[str]):
|
|
|
473
476
|
label="users.count",
|
|
474
477
|
)
|
|
475
478
|
)
|
|
476
|
-
return result.map(lambda value: int(value.value))
|
|
479
|
+
return result.map(lambda value: int(value.value))
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
# --- 0.6.0: typed parameters and stored-procedure support ---
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def test_db_parameter_input_captures_name_value_and_optional_type_hint() -> None:
|
|
486
|
+
plain = DbParameter.input("id", 42)
|
|
487
|
+
assert plain.name == "id"
|
|
488
|
+
assert plain.value == 42
|
|
489
|
+
assert plain.direction is DbParameterDirection.INPUT
|
|
490
|
+
assert plain.type_hint is None
|
|
491
|
+
|
|
492
|
+
hinted = DbParameter.input("picture", b"\x01\x02\x03", "varbinary(max)")
|
|
493
|
+
assert hinted.direction is DbParameterDirection.INPUT
|
|
494
|
+
assert hinted.type_hint == "varbinary(max)"
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def test_db_parameter_output_carries_no_input_value_and_defaults_direction() -> None:
|
|
498
|
+
out = DbParameter.output("total", "int")
|
|
499
|
+
assert out.name == "total"
|
|
500
|
+
assert out.value is None
|
|
501
|
+
assert out.direction is DbParameterDirection.OUTPUT
|
|
502
|
+
assert out.type_hint == "int"
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def test_db_parameter_input_output_marks_bidirectional_parameters() -> None:
|
|
506
|
+
io = DbParameter.input_output("counter", 1, "int")
|
|
507
|
+
assert io.direction is DbParameterDirection.INPUT_OUTPUT
|
|
508
|
+
assert io.value == 1
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def test_db_parameter_defaults_direction_to_input_when_constructed_directly() -> None:
|
|
512
|
+
param = DbParameter(name="name", value="foto.jpg")
|
|
513
|
+
assert param.direction is DbParameterDirection.INPUT
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def test_db_parameter_flows_through_db_command_parameters_unchanged() -> None:
|
|
517
|
+
command = DbCommand(
|
|
518
|
+
kind=DbCommandKind.PROCEDURE,
|
|
519
|
+
text="spEliminarFoto",
|
|
520
|
+
parameters=(DbParameter.input("nombre", "foto.jpg"), "positional-still-allowed"),
|
|
521
|
+
)
|
|
522
|
+
assert len(command.parameters) == 2
|
|
523
|
+
assert isinstance(command.parameters[0], DbParameter)
|
|
524
|
+
assert command.parameters[0].name == "nombre"
|
|
525
|
+
assert command.parameters[1] == "positional-still-allowed"
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def test_db_command_kind_exposes_procedure() -> None:
|
|
529
|
+
assert DbCommandKind.PROCEDURE.value == "procedure"
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def test_db_procedure_outcome_carries_return_value_and_output_parameters() -> None:
|
|
533
|
+
outcome = DbProcedureOutcome(return_value=0, output_parameters={"total": 5})
|
|
534
|
+
assert outcome.return_value == 0
|
|
535
|
+
assert outcome.output_parameters == {"total": 5}
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def test_db_procedure_outcome_allows_both_fields_to_be_absent() -> None:
|
|
539
|
+
empty = DbProcedureOutcome()
|
|
540
|
+
assert empty.return_value is None
|
|
541
|
+
assert empty.output_parameters is None
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def test_db_procedure_outcome_attaches_optionally_to_db_row_set() -> None:
|
|
545
|
+
without_outcome = DbRowSet(
|
|
546
|
+
rows=[{"id": 1}],
|
|
547
|
+
metadata=DbExecutionMetadata(duration=1),
|
|
548
|
+
)
|
|
549
|
+
assert without_outcome.procedure is None
|
|
550
|
+
|
|
551
|
+
with_outcome = DbRowSet(
|
|
552
|
+
rows=[{"id": 1}],
|
|
553
|
+
metadata=DbExecutionMetadata(duration=1),
|
|
554
|
+
procedure=DbProcedureOutcome(return_value=0),
|
|
555
|
+
)
|
|
556
|
+
assert with_outcome.procedure is not None
|
|
557
|
+
assert with_outcome.procedure.return_value == 0
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def test_db_procedure_outcome_attaches_optionally_to_db_execution_summary() -> None:
|
|
561
|
+
without_outcome = DbExecutionSummary(
|
|
562
|
+
affected_count=1,
|
|
563
|
+
metadata=DbExecutionMetadata(duration=1),
|
|
564
|
+
)
|
|
565
|
+
assert without_outcome.procedure is None
|
|
566
|
+
|
|
567
|
+
with_outcome = DbExecutionSummary(
|
|
568
|
+
affected_count=1,
|
|
569
|
+
metadata=DbExecutionMetadata(duration=1),
|
|
570
|
+
procedure=DbProcedureOutcome(output_parameters={"id": 99}),
|
|
571
|
+
)
|
|
572
|
+
assert with_outcome.procedure is not None
|
|
573
|
+
assert with_outcome.procedure.output_parameters == {"id": 99}
|
{macss_modular_api_sqlserver-0.4.7 → macss_modular_api_sqlserver-0.6.0}/tests/test_db_conformance.py
RENAMED
|
@@ -3,7 +3,16 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from modular_api_sqlserver import
|
|
6
|
+
from modular_api_sqlserver import (
|
|
7
|
+
DbCommand,
|
|
8
|
+
DbCommandKind,
|
|
9
|
+
DbConnectionSettings,
|
|
10
|
+
DbFailure,
|
|
11
|
+
DbFailureKind,
|
|
12
|
+
DbParameter,
|
|
13
|
+
DbProcedureOutcome,
|
|
14
|
+
DbResult,
|
|
15
|
+
)
|
|
7
16
|
|
|
8
17
|
|
|
9
18
|
def _load_fixture() -> dict[str, object]:
|
|
@@ -65,4 +74,45 @@ def test_matches_the_shared_db_result_fixture() -> None:
|
|
|
65
74
|
)
|
|
66
75
|
)
|
|
67
76
|
|
|
68
|
-
assert mapped_failure.failure.code == result_fixture["wrappedFailureCode"]
|
|
77
|
+
assert mapped_failure.failure.code == result_fixture["wrappedFailureCode"]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_matches_the_shared_typed_parameter_and_stored_procedure_fixture() -> None:
|
|
81
|
+
command_fixture = _load_fixture()["command"]
|
|
82
|
+
input_fixture = command_fixture["inputParameter"]
|
|
83
|
+
|
|
84
|
+
input_parameter = DbParameter.input(
|
|
85
|
+
input_fixture["name"], input_fixture["value"], input_fixture["typeHint"]
|
|
86
|
+
)
|
|
87
|
+
assert input_parameter.name == input_fixture["name"]
|
|
88
|
+
assert input_parameter.value == input_fixture["value"]
|
|
89
|
+
assert input_parameter.type_hint == input_fixture["typeHint"]
|
|
90
|
+
assert input_parameter.direction.value == input_fixture["expectedDirection"]
|
|
91
|
+
|
|
92
|
+
output_fixture = command_fixture["outputParameter"]
|
|
93
|
+
output_parameter = DbParameter.output(output_fixture["name"], output_fixture["typeHint"])
|
|
94
|
+
assert output_parameter.value is None
|
|
95
|
+
assert output_parameter.direction.value == output_fixture["expectedDirection"]
|
|
96
|
+
|
|
97
|
+
command = DbCommand(
|
|
98
|
+
kind=DbCommandKind.PROCEDURE,
|
|
99
|
+
text=command_fixture["procedureName"],
|
|
100
|
+
parameters=(input_parameter,),
|
|
101
|
+
)
|
|
102
|
+
assert command.kind.value == "procedure"
|
|
103
|
+
assert command.text == command_fixture["procedureName"]
|
|
104
|
+
assert isinstance(command.parameters[0], DbParameter)
|
|
105
|
+
|
|
106
|
+
outcome_fixture = command_fixture["outcome"]
|
|
107
|
+
outcome = DbProcedureOutcome(
|
|
108
|
+
return_value=outcome_fixture["returnValue"],
|
|
109
|
+
output_parameters={
|
|
110
|
+
outcome_fixture["outputParameterName"]: outcome_fixture["outputParameterValue"]
|
|
111
|
+
},
|
|
112
|
+
)
|
|
113
|
+
assert outcome.return_value == outcome_fixture["returnValue"]
|
|
114
|
+
assert outcome.output_parameters is not None
|
|
115
|
+
assert (
|
|
116
|
+
outcome.output_parameters[outcome_fixture["outputParameterName"]]
|
|
117
|
+
== outcome_fixture["outputParameterValue"]
|
|
118
|
+
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|