/**
* postgres-mcp - PostgreSQL Adapter Mock
*
* Provides mock implementation of PostgresAdapter for testing
* tools, resources, and prompts without database dependency.
*/
import { vi } from "vitest";
import type { PostgresAdapter } from "../../adapters/postgresql/PostgresAdapter.js";
import type {
QueryResult,
TableInfo,
IndexInfo,
SchemaInfo,
HealthStatus,
ColumnInfo,
} from "../../types/index.js";
/**
* Create a mock query result
*/
export function createMockQueryResult(
rows: Record<string, unknown>[] = [],
affectedRows = 0,
): QueryResult {
return {
rows,
rowsAffected: affectedRows,
executionTimeMs: 5,
};
}
/**
* Create a mock column info
*/
export function createMockColumnInfo(
name: string,
type: string,
nullable = true,
primaryKey = false,
): ColumnInfo {
return {
name,
type,
nullable,
primaryKey,
defaultValue: null,
};
}
/**
* Create a mock table info
*/
export function createMockTableInfo(
name: string,
schemaName = "public",
rowCount = 100,
): TableInfo {
return {
name,
schema: schemaName,
type: "table",
columns: [
createMockColumnInfo("id", "integer", false, true),
createMockColumnInfo("name", "varchar(255)", true, false),
createMockColumnInfo(
"created_at",
"timestamp with time zone",
false,
false,
),
],
rowCount,
};
}
/**
* Create mock index info
*/
export function createMockIndexInfo(
tableName: string,
indexName: string,
schemaName = "public",
): IndexInfo {
return {
name: indexName,
tableName,
schemaName,
columns: ["id"],
unique: indexName.endsWith("_pkey"),
type: "btree",
};
}
/**
* Create mock schema info
*/
export function createMockSchemaInfo(): SchemaInfo {
return {
tables: [createMockTableInfo("users"), createMockTableInfo("products")],
views: [],
indexes: [createMockIndexInfo("users", "users_pkey")],
};
}
/**
* Create mock health status
*/
export function createMockHealthStatus(connected = true): HealthStatus {
return {
connected,
latencyMs: 5,
version: "16.1",
poolStats: {
total: 10,
active: 2,
idle: 8,
waiting: 0,
totalQueries: 100,
},
};
}
/**
* Create a mock PostgresAdapter
*/
export function createMockPostgresAdapter(): Partial<PostgresAdapter> & {
executeQuery: ReturnType<typeof vi.fn>;
executeReadQuery: ReturnType<typeof vi.fn>;
executeWriteQuery: ReturnType<typeof vi.fn>;
getTableIndexes: ReturnType<typeof vi.fn>;
getAllIndexes: ReturnType<typeof vi.fn>;
describeTable: ReturnType<typeof vi.fn>;
listTables: ReturnType<typeof vi.fn>;
listSchemas: ReturnType<typeof vi.fn>;
getSchema: ReturnType<typeof vi.fn>;
} {
const mockQueryResult = createMockQueryResult([{ id: 1, name: "test" }]);
return {
type: "postgresql" as const,
name: "PostgreSQL Adapter",
version: "0.1.0",
// Connection methods
connect: vi.fn().mockResolvedValue(undefined),
disconnect: vi.fn().mockResolvedValue(undefined),
getHealth: vi.fn().mockResolvedValue(createMockHealthStatus()),
// Query execution
executeQuery: vi.fn().mockResolvedValue(mockQueryResult),
executeReadQuery: vi.fn().mockResolvedValue(mockQueryResult),
executeWriteQuery: vi.fn().mockResolvedValue(mockQueryResult),
// Transaction methods
beginTransaction: vi.fn().mockResolvedValue("txn-123"),
commitTransaction: vi.fn().mockResolvedValue(undefined),
rollbackTransaction: vi.fn().mockResolvedValue(undefined),
createSavepoint: vi.fn().mockResolvedValue(undefined),
releaseSavepoint: vi.fn().mockResolvedValue(undefined),
rollbackToSavepoint: vi.fn().mockResolvedValue(undefined),
getTransactionConnection: vi.fn().mockReturnValue(undefined),
executeOnConnection: vi.fn().mockResolvedValue(createMockQueryResult()),
// Schema methods
getSchema: vi.fn().mockResolvedValue(createMockSchemaInfo()),
listTables: vi.fn().mockResolvedValue([createMockTableInfo("users")]),
describeTable: vi.fn().mockResolvedValue(createMockTableInfo("users")),
listSchemas: vi.fn().mockResolvedValue(["public", "pg_catalog"]),
getTableIndexes: vi
.fn()
.mockResolvedValue([createMockIndexInfo("users", "users_pkey")]),
getAllIndexes: vi
.fn()
.mockResolvedValue([createMockIndexInfo("users", "users_pkey")]),
// Capabilities
getCapabilities: vi.fn().mockReturnValue({
json: true,
fullTextSearch: true,
vector: true,
geospatial: true,
transactions: true,
preparedStatements: true,
connectionPooling: true,
partitioning: true,
ltree: true,
cron: true,
}),
getSupportedToolGroups: vi
.fn()
.mockReturnValue([
"core",
"transactions",
"jsonb",
"text",
"fulltext",
"performance",
"admin",
"monitoring",
"backup",
"vector",
"postgis",
"partitioning",
]),
// Definition getters
getToolDefinitions: vi.fn().mockReturnValue([]),
getResourceDefinitions: vi.fn().mockReturnValue([]),
getPromptDefinitions: vi.fn(),
// Pool access
getPool: vi.fn().mockReturnValue(null),
};
}
/**
* Create a mock RequestContext for handler testing
*/
export function createMockRequestContext(): {
timestamp: Date;
requestId: string;
} {
return {
timestamp: new Date(),
requestId: "test-request-" + Math.random().toString(36).slice(2, 9),
};
}
/**
* Helper to configure mock adapter response for specific queries
*/
export function configureMockAdapterQuery(
adapter: ReturnType<typeof createMockPostgresAdapter>,
pattern: string,
result: QueryResult,
): void {
const originalImpl = adapter.executeQuery.getMockImplementation() as
| ((sql: string) => Promise<QueryResult>)
| undefined;
const impl = (sql: string): Promise<QueryResult> => {
if (sql.includes(pattern)) {
return Promise.resolve(result);
}
if (typeof originalImpl === "function") {
return originalImpl(sql);
}
return Promise.resolve(createMockQueryResult());
};
// eslint-disable-next-line @typescript-eslint/no-misused-promises
adapter.executeQuery.mockImplementation(impl);
}
/**
* Create a mock PostgresAdapter that returns empty results
*/
export function createMockPostgresAdapterEmpty(): ReturnType<
typeof createMockPostgresAdapter
> {
const adapter = createMockPostgresAdapter();
const emptyResult = createMockQueryResult([]);
adapter.executeQuery.mockResolvedValue(emptyResult);
adapter.executeReadQuery.mockResolvedValue(emptyResult);
adapter.executeWriteQuery.mockResolvedValue({
rows: [],
rowsAffected: 0,
executionTimeMs: 1,
});
return adapter;
}
/**
* Create a mock PostgresAdapter that throws on query execution
*/
export function createMockPostgresAdapterWithError(
errorMessage = "Database connection failed",
): ReturnType<typeof createMockPostgresAdapter> {
const adapter = createMockPostgresAdapter();
const dbError = new Error(errorMessage);
adapter.executeQuery.mockRejectedValue(dbError);
adapter.executeReadQuery.mockRejectedValue(dbError);
adapter.executeWriteQuery.mockRejectedValue(dbError);
(adapter.getHealth as ReturnType<typeof vi.fn>).mockResolvedValue(
createMockHealthStatus(false),
);
return adapter;
}
/**
* Create a mock adapter for transaction testing with a mock connection
*/
export function createMockPostgresAdapterWithTransaction(): ReturnType<
typeof createMockPostgresAdapter
> & {
mockConnection: {
query: ReturnType<typeof vi.fn>;
release: ReturnType<typeof vi.fn>;
};
} {
const adapter = createMockPostgresAdapter();
const mockConnection = {
query: vi.fn().mockResolvedValue({ rows: [], rowCount: 0 }),
release: vi.fn(),
};
(
adapter.getTransactionConnection as ReturnType<typeof vi.fn>
).mockReturnValue(mockConnection);
return { ...adapter, mockConnection };
}
/**
* Type alias for the mock adapter return type
*/
export type MockPostgresAdapter = ReturnType<typeof createMockPostgresAdapter>;