Skip to content

feat: MSSQL connector#197

Open
vkuttyp wants to merge 24 commits intounjs:mainfrom
vkuttyp:add-mssql-support
Open

feat: MSSQL connector#197
vkuttyp wants to merge 24 commits intounjs:mainfrom
vkuttyp:add-mssql-support

Conversation

@vkuttyp
Copy link
Copy Markdown

@vkuttyp vkuttyp commented Nov 27, 2025

Based on this PR #121
Resolves #120

Summary by CodeRabbit

  • New Features

    • Added MSSQL database connector support with full configuration options and Docker setup.
  • Documentation

    • Added MSSQL connector documentation with usage examples and configuration guide.
  • Tests

    • Added comprehensive test suite for MSSQL connector.
    • Added HTML coverage reports alongside existing coverage formats.
  • Chores

    • Integrated Codecov coverage reporting into CI pipeline.

@vkuttyp vkuttyp changed the title Add MSSQL Server support to db0 feat: MSSQL connector Nov 28, 2025
@vkuttyp vkuttyp marked this pull request as draft November 28, 2025 14:45
@vkuttyp vkuttyp marked this pull request as ready for review November 28, 2025 14:46
Copilot AI added a commit to vkuttyp/db0 that referenced this pull request Feb 1, 2026
Resolved conflicts between PR unjs#197 (MSSQL connector) and upstream main:
- Updated docker-compose.yaml to use port mappings for all services (pg, mysql, mssql)
- Merged formatting changes in src/types.ts
- Merged package.json dependency updates
- Regenerated pnpm-lock.yaml to resolve merge conflicts
- Applied tsconfig.json updates from upstream
- Included all MSSQL connector files and tests

Build and lint verified successfully.

Co-authored-by: vkuttyp <146238+vkuttyp@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces MSSQL connector support using the tedious driver. Changes include environment variable configuration, Docker MSSQL service setup, documentation, tedious dependency addition, connector registration in the type system, a complete MSSQL connector implementation with SQL parameter handling and result mapping, comprehensive test coverage including integration and edge cases, and CI/CD updates for Codecov.

Changes

Cohort / File(s) Summary
Configuration & Infrastructure
.env.example, docker-compose.yaml, .github/workflows/ci.yml
Added MSSQL environment variable templates, Docker MSSQL 2022 service configuration with host networking, and Codecov upload step to CI pipeline.
Documentation
docs/2.connectors/1.index.md, docs/2.connectors/mssql.md
Added MSSQL connector entry to supported connectors list and new documentation page covering tedious installation and connector initialization.
Package Configuration
package.json
Added tedious (v19.1.3) to devDependencies, peerDependencies (as optional), and peerDependenciesMeta.
Type System & Registration
src/types.ts, src/_connectors.ts, scripts/gen-connectors.ts
Added "mssql" to SQLDialect union, registered MSSQL in connector mapping with path db0/connectors/mssql, and configured custom options type naming for MSSQL connector.
MSSQL Connector Implementation
src/connectors/mssql.ts
New connector module implementing MSSQL support via tedious driver with connection management, parameterized SQL execution, type mapping, prepared statements, and result/error handling.
Test Infrastructure & MSSQL Tests
test/connectors/_tests.ts, test/connectors/mssql.test.ts, vitest.config.ts
Extended shared test logic for MSSQL dialect syntax (bracketed identifiers, NVARCHAR), added HTML reporter to coverage config, and introduced comprehensive test suite covering integration, stored procedures, JSON queries, transactions, error handling, and performance.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant MSSQLConnector
    participant Tedious as Tedious Driver
    participant MSSQL as MSSQL Server

    App->>MSSQLConnector: getInstance() / getClient()
    MSSQLConnector->>Tedious: new Connection(config)
    Tedious->>MSSQL: TCP Connect
    MSSQL-->>Tedious: Connected
    Tedious-->>MSSQLConnector: Connection Ready

    App->>MSSQLConnector: exec(sql, parameters?)
    MSSQLConnector->>MSSQLConnector: prepareSqlParameters(sql, params)
    Note over MSSQLConnector: Replace ? with `@1`, `@2`, ...
    
    MSSQLConnector->>Tedious: Request + addParameter()
    Tedious->>MSSQL: Execute Query
    MSSQL-->>Tedious: Row Events + requestCompleted

    MSSQLConnector->>MSSQLConnector: Accumulate Rows
    Tedious-->>MSSQLConnector: requestCompleted / error
    MSSQLConnector-->>App: Rows or Error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Poem

🐰 A connector hops in with tedious grace,
MSSQL queries now find their place,
Parameters dance from ? to @1,
Tests comprehensive—coverage is won! ✨
Welcome, dear MSSQL, to our burrow's embrace!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: MSSQL connector' is concise and clearly summarizes the main change—adding MSSQL connector support to the project.
Linked Issues check ✅ Passed The PR successfully implements MSSQL connector support using the tedious library as requested in issue #120, with complete connector code, tests, documentation, and CI integration.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing MSSQL connector support; no unrelated out-of-scope modifications were introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
src/connectors/mssql.ts (1)

1-7: Remove duplicate import.

Connection is imported on line 2 and again aliased on line 4 as TediousConnection. Only one import is needed.

♻️ Remove duplicate import
 import {
   Connection,
   Request,
-  Connection as TediousConnection,
   type ConnectionConfiguration,
   TYPES,
 } from "tedious";
+
+type TediousConnection = Connection;

Or simply use Connection throughout the code instead of TediousConnection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/connectors/mssql.ts` around lines 1 - 7, The import list in
src/connectors/mssql.ts duplicates the same symbol—you're importing Connection
twice (once as Connection and again aliased as TediousConnection); remove the
redundant alias and use a single import (either keep Connection and replace all
TediousConnection usages with Connection, or keep the alias and remove the plain
Connection) so only one import of the tedious Connection remains and update any
references to the chosen identifier (Connection or TediousConnection)
accordingly.
test/connectors/mssql.test.ts (3)

340-354: Commented-out cleanup code may leave test artifacts.

The afterAll block has the database cleanup code commented out (lines 342-352). This could leave the TestDB_CreateTest database on the server between test runs.

♻️ Either uncomment the cleanup or add a comment explaining why it's disabled
   afterAll(async () => {
-    // Clean up: drop the test database if it exists
-    // try {
-    //   await db.exec(`
-    //     IF EXISTS (SELECT * FROM sys.databases WHERE name = '${testDbName}')
-    //     BEGIN
-    //       ALTER DATABASE [${testDbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
-    //       DROP DATABASE [${testDbName}];
-    //     END
-    //   `);
-    // } catch (error) {
-    //   // Ignore errors if database doesn't exist
-    // }
+    // Clean up: drop the test database if it exists
+    try {
+      await db.exec(`
+        IF EXISTS (SELECT * FROM sys.databases WHERE name = '${testDbName}')
+        BEGIN
+          ALTER DATABASE [${testDbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
+          DROP DATABASE [${testDbName}];
+        END
+      `);
+    } catch {
+      // Ignore errors if database doesn't exist
+    }
     await db.dispose();
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/connectors/mssql.test.ts` around lines 340 - 354, The afterAll cleanup
currently has the db.exec block commented out, which risks leaving the
TestDB_CreateTest database behind; either uncomment and restore the cleanup SQL
that checks existence and drops testDbName using db.exec (ensuring ALTER
DATABASE ... SET SINGLE_USER WITH ROLLBACK IMMEDIATE before DROP) and then call
db.dispose(), or add a clear inline comment in the afterAll next to the db.exec
block explaining why the cleanup is intentionally disabled (referencing
afterAll, db.exec, testDbName, and db.dispose) so future maintainers know this
is deliberate.

395-407: Skipped test should explain why it's disabled.

it.skip("should drop an existing database", ...) doesn't have an explanation for why it's skipped. Consider adding a comment or TODO explaining the reason (e.g., connection issues, race condition with other tests, etc.).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/connectors/mssql.test.ts` around lines 395 - 407, The skipped test
it.skip("should drop an existing database", ...) lacks an explanation for why
it's disabled; update that test by either replacing it with test.todo("should
drop an existing database", "reason...") or leaving it skipped but adding a
short comment/TODO directly above the it.skip describing the cause (e.g.,
connection flakiness, race condition, required environment, or reference to an
issue/JIRA id) so future readers know when and how to re-enable the test;
reference the test name ("should drop an existing database") when making the
change.

543-551: Consider using expect(...).rejects.toThrow() pattern instead of try/catch with expect.fail().

The vitest/jest idiomatic way to test for thrown errors is using the rejects matcher. Additionally, expect.fail() may not be available in all vitest configurations.

♻️ Suggested refactor
-  it("should provide error context with SQL and parameters", async () => {
-    try {
-      const stmt = db.prepare("SELECT * FROM invalid_table WHERE id = ?");
-      await stmt.all(123);
-      expect.fail("Should have thrown an error");
-    } catch (error: any) {
-      expect(error.sql).toBeDefined();
-      expect(error.parameters).toBeDefined();
-    }
-  });
+  it("should provide error context with SQL and parameters", async () => {
+    const stmt = db.prepare("SELECT * FROM invalid_table WHERE id = ?");
+    await expect(stmt.all(123)).rejects.toMatchObject({
+      sql: expect.any(String),
+      parameters: expect.any(Array),
+    });
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/connectors/mssql.test.ts` around lines 543 - 551, Replace the try/catch
pattern with the vitest async matcher: call db.prepare(...) to get stmt and then
assert the promise rejection with await
expect(stmt.all(123)).rejects.toMatchObject({ sql: expect.anything(),
parameters: expect.anything() }) (or use rejects.toHaveProperty for each field)
instead of using expect.fail(); this keeps the test idiomatic and lets you
assert the error shape from the stmt.all call directly.
docker-compose.yaml (1)

19-26: Consider using port mapping instead of network_mode: "host" for cross-platform compatibility.

The pg and mysql services use explicit port mappings, but mssql uses network_mode: "host". Host networking doesn't work the same way on macOS and Windows (Docker Desktop), which may cause connectivity issues for contributors on those platforms.

♻️ Suggested change for consistency with other services
   mssql:
     # https://hub.docker.com/_/microsoft-mssql-server
     image: mcr.microsoft.com/mssql/server:2022-latest
-    network_mode: "host"
+    ports: ["1433:1433"]
     environment:
       ACCEPT_EULA: "Y"
       MSSQL_SA_PASSWORD: "MyStrong!Passw0rd"
       MSSQL_PID: "Developer"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yaml` around lines 19 - 26, The mssql service currently uses
network_mode: "host" which breaks Docker Desktop on macOS/Windows; replace
network_mode in the mssql service with explicit port mapping (add a ports
section mapping host 1433 to container 1433, e.g., "1433:1433") and remove
network_mode to match how pg and mysql are configured, ensuring the
MSSQL_SA_PASSWORD and other environment variables remain unchanged so local
containers remain reachable cross-platform.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.example:
- Around line 14-18: The MSSQL env block variables (MSSQL_HOST, MSSQL_DB_NAME,
MSSQL_PORT, MSSQL_USERNAME, MSSQL_PASSWORD) are out-of-order and the file lacks
a trailing blank line; reorder the block to satisfy the linter (e.g.,
alphabetically: MSSQL_DB_NAME, MSSQL_HOST, MSSQL_PASSWORD, MSSQL_PORT,
MSSQL_USERNAME or follow the project's env ordering convention) and add a single
trailing newline at EOF so the .env.example passes dotenv-linter checks.

In `@src/connectors/mssql.ts`:
- Around line 84-92: The code currently calls connection.close() inside
request.on("requestCompleted") and request.on("error"), which breaks connection
reuse via the cached _client returned by getClient(); remove the
connection.close() calls from both request handlers so requests resolve/reject
without closing the shared connection, keep the resolve({ rows, success }) and
reject(error) behavior, and add a dispose() method on the MSSQL connector class
that closes the underlying _client connection and clears _client when the
database instance is torn down so connections are cleaned up properly.
- Around line 23-31: The connect callback in the Promise created for new
Connection(opts) calls reject(error) but continues execution and still assigns
_client = client; update the client.connect callback (the anonymous function
passed to client.connect) to stop execution after a failure—either by adding a
return immediately after reject(error) or by using an if/else so _client =
client only runs when there is no error—so the cached _client is only set on
successful connections.
- Around line 112-155: Add a dispose() implementation on the returned Connector
object to close the underlying Tedious connection: call the client
shutdown/close method obtained via getClient() (or the instance returned by
getInstance()) and ensure it returns a Promise<void>; reference the connector
returned in the function, the getClient()/getInstance() helpers, and the
TediousConnection type so dispose() invokes the proper close/disconnect on that
connection and handles any errors asynchronously.

---

Nitpick comments:
In `@docker-compose.yaml`:
- Around line 19-26: The mssql service currently uses network_mode: "host" which
breaks Docker Desktop on macOS/Windows; replace network_mode in the mssql
service with explicit port mapping (add a ports section mapping host 1433 to
container 1433, e.g., "1433:1433") and remove network_mode to match how pg and
mysql are configured, ensuring the MSSQL_SA_PASSWORD and other environment
variables remain unchanged so local containers remain reachable cross-platform.

In `@src/connectors/mssql.ts`:
- Around line 1-7: The import list in src/connectors/mssql.ts duplicates the
same symbol—you're importing Connection twice (once as Connection and again
aliased as TediousConnection); remove the redundant alias and use a single
import (either keep Connection and replace all TediousConnection usages with
Connection, or keep the alias and remove the plain Connection) so only one
import of the tedious Connection remains and update any references to the chosen
identifier (Connection or TediousConnection) accordingly.

In `@test/connectors/mssql.test.ts`:
- Around line 340-354: The afterAll cleanup currently has the db.exec block
commented out, which risks leaving the TestDB_CreateTest database behind; either
uncomment and restore the cleanup SQL that checks existence and drops testDbName
using db.exec (ensuring ALTER DATABASE ... SET SINGLE_USER WITH ROLLBACK
IMMEDIATE before DROP) and then call db.dispose(), or add a clear inline comment
in the afterAll next to the db.exec block explaining why the cleanup is
intentionally disabled (referencing afterAll, db.exec, testDbName, and
db.dispose) so future maintainers know this is deliberate.
- Around line 395-407: The skipped test it.skip("should drop an existing
database", ...) lacks an explanation for why it's disabled; update that test by
either replacing it with test.todo("should drop an existing database",
"reason...") or leaving it skipped but adding a short comment/TODO directly
above the it.skip describing the cause (e.g., connection flakiness, race
condition, required environment, or reference to an issue/JIRA id) so future
readers know when and how to re-enable the test; reference the test name
("should drop an existing database") when making the change.
- Around line 543-551: Replace the try/catch pattern with the vitest async
matcher: call db.prepare(...) to get stmt and then assert the promise rejection
with await expect(stmt.all(123)).rejects.toMatchObject({ sql: expect.anything(),
parameters: expect.anything() }) (or use rejects.toHaveProperty for each field)
instead of using expect.fail(); this keeps the test idiomatic and lets you
assert the error shape from the stmt.all call directly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9c326f28-39c7-436f-9922-4d9f9572fc9b

📥 Commits

Reviewing files that changed from the base of the PR and between 60202ee and e02e32a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • .env.example
  • .github/workflows/ci.yml
  • docker-compose.yaml
  • docs/2.connectors/1.index.md
  • docs/2.connectors/mssql.md
  • package.json
  • scripts/gen-connectors.ts
  • src/_connectors.ts
  • src/connectors/mssql.ts
  • src/types.ts
  • test/connectors/_tests.ts
  • test/connectors/mssql.test.ts
  • vitest.config.ts

Comment thread .env.example
Comment thread src/connectors/mssql.ts
Comment thread src/connectors/mssql.ts
Comment thread src/connectors/mssql.ts
Comment thread src/connectors/mssql.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MSSQL Connector

1 participant