Skip to content

Commit

Permalink
refactor(experimental): graphql: export components for stitching sche…
Browse files Browse the repository at this point in the history
…ma (#2814)
  • Loading branch information
buffalojoec committed Jun 14, 2024
1 parent 627fe29 commit f0f86d0
Show file tree
Hide file tree
Showing 17 changed files with 72 additions and 35 deletions.
4 changes: 2 additions & 2 deletions packages/rpc-graphql/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ for use in order to properly execute all queries.
Rpc<GetAccountInfoApi & GetBlockApi & GetMultipleAccountsApi & GetProgramAccountsApi & GetTransactionApi>;
```

To initialize the RPC-GraphQL client, simple use `createRpcGraphQL`.
To initialize the RPC-GraphQL client, simple use `createSolanaRpcGraphQL`.

```ts
import { createSolanaRpc } from '@solana/rpc';
Expand All @@ -44,7 +44,7 @@ import { createSolanaRpc } from '@solana/rpc';
const rpc = createSolanaRpc('https://api.devnet.solana.com');

// Create the RPC-GraphQL client
const rpcGraphQL = createRpcGraphQL(rpc);
const rpcGraphQL = createSolanaRpcGraphQL(rpc);
```

The `RpcGraphQL` type supports one method `query` which accepts a string
Expand Down
4 changes: 2 additions & 2 deletions packages/rpc-graphql/src/__tests__/account-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../index';
import { createLocalhostSolanaRpc } from './__setup__';

type GraphQLCompliantRpc = Rpc<
Expand All @@ -19,7 +19,7 @@ describe('account', () => {
let rpcGraphQL: RpcGraphQL;
beforeEach(() => {
rpc = createLocalhostSolanaRpc();
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});

describe('basic queries', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rpc-graphql/src/__tests__/block-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@solana/rpc';
import type { Slot } from '@solana/rpc-types';

import { createRpcGraphQL, RpcGraphQL } from '../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../index';
import { mockBlockFull, mockBlockFullBase58, mockBlockFullBase64, mockBlockSignatures } from './__setup__';

type GraphQLCompliantRpc = Rpc<
Expand Down Expand Up @@ -37,7 +37,7 @@ describe('block', () => {
return target[p as keyof GraphQLCompliantRpc];
},
});
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('basic queries', () => {
it("can query a block's block time", async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rpc-graphql/src/__tests__/program-accounts-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../index';
import { createLocalhostSolanaRpc } from './__setup__';

type GraphQLCompliantRpc = Rpc<
Expand All @@ -19,7 +19,7 @@ describe('programAccounts', () => {
let rpcGraphQL: RpcGraphQL;
beforeEach(() => {
rpc = createLocalhostSolanaRpc();
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});

describe('basic queries', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/rpc-graphql/src/__tests__/transaction-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../index';
import {
mockTransactionAddressLookup,
mockTransactionBase58,
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('transaction', () => {
return target[p as keyof GraphQLCompliantRpc];
},
});
rpcGraphQL = createRpcGraphQL(mockRpc);
rpcGraphQL = createSolanaRpcGraphQL(mockRpc);
});

describe('basic queries', () => {
Expand Down
35 changes: 31 additions & 4 deletions packages/rpc-graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ export interface RpcGraphQL {
): ReturnType<typeof graphql>;
}

/**
* Create a GraphQL RPC client resolver.
*
* @param rpc Solana RPC client.
* @param schema GraphQL schema.
* @param config Optional GraphQL resolver configurations.
* @returns GraphQL RPC client resolver.
*/
export function createRpcGraphQL(
rpc: Parameters<typeof createSolanaGraphQLContext>[0],
schema: ReturnType<typeof makeExecutableSchema>,
config?: Partial<Parameters<typeof createSolanaGraphQLContext>[1]>,
): RpcGraphQL {
const rpcGraphQLConfig = {
maxDataSliceByteRange: config?.maxDataSliceByteRange ?? 200,
maxMultipleAccountsBatchSize: config?.maxMultipleAccountsBatchSize ?? 100,
};
const schema = makeExecutableSchema({
resolvers: createSolanaGraphQLTypeResolvers(),
typeDefs: createSolanaGraphQLTypeDefs(),
});
return {
async query(source, variableValues?) {
const contextValue = createSolanaGraphQLContext(rpc, rpcGraphQLConfig);
Expand All @@ -36,3 +41,25 @@ export function createRpcGraphQL(
},
};
}

/**
* Create a Solana GraphQL RPC client resolver.
*
* Configures the client resolver to use the default Solana GraphQL schema.
*
* @param rpc Solana RPC client.
* @param config Optional GraphQL resolver configurations.
* @returns Solana GraphQL RPC client resolver.
*/
export function createSolanaRpcGraphQL(
rpc: Parameters<typeof createSolanaGraphQLContext>[0],
config?: Partial<Parameters<typeof createSolanaGraphQLContext>[1]>,
): RpcGraphQL {
const schema = makeExecutableSchema({
resolvers: createSolanaGraphQLTypeResolvers(),
typeDefs: createSolanaGraphQLTypeDefs(),
});
return createRpcGraphQL(rpc, schema, config);
}

export { createSolanaGraphQLTypeDefs, createSolanaGraphQLTypeResolvers };
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -34,7 +34,7 @@ describe('account loader', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(
rpcGraphQL = createSolanaRpcGraphQL(
rpc as unknown as Rpc<
GetAccountInfoApi & GetBlockApi & GetMultipleAccountsApi & GetProgramAccountsApi & GetTransactionApi
>,
Expand Down Expand Up @@ -556,7 +556,7 @@ describe('account loader', () => {
it('breaks multiple account requests into multiple `getMultipleAccounts` requests if the batch limit is exceeded', async () => {
expect.assertions(3);

rpcGraphQL = createRpcGraphQL(
rpcGraphQL = createSolanaRpcGraphQL(
rpc as unknown as Rpc<
GetAccountInfoApi &
GetBlockApi &
Expand Down Expand Up @@ -1265,7 +1265,7 @@ describe('account loader', () => {
it('splits multiple data slice requests beyond a provided byte limit into two requests', async () => {
expect.assertions(3);
const maxDataSliceByteRange = 100;
rpcGraphQL = createRpcGraphQL(
rpcGraphQL = createSolanaRpcGraphQL(
rpc as unknown as Rpc<
GetAccountInfoApi &
GetBlockApi &
Expand Down Expand Up @@ -1427,7 +1427,7 @@ describe('account loader', () => {
it('honors a provided byte limit across encodings', async () => {
expect.assertions(5);
const maxDataSliceByteRange = 100;
rpcGraphQL = createRpcGraphQL(
rpcGraphQL = createSolanaRpcGraphQL(
rpc as unknown as Rpc<
GetAccountInfoApi &
GetBlockApi &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
} from '@solana/rpc';
import type { Slot } from '@solana/rpc-types';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -29,7 +29,7 @@ describe('account loader', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('cached responses', () => {
it('coalesces multiple requests for the same block into one', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -28,7 +28,7 @@ describe('account loader', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('cached responses', () => {
it('coalesces multiple requests for the same program into one', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -28,7 +28,7 @@ describe('account loader', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('cached responses', () => {
it('coalesces multiple requests for the same transaction into one', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('account resolver', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('address-only requests', () => {
describe('in the first level', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../..';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../..';
import { mockBlockFull } from '../../__tests__/__setup__';

type GraphQLCompliantRpc = Rpc<
Expand All @@ -34,7 +34,7 @@ describe('block inputs', () => {
return target[p as keyof GraphQLCompliantRpc];
},
});
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
// Does not accept raw bigint, ie. 511226n
it('can accept a bigint parameter as variable', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
} from '@solana/rpc';
import type { Slot } from '@solana/rpc-types';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -29,7 +29,7 @@ describe('block resolver', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('fragment spreads', () => {
it('will resolve fields from fragment spreads', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -25,7 +25,7 @@ describe('program accounts resolver', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('inline fragments', () => {
it('will resolve inline fragments with `jsonParsed` when `jsonParsed` fields are requested', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
Rpc,
} from '@solana/rpc';

import { createRpcGraphQL, RpcGraphQL } from '../../index';
import { createSolanaRpcGraphQL, RpcGraphQL } from '../../index';

const FOREVER_PROMISE = new Promise(() => {
/* never resolve */
Expand All @@ -27,7 +27,7 @@ describe('transaction resolver', () => {
getProgramAccounts: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
getTransaction: jest.fn().mockReturnValue({ send: jest.fn().mockReturnValue(FOREVER_PROMISE) }),
};
rpcGraphQL = createRpcGraphQL(rpc);
rpcGraphQL = createSolanaRpcGraphQL(rpc);
});
describe('fragment spreads', () => {
it('will resolve fields from fragment spreads', async () => {
Expand Down
5 changes: 5 additions & 0 deletions packages/rpc-graphql/src/schema/type-defs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { rootTypeDefs } from './root';
import { transactionTypeDefs } from './transaction';
import { typeTypeDefs } from './types';

/**
* Creates the GraphQL type definitions for the Solana GraphQL schema.
*
* @returns Solana GraphQL type definitions.
*/
export function createSolanaGraphQLTypeDefs() {
return [accountTypeDefs, blockTypeDefs, instructionTypeDefs, rootTypeDefs, typeTypeDefs, transactionTypeDefs];
}
5 changes: 5 additions & 0 deletions packages/rpc-graphql/src/schema/type-resolvers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import { rootTypeResolvers } from './root';
import { transactionTypeResolvers } from './transaction';
import { typeTypeResolvers } from './types';

/**
* Create the GraphQL type resolvers for the Solana GraphQL schema.
*
* @returns Solana GraphQL type resolvers.
*/
export function createSolanaGraphQLTypeResolvers(): Parameters<typeof makeExecutableSchema>[0]['resolvers'] {
return {
...accountTypeResolvers,
Expand Down

0 comments on commit f0f86d0

Please sign in to comment.