Skip to content

Fix to put workspaceId in parameter to connect DB via UI#23

Merged
hackerwins merged 2 commits into
mainfrom
postgres-connection
Mar 6, 2026
Merged

Fix to put workspaceId in parameter to connect DB via UI#23
hackerwins merged 2 commits into
mainfrom
postgres-connection

Conversation

@ggyuchive

@ggyuchive ggyuchive commented Mar 6, 2026

Copy link
Copy Markdown
Member

Summary

Fix to put workspaceId in API parameter to connect PostgreSQL instance via UI

Why

Previously, it can not connect PostgreSQL instance via Data Sources tab UI with below error.

[Nest] 31626  - 03/06/2026, 12:37:30 AM   ERROR [ExceptionsHandler] PrismaClientValidationError: 
[1] Invalid `this.prisma.workspace.findUnique()` invocation in
[1] /Users/ggyuchive/yorkieProject/wafflebase/packages/backend/src/workspace/workspace.service.ts:159:51
[1] 
[1]   156     idOrSlug,
[1]   157   );
[1]   158 if (isUUID) return idOrSlug;
[1] → 159 const workspace = await this.prisma.workspace.findUnique({
[1]         where: {
[1]           slug: undefined,
[1]       ?   id?: String,
[1]       ?   AND?: WorkspaceWhereInput | WorkspaceWhereInput[],
[1]       ?   OR?: WorkspaceWhereInput[],
[1]       ?   NOT?: WorkspaceWhereInput | WorkspaceWhereInput[],
[1]       ?   name?: StringFilter | String,
[1]       ?   createdAt?: DateTimeFilter | DateTime,
[1]       ?   members?: WorkspaceMemberListRelationFilter,
[1]       ?   documents?: DocumentListRelationFilter,
[1]       ?   invites?: WorkspaceInviteListRelationFilter,
[1]       ?   datasources?: DataSourceListRelationFilter
[1]         },
[1]         select: {
[1]           id: true
[1]         }
[1]       })
[1] 
[1] Argument `where` of type WorkspaceWhereUniqueInput needs at least one of `id` or `slug` arguments. Available options are marked with ?.

Linked Issues

Fixes #

Verification

CI automatically posts a verification summary comment on this PR with
per-lane results for both verify:self and verify:integration.

  • verify:self — CI comment shows ✅
  • verify:integration — CI comment shows ✅ (or explicit skip reason below)

Skip reason (if applicable):

Risk Assessment

  • User-facing risk:
  • Data/security risk:
  • Rollback plan:

Notes for Reviewers

  • UI changes (screenshots/gifs if applicable):
  • Follow-up work (if any):

Summary by CodeRabbit

  • New Features

    • Workspace-scoped data source management: listing, creation, editing, and selection now respect workspace context; creation is disabled when no workspace is selected.
    • Data source objects now include workspace association for clearer scoping.
  • Tests

    • Added an end-to-end database integration test covering temporary table creation, data insertion, querying, and cleanup.

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Threads workspaceId through frontend data-source components and types to enable workspace-scoped creation and listing; updates dialog and selector to call workspace-scoped APIs. Adds an end-to-end backend test that creates a temporary Postgres table, inserts rows, and verifies listing and querying via DataSourceService.

Changes

Cohort / File(s) Summary
Backend Test
packages/backend/test/database.e2e-spec.ts
Adds an end-to-end test using pg Client: creates a temp table, inserts rows, verifies information_schema listing and data queries via DataSourceService, then cleans up.
Type
packages/frontend/src/types/datasource.ts
Adds new workspaceId: string field to DataSource type.
Dialog & Selector (frontend)
packages/frontend/src/components/datasource-dialog.tsx, packages/frontend/src/components/datasource-selector.tsx
Add workspaceId prop to components; selector fetches workspace-scoped datasources; dialog uses createWorkspaceDataSource(workspaceId, ...) for save/test flows.
List & Integration Points (frontend)
packages/frontend/src/app/datasources/datasource-list.tsx, packages/frontend/src/app/workspaces/workspace-datasources.tsx, packages/frontend/src/app/documents/document-detail.tsx
DataSourceList accepts optional workspaceId; callers pass workspace context (route params or documentData); cache invalidation and create-button enabled state are gated by workspace presence.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant DocumentDetail as Document Detail
    participant DataSourceSelector as DataSource Selector
    participant DataSourceDialog as DataSource Dialog
    participant API as Workspace API
    participant Backend as Backend Service

    User->>DocumentDetail: open document (has workspaceId)
    DocumentDetail->>DataSourceSelector: pass workspaceId
    User->>DataSourceSelector: click "New Data Source"
    DataSourceSelector->>DataSourceDialog: open with workspaceId
    User->>DataSourceDialog: configure + save
    DataSourceDialog->>API: createWorkspaceDataSource(workspaceId, config)
    API->>Backend: create data source scoped to workspace
    Backend-->>API: created
    API-->>DataSourceDialog: success
    DataSourceDialog-->>DataSourceSelector: refresh list (workspace scope)
    DataSourceSelector-->>User: show new data source
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through workspaces, small and spry,
Planted sources under each sky,
Tables and tests I nibbled through,
Now scoped and tidy — ready for you,
A rabbit's cheer for code that flies!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding workspaceId parameter to enable PostgreSQL database connections via the UI. It directly relates to the core objective of fixing workspace-scoped datasource operations.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch postgres-connection

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.

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 78.3s

Lane Status Duration
verify:fast ✅ pass 32.0s
frontend:build ✅ pass 12.0s
verify:frontend:chunks ✅ pass 0.3s
verify:frontend:visual ✅ pass 7.1s
backend:build ✅ pass 3.8s
sheet:build ✅ pass 10.7s
verify:entropy ✅ pass 12.1s
verify:browser ✅ pass 0.3s

Verification: verify:integration

Result: ✅ PASS

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/frontend/src/app/documents/document-detail.tsx (1)

450-457: ⚠️ Potential issue | 🟠 Major

Don’t pass an empty workspace ID into the selector.

Falling back to "" turns “document workspace not loaded yet” into a real API parameter. If the user opens the datasource flow before documentData resolves, the dialog will try to create against /workspaces//datasources instead of the document’s workspace.

Suggested fix
-      {showDsSelector && (
+      {showDsSelector && documentData?.workspaceId && (
         <Suspense fallback={null}>
           <DataSourceSelector
-            workspaceId={documentData?.workspaceId ?? ""}
+            workspaceId={documentData.workspaceId}
             open={showDsSelector}
             onOpenChange={setShowDsSelector}
             onSelect={addDataSourceTab}
           />
         </Suspense>
       )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/documents/document-detail.tsx` around lines 450 -
457, The DataSourceSelector is being passed an empty string when documentData is
not yet loaded, causing API calls to use a malformed workspace ID; change the
rendering or prop so you never pass "" into DataSourceSelector.workspaceId —
e.g., compute const workspaceId = documentData?.workspaceId ?? undefined and
only render the DataSourceSelector (or open it) when workspaceId is truthy, or
gate the showDsSelector flag until documentData?.workspaceId exists; update
references to DataSourceSelector, workspaceId, showDsSelector, and
addDataSourceTab accordingly so the selector never receives an empty string.
🧹 Nitpick comments (1)
packages/backend/test/database.e2e-spec.ts (1)

119-141: Wrap raw client operations in try-finally to prevent connection leaks.

If rawClient.connect() succeeds but a subsequent query or assertion fails, rawClient.end() won't execute, leaving an orphaned connection. The same applies to cleanupClient. In CI environments with parallel tests, leaked connections can exhaust the pool and cause flakiness.

♻️ Proposed fix using try-finally
       const rawClient = new Client({
         host: pgConfig.host,
         port: pgConfig.port,
         database: pgConfig.database,
         user: pgConfig.username,
         password: pgConfig.password,
       });
       await rawClient.connect();
-      await rawClient.query(`
-        CREATE TABLE IF NOT EXISTS _test_products (
-          id SERIAL PRIMARY KEY,
-          name TEXT NOT NULL,
-          price NUMERIC(10, 2) NOT NULL
-        )
-      `);
-      await rawClient.query(`TRUNCATE _test_products RESTART IDENTITY`);
-      await rawClient.query(`
-        INSERT INTO _test_products (name, price) VALUES
-          ('Widget', 9.99),
-          ('Gadget', 24.50),
-          ('Doohickey', 3.75)
-      `);
-      await rawClient.end();
+      try {
+        await rawClient.query(`
+          CREATE TABLE IF NOT EXISTS _test_products (
+            id SERIAL PRIMARY KEY,
+            name TEXT NOT NULL,
+            price NUMERIC(10, 2) NOT NULL
+          )
+        `);
+        await rawClient.query(`TRUNCATE _test_products RESTART IDENTITY`);
+        await rawClient.query(`
+          INSERT INTO _test_products (name, price) VALUES
+            ('Widget', 9.99),
+            ('Gadget', 24.50),
+            ('Doohickey', 3.75)
+        `);
+      } finally {
+        await rawClient.end();
+      }

Apply the same pattern to the cleanup client (lines 178-187).

Also applies to: 177-187

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

In `@packages/backend/test/database.e2e-spec.ts` around lines 119 - 141, The test
creates a rawClient (new Client(...)) and performs connect/query/end sequences
without ensuring end() runs on errors; wrap the rawClient.connect(), subsequent
queries, and rawClient.end() in a try { ... } finally { await rawClient.end(); }
block to guarantee the connection is always closed, and apply the same
try-finally pattern to the cleanupClient usage (the cleanupClient
connect/query/end block) so both rawClient and cleanupClient cannot leak
connections if an assertion or query throws.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/frontend/src/app/datasources/datasource-list.tsx`:
- Around line 57-58: The component DataSourceList currently infers create scope
from the first data row via resolvedWorkspaceId = workspaceId ??
data[0]?.workspaceId ?? "", which can create in the wrong workspace or produce
/workspaces//datasources when data is empty; change the logic to only accept an
explicit workspace context (use workspaceId prop or null/undefined) and stop
falling back to data[0]?.workspaceId; update any code paths that open
DataSourceDialog or construct create URLs (references: DataSourceList,
DataSourceDialog, and the create button handlers around the other occurrence at
the same pattern) to require a non-empty workspaceId (disable the create button
or show a workspace selector when none is provided) and ensure you never
interpolate an empty string into /workspaces/{id}/datasources.
- Around line 57-58: The workspace-scoped datasource list isn't invalidated
after mutations; update the three mutation handlers in DataSourceList (the
delete handler, the onCreate callback, and the onSaved/onSave handler) to
invalidate both the global key ["datasources"] and the workspace-scoped key
["workspaces", resolvedWorkspaceId, "datasources"] (use the existing
resolvedWorkspaceId variable) so the workspace page is refreshed after
create/edit/delete; call your queryClient.invalidateQueries for both keys in
each handler.

In `@packages/frontend/src/components/datasource-selector.tsx`:
- Around line 17-18: The component DataSourceSelector (type
DataSourceSelectorProps) currently uses the global fetchDataSources() call which
ignores workspace scoping; replace that with the workspace-scoped query (e.g.,
fetchDataSourcesForWorkspace / the existing workspace-scoped hook/query) and
pass workspaceId into the query so the selector only loads datasources for the
current workspace; update any refetch/invalidate logic (including after creation
in DataSourceDialog) to use the same workspaceId-scoped query so creation and
selection operate on the same scope and the modal cannot show datasources from
other workspaces.

---

Outside diff comments:
In `@packages/frontend/src/app/documents/document-detail.tsx`:
- Around line 450-457: The DataSourceSelector is being passed an empty string
when documentData is not yet loaded, causing API calls to use a malformed
workspace ID; change the rendering or prop so you never pass "" into
DataSourceSelector.workspaceId — e.g., compute const workspaceId =
documentData?.workspaceId ?? undefined and only render the DataSourceSelector
(or open it) when workspaceId is truthy, or gate the showDsSelector flag until
documentData?.workspaceId exists; update references to DataSourceSelector,
workspaceId, showDsSelector, and addDataSourceTab accordingly so the selector
never receives an empty string.

---

Nitpick comments:
In `@packages/backend/test/database.e2e-spec.ts`:
- Around line 119-141: The test creates a rawClient (new Client(...)) and
performs connect/query/end sequences without ensuring end() runs on errors; wrap
the rawClient.connect(), subsequent queries, and rawClient.end() in a try { ...
} finally { await rawClient.end(); } block to guarantee the connection is always
closed, and apply the same try-finally pattern to the cleanupClient usage (the
cleanupClient connect/query/end block) so both rawClient and cleanupClient
cannot leak connections if an assertion or query throws.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0eef7165-e79c-4667-b686-a5a651c49683

📥 Commits

Reviewing files that changed from the base of the PR and between 28f7f59 and 31d02c0.

📒 Files selected for processing (7)
  • packages/backend/test/database.e2e-spec.ts
  • packages/frontend/src/app/datasources/datasource-list.tsx
  • packages/frontend/src/app/documents/document-detail.tsx
  • packages/frontend/src/app/workspaces/workspace-datasources.tsx
  • packages/frontend/src/components/datasource-dialog.tsx
  • packages/frontend/src/components/datasource-selector.tsx
  • packages/frontend/src/types/datasource.ts

Comment thread packages/frontend/src/app/datasources/datasource-list.tsx Outdated
Comment thread packages/frontend/src/components/datasource-selector.tsx
Address CodeRabbit review feedback: stop inferring workspaceId from
the first data row, use workspace-scoped fetch in DataSourceSelector,
guard against empty workspaceId in document detail, invalidate both
global and workspace-scoped query keys after mutations, and wrap raw
pg clients in try-finally to prevent connection leaks in tests.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/frontend/src/app/datasources/datasource-list.tsx (1)

305-311: ⚠️ Potential issue | 🟠 Major

Empty state button bypasses the workspaceId guard.

The header button (line 254) correctly disables when !resolvedWorkspaceId, but this empty state button lacks the same guard. On the global datasources page, which renders DataSourceList without passing workspaceId, users with an empty list could click this button and open DataSourceDialog without a valid workspace context, leading to an API call to /workspaces/undefined/datasources.

🐛 Proposed fix
                     <Button
                       size="sm"
                       onClick={() => setShowCreate(true)}
+                      disabled={!resolvedWorkspaceId}
                     >
                       <Plus className="w-4 h-4 mr-1" />
                       New DataSource
                     </Button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/datasources/datasource-list.tsx` around lines 305 -
311, The empty-state "New DataSource" Button in DataSourceList currently calls
setShowCreate(true) without checking resolvedWorkspaceId, allowing the
DataSourceDialog to open with an undefined workspace; update the Button (the one
rendering <Plus ... /> and calling setShowCreate) to match the header button
guard by disabling it when !resolvedWorkspaceId (add
disabled={!resolvedWorkspaceId}) and/or wrap the onClick to no-op unless
resolvedWorkspaceId is truthy (e.g., onClick={() => resolvedWorkspaceId &&
setShowCreate(true)}), ensuring DataSourceDialog creation is only possible when
resolvedWorkspaceId exists.
🧹 Nitpick comments (1)
packages/frontend/src/app/datasources/datasource-list.tsx (1)

57-58: Good fix for past review concern - consider removing redundant variable.

The previous issue of inferring workspaceId from data[0]?.workspaceId is properly addressed. However, resolvedWorkspaceId = workspaceId is now a redundant assignment—you could use workspaceId directly throughout the component.

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

In `@packages/frontend/src/app/datasources/datasource-list.tsx` around lines 57 -
58, The component DataSourceList contains a redundant assignment const
resolvedWorkspaceId = workspaceId;—remove this variable and replace all uses of
resolvedWorkspaceId with the existing workspaceId parameter (update any
JSX/logic referencing resolvedWorkspaceId), keeping the function signature
DataSourceList({ data, workspaceId }) unchanged so there is no behavioral
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/frontend/src/app/datasources/datasource-list.tsx`:
- Around line 305-311: The empty-state "New DataSource" Button in DataSourceList
currently calls setShowCreate(true) without checking resolvedWorkspaceId,
allowing the DataSourceDialog to open with an undefined workspace; update the
Button (the one rendering <Plus ... /> and calling setShowCreate) to match the
header button guard by disabling it when !resolvedWorkspaceId (add
disabled={!resolvedWorkspaceId}) and/or wrap the onClick to no-op unless
resolvedWorkspaceId is truthy (e.g., onClick={() => resolvedWorkspaceId &&
setShowCreate(true)}), ensuring DataSourceDialog creation is only possible when
resolvedWorkspaceId exists.

---

Nitpick comments:
In `@packages/frontend/src/app/datasources/datasource-list.tsx`:
- Around line 57-58: The component DataSourceList contains a redundant
assignment const resolvedWorkspaceId = workspaceId;—remove this variable and
replace all uses of resolvedWorkspaceId with the existing workspaceId parameter
(update any JSX/logic referencing resolvedWorkspaceId), keeping the function
signature DataSourceList({ data, workspaceId }) unchanged so there is no
behavioral change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f49617e1-f9e1-4100-82cb-b45280ff3fe2

📥 Commits

Reviewing files that changed from the base of the PR and between 31d02c0 and 908eadc.

📒 Files selected for processing (4)
  • packages/backend/test/database.e2e-spec.ts
  • packages/frontend/src/app/datasources/datasource-list.tsx
  • packages/frontend/src/app/documents/document-detail.tsx
  • packages/frontend/src/components/datasource-selector.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/frontend/src/components/datasource-selector.tsx
  • packages/backend/test/database.e2e-spec.ts

@hackerwins
hackerwins self-requested a review March 6, 2026 15:40

@hackerwins hackerwins left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for your contribution.

@hackerwins
hackerwins merged commit a567f67 into main Mar 6, 2026
2 checks passed
@hackerwins
hackerwins deleted the postgres-connection branch March 6, 2026 15:41
@coderabbitai coderabbitai Bot mentioned this pull request Mar 8, 2026
6 tasks
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