Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions apps/ensdb-inspector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# ENSDb Inspector

A CLI tool for inspecting ENSNode database schemas and their metadata. This tool helps you understand the structure and content of PostgreSQL databases used by ENSNode services.

## Features

- **Schema Discovery**: Automatically categorize database schemas into:
- `ponder_sync`: Ponder's internal sync and RPC cache schema
- `ensdb`: ENS indexer schemas following the ENSNode data model
- `unknown`: Other schemas not matching known patterns

- **Schema Analysis**: Get detailed information about individual schemas including:
- Table counts and sizes
- Row counts and last modification times
- ENS-specific metrics (domain counts, latest registrations)
- Ponder-specific metrics (RPC cache entries)

- **Database Overview**: View overall database statistics including:
- Total database size and connection info
- PostgreSQL version and uptime
- Connection statistics and activity metrics
- Schema breakdown by type

## Installation

This tool is part of the ENSNode monorepo. Install dependencies:

```bash
pnpm install
```

## Usage

All commands require a PostgreSQL connection string. You can use any of these formats:

```bash
# Basic format
postgresql://username:password@host:port/database

# With options
postgresql://username:password@host:port/database?sslmode=require
```

### List All Schemas

```bash
pnpm run list-schemas --database-url "postgresql://user:pass@localhost:5432/ensnode"
```

This command will:
- Connect to the database
- Discover all user schemas (excluding system schemas)
- Categorize each schema by type
- Display a summary with table counts and sizes

### Get Schema Details

```bash
pnpm run schema-info "schema_name" --database-url "postgresql://user:pass@localhost:5432/ensnode"
```

This command provides detailed information about a specific schema including:
- Schema type and basic statistics
- Table-by-table breakdown with sizes and row counts
- ENS-specific information for ENSDb schemas
- Ponder-specific information for sync schemas

### Get Database Overview

```bash
pnpm run db-info --database-url "postgresql://user:pass@localhost:5432/ensnode"
```

This command shows:
- Database connection and server information
- Overall size and schema count
- PostgreSQL version and uptime
- Connection statistics
- Schema breakdown by type
- Database activity metrics

## Examples

### Connecting to a Local Development Database

```bash
# List schemas in local development database
pnpm run list-schemas --database-url "postgresql://postgres:password@localhost:5432/ensnode"

# Get details about a specific ENS indexer schema
pnpm run schema-info "mainnet_v1" --database-url "postgresql://postgres:password@localhost:5432/ensnode"

# Get overall database info
pnpm run db-info --database-url "postgresql://postgres:password@localhost:5432/ensnode"
```

### Connecting to a Production Database

```bash
# Using environment variable for connection string
export DATABASE_URL="postgresql://user:pass@prod-host:5432/ensnode?sslmode=require"

pnpm run list-schemas --database-url "$DATABASE_URL"
```

## Schema Types

### ponder_sync
Ponder's internal schema containing:
- RPC request/response cache
- Indexing state and metadata
- Sync progress tracking

### ensdb
ENS indexer schemas following the ENSNode data model:
- `domain` table with ENS domain records
- `registration` table with registration events
- `resolver` table with resolver records
- Various ENS-specific event tables

### unknown
Any other schemas that don't match the above patterns.

## Development

### Running in Development

```bash
# Run any command directly with tsx
npx tsx src/cli.ts list-schemas --database-url "..."
npx tsx src/cli.ts schema-info "schema_name" --database-url "..."
npx tsx src/cli.ts db-info --database-url "..."
```

### Testing

```bash
pnpm test
```

### Linting

```bash
pnpm lint
```

## Technical Details

- Built with TypeScript and Drizzle ORM
- Uses `postgres` client for database connections
- Follows the ENSNode monorepo patterns
- Designed for read-only database inspection

## Troubleshooting

### Connection Issues

- Ensure your PostgreSQL server is running and accessible
- Check that the connection string format is correct
- Verify firewall and network settings allow the connection
- For SSL connections, ensure certificates are properly configured

### Permission Issues

- The tool requires at least read access to `information_schema` and `pg_stat_*` views
- Some database activity metrics require additional permissions

### Schema Recognition

- ENSDb schema detection is based on table name patterns
- If a schema isn't recognized as ENSDb, check that it contains tables like `domain`, `registration`, etc.
- Unknown schemas are still analyzed but without ENS-specific features
43 changes: 43 additions & 0 deletions apps/ensdb-inspector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "ensdb-inspector",
"version": "0.31.0",
"private": true,
"type": "module",
"description": "A CLI tool for inspecting ENSNode database schemas and their metadata",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/namehash/ensnode.git",
"directory": "apps/ensdb-inspector"
},
"homepage": "https://github.com/namehash/ensnode/tree/main/apps/ensdb-inspector",
"scripts": {
"dev": "tsx src/cli.ts",
"list-schemas": "tsx src/cli.ts list-schemas",
"schema-info": "tsx src/cli.ts schema-info",
"db-info": "tsx src/cli.ts db-info",
"test": "vitest",
"lint": "biome check --write .",
"lint:ci": "biome ci",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@ensnode/ensnode-schema": "workspace:*",
"@ensnode/ponder-metadata": "workspace:*",
"drizzle-orm": "catalog:",
"postgres": "^3.4.5",
"pg-connection-string": "^2.9.0",
"yargs": "^17.7.2",
"pino": "^8.19.0",
"pino-pretty": "^10.3.1"
},
"devDependencies": {
"@ensnode/shared-configs": "workspace:*",
"@types/node": "catalog:",
"@types/yargs": "^17.0.32",
"@vitest/coverage-v8": "catalog:",
"tsx": "^4.19.3",
"typescript": "catalog:",
"vitest": "catalog:"
}
}
98 changes: 98 additions & 0 deletions apps/ensdb-inspector/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { resolve } from "path";
import { fileURLToPath } from "url";
import type { ArgumentsCamelCase, Argv } from "yargs";
import { hideBin } from "yargs/helpers";
import yargs from "yargs/yargs";

import { dbInfoCommand } from "@/commands/db-info-command";
import { listSchemasCommand } from "@/commands/list-schemas-command";
import { schemaInfoCommand } from "@/commands/schema-info-command";

export interface CLIOptions {
exitProcess?: boolean;
}

interface ListSchemasArgs {
"database-url": string;
}

interface SchemaInfoArgs {
"database-url": string;
schema: string;
}

interface DbInfoArgs {
"database-url": string;
}

export function createCLI(options: CLIOptions = {}) {
const { exitProcess = true } = options;

return yargs()
.scriptName("ensdb-inspector")
.exitProcess(exitProcess)
.command(
"list-schemas",
"List all database schemas and categorize them",
(yargs: Argv) => {
return yargs.option("database-url", {
type: "string",
description: "PostgreSQL connection string",
demandOption: true,
});
},
async (argv: ArgumentsCamelCase<ListSchemasArgs>) => {
await listSchemasCommand({
databaseUrl: argv["database-url"],
});
},
)
.command(
"schema-info <schema>",
"Get detailed information about a specific schema",
(yargs: Argv) => {
return yargs
.positional("schema", {
type: "string",
description: "Schema name to inspect",
demandOption: true,
})
.option("database-url", {
type: "string",
description: "PostgreSQL connection string",
demandOption: true,
});
},
async (argv: ArgumentsCamelCase<SchemaInfoArgs>) => {
await schemaInfoCommand({
databaseUrl: argv["database-url"],
schemaName: argv.schema,
});
},
)
.command(
"db-info",
"Get overall database information and statistics",
(yargs: Argv) => {
return yargs.option("database-url", {
type: "string",
description: "PostgreSQL connection string",
demandOption: true,
});
},
async (argv: ArgumentsCamelCase<DbInfoArgs>) => {
await dbInfoCommand({
databaseUrl: argv["database-url"],
});
},
)
.demandCommand(1, "You must specify a command")
.strict()
.help();
}

// Only execute if this is the main module
const isMainModule = resolve(process.argv[1]) === fileURLToPath(import.meta.url);
if (isMainModule) {
createCLI().parse(hideBin(process.argv));
}
Loading
Loading