Context
Real-world validation against production SQL Server (experiment X4: stored procedures + VARBINARY(MAX) round-trips) surfaced two contract gaps that are identical across all 6 db packages (sqlserver + postgres x TS/Dart/Python). These are limits of the contract itself — no adapter, however good, can work around them.
Gap 1 (G2) — DbCommand.parameters is an untyped positional list
Today: parameters: unknown[] (TS) / List<Object?> (Dart) / tuple[object, ...] (Python). There is no way to declare a parameter's name, direction (input/output/inout), or a type hint. Adapters cannot bind named parameters or read output parameters.
Gap 2 (G3) — DbCommandKind has no procedure
Today: query | execute | batch | scalar. Adapters cannot distinguish stored-procedure execution (e.g. mssql request.execute(spName) vs request.query(sql)), and there is no contract slot for a procedure's return value or output parameters.
Proposal — additive, non-breaking
DbParameter value object: { name, value, direction: input|output|inputOutput, typeHint? }. typeHint is a free-form string interpreted by the adapter (e.g. varbinary(max), int) — the package imports nothing from any driver (contracts-only). Static helpers input/output/inputOutput.
DbCommand.parameters accepts a mix of raw positional values (current behaviour, preserved) and DbParameter.
DbCommandKind.procedure: text = SP name; the adapter decides EXEC/CALL per engine. SP returning rows goes through query(); SP without rows through execute(). No new required methods on DbCommandExecutor (adding one would break every implementer).
- Optional
DbProcedureOutcome { returnValue?: unknown; outputParameters? } on DbRowSet/DbExecutionSummary. returnValue is engine-agnostic (unknown/Object?/object) — the SQL Server integer RETURN is not assumed.
Scope
- All 6 db packages, with real parity (tests in the 3 SDKs).
- Reference adapter guide in
docs/guides/ (READMEs link to it).
- ADR formalizing the contracts-only stance (no official driver bindings, ever) + README cleanup removing the implicit "first slice" promise.
- Target: 0.6.0, coordinated across the 15 packages (single tag, per ADR-0002).
Explicitly out of scope (separate dedicated, breaking iterations)
- Python db contracts are sync while the rest of the Python SDK is async/ASGI (event-loop blocking) — backlog issue.
- Dart
modular_api_sqlserver hard-depends on dart_odbc via SqlServerMetadataReader, breaking contracts-only — backlog issue (fix by removing the driver from the package, not wrapping it).
Context
Real-world validation against production SQL Server (experiment X4: stored procedures +
VARBINARY(MAX)round-trips) surfaced two contract gaps that are identical across all 6 db packages (sqlserver + postgres x TS/Dart/Python). These are limits of the contract itself — no adapter, however good, can work around them.Gap 1 (G2) —
DbCommand.parametersis an untyped positional listToday:
parameters: unknown[](TS) /List<Object?>(Dart) /tuple[object, ...](Python). There is no way to declare a parameter's name, direction (input/output/inout), or a type hint. Adapters cannot bind named parameters or read output parameters.Gap 2 (G3) —
DbCommandKindhas noprocedureToday:
query | execute | batch | scalar. Adapters cannot distinguish stored-procedure execution (e.g. mssqlrequest.execute(spName)vsrequest.query(sql)), and there is no contract slot for a procedure's return value or output parameters.Proposal — additive, non-breaking
DbParametervalue object:{ name, value, direction: input|output|inputOutput, typeHint? }.typeHintis a free-form string interpreted by the adapter (e.g.varbinary(max),int) — the package imports nothing from any driver (contracts-only). Static helpersinput/output/inputOutput.DbCommand.parametersaccepts a mix of raw positional values (current behaviour, preserved) andDbParameter.DbCommandKind.procedure:text= SP name; the adapter decidesEXEC/CALLper engine. SP returning rows goes throughquery(); SP without rows throughexecute(). No new required methods onDbCommandExecutor(adding one would break every implementer).DbProcedureOutcome { returnValue?: unknown; outputParameters? }onDbRowSet/DbExecutionSummary.returnValueis engine-agnostic (unknown/Object?/object) — the SQL Server integer RETURN is not assumed.Scope
docs/guides/(READMEs link to it).Explicitly out of scope (separate dedicated, breaking iterations)
modular_api_sqlserverhard-depends ondart_odbcviaSqlServerMetadataReader, breaking contracts-only — backlog issue (fix by removing the driver from the package, not wrapping it).