Skip to content

Commit

Permalink
Use MaybeAccount types in fetch account helpers of js-experimental (#152
Browse files Browse the repository at this point in the history
)

* Rename safeFetch into fetchMaybe functions

* Generate MaybeAccount type for each account

* Update account fetch helpers

* Add changeset
  • Loading branch information
lorisleiva authored Jan 11, 2024
1 parent 1877460 commit 7695a7a
Show file tree
Hide file tree
Showing 21 changed files with 525 additions and 307 deletions.
5 changes: 5 additions & 0 deletions .changeset/little-beans-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@metaplex-foundation/kinobi': patch
---

Use MaybeAccount types in fetch account helpers of js-experimental
32 changes: 15 additions & 17 deletions src/renderers/js-experimental/fragments/accountFetchHelpers.njk
Original file line number Diff line number Diff line change
@@ -1,45 +1,43 @@
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): {{ accountType }}<TAddress> {
return decodeAccount(encodedAccount, {{ decoderFunction }});
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): {{ accountType }}<TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): {{ accountMaybeType }}<TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>): {{ accountType }}<TAddress> | {{ accountMaybeType }}<TAddress> {
return decodeAccount(encodedAccount as MaybeEncodedAccount<TAddress>, {{ decoderFunction }});
}

export async function {{ fetchFunction }}<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig,
): Promise<{{ accountType }}<TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
const maybeAccount = await {{ fetchMaybeFunction }}(rpc, address, config);
assertAccountExists(maybeAccount);
return {{ decodeFunction }}(maybeAccount);
return maybeAccount;
}

export async function {{ safeFetchFunction }}<TAddress extends string = string>(
export async function {{ fetchMaybeFunction }}<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig,
): Promise<{{ accountType }}<TAddress> | null> {
): Promise<{{ accountMaybeType }}<TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
return maybeAccount.exists ? {{ decodeFunction }}(maybeAccount) : null;
return {{ decodeFunction }}(maybeAccount);
}

export async function {{ fetchAllFunction }}(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig,
): Promise<{{ accountType }}[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts.map((maybeAccount) => {
assertAccountExists(maybeAccount);
return {{ decodeFunction }}(maybeAccount);
});
const maybeAccounts = await {{ fetchAllMaybeFunction }}(rpc, addresses, config);
assertAccountsExist(maybeAccounts);
return maybeAccounts;
}

export async function {{ safeFetchAllFunction }}(
export async function {{ fetchAllMaybeFunction }}(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig,
): Promise<{{ accountType }}[]> {
): Promise<{{ accountMaybeType }}[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts
.filter((maybeAccount) => maybeAccount.exists)
.map((maybeAccount) => {{ decodeFunction }}(maybeAccount as EncodedAccount));
return maybeAccounts.map((maybeAccount) => {{ decodeFunction }}(maybeAccount));
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,26 @@ export function getAccountFetchHelpersFragment(
return fragmentFromTemplate('accountFetchHelpers.njk', {
decoderFunction: decoderFunctionFragment.render,
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
decodeFunction: nameApi.accountDecodeFunction(accountNode.name),
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
safeFetchFunction: nameApi.accountSafeFetchFunction(accountNode.name),
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),
fetchAllFunction: nameApi.accountFetchAllFunction(accountNode.name),
safeFetchAllFunction: nameApi.accountSafeFetchAllFunction(accountNode.name),
fetchAllMaybeFunction: nameApi.accountFetchAllMaybeFunction(
accountNode.name
),
})
.mergeImportsWith(decoderFunctionFragment)
.addImports('solanaAddresses', ['Address'])
.addImports('solanaAccounts', [
'assertAccountExists',
'assertAccountsExist',
'decodeAccount',
'EncodedAccount',
'fetchEncodedAccount',
'fetchEncodedAccounts',
'FetchAccountConfig',
'FetchAccountsConfig',
'MaybeEncodedAccount',
]);
}
12 changes: 6 additions & 6 deletions src/renderers/js-experimental/fragments/accountPdaHelpers.njk
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ export async function {{ fetchFromSeedsFunction }}(
{% endif %}
config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<{{ accountType }}> {
const { programAddress, ...fetchConfig } = config;
const [address] = await {{ findPdaFunction }}({% if hasVariableSeeds %}seeds, {% endif %}{ programAddress });
return {{ fetchFunction }}(rpc, address, fetchConfig);
const maybeAccount = await {{ fetchMaybeFromSeedsFunction }}(rpc, {% if hasVariableSeeds %}seeds, {% endif %}config);
assertAccountExists(maybeAccount);
return maybeAccount;
}

export async function {{ safeFetchFromSeedsFunction }}(
export async function {{ fetchMaybeFromSeedsFunction }}(
rpc: Parameters<typeof fetchEncodedAccount>[0],
{% if hasVariableSeeds %}
seeds: {{ pdaSeedsType }},
{% endif %}
config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<{{ accountType }} | null> {
): Promise<{{ accountMaybeType }}> {
const { programAddress, ...fetchConfig } = config;
const [address] = await {{ findPdaFunction }}({% if hasVariableSeeds %}seeds, {% endif %}{ programAddress });
return {{ safeFetchFunction }}(rpc, address, fetchConfig);
return {{ fetchMaybeFunction }}(rpc, address, fetchConfig);
}
10 changes: 7 additions & 3 deletions src/renderers/js-experimental/fragments/accountPdaHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ export function getAccountPdaHelpersFragment(

return fragmentFromTemplate('accountPdaHelpers.njk', {
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
pdaSeedsType,
findPdaFunction,
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
safeFetchFunction: nameApi.accountSafeFetchFunction(accountNode.name),
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),
fetchFromSeedsFunction: nameApi.accountFetchFromSeedsFunction(
accountNode.name
),
safeFetchFromSeedsFunction: nameApi.accountSafeFetchFromSeedsFunction(
fetchMaybeFromSeedsFunction: nameApi.accountFetchMaybeFromSeedsFunction(
accountNode.name
),
program: programNode,
Expand All @@ -40,5 +41,8 @@ export function getAccountPdaHelpersFragment(
hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]
)
.addImports('solanaAddresses', ['Address'])
.addImports('solanaAccounts', ['FetchAccountConfig']);
.addImports('solanaAccounts', [
'assertAccountExists',
'FetchAccountConfig',
]);
}
2 changes: 2 additions & 0 deletions src/renderers/js-experimental/fragments/accountType.njk
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
{{ macros.docblock(docs) }}
export type {{ accountType }}<TAddress extends string = string> = Account<{{ dataName }}, TAddress>;

export type {{ accountMaybeType }}<TAddress extends string = string> = MaybeAccount<{{ dataName }}, TAddress>;

{{ typeWithCodec }}
3 changes: 2 additions & 1 deletion src/renderers/js-experimental/fragments/accountType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ export function getAccountTypeFragment(

return fragmentFromTemplate('accountType.njk', {
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
dataName: dataNameFragment.render,
typeWithCodec: typeWithCodecFragment,
})
.mergeImportsWith(dataNameFragment, typeWithCodecFragment)
.addImports('solanaAccounts', 'Account');
.addImports('solanaAccounts', ['Account', 'MaybeAccount']);
}
16 changes: 9 additions & 7 deletions src/renderers/js-experimental/nameTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ export type NameTransformerKey =
| 'pdaSeedsType'
| 'pdaFindFunction'
| 'accountType'
| 'accountMaybeType'
| 'accountDataType'
| 'accountDecodeFunction'
| 'accountFetchFunction'
| 'accountFetchAllFunction'
| 'accountSafeFetchFunction'
| 'accountSafeFetchAllFunction'
| 'accountFetchMaybeFunction'
| 'accountFetchAllMaybeFunction'
| 'accountFetchFromSeedsFunction'
| 'accountSafeFetchFromSeedsFunction'
| 'accountFetchMaybeFromSeedsFunction'
| 'accountGetSizeFunction'
| 'scalarEnumVariant'
| 'dataEnumDiscriminator'
Expand Down Expand Up @@ -102,15 +103,16 @@ export const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {
pdaSeedsType: (name) => `${pascalCase(name)}Seeds`,
pdaFindFunction: (name) => `find${pascalCase(name)}Pda`,
accountType: (name) => `${pascalCase(name)}`,
accountMaybeType: (name) => `Maybe${pascalCase(name)}`,
accountDataType: (name) => `${pascalCase(name)}AccountData`,
accountDecodeFunction: (name) => `decode${pascalCase(name)}`,
accountFetchFunction: (name) => `fetch${pascalCase(name)}`,
accountFetchAllFunction: (name) => `fetchAll${pascalCase(name)}`,
accountSafeFetchFunction: (name) => `safeFetch${pascalCase(name)}`,
accountSafeFetchAllFunction: (name) => `safeFetchAll${pascalCase(name)}`,
accountFetchMaybeFunction: (name) => `fetchMaybe${pascalCase(name)}`,
accountFetchAllMaybeFunction: (name) => `fetchAllMaybe${pascalCase(name)}`,
accountFetchFromSeedsFunction: (name) => `fetch${pascalCase(name)}FromSeeds`,
accountSafeFetchFromSeedsFunction: (name) =>
`safeFetch${pascalCase(name)}FromSeeds`,
accountFetchMaybeFromSeedsFunction: (name) =>
`fetchMaybe${pascalCase(name)}FromSeeds`,
accountGetSizeFunction: (name) => `get${pascalCase(name)}Size`,
scalarEnumVariant: (name) => `${pascalCase(name)}`,
dataEnumDiscriminator: () => '__kind',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
EncodedAccount,
FetchAccountConfig,
FetchAccountsConfig,
MaybeAccount,
MaybeEncodedAccount,
assertAccountExists,
assertAccountsExist,
decodeAccount,
fetchEncodedAccount,
fetchEncodedAccounts,
Expand Down Expand Up @@ -52,6 +55,11 @@ export type CandyMachine<TAddress extends string = string> = Account<
TAddress
>;

export type MaybeCandyMachine<TAddress extends string = string> = MaybeAccount<
CandyMachineAccountData,
TAddress
>;

export type CandyMachineAccountData = {
discriminator: Array<number>;
/** Features versioning flags. */
Expand Down Expand Up @@ -139,48 +147,53 @@ export function getCandyMachineAccountDataCodec(): Codec<

export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: EncodedAccount<TAddress>
): CandyMachine<TAddress> {
return decodeAccount(encodedAccount, getCandyMachineAccountDataDecoder());
): CandyMachine<TAddress>;
export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: MaybeEncodedAccount<TAddress>
): MaybeCandyMachine<TAddress>;
export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>
): CandyMachine<TAddress> | MaybeCandyMachine<TAddress> {
return decodeAccount(
encodedAccount as MaybeEncodedAccount<TAddress>,
getCandyMachineAccountDataDecoder()
);
}

export async function fetchCandyMachine<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig
): Promise<CandyMachine<TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
const maybeAccount = await fetchMaybeCandyMachine(rpc, address, config);
assertAccountExists(maybeAccount);
return decodeCandyMachine(maybeAccount);
return maybeAccount;
}

export async function safeFetchCandyMachine<TAddress extends string = string>(
export async function fetchMaybeCandyMachine<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig
): Promise<CandyMachine<TAddress> | null> {
): Promise<MaybeCandyMachine<TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
return maybeAccount.exists ? decodeCandyMachine(maybeAccount) : null;
return decodeCandyMachine(maybeAccount);
}

export async function fetchAllCandyMachine(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig
): Promise<CandyMachine[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts.map((maybeAccount) => {
assertAccountExists(maybeAccount);
return decodeCandyMachine(maybeAccount);
});
const maybeAccounts = await fetchAllMaybeCandyMachine(rpc, addresses, config);
assertAccountsExist(maybeAccounts);
return maybeAccounts;
}

export async function safeFetchAllCandyMachine(
export async function fetchAllMaybeCandyMachine(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig
): Promise<CandyMachine[]> {
): Promise<MaybeCandyMachine[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts
.filter((maybeAccount) => maybeAccount.exists)
.map((maybeAccount) => decodeCandyMachine(maybeAccount as EncodedAccount));
return maybeAccounts.map((maybeAccount) => decodeCandyMachine(maybeAccount));
}
Loading

0 comments on commit 7695a7a

Please sign in to comment.