Skip to content

feat: neon connector#117

Open
arashsheyda wants to merge 12 commits intounjs:mainfrom
arashsheyda:feat/neon-connector
Open

feat: neon connector#117
arashsheyda wants to merge 12 commits intounjs:mainfrom
arashsheyda:feat/neon-connector

Conversation

@arashsheyda
Copy link
Copy Markdown
Contributor

@arashsheyda arashsheyda commented Oct 24, 2024

🔗 Linked issue

related to #32

❓ Type of change

  • 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality like performance)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

this PR adds support for neon connector using @neondatabase/serverless + an example of neon

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Summary by CodeRabbit

  • New Features

    • Added Neon Serverless Postgres connector with PostgreSQL dialect, prepared statements, and lazy connection handling.
  • Documentation

    • Replaced introductory note with a full Usage section: installation, examples, options, and a simplified external link.
  • Tests

    • Added tests that mock the serverless Postgres driver to validate connector behavior.
  • Chores

    • Added the serverless driver as a devDependency and optional peer dependency.

@codecov
Copy link
Copy Markdown

codecov bot commented Oct 24, 2024

Codecov Report

Attention: Patch coverage is 25.00000% with 33 lines in your changes missing coverage. Please review.

Please upload report for BASE (main@61e6c3f). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/connectors/neon.ts 25.58% 32 Missing ⚠️
src/_connectors.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #117   +/-   ##
=======================================
  Coverage        ?   41.47%           
=======================================
  Files           ?       23           
  Lines           ?      892           
  Branches        ?       91           
=======================================
  Hits            ?      370           
  Misses          ?      516           
  Partials        ?        6           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

import connector from "../../src/connectors/neon";
import { testConnector } from "./_tests";

describe.runIf(process.env.POSTGRESQL_URL)(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wish we could somehow mock @neondatabase/serverless (not sure if in their SDK they have it already). We could use something like pglite to emulate their interface in order to allow automated tests.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 12, 2026

Warning

Rate limit exceeded

@pi0 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 5 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4d002a67-39ce-42e9-b8d2-2fcc02d1052f

📥 Commits

Reviewing files that changed from the base of the PR and between e16c33d and 7984b0f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • package.json
📝 Walkthrough

Walkthrough

Adds a Neon Serverless PostgreSQL connector: implementation, registration, docs, dependency declarations, and tests (mocked Neon via pglite). Introduces a new connector name and options (url) and registers the connector in the connectors map. No existing public signatures removed.

Changes

Cohort / File(s) Summary
Documentation
docs/2.connectors/neon.md, docs/2.connectors/1.index.md
Replaced an issue note with a Usage section (installation, example, Options documenting url), and added Neon to the supported connectors list.
Dependency Management
package.json
Adds @neondatabase/serverless as a devDependency (^1.0.2), a peerDependency ("*") and marks it optional via peerDependenciesMeta.
Connector Registry
src/_connectors.ts
Adds "neon" to ConnectorName union, extends ConnectorOptions with neon: NeonOptions, and registers "neon": "db0/connectors/neon" in the exported connectors map.
Connector Implementation
src/connectors/neon.ts
New Neon connector implementation: exported ConnectorOptions (requires url), lazy Neon client initialization, SQL placeholder normalization (?$1,$2...), internal query wrapper and StatementWrapper with all(), run(), get().
Tests
test/connectors/neon.test.ts
Adds tests that mock @neondatabase/serverless using pglite to simulate Neon and exercise the Neon connector via existing test utilities.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Connector as Neon Connector
    participant NeonClient as Neon Client
    participant DB as Neon Database

    App->>Connector: create/use connector (url)
    Connector->>Connector: lazy init client on first query

    App->>Connector: prepare(sql) / execute(sql, params)
    Connector->>Connector: normalizeParams(sql) 
    rect rgba(100,150,200,0.5)
    Note over Connector: Replace ? with $1, $2, ...
    end

    Connector->>NeonClient: query(normalized_sql, params)
    NeonClient->>DB: execute SQL
    DB-->>NeonClient: rows
    NeonClient-->>Connector: rows
    Connector-->>App: results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibble on code, a connector takes flight,
Neon paths glow and queries hop bright.
Question marks turn to $1 in a blink,
Lazy roots awaken and link by link.
Hooray for tests, docs, and a rabbit's delight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: neon connector' accurately reflects the main objective of this pull request, which adds support for a Neon database connector.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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: 4

🧹 Nitpick comments (1)
src/connectors/neon.ts (1)

42-48: Consider implementing optional dispose method for connection cleanup.

The Connector interface includes an optional dispose method. While not strictly required, implementing it would allow users to properly clean up the Neon connection when needed, following the pattern established by other connectors.

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

In `@src/connectors/neon.ts` around lines 42 - 48, Add an optional dispose method
to the object returned by the neon connector so callers can cleanly close the
Neon connection; specifically, extend the returned connector (currently with
name, dialect, getInstance, exec, prepare) to include a dispose: async () => {
... } that obtains the connection via getConnection() (or getInstance()), calls
the appropriate shutdown method on the underlying client (e.g., end(), close(),
or release() as supported), and gracefully handles/propagates errors; update any
types if needed to satisfy the Connector interface and ensure StatementWrapper,
query, getConnection references remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/connectors/neon.ts`:
- Around line 23-26: The function neonConnector currently declares its return
type Connector<NeonQueryFunction<undefined, undefined>> which no longer matches
the corrected ConnectorOptions generic parameters; update the return type of
neonConnector to use the same generic type parameters as ConnectorOptions (so
the Connector<> wraps NeonQueryFunction with the same generics used by
ConnectorOptions) and ensure the internal _connection variable declaration
(NeonQueryFunction<...>) uses the same matching generics as well.
- Around line 71-77: The run method spreads the array result (res from
this.#query) into the returned object, which creates numeric keys and violates
the BoundableStatement contract that run() should return only { success: boolean
}; update the run method (function run in this class using this.#query and
this.#sql) to stop spreading ...res and instead return an object with only
success: true (or success: false on error), and if you need to expose rows keep
them in a separate explicit property (e.g., rows) rather than spreading the
array into the object.
- Around line 37-40: The InternalQuery type currently doesn't match the actual
return shape from neon()<false,false>; update the InternalQuery type signature
to return the correct Promise<Record<string, unknown>[]> (or a union that
includes that shape) so the query constant (const query: InternalQuery = async
(sql, params) => { const connection = getConnection(); return
connection(normalizeParams(sql), params); }) correctly types the result; locate
and change the InternalQuery type definition to reflect neon()'s <false, false>
return type (rows as Record<string, unknown>[]), and ensure any call sites
expecting the previous type are adjusted if necessary.
- Around line 9-12: ConnectorOptions extends HTTPTransactionOptions with invalid
generics (undefined, undefined); update the generics to proper boolean literals
to satisfy the type constraints in `@neondatabase/serverless`: change the extends
clause for ConnectorOptions to use the intended ArrayMode and FullResults
booleans (e.g., HTTPTransactionOptions<false, false> if you want rows as objects
and only rows returned) so TypeScript compiles; locate the ConnectorOptions
declaration in src/connectors/neon.ts and replace the undefined generics with
the appropriate true/false values matching the desired transaction result shape.

---

Nitpick comments:
In `@src/connectors/neon.ts`:
- Around line 42-48: Add an optional dispose method to the object returned by
the neon connector so callers can cleanly close the Neon connection;
specifically, extend the returned connector (currently with name, dialect,
getInstance, exec, prepare) to include a dispose: async () => { ... } that
obtains the connection via getConnection() (or getInstance()), calls the
appropriate shutdown method on the underlying client (e.g., end(), close(), or
release() as supported), and gracefully handles/propagates errors; update any
types if needed to satisfy the Connector interface and ensure StatementWrapper,
query, getConnection references remain unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d062f6a-c51b-4875-8bb1-61ef239d4472

📥 Commits

Reviewing files that changed from the base of the PR and between 3c067b5 and 625d06c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • docs/2.connectors/neon.md
  • package.json
  • src/_connectors.ts
  • src/connectors/neon.ts
  • test/connectors/neon.test.ts

Comment on lines +37 to +40
const query: InternalQuery = async (sql, params) => {
const connection = getConnection();
return connection(normalizeParams(sql), params);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix InternalQuery return type to match neon() actual return type.

The neon() function with <false, false> parameters returns rows as Record<string, unknown>[]. The InternalQuery type should reflect this more accurately.

🔧 Proposed fix
-type InternalQuery = (sql: string, params?: Primitive[]) => Promise<unknown[]>;
+type InternalQuery = (sql: string, params?: Primitive[]) => Promise<Record<string, unknown>[]>;
🧰 Tools
🪛 GitHub Check: tests

[failure] 37-37:
Type '(sql: string, params: Primitive[] | undefined) => Promise<Record<string, any>[] | any[][] | FullQueryResults>' is not assignable to type 'InternalQuery'.

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

In `@src/connectors/neon.ts` around lines 37 - 40, The InternalQuery type
currently doesn't match the actual return shape from neon()<false,false>; update
the InternalQuery type signature to return the correct Promise<Record<string,
unknown>[]> (or a union that includes that shape) so the query constant (const
query: InternalQuery = async (sql, params) => { const connection =
getConnection(); return connection(normalizeParams(sql), params); }) correctly
types the result; locate and change the InternalQuery type definition to reflect
neon()'s <false, false> return type (rows as Record<string, unknown>[]), and
ensure any call sites expecting the previous type are adjusted if necessary.

Comment on lines +71 to +77
async run(...params: Primitive[]) {
const res = await this.#query(this.#sql, params);
return {
success: true,
...res,
};
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Spreading an array into an object produces unexpected results.

The res variable is an array (unknown[]), so spreading it into an object with ...res will produce numeric keys (0, 1, 2...) rather than meaningful properties. The run() method should only return { success: boolean } per the BoundableStatement interface contract.

🐛 Proposed fix
   async run(...params: Primitive[]) {
-    const res = await this.#query(this.#sql, params);
+    await this.#query(this.#sql, params);
     return {
       success: true,
-      ...res,
     };
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async run(...params: Primitive[]) {
const res = await this.#query(this.#sql, params);
return {
success: true,
...res,
};
}
async run(...params: Primitive[]) {
await this.#query(this.#sql, params);
return {
success: true,
};
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/connectors/neon.ts` around lines 71 - 77, The run method spreads the
array result (res from this.#query) into the returned object, which creates
numeric keys and violates the BoundableStatement contract that run() should
return only { success: boolean }; update the run method (function run in this
class using this.#query and this.#sql) to stop spreading ...res and instead
return an object with only success: true (or success: false on error), and if
you need to expose rows keep them in a separate explicit property (e.g., rows)
rather than spreading the array into the object.

@pi0
Copy link
Copy Markdown
Member

pi0 commented Mar 16, 2026

Thanks for rebasing PR @arashsheyda ❤️ We have another variant of PR #191 that uses pg client. @atilafassina and i were discussing to reach out to original SDK connector to figure out which is best.

@arashsheyda
Copy link
Copy Markdown
Contributor Author

@pi0 oh nice! thanks

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.

2 participants