Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2006959
feat: add CSV conversion command to ensrainbow CLI
djstrong Sep 30, 2025
b491441
refactor
djstrong Sep 30, 2025
4c18e0b
Create brave-kiwis-notice.md
djstrong Sep 30, 2025
5aefe9d
fix tests
djstrong Oct 1, 2025
f2c8f20
use fast-csv package
djstrong Oct 1, 2025
e20932d
add documentation for csv convert
djstrong Oct 6, 2025
b9c31b0
feat: add filtering capabilities to CSV conversion
djstrong Oct 17, 2025
e2b9255
feat: enhance CSV conversion with Bloom filter and deduplication options
djstrong Nov 24, 2025
2c94d41
refactor: simplify command options in package.json
djstrong Nov 24, 2025
721a50d
refactor: improve memory management and logging in CSV conversion
djstrong Dec 11, 2025
56bc356
refactor: streamline CSV conversion CLI options and improve logging
djstrong Dec 15, 2025
11992d7
fix: improve error handling and logging in CSV conversion tests
djstrong Dec 15, 2025
3dea60e
refactor: update CSV conversion logic and improve deduplication handling
djstrong Dec 16, 2025
b6c668a
Merge branch 'main' into csv-conversion-tool
djstrong Dec 16, 2025
b02b7f1
refactor: remove unused dependencies and enhance CSV conversion tests
djstrong Dec 17, 2025
35a05cb
Apply suggestions from code review
djstrong Jan 5, 2026
2cc8cad
refactor: rename convert command to convert-sql and update CLI docume…
djstrong Jan 5, 2026
bbc2786
refactor: update CLI documentation for output file and label set desc…
djstrong Jan 5, 2026
af4b041
docs: enhance SQL conversion section with repository link for legacy …
djstrong Jan 5, 2026
0ebee69
refactor: update CLI to make output-file optional and enhance documen…
djstrong Jan 5, 2026
9cdbb39
fix: enforce existing database path requirement in CLI and improve er…
djstrong Jan 5, 2026
a7fd4f3
refactor: update createRainbowRecord function to use RainbowRecord ty…
djstrong Jan 5, 2026
aac6789
refactor: remove label set version requirement from CLI and enhance o…
djstrong Jan 6, 2026
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
5 changes: 5 additions & 0 deletions .changeset/brave-kiwis-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ensrainbow": patch
---

feat: add CSV conversion command to ensrainbow CLI to convert rainbow tables from CSV format to ensrainbow format
4 changes: 3 additions & 1 deletion apps/ensrainbow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"validate:lite": "tsx src/cli.ts validate --lite",
"purge": "tsx src/cli.ts purge",
"convert": "tsx src/cli.ts convert",
"convert-sql": "tsx src/cli.ts convert-sql",
"test": "vitest",
"test:coverage": "vitest --coverage",
"lint": "biome check --write .",
Expand All @@ -38,7 +39,8 @@
"progress": "^2.0.3",
"protobufjs": "^7.4.0",
"viem": "catalog:",
"yargs": "^17.7.2"
"yargs": "^17.7.2",
"@fast-csv/parse": "^5.0.0"
Comment on lines +42 to +43
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

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

The new @fast-csv/parse dependency is added to the dependencies list, but it's placed after yargs with a trailing comma. The placement is correct, but ensure the dependency ordering follows the project's conventions (typically alphabetical order would place it before the existing dependencies).

Copilot uses AI. Check for mistakes.
},
"devDependencies": {
"@ensnode/shared-configs": "workspace:*",
Expand Down
22 changes: 11 additions & 11 deletions apps/ensrainbow/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe("CLI", () => {

expect(() =>
cli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -122,7 +122,7 @@ describe("CLI", () => {
// Successful convert with args
const ingestCli = createCLI({ exitProcess: false });
await ingestCli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -132,7 +132,7 @@ describe("CLI", () => {
"--label-set-version",
labelSetVersion.toString(),
]);
//command: pnpm convert --input-file test/fixtures/test_ens_names.sql.gz --output-file test/fixtures/test_ens_names_0.ensrainbow --label-set-id test-ens-names --label-set-version 0
//command: pnpm convert-sql --input-file test/fixtures/test_ens_names.sql.gz --output-file test/fixtures/test_ens_names_0.ensrainbow --label-set-id test-ens-names --label-set-version 0
//verify that the file is created

await expect(stat(ensrainbowOutputFile)).resolves.toBeDefined();
Expand Down Expand Up @@ -163,7 +163,7 @@ describe("CLI", () => {

expect(() =>
cli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -174,7 +174,7 @@ describe("CLI", () => {
// Successful convert with args
const ingestCli = createCLI({ exitProcess: false });
await ingestCli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -184,7 +184,7 @@ describe("CLI", () => {
"--label-set-version",
labelSetVersion.toString(),
]);
//command: pnpm convert --input-file test_ens_names.sql.gz --output-file test_ens_names_0.ensrainbow --label-set-id test-ens-names --label-set-version 0
//command: pnpm convert-sql --input-file test_ens_names.sql.gz --output-file test_ens_names_0.ensrainbow --label-set-id test-ens-names --label-set-version 0
//verify that the file is created

await expect(stat(ensrainbowOutputFile)).resolves.toBeDefined();
Expand All @@ -211,7 +211,7 @@ describe("CLI", () => {

expect(() =>
cli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -222,7 +222,7 @@ describe("CLI", () => {
const ingestCli2 = createCLI({ exitProcess: false });
// Successful convert with args
await ingestCli2.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand Down Expand Up @@ -266,7 +266,7 @@ describe("CLI", () => {
// Successful convert with label set version 2
const convertCli = createCLI({ exitProcess: false });
await convertCli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand Down Expand Up @@ -318,7 +318,7 @@ describe("CLI", () => {
// Create second file with different label set id and label set version 0
const convertCli = createCLI({ exitProcess: false });
await convertCli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand All @@ -331,7 +331,7 @@ describe("CLI", () => {

// Create third file with different label set id and label set version 1
await convertCli.parse([
"convert",
"convert-sql",
"--input-file",
sqlInputFile,
"--output-file",
Expand Down
80 changes: 70 additions & 10 deletions apps/ensrainbow/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from "@ensnode/ensnode-sdk";

import { convertCommand } from "@/commands/convert-command";
import { convertCsvCommand } from "@/commands/convert-csv-command";
// import { ingestCommand } from "@/commands/ingest-command";
import { ingestProtobufCommand } from "@/commands/ingest-protobuf-command";
import { purgeCommand } from "@/commands/purge-command";
Expand Down Expand Up @@ -56,11 +57,20 @@ interface PurgeArgs {

interface ConvertArgs {
"input-file": string;
"output-file": string;
"output-file"?: string;
"label-set-id": LabelSetId;
"label-set-version": LabelSetVersion;
}

interface ConvertCsvArgs {
"input-file": string;
"output-file"?: string;
"label-set-id": LabelSetId;
"progress-interval"?: number;
"existing-db-path"?: string;
silent?: boolean;
}

export interface CLIOptions {
exitProcess?: boolean;
}
Expand Down Expand Up @@ -184,36 +194,86 @@ export function createCLI(options: CLIOptions = {}) {
)
.command(
"convert",
"Convert rainbow tables from SQL dump to protobuf format",
"Convert rainbow tables from CSV format to ensrainbow format",
(yargs: Argv) => {
return yargs
.option("input-file", {
type: "string",
description: "Path to the gzipped SQL dump file",
default: join(process.cwd(), "ens_names.sql.gz"),
description: "Path to the CSV input file",
demandOption: true,
})
.option("label-set-id", {
type: "string",
description: "Label set id for the generated ensrainbow file",
demandOption: true,
})
.coerce("label-set-id", buildLabelSetId)
.option("output-file", {
type: "string",
description: "Path to the output protobuf file",
default: join(process.cwd(), "rainbow-records.ensrainbow"),
description:
"Path to where the resulting ensrainbow file will be output (if not provided, will be generated automatically)",
})
.option("progress-interval", {
type: "number",
description: "Number of records to process before logging progress",
default: 50000,
})
.option("existing-db-path", {
type: "string",
description:
"Path to existing ENSRainbow database to filter out existing labels and determine the next label set version (if not provided, version will be 0)",
})
.option("silent", {
type: "boolean",
description: "Disable progress bar (useful for scripts)",
default: false,
});
},
async (argv: ArgumentsCamelCase<ConvertCsvArgs>) => {
await convertCsvCommand({
inputFile: argv["input-file"],
outputFile: argv["output-file"],
labelSetId: argv["label-set-id"],
progressInterval: argv["progress-interval"],
existingDbPath: argv["existing-db-path"],
silent: argv["silent"],
});
},
)
.command(
"convert-sql",
"Convert rainbow tables from legacy SQL dump to ensrainbow format",
(yargs: Argv) => {
return yargs
.option("input-file", {
type: "string",
description: "Path to the gzipped SQL dump file",
default: join(process.cwd(), "ens_names.sql.gz"),
})
.option("label-set-id", {
type: "string",
description: "Label set id for the rainbow record collection",
description: "Label set id for the generated ensrainbow file",
demandOption: true,
})
.coerce("label-set-id", buildLabelSetId)
.option("label-set-version", {
type: "number",
description: "Label set version for the rainbow record collection",
description: "Label set version for the generated ensrainbow file",
demandOption: true,
})
.coerce("label-set-version", buildLabelSetVersion);
.coerce("label-set-version", buildLabelSetVersion)
.option("output-file", {
type: "string",
description: "Path to where the resulting ensrainbow file will be output",
});
},
async (argv: ArgumentsCamelCase<ConvertArgs>) => {
const outputFile =
argv["output-file"] ??
join(process.cwd(), `${argv["label-set-id"]}_${argv["label-set-version"]}.ensrainbow`);
await convertCommand({
inputFile: argv["input-file"],
outputFile: argv["output-file"],
outputFile,
labelSetId: argv["label-set-id"],
labelSetVersion: argv["label-set-version"],
});
Expand Down
Loading