-
Notifications
You must be signed in to change notification settings - Fork 15
WIP ENSDb schema: off-chain #1714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||
| import { defineConfig } from "drizzle-kit"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export default defineConfig({ | ||||||||||||||||||||||||||||||||||||||
| dialect: "postgresql", | ||||||||||||||||||||||||||||||||||||||
| schema: "./drizzle.schema.ts", | ||||||||||||||||||||||||||||||||||||||
| out: "./drizzle", | ||||||||||||||||||||||||||||||||||||||
| dbCredentials: { | ||||||||||||||||||||||||||||||||||||||
| url: "postgresql://dbuser:abcd1234@localhost:54320/ensnode_local_ponder_0_16", | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+7
to
+9
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove hardcoded database credentials from source. Line 8 commits a concrete DB user/password, which is a security and configuration-management risk. Proposed secure config change import { defineConfig } from "drizzle-kit";
+const databaseUrl = process.env.ENSDB_DATABASE_URL;
+if (!databaseUrl) {
+ throw new Error("ENSDB_DATABASE_URL is required");
+}
+
export default defineConfig({
dialect: "postgresql",
schema: "./drizzle.schema.ts",
out: "./drizzle",
dbCredentials: {
- url: "postgresql://dbuser:abcd1234@localhost:54320/ensnode_local_ponder_0_16",
+ url: databaseUrl,
},
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from "@ensnode/ensnode-schema/offchain"; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,6 @@ | ||||||
| CREATE SCHEMA "offchain"; | ||||||
|
||||||
| CREATE SCHEMA "offchain"; | |
| CREATE SCHEMA IF NOT EXISTS "offchain"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| { | ||
| "id": "771c3fcb-f4ef-439b-b931-1a2bf77a117a", | ||
| "prevId": "00000000-0000-0000-0000-000000000000", | ||
| "version": "7", | ||
| "dialect": "postgresql", | ||
| "tables": { | ||
| "offchain.ensnode_metadata": { | ||
| "name": "ensnode_metadata", | ||
| "schema": "offchain", | ||
| "columns": { | ||
| "key": { | ||
| "name": "key", | ||
| "type": "text", | ||
| "primaryKey": true, | ||
| "notNull": true | ||
| }, | ||
| "value": { | ||
| "name": "value", | ||
| "type": "jsonb", | ||
| "primaryKey": false, | ||
| "notNull": true | ||
| } | ||
| }, | ||
| "indexes": {}, | ||
| "foreignKeys": {}, | ||
| "compositePrimaryKeys": {}, | ||
| "uniqueConstraints": {}, | ||
| "policies": {}, | ||
| "checkConstraints": {}, | ||
| "isRLSEnabled": false | ||
| } | ||
| }, | ||
| "enums": {}, | ||
| "schemas": { | ||
| "offchain": "offchain" | ||
| }, | ||
| "sequences": {}, | ||
| "roles": {}, | ||
| "policies": {}, | ||
| "views": {}, | ||
| "_meta": { | ||
| "columns": {}, | ||
| "schemas": {}, | ||
| "tables": {} | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| { | ||
| "version": "7", | ||
| "dialect": "postgresql", | ||
| "entries": [ | ||
| { | ||
| "idx": 0, | ||
| "version": "7", | ||
| "when": 1772604594657, | ||
| "tag": "0000_orange_veda", | ||
| "breakpoints": true | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -47,6 +47,7 @@ | |||||
| "@types/dns-packet": "^5.6.5", | ||||||
| "@types/node": "catalog:", | ||||||
| "@types/pg": "8.16.0", | ||||||
| "drizzle-kit": "0.30.1", | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider using Other dependencies in this file use ♻️ Suggested change- "drizzle-kit": "0.30.1",
+ "drizzle-kit": "catalog:",Then add the version to your pnpm catalog configuration. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| "typescript": "catalog:", | ||||||
| "vitest": "catalog:" | ||||||
| } | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,7 +1,8 @@ | ||||||
| import type { NodePgDatabase } from "drizzle-orm/node-postgres"; | ||||||
| import { migrate } from "drizzle-orm/node-postgres/migrator"; | ||||||
| import { eq, sql } from "drizzle-orm/sql"; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused The pipeline reports unused imports. The 🧹 Suggested fix-import { eq, sql } from "drizzle-orm/sql";
+import { eq } from "drizzle-orm/sql";📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Test: CI[warning] 3-14: Unused imports might be the result of an incomplete refactoring. 🤖 Prompt for AI Agents |
||||||
|
|
||||||
| import { ensNodeMetadata } from "@ensnode/ensnode-schema"; | ||||||
| import { ensNodeMetadata } from "@ensnode/ensnode-schema/offchain"; | ||||||
| import { | ||||||
|
Comment on lines
+5
to
6
|
||||||
| type CrossChainIndexingStatusSnapshot, | ||||||
| deserializeCrossChainIndexingStatusSnapshot, | ||||||
|
|
@@ -65,6 +66,10 @@ export class EnsDbClient implements EnsDbClientQuery, EnsDbClientMutation { | |||||
| }); | ||||||
| } | ||||||
|
|
||||||
| async runMigrations(migrationsFolder: string): Promise<void> { | ||||||
| await migrate(this.db, { migrationsFolder }); | ||||||
| } | ||||||
|
Comment on lines
+69
to
+71
|
||||||
|
|
||||||
| /** | ||||||
| * @inheritdoc | ||||||
| */ | ||||||
|
|
@@ -176,25 +181,15 @@ export class EnsDbClient implements EnsDbClientQuery, EnsDbClientMutation { | |||||
| private async upsertEnsNodeMetadata< | ||||||
| EnsNodeMetadataType extends SerializedEnsNodeMetadata = SerializedEnsNodeMetadata, | ||||||
| >(metadata: EnsNodeMetadataType): Promise<void> { | ||||||
| await this.db.transaction(async (tx) => { | ||||||
| // Ponder live-query triggers insert into live_query_tables. | ||||||
| // Because this worker writes outside the Ponder runtime connection pool, | ||||||
| // the temp table must be ensured to exist on this connection. Without this, | ||||||
| // the upsert would fail with "relation 'live_query_tables' does not exist" error. | ||||||
| await tx.execute( | ||||||
| sql`CREATE TEMP TABLE IF NOT EXISTS live_query_tables (table_name TEXT PRIMARY KEY)`, | ||||||
| ); | ||||||
|
|
||||||
| await tx | ||||||
| .insert(ensNodeMetadata) | ||||||
| .values({ | ||||||
| key: metadata.key, | ||||||
| value: metadata.value, | ||||||
| }) | ||||||
| .onConflictDoUpdate({ | ||||||
| target: ensNodeMetadata.key, | ||||||
| set: { value: metadata.value }, | ||||||
| }); | ||||||
| }); | ||||||
| await this.db | ||||||
| .insert(ensNodeMetadata) | ||||||
| .values({ | ||||||
| key: metadata.key, | ||||||
| value: metadata.value, | ||||||
| }) | ||||||
| .onConflictDoUpdate({ | ||||||
| target: ensNodeMetadata.key, | ||||||
| set: { value: metadata.value }, | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -60,6 +60,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -79,6 +80,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
| await worker.run(); | ||||||||||||
|
|
||||||||||||
| // assert - verify initial upserts happened | ||||||||||||
| expect(ensDbClient.runMigrations).toHaveBeenCalledTimes(1); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Assert migration-folder argument, not only call count. Line 83 only verifies invocation count; it won’t catch an incorrect folder being passed to Suggested test hardening- expect(ensDbClient.runMigrations).toHaveBeenCalledTimes(1);
+ expect(ensDbClient.runMigrations).toHaveBeenCalledTimes(1);
+ expect(ensDbClient.runMigrations).toHaveBeenCalledWith(
+ expect.stringMatching(/(?:\/|\\)drizzle$/),
+ );📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||
| expect(ensDbClient.upsertEnsDbVersion).toHaveBeenCalledWith(publicConfig.versionInfo.ensDb); | ||||||||||||
| expect(ensDbClient.upsertEnsIndexerPublicConfig).toHaveBeenCalledWith(publicConfig); | ||||||||||||
|
|
||||||||||||
|
|
@@ -99,6 +101,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(publicConfig), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -148,6 +151,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -196,6 +200,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot, | ||||||||||||
|
|
@@ -245,6 +250,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -283,6 +289,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(storedConfig), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -315,6 +322,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -344,6 +352,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockRejectedValue(dbError), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi.fn().mockResolvedValue(undefined), | ||||||||||||
|
|
@@ -399,6 +408,7 @@ describe("EnsDbWriterWorker", () => { | |||||||||||
|
|
||||||||||||
| const ensDbClient = { | ||||||||||||
| getEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| runMigrations: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsDbVersion: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertEnsIndexerPublicConfig: vi.fn().mockResolvedValue(undefined), | ||||||||||||
| upsertIndexingStatusSnapshot: vi | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,8 @@ | |
| "Ponder" | ||
| ], | ||
| "exports": { | ||
| ".": "./src/ponder.schema.ts" | ||
| ".": "./src/ponder.schema.ts", | ||
| "./offchain": "./src/offchain.schema.ts" | ||
|
Comment on lines
+19
to
+20
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's examine the full package.json structure for ensnode-schema
cat packages/ensnode-schema/package.jsonRepository: namehash/ensnode Length of output: 1355 🏁 Script executed: # Check for tsup configuration
fd -t f 'tsup' packages/ensnode-schema/ --exec cat {}Repository: namehash/ensnode Length of output: 388 🏁 Script executed: # Check if offchain.schema.ts exists
ls -la packages/ensnode-schema/src/ | grep -E '\.ts$'Repository: namehash/ensnode Length of output: 191 🏁 Script executed: # Look for any build configuration in the ensnode-schema directory
ls -la packages/ensnode-schema/Repository: namehash/ensnode Length of output: 540 🏁 Script executed: # Check the content of offchain.schema.ts to understand its purpose
cat packages/ensnode-schema/src/offchain.schema.tsRepository: namehash/ensnode Length of output: 110 🏁 Script executed: # Check if there are any references to offchain in the codebase to understand usage intent
rg "offchain.schema" --type ts --type jsonRepository: namehash/ensnode Length of output: 141 Add The 🔧 Suggested fixesUpdate export default defineConfig({
- entry: ["src/ponder.schema.ts"],
+ entry: ["src/ponder.schema.ts", "src/offchain.schema.ts"],
platform: "neutral",Update "publishConfig": {
"access": "public",
"exports": {
+ ".": {
"types": "./dist/ponder.schema.d.ts",
"default": "./dist/ponder.schema.js"
+ },
+ "./offchain": {
+ "types": "./dist/offchain.schema.d.ts",
+ "default": "./dist/offchain.schema.js"
+ }
},🤖 Prompt for AI Agents |
||
| }, | ||
| "files": [ | ||
| "dist" | ||
|
|
@@ -40,9 +41,13 @@ | |
| "ponder": "catalog:", | ||
| "viem": "catalog:" | ||
| }, | ||
| "peerDependencies": { | ||
| "drizzle-orm": "catalog:" | ||
| }, | ||
| "devDependencies": { | ||
| "@ensnode/ensnode-sdk": "workspace:", | ||
| "@ensnode/shared-configs": "workspace:*", | ||
| "drizzle-orm": "catalog:", | ||
| "tsup": "catalog:", | ||
| "typescript": "catalog:" | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export * from "./schemas/ensnode-metadata.schema"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,6 @@ | |
| * Merge the various sub-schemas into a single ponder (drizzle) schema. | ||
| */ | ||
|
|
||
| export * from "./schemas/ensnode-metadata.schema"; | ||
| export * from "./schemas/ensv2.schema"; | ||
|
||
| export * from "./schemas/protocol-acceleration.schema"; | ||
| export * from "./schemas/registrars.schema"; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drizzle.config.tshardcodes a Postgres connection URL including credentials. This is easy to accidentally use against the wrong DB and is risky to commit (even if the password is “local”). Prefer reading the URL from env (e.g.process.env.DATABASE_URL) and/or usingdotenv-style config, or omitdbCredentialsand pass it via CLI when generating migrations.