Skip to content

feat: Added separate Database application.#1153

Open
ShogunPanda wants to merge 3 commits into
supabase:masterfrom
platformatic:watt-db-application
Open

feat: Added separate Database application.#1153
ShogunPanda wants to merge 3 commits into
supabase:masterfrom
platformatic:watt-db-application

Conversation

@ShogunPanda

Copy link
Copy Markdown

This PR adds a separate Watt database application and routes PostgreSQL operations through Platformatic messaging when Watt messaging is available.

Main areas:

  1. Database Watt app
  2. Storage-to-database messaging integration
  3. Watt runtime config and acceptance coverage

Review Order

  1. watt.json
  2. watt.database.json
  3. src/database/index.ts
  4. src/database/pools.ts
  5. src/database/locks.ts
  6. src/internal/database/client.ts
  7. src/internal/database/watt-connection.ts
  8. acceptance/specs/database-watt.test.ts

High-Risk Areas

  1. WattPgTenantConnection and WattPgTransaction are cast to PgTenantConnection/PgTransaction, not actual instances. Review any instanceof PgTransaction usage.
  2. toPgQueryResult() returns empty command, fields, and oid: src/internal/database/watt-connection.ts:372. Any caller relying on those fields may regress.
  3. Pool global budget checks may race under concurrent acquisition: src/database/pools.ts:138.
  4. Acquire timeout races pool.connect(): src/database/pools.ts:57. Verify no delayed client leak.
  5. beginTransaction validation does not appear to validate isolationLevel/readOnly: src/database/validation.ts:5.
  6. Error responses carry stack traces across messaging: src/internal/database/watt-connection.ts:339. Confirm this is acceptable.
  7. watt.json uses schema/runtime 3.56.0, while package.json still has platformatic and wattpm at ^3.52.0: package.json:109.

Manual Review Focus

Check these behaviors carefully:

  1. Single-tenant Watt DB routing.
  2. Multitenant tenant resolution.
  3. Transaction commit, rollback, and savepoint behavior.
  4. Query cancellation during long-running SQL.
  5. Duplicate-key/Postgres error SQLSTATE mapping.
  6. Pool exhaustion and acquire timeout behavior.
  7. Vector operations, because transaction compatibility is a likely risk area.
  8. Shutdown while a transaction/query is active.

@ShogunPanda ShogunPanda requested a review from a team as a code owner June 12, 2026 14:23
Copilot AI review requested due to automatic review settings June 12, 2026 14:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Introduces a “Database Watt” background application and routes PostgreSQL access through Platformatic Watt messaging when available, while preserving a direct pg fallback for non-Watt/local execution.

Changes:

  • Convert watt.json to a Platformatic Runtime config with two applications (storage, database) and add per-app configs.
  • Add Database Watt implementation (pooling, destination resolution, locks, cancellation, validation, metrics) plus unit/integration/acceptance coverage.
  • Route internal storage DB access (getPostgresConnection, multitenantPgExecutor) through Database Watt when Watt messaging is present, and update Platformatic deps.

Reviewed changes

Copilot reviewed 36 out of 38 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
watt.storage.json Adds Watt app config for the storage service entrypoint.
watt.json Switches to Platformatic Runtime schema and defines storage + database applications.
watt.database.json Adds Watt app config for the database background worker (no server).
src/internal/database/watt-connection.ts Implements a pg-like tenant connection/executor over Watt messaging (query/tx/cancel/error mapping).
src/internal/database/watt-connection.test.ts Adds unit tests for the Watt connection adapter behavior.
src/internal/database/pg-connection.ts Introduces *Like interfaces and aligns existing classes to implement them.
src/internal/database/multitenant-pg.ts Routes master DB executor through Database Watt when messaging exists.
src/internal/database/multitenant-pg.test.ts Extends tests to cover Watt-messaging routing behavior.
src/internal/database/migrations/migrate.ts Documents that migrations still use direct pg.
src/internal/database/client.ts Routes getPostgresConnection() through Database Watt when messaging exists and validates tenant host rules.
src/internal/database/client.test.ts Adds tests for Watt vs direct-pg routing and forwarded-host validation.
src/database/validation.ts Adds wire-protocol validation for Database Watt requests.
src/database/types.ts Adds typed wire request/response contracts for Database Watt messages.
src/database/tests/validation.test.ts Tests protocol validation limits and error cases.
src/database/tests/result-limits.test.ts Tests row/byte result limiting behavior.
src/database/tests/locks.test.ts Tests lock registry semantics and serialization of lock-bound work.
src/database/tests/index.test.ts Tests Database Watt messaging handlers end-to-end with loopback messaging + mocked pg.
src/database/tests/errors.test.ts Tests error serialization/mapping contract.
src/database/tests/cancellation.test.ts Tests cancellation registry behavior, including pg cancel path.
src/database/ssl.ts Adds SSL-mode parsing and ssl settings helper for pg pools.
src/database/result-limits.ts Adds result size/row limit enforcement for handler responses.
src/database/pools.ts Implements destination pool registry with budgeting, timeouts, eviction, and stats.
src/database/pg-lib-connection.d.ts Adds TS typings for pg/lib/connection used in cancellation.
src/database/metrics.ts Adds OpenTelemetry gauges for pool/connection/waiting metrics.
src/database/locks.ts Implements pinned-connection lock registry + tx commit/rollback semantics.
src/database/index.ts Implements Database Watt application and registers messaging handlers.
src/database/errors.ts Adds Database Watt error types and safe response mapping.
src/database/destinations.ts Resolves destinations (single-tenant, tenant via master DB, reserved master).
src/database/config.ts Adds Database Watt config (limits/timeouts/budgets, multitenant master config).
src/database/cancellation.ts Adds query cancellation registry and pg cancel execution helper.
src/admin-app.ts Switches Watt-environment detection to hasField('applicationId').
src/admin-app.test.ts Refactors tests to set/clear Watt globals for pprof registration checks.
package.json Bumps Platformatic packages and adds @platformatic/runtime + a Watt-specific acceptance runner.
docs/database-watt-postgresql-scope.md Documents which DB access is routed via Database Watt vs intentionally left direct.
acceptance/specs/database-watt.test.ts Adds acceptance coverage for key Database Watt behaviors (query/tx/savepoint/cancel/multitenant).
acceptance/scripts/run-managed-watt-local.ts Adds local managed Watt runner for acceptance (starts Watt + waits for apps).
acceptance/scripts/run-managed-local.ts Explicitly disables Database Watt acceptance path for non-Watt managed runs.
Comments suppressed due to low confidence (6)

src/internal/database/watt-connection.test.ts:1

  • vi and afterEach are used in this file but not imported from vitest (e.g., vi.fn(...) inside installWattMessagingMock and afterEach(...) at line 33). Add the missing imports to avoid runtime/TS failures.
    src/internal/database/watt-connection.test.ts:1
  • vi and afterEach are used in this file but not imported from vitest (e.g., vi.fn(...) inside installWattMessagingMock and afterEach(...) at line 33). Add the missing imports to avoid runtime/TS failures.
    src/database/tests/index.test.ts:1
  • This test file uses beforeAll, beforeEach, and afterAll but does not import them from vitest. If the repo’s Vitest setup doesn’t enable globals, the suite will fail; align imports with other updated tests by adding these hooks to the import list.
import { setupLoopbackMessaging } from '@platformatic/runtime'

src/database/tests/index.test.ts:1

  • This test file uses beforeAll, beforeEach, and afterAll but does not import them from vitest. If the repo’s Vitest setup doesn’t enable globals, the suite will fail; align imports with other updated tests by adding these hooks to the import list.
import { setupLoopbackMessaging } from '@platformatic/runtime'

src/database/tests/index.test.ts:1

  • This test file uses beforeAll, beforeEach, and afterAll but does not import them from vitest. If the repo’s Vitest setup doesn’t enable globals, the suite will fail; align imports with other updated tests by adding these hooks to the import list.
import { setupLoopbackMessaging } from '@platformatic/runtime'

src/internal/database/watt-connection.ts:1

  • For most timeout codes this returns a pg.DatabaseError with error.code set to undefined, which can break downstream logic that expects a stable code/SQLSTATE. Consider either (a) mapping all of these to a meaningful SQLSTATE (and preserving the original timeout code on a separate property), or (b) returning a non-DatabaseError with code set to the timeout code (similar to the generic branch below that preserves databaseCode/databaseResponse).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,304 @@
import { setupLoopbackMessaging } from '@platformatic/runtime'
import { afterEach, describe, expect, it, vi } from 'vitest'
Comment thread src/admin-app.test.ts Outdated
@@ -1,23 +1,78 @@
import { vi } from 'vitest'
Comment thread src/admin-app.test.ts
describe('admin app pprof registration', () => {
it('does not register pprof endpoints outside Watt', async () => {
getGlobal.mockReturnValue(undefined)
beforeEach(async () => {
Comment thread src/admin-app.test.ts
await clearWattGlobals()
})

afterEach(async () => {
Comment thread src/database/ssl.ts Outdated
Comment on lines +17 to +21
if (sslMode === 'require' || sslMode === 'prefer') {
return {
rejectUnauthorized: false,
}
}
Comment on lines +36 to +42
return {
connectionString,
id: destination,
isExternalPool: Boolean(process.env.DATABASE_POOL_URL),
maxConnections: this.config.destinationMaxConnections,
poolMode: this.config.poolMode,
}
Comment thread src/database/pools.ts
Comment on lines +77 to +94
getStats(): PoolRegistryStats {
let inUseConnections = 0
let totalConnections = 0
let waitingRequests = 0

for (const entry of this.pools.values()) {
inUseConnections += Math.max(entry.pool.totalCount - entry.pool.idleCount, 0)
totalConnections += entry.pool.totalCount
waitingRequests += entry.pool.waitingCount
}

return {
inUseConnections,
pools: this.pools.size,
totalConnections,
waitingRequests,
}
}
Comment thread src/database/pools.ts
Comment on lines +138 to +143
private assertCanAcquire(entry: PoolEntry): void {
const stats = this.getStats()

if (this.pendingGlobalAcquisitions >= this.config.globalAcquireQueueLimit) {
throw new DatabaseWattError('BUSY', 'Global acquisition queue is full')
}
Signed-off-by: Paolo Insogna <paolo@cowtech.it>
Signed-off-by: Paolo Insogna <paolo@cowtech.it>
Signed-off-by: Paolo Insogna <paolo@cowtech.it>
@ShogunPanda ShogunPanda force-pushed the watt-db-application branch from 495856e to 58b8aaf Compare June 15, 2026 10:43
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