Skip to content

Commit

Permalink
Merge pull request #205 from metaplex-foundation/mark/fetchAllAssets
Browse files Browse the repository at this point in the history
new helper fetchAllAssets
  • Loading branch information
MarkSackerberg authored Dec 20, 2024
2 parents 30fbdf1 + a4eccbf commit 87e2e35
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
60 changes: 60 additions & 0 deletions clients/js/src/helpers/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import {
AssetV1,
CollectionV1,
fetchAllAssetV1,
fetchAllCollectionV1,
fetchAssetV1,
fetchCollectionV1,
Expand Down Expand Up @@ -147,6 +148,65 @@ export const fetchAsset = async (
return deriveAssetPlugins(assetV1, await fetchCollectionV1(umi, collection));
};

/**
* Helper function to fetch multiple assets and derive plugins from their collections if applicable.
*
* @param umi Context
* @param assets Array of asset addresses to fetch
* @param options Options, `skipDerivePlugins` plugins from collection is false by default; `chunksize` how many assets to fetch in a single rpc call.
* @returns Promise of a list of `AssetV1`
*/
export const fetchAllAssets = async (
umi: Context,
assets: Array<PublicKey | string>,
options: {
skipDerivePlugins?: boolean;
chunkSize?: number;
} & RpcGetAccountOptions = {}
): Promise<AssetV1[]> => {
const chunkSize = options.chunkSize ?? 1000;
const assetChunks = [];
for (let i = 0; i < assets.length; i += chunkSize) {
assetChunks.push(assets.slice(i, i + chunkSize));
}

const assetV1s = (
await Promise.all(
assetChunks.map((chunk) =>
fetchAllAssetV1(
umi,
chunk.map((asset) => publicKey(asset))
)
)
)
).flat();

if (options.skipDerivePlugins) {
return assetV1s;
}

const collectionKeys = Array.from(
new Set(assetV1s.map((asset) => collectionAddress(asset)))
).filter((collection): collection is PublicKey => !!collection);

const collections = await fetchAllCollectionV1(umi, collectionKeys);
const collectionMap = collections.reduce(
(map, collection) => {
map[collection.publicKey] = collection;
return map;
},
{} as { [key: string]: CollectionV1 }
);

return assetV1s.map((assetV1) => {
const collection = collectionAddress(assetV1);
if (!collection) {
return assetV1;
}
return deriveAssetPlugins(assetV1, collectionMap[collection]);
});
};

/**
* Helper function to fetch a collection.
*
Expand Down
91 changes: 91 additions & 0 deletions clients/js/test/helps/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
fetchAssetsByCollection,
fetchAssetsByOwner,
fetchCollectionsByUpdateAuthority,
fetchAllAssets,
} from '../../src';
import { createUmi } from '../_setupRaw';
import { createAsset, createCollection } from '../_setupSdk';
Expand Down Expand Up @@ -161,3 +162,93 @@ test('it can use helper to fetch assets by collection and derive plugins', async
}
});
});

test('it can use helper to fetch all assets', async (t) => {
const umi = await createUmi();

const collection = await createCollection(umi, {
plugins: [
{
type: 'ImmutableMetadata',
},
],
});

const assetsOfOwner1 = await Promise.all(
Array(2)
.fill(0)
.map((_, index) =>
createAsset(umi, {
collection,
name: `Asset ${index + 1}`,
plugins: [
{
type: 'Attributes',
attributeList: [
{
key: 'asset',
value: 'asset',
},
],
},
],
})
)
);

const assetsOfOwner2 = await Promise.all(
Array(2)
.fill(0)
.map((_, index) =>
createAsset(umi, {
collection,
name: `Asset ${index + 1}`,
plugins: [
{
type: 'Attributes',
attributeList: [
{
key: 'asset',
value: 'asset',
},
],
},
],
})
)
);

const allCreatedAssets = [...assetsOfOwner1, ...assetsOfOwner2];

const assetPublicKeys = [...assetsOfOwner1, ...assetsOfOwner2].map(
(asset) => asset.publicKey
);

const fetchedAssets = await fetchAllAssets(umi, assetPublicKeys);

const createdAssetPubkeys = allCreatedAssets
.map((asset) => asset.publicKey)
.sort();
const fetchedAssetPubkeys = fetchedAssets
.map((asset) => asset.publicKey)
.filter((pubkey) => createdAssetPubkeys.includes(pubkey))
.sort();

t.deepEqual(
fetchedAssetPubkeys,
createdAssetPubkeys,
'All created assets should be found in fetched assets'
);

t.deepEqual(
fetchedAssets[0].attributes,
allCreatedAssets[0].attributes,
'Asset level attribute plugin should be found in fetched assets'
);

t.deepEqual(
fetchedAssets[0].immutableMetadata,
collection.immutableMetadata,
'Collection level immutableMetadata plugin should be found in fetched assets'
);
});

0 comments on commit 87e2e35

Please sign in to comment.