@ensnode/ponder-subgraph
Version:
A Hono middleware for generating Subgraph-compatible GraphQL schema.
106 lines (100 loc) • 3.66 kB
TypeScript
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
import { PgliteDatabase } from 'drizzle-orm/pglite';
import DataLoader from 'dataloader';
import { TableRelationalConfig } from 'drizzle-orm';
import { TableConfig, PgTableExtraConfig, PgTable } from 'drizzle-orm/pg-core';
import { GraphQLSchema } from 'graphql';
type SubgraphMetaBlock = {
/** Block number */
number: bigint;
/** Block unix timestamp */
timestamp: bigint;
/** Block hash */
hash: `0x${string}`;
/** Block parent hash */
parentHash: `0x${string}`;
};
/**
* The metadata provider interface used to fetch data from the application layer.
*/
interface PonderMetadataProvider {
/**
* ENSIndexer app version.
*/
version: string;
/**
* Get last indexed block status
* @returns The last indexed block status
*/
getLastIndexedDeploymentChainBlock(): Promise<SubgraphMetaBlock>;
/**
* Get the Ponder build ID
* @returns The Ponder build ID
*/
getPonderBuildId(): Promise<string>;
/**
* Get the indexing errors status
* @returns The indexing errors status
*/
hasIndexingErrors: () => Promise<boolean>;
}
/**
* This is a graphql schema generated from a drizzle (sql) schema, initially based on ponder's.
* https://github.com/ponder-sh/ponder/blob/main/packages/core/src/graphql/index.ts
*
* Its goal is to mimic the subgraph graphql api for queries we've deemed relevant (see docs).
*
* 1. inlines some ponder internal types
* 2. implement subgraph's simpler offset pagination with first & skip w/out Page types
* 3. PascalCase entity names
* 4. Polymorphic Interfaces
* 5. lower-case and/or filters
* 6. relation id shorthand filters (i.e. domains(where: { owner_id: String }))
* 7. sortable id columns
* 8. temporarily ignores column normalization that was fixed in
* https://github.com/ponder-sh/ponder/pull/1517/files
*/
type Drizzle<TSchema extends Schema = {
[name: string]: never;
}> = NodePgDatabase<TSchema> | PgliteDatabase<TSchema>;
type Schema = {
[name: string]: unknown;
};
declare const onchain: unique symbol;
type OnchainTable<T extends TableConfig & {
extra: PgTableExtraConfig | undefined;
} = TableConfig & {
extra: PgTableExtraConfig | undefined;
}> = PgTable<T> & {
[Key in keyof T["columns"]]: T["columns"][Key];
} & {
[onchain]: true;
} & {
enableRLS: () => Omit<OnchainTable<T>, "enableRLS">;
};
/**
* the following type describes:
* 1. `types` — mapping a polymorphic type name to the set of entities that implement that interface
* ex: DomainEvent -> [TransferEvent, ...]
* 2. `fields` — mapping a typeName to the polymorphic type it represents
* ex: Domain.events -> DomainEvent
*
* NOTE: in future implementations of ponder, this information could be provided by the schema
* using materialized views, and most/all of this code can be removed.
*/
interface PolymorphicConfig {
types: Record<string, PgTable<TableConfig>[]>;
fields: Record<string, string>;
}
interface BuildGraphQLSchemaOptions {
schema: Schema;
polymorphicConfig?: PolymorphicConfig;
metadataProvider: PonderMetadataProvider;
}
declare function buildGraphQLSchema({ schema: _schema, polymorphicConfig: _polymorphicConfig, metadataProvider, }: BuildGraphQLSchemaOptions): GraphQLSchema;
declare function buildDataLoaderCache({ drizzle }: {
drizzle: Drizzle<Schema>;
}): ({ table }: {
table: TableRelationalConfig;
}) => DataLoader<string, any, string>;
export { type Drizzle, type OnchainTable, type PolymorphicConfig, type Schema, buildDataLoaderCache, buildGraphQLSchema, onchain };