Skip to content

Commit 6b81970

Browse files
committed
feat: implement collection asset search
1 parent 4a5afc4 commit 6b81970

14 files changed

+240
-70
lines changed

api-schema.graphql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ type Query {
711711
appConfig: AppConfig!
712712
me: User
713713
uptime: Float!
714+
userCollectionAssetFindMany(input: UserCollectionAssetFindManyInput!): [CollectionAsset!]
714715
userCollectionFindMany(input: UserCollectionFindManyInput!): [Collection!]
715716
userCollectionFindOne(collectionId: String!): Collection
716717
userFindManyBotRoles(botId: String!, serverId: String!): [BotRole!]
@@ -879,6 +880,11 @@ input UserAddIdentityGrantInput {
879880
providerId: String!
880881
}
881882

883+
input UserCollectionAssetFindManyInput {
884+
collectionId: String!
885+
search: String
886+
}
887+
882888
input UserCollectionCreateInput {
883889
communityId: String!
884890
tokenId: String!

libs/api/collection/data-access/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './lib/api-collection.data-access.module'
22
export * from './lib/api-collection.service'
3+
export * from './lib/api-collection-assets.service'
34
export * from './lib/dto/user-collection-create-input'
45
export * from './lib/dto/user-collection-find-many.input'
56
export * from './lib/entity/collection-asset'
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { BadRequestException, Injectable, Logger } from '@nestjs/common'
2+
import { ApiCacheService } from '@pubkey-link/api-cache-data-access'
3+
import { ApiCoreService } from '@pubkey-link/api-core-data-access'
4+
import { CollectionAsset } from '@pubkey-link/sdk'
5+
import { DAS } from 'helius-sdk'
6+
import slugify from 'slugify'
7+
import { UserCollectionCreateInput } from './dto/user-collection-create-input'
8+
import { UserCollectionAssetFindManyInput, UserCollectionFindManyInput } from './dto/user-collection-find-many.input'
9+
import { CollectionAssetAttribute } from './entity/collection-asset-attribute'
10+
import { Collection } from './entity/collection.entity'
11+
12+
@Injectable()
13+
export class ApiCollectionAssetService {
14+
constructor(private readonly core: ApiCoreService, private readonly cache: ApiCacheService) {}
15+
16+
async findMany({ collectionId, search }: UserCollectionAssetFindManyInput): Promise<CollectionAsset[]> {
17+
const collection = await this.ensureCollection(collectionId)
18+
if (!collection.token) {
19+
throw new Error(`Token for collection ${collection.slug} not found`)
20+
}
21+
const resolver = this.cache.createTokenResolver(collection.token)
22+
if (!resolver) {
23+
throw new Error(`Resolver ${collection.token.account} not found`)
24+
}
25+
26+
try {
27+
const snapshot = await this.cache.assetsSnapshot({ cluster: collection.token.cluster, id: resolver.id })
28+
const items: DAS.GetAssetResponse[] = (snapshot.items ?? []) as DAS.GetAssetResponse[]
29+
30+
const assets = items.map((asset) => ({
31+
id: asset.id,
32+
name: asset.content?.metadata?.name ?? '',
33+
description: asset.content?.metadata?.description ?? '',
34+
imageUrl: asset.content?.files?.[0]?.uri ?? '',
35+
owner: asset.ownership.owner,
36+
attributes: renameAttributes(asset.content?.metadata?.attributes ?? []),
37+
}))
38+
39+
return assets.filter((assets) => {
40+
if (!search?.length) {
41+
return true
42+
}
43+
44+
return (
45+
assets.name.toLowerCase().includes(search.toLowerCase()) ||
46+
assets.description.toLowerCase().includes(search.toLowerCase())
47+
)
48+
})
49+
} catch (e) {
50+
console.log('error', e)
51+
throw e
52+
}
53+
}
54+
55+
private async ensureCollection(collectionId: string) {
56+
const found = await this.core.data.collection.findUnique({
57+
where: { id: collectionId },
58+
include: { token: true },
59+
})
60+
if (!found) {
61+
throw new Error(`Collection ${collectionId} not found`)
62+
}
63+
return found
64+
}
65+
}
66+
67+
function renameAttributes(items: { trait_type: string; value: string }[] = []): CollectionAssetAttribute[] {
68+
return items.map((item) => ({
69+
key: item.trait_type,
70+
value: item.value,
71+
}))
72+
}

libs/api/collection/data-access/src/lib/api-collection.data-access.module.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { Module } from '@nestjs/common'
22
import { ApiCacheDataAccessModule } from '@pubkey-link/api-cache-data-access'
33
import { ApiCoreDataAccessModule } from '@pubkey-link/api-core-data-access'
44
import { ApiCollectionService } from './api-collection.service'
5+
import { ApiCollectionAssetService } from './api-collection-assets.service'
56

67
@Module({
78
imports: [ApiCoreDataAccessModule, ApiCacheDataAccessModule],
8-
providers: [ApiCollectionService],
9-
exports: [ApiCollectionService],
9+
providers: [ApiCollectionService, ApiCollectionAssetService],
10+
exports: [ApiCollectionService, ApiCollectionAssetService],
1011
})
1112
export class ApiCollectionDataAccessModule {}

libs/api/collection/data-access/src/lib/api-collection.service.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ export class ApiCollectionService {
5353
return {
5454
...collection,
5555
attributes: accumulateAttributes(assets),
56-
assets,
5756
}
5857
} catch (e) {
5958
console.log('error', e)

libs/api/collection/data-access/src/lib/dto/user-collection-find-many.input.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ export class UserCollectionFindManyInput {
77
@Field({ nullable: true })
88
search?: string
99
}
10+
11+
@InputType()
12+
export class UserCollectionAssetFindManyInput {
13+
@Field()
14+
collectionId!: string
15+
@Field({ nullable: true })
16+
search?: string
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { UseGuards } from '@nestjs/common'
2+
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'
3+
import { ApiAuthGraphQLUserGuard, CtxUserId } from '@pubkey-link/api-auth-data-access'
4+
import {
5+
ApiCollectionAssetService,
6+
ApiCollectionService,
7+
Collection,
8+
CollectionAsset,
9+
UserCollectionAssetFindManyInput,
10+
UserCollectionCreateInput,
11+
UserCollectionFindManyInput,
12+
} from '@pubkey-link/api-collection-data-access'
13+
14+
@Resolver()
15+
@UseGuards(ApiAuthGraphQLUserGuard)
16+
export class ApiCollectionAssetUserResolver {
17+
constructor(private readonly service: ApiCollectionAssetService) {}
18+
19+
@Query(() => [CollectionAsset], { nullable: true })
20+
userCollectionAssetFindMany(@Args('input') input: UserCollectionAssetFindManyInput) {
21+
return this.service.findMany(input)
22+
}
23+
}

libs/api/collection/feature/src/lib/api-collection.feature.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'
22
import { ApiCollectionDataAccessModule } from '@pubkey-link/api-collection-data-access'
33
import { ApiCollectionUserResolver } from './api-collection-user.resolver'
44
import { ApiCollectionResolver } from './api-collection.resolver'
5+
import { ApiCollectionAssetUserResolver } from './api-collection-asset-user.resolver'
56

67
@Module({
78
imports: [ApiCollectionDataAccessModule],
8-
providers: [ApiCollectionResolver, ApiCollectionUserResolver],
9+
providers: [ApiCollectionResolver, ApiCollectionAssetUserResolver, ApiCollectionUserResolver],
910
})
1011
export class ApiCollectionFeatureModule {}

libs/sdk/src/generated/graphql-sdk.ts

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,7 @@ export type Query = {
10801080
appConfig: AppConfig
10811081
me?: Maybe<User>
10821082
uptime: Scalars['Float']['output']
1083+
userCollectionAssetFindMany?: Maybe<Array<CollectionAsset>>
10831084
userCollectionFindMany?: Maybe<Array<Collection>>
10841085
userCollectionFindOne?: Maybe<Collection>
10851086
userFindManyBotRoles?: Maybe<Array<BotRole>>
@@ -1222,6 +1223,10 @@ export type QueryAnonRequestIdentityChallengeArgs = {
12221223
input: RequestIdentityChallengeInput
12231224
}
12241225

1226+
export type QueryUserCollectionAssetFindManyArgs = {
1227+
input: UserCollectionAssetFindManyInput
1228+
}
1229+
12251230
export type QueryUserCollectionFindManyArgs = {
12261231
input: UserCollectionFindManyInput
12271232
}
@@ -1509,6 +1514,11 @@ export type UserAddIdentityGrantInput = {
15091514
providerId: Scalars['String']['input']
15101515
}
15111516

1517+
export type UserCollectionAssetFindManyInput = {
1518+
collectionId: Scalars['String']['input']
1519+
search?: InputMaybe<Scalars['String']['input']>
1520+
}
1521+
15121522
export type UserCollectionCreateInput = {
15131523
communityId: Scalars['String']['input']
15141524
tokenId: Scalars['String']['input']
@@ -2503,6 +2513,28 @@ export type UserCollectionFindManyQuery = {
25032513
}> | null
25042514
}
25052515

2516+
export type UserCollectionAssetFindManyQueryVariables = Exact<{
2517+
input: UserCollectionAssetFindManyInput
2518+
}>
2519+
2520+
export type UserCollectionAssetFindManyQuery = {
2521+
__typename?: 'Query'
2522+
items?: Array<{
2523+
__typename?: 'CollectionAsset'
2524+
id: string
2525+
name: string
2526+
description: string
2527+
imageUrl: string
2528+
owner: string
2529+
attributes?: Array<{
2530+
__typename?: 'CollectionAssetAttribute'
2531+
key: string
2532+
value?: string | null
2533+
count?: number | null
2534+
}> | null
2535+
}> | null
2536+
}
2537+
25062538
export type UserCollectionFindOneQueryVariables = Exact<{
25072539
collectionId: Scalars['String']['input']
25082540
}>
@@ -2522,20 +2554,6 @@ export type UserCollectionFindOneQuery = {
25222554
value?: string | null
25232555
count?: number | null
25242556
}> | null
2525-
assets?: Array<{
2526-
__typename?: 'CollectionAsset'
2527-
id: string
2528-
name: string
2529-
description: string
2530-
imageUrl: string
2531-
owner: string
2532-
attributes?: Array<{
2533-
__typename?: 'CollectionAssetAttribute'
2534-
key: string
2535-
value?: string | null
2536-
count?: number | null
2537-
}> | null
2538-
}> | null
25392557
token?: {
25402558
__typename?: 'NetworkToken'
25412559
id: string
@@ -9774,21 +9792,25 @@ export const UserCollectionFindManyDocument = gql`
97749792
}
97759793
${CollectionDetailsFragmentDoc}
97769794
`
9795+
export const UserCollectionAssetFindManyDocument = gql`
9796+
query userCollectionAssetFindMany($input: UserCollectionAssetFindManyInput!) {
9797+
items: userCollectionAssetFindMany(input: $input) {
9798+
...CollectionAssetDetails
9799+
}
9800+
}
9801+
${CollectionAssetDetailsFragmentDoc}
9802+
`
97779803
export const UserCollectionFindOneDocument = gql`
97789804
query userCollectionFindOne($collectionId: String!) {
97799805
item: userCollectionFindOne(collectionId: $collectionId) {
97809806
...CollectionDetails
97819807
attributes {
97829808
...CollectionAssetAttributeDetails
97839809
}
9784-
assets {
9785-
...CollectionAssetDetails
9786-
}
97879810
}
97889811
}
97899812
${CollectionDetailsFragmentDoc}
97909813
${CollectionAssetAttributeDetailsFragmentDoc}
9791-
${CollectionAssetDetailsFragmentDoc}
97929814
`
97939815
export const UserCollectionCreateDocument = gql`
97949816
mutation userCollectionCreate($input: UserCollectionCreateInput!) {
@@ -10844,6 +10866,7 @@ const AdminCacheDetailDocumentString = print(AdminCacheDetailDocument)
1084410866
const AdminCacheResolveDocumentString = print(AdminCacheResolveDocument)
1084510867
const AdminCacheSyncDocumentString = print(AdminCacheSyncDocument)
1084610868
const UserCollectionFindManyDocumentString = print(UserCollectionFindManyDocument)
10869+
const UserCollectionAssetFindManyDocumentString = print(UserCollectionAssetFindManyDocument)
1084710870
const UserCollectionFindOneDocumentString = print(UserCollectionFindOneDocument)
1084810871
const UserCollectionCreateDocumentString = print(UserCollectionCreateDocument)
1084910872
const UserCollectionDeleteDocumentString = print(UserCollectionDeleteDocument)
@@ -11700,6 +11723,27 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper =
1170011723
variables,
1170111724
)
1170211725
},
11726+
userCollectionAssetFindMany(
11727+
variables: UserCollectionAssetFindManyQueryVariables,
11728+
requestHeaders?: GraphQLClientRequestHeaders,
11729+
): Promise<{
11730+
data: UserCollectionAssetFindManyQuery
11731+
errors?: GraphQLError[]
11732+
extensions?: any
11733+
headers: Headers
11734+
status: number
11735+
}> {
11736+
return withWrapper(
11737+
(wrappedRequestHeaders) =>
11738+
client.rawRequest<UserCollectionAssetFindManyQuery>(UserCollectionAssetFindManyDocumentString, variables, {
11739+
...requestHeaders,
11740+
...wrappedRequestHeaders,
11741+
}),
11742+
'userCollectionAssetFindMany',
11743+
'query',
11744+
variables,
11745+
)
11746+
},
1170311747
userCollectionFindOne(
1170411748
variables: UserCollectionFindOneQueryVariables,
1170511749
requestHeaders?: GraphQLClientRequestHeaders,
@@ -14366,6 +14410,13 @@ export function UserAddIdentityGrantInputSchema(): z.ZodObject<Properties<UserAd
1436614410
})
1436714411
}
1436814412

14413+
export function UserCollectionAssetFindManyInputSchema(): z.ZodObject<Properties<UserCollectionAssetFindManyInput>> {
14414+
return z.object({
14415+
collectionId: z.string(),
14416+
search: z.string().nullish(),
14417+
})
14418+
}
14419+
1436914420
export function UserCollectionCreateInputSchema(): z.ZodObject<Properties<UserCollectionCreateInput>> {
1437014421
return z.object({
1437114422
communityId: z.string(),

libs/sdk/src/graphql/feature-collection.graphql

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ query userCollectionFindMany($input: UserCollectionFindManyInput!) {
3232
}
3333
}
3434

35+
query userCollectionAssetFindMany($input: UserCollectionAssetFindManyInput!) {
36+
items: userCollectionAssetFindMany(input: $input) {
37+
...CollectionAssetDetails
38+
}
39+
}
40+
3541
query userCollectionFindOne($collectionId: String!) {
3642
item: userCollectionFindOne(collectionId: $collectionId) {
3743
...CollectionDetails
3844
attributes {
3945
...CollectionAssetAttributeDetails
4046
}
41-
assets {
42-
...CollectionAssetDetails
43-
}
4447
}
4548
}
4649

0 commit comments

Comments
 (0)