Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡ Event Lists supercharged #39

Merged
merged 17 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 245 additions & 50 deletions src/clients/SquidClient.ts

Large diffs are not rendered by default.

52 changes: 35 additions & 17 deletions src/clients/abstractClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { BaseEvent, GraphLike, GraphQuery, ObjProp, QueryProps } from '../types'
interface AbstractClient<C, T, E = BaseEvent> {
collectionById(id: string, fields?: ObjProp<C>): GraphQuery
// collectionListBy(id: string, field: KeyOf<C>, fields?: ObjProp<C>): GraphQuery
collectionCountByIssuer(issuer: string): GraphQuery ;
collectionCountByName(name: string): GraphQuery ;
collectionCountByOwner(owner: string): GraphQuery ;
collectionCountCreatedAfter(date: Date): GraphQuery ;
collectionCountByIssuer(issuer: string): GraphQuery
collectionCountByName(name: string): GraphQuery
collectionCountByOwner(owner: string): GraphQuery
collectionCountCreatedAfter(date: Date): GraphQuery
collectionListByIssuer(issuer: string, options?: QueryProps<C>): GraphQuery
collectionListByName(name: string, options?: QueryProps<C>): GraphQuery
collectionListByOwner(owner: string, options?: QueryProps<C>): GraphQuery
Expand All @@ -15,23 +15,41 @@ interface AbstractClient<C, T, E = BaseEvent> {
eventList(options?: QueryProps<E>): GraphQuery
eventListByAddress(address: string, options?: QueryProps<E>): GraphQuery
eventListByCollectionId(id: string, options?: QueryProps<E>): GraphQuery
// eventListByCollectionIdAndInteraction(id: string, interaction: string, options?: QueryProps<E>): GraphQuery
eventListByInteraction(interaction: string, options?: QueryProps<E>): GraphQuery
eventListByCollectionIdAndInteraction(id: string, interaction: string, options?: QueryProps<E>): GraphQuery
eventListByCollectionIdAndInteractionList(id: string, interactions: string[], options?: QueryProps<E>): GraphQuery
eventListByInteraction(
interaction: string,
options?: QueryProps<E>,
): GraphQuery
eventListByItemId(id: string, options?: QueryProps<E>): GraphQuery
eventListByItemIdAndInteraction(
id: string,
interaction: string,
options?: QueryProps<E>,
): GraphQuery
eventListByItemIdAndInteractionList(
id: string,
interactions: string[],
options?: QueryProps<E>,
): GraphQuery
itemById(id: string, fields?: ObjProp<T>): GraphQuery
itemCountByOwner(owner: string): GraphQuery ;
itemCountByIssuer(issuer: string): GraphQuery ;
itemCountByName(name: string): GraphQuery ;
itemCountCollectedBy(address: string): GraphQuery ;
itemCountSoldBy(address: string): GraphQuery ;
itemCountByCollectionId(id: string): GraphQuery ;
itemCountForSale(): GraphQuery ;
itemCountForSaleByCollectionId(id: string): GraphQuery ;
itemCountByCollectionIdAndOwner(id: string, owner: string): GraphQuery ;
itemCountCreatedAfter(date: Date): GraphQuery ;
itemCountByOwner(owner: string): GraphQuery
itemCountByIssuer(issuer: string): GraphQuery
itemCountByName(name: string): GraphQuery
itemCountCollectedBy(address: string): GraphQuery
itemCountSoldBy(address: string): GraphQuery
itemCountByCollectionId(id: string): GraphQuery
itemCountForSale(): GraphQuery
itemCountForSaleByCollectionId(id: string): GraphQuery
itemCountByCollectionIdAndOwner(id: string, owner: string): GraphQuery
itemCountCreatedAfter(date: Date): GraphQuery
// itemListBy(id: string, field: KeyOf<T>, fields?: ObjProp<T>): GraphQuery
itemListByCollectionId(id: string, options?: QueryProps<T>): GraphQuery
itemListByCollectionIdAndOwner(id: string, owner: string, options?: QueryProps<T>): GraphQuery
itemListByCollectionIdAndOwner(
id: string,
owner: string,
options?: QueryProps<T>,
): GraphQuery
itemListByCollectionIdList(ids: string[], options?: QueryProps<T>): GraphQuery
itemListByIssuer(issuer: string, options?: QueryProps<T>): GraphQuery
itemListByName(name: string, options?: QueryProps<T>): GraphQuery
Expand Down
69 changes: 52 additions & 17 deletions src/clients/defaults.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,63 @@
import { ObjProp, Fields, QueryOptions, BaseEvent, AbstractBase, QueryProps, QueryEntity } from '../types'

export const defaultField: ObjProp<AbstractBase> = ['id', 'createdAt', 'name', 'metadata', 'currentOwner', 'issuer']
export const defaultEventField: ObjProp<BaseEvent> = ['id', 'interaction', 'timestamp', 'caller', 'meta']
export const DEFAULT_LIMIT = 100
import {
AbstractBase,
BaseEvent,
Fields,
ObjProp,
QueryEntity,
QueryOptions,
QueryProps,
} from '../types'

export const defaultField: ObjProp<AbstractBase> = [
'id',
'createdAt',
'name',
'metadata',
'currentOwner',
'issuer',
]
export const defaultEventField: ObjProp<BaseEvent> = [
'id',
'interaction',
'timestamp',
'caller',
'meta',
]
export const DEFAULT_LIMIT = 200
// todo: add default orderBy
export const defaultQueryOptions: QueryOptions = {
limit: DEFAULT_LIMIT
limit: DEFAULT_LIMIT,
}

function hasMetaField(field: any): boolean {
return typeof field === 'string' && field === 'meta'
}

export function extendFields<T extends AbstractBase>(fields: ObjProp<T>): ObjProp<T> {
export function extendFields<T extends AbstractBase>(
fields: ObjProp<T>,
): ObjProp<T> {
const set = new Set([...defaultField, ...fields])
return [...set]
}

export function getFields<T>(fields?: ObjProp<T>, defaultList: ObjProp<T> | string[] = defaultField, replaceMetaField = true): Fields<T> {
export function getFields<T>(
fields?: ObjProp<T>,
defaultList: ObjProp<T> | string[] = defaultField,
replaceMetaField = true,
): Fields<T> {
const list = fields ?? defaultList

if (replaceMetaField) {
const metaIndex = list.findIndex(hasMetaField)

if (metaIndex !== -1) {
list.splice(metaIndex, 1, { meta: ['id', 'name', 'description', 'image', 'animationUrl', 'type'] } as any)
list.splice(
metaIndex,
1,
{
meta: ['id', 'name', 'description', 'image', 'animationUrl', 'type'],
} as any,
)
}
}
return list
Expand All @@ -36,7 +69,7 @@ export function wrapSubqueryList<T>(fields: Fields<T>): [{ nodes: Fields<T> }] {

export function optionToQuery(
options: QueryOptions,
injectDefault = true
injectDefault = true,
): string {
const final = injectDefault ? ensureOptions(options) : options
let query = ''
Expand All @@ -57,7 +90,10 @@ export function ensureOptions(options?: QueryOptions): QueryOptions {
return {
...defaultQueryOptions,
...queryOptions,
limit: Math.min(queryOptions.limit ?? DEFAULT_LIMIT, defaultQueryOptions.limit)
limit: Math.min(
queryOptions.limit ?? DEFAULT_LIMIT,
defaultQueryOptions.limit,
),
}
}

Expand Down Expand Up @@ -91,23 +127,22 @@ type GraphEntity = 'collection' | 'item' | 'event'
export const realEntityName: Record<GraphEntity, string> = {
collection: 'CollectionEntity',
item: 'NFTEntity',
event: 'Event'
event: 'Event',
}

function addWhere(whereType: string, whereValue?: any) {
if (whereValue) {
return {
where: {
type: whereType,
value: whereValue
}
value: whereValue,
},
}
}

return {}
}


type OperationName = `${GraphEntity}Count`
export function genericCountQuery(entity: GraphEntity, whereValue?: any) {
const name = entity + 'Count' as OperationName
Expand All @@ -120,8 +155,8 @@ export function genericCountQuery(entity: GraphEntity, whereValue?: any) {
fields: ['totalCount'],
variables: {
orderBy: { value: 'id_ASC', type: `[${types}OrderByInput!]!` },
...where
...where,
},
whereType: `${types}WhereInput`
whereType: `${types}WhereInput`,
}
}
16 changes: 10 additions & 6 deletions src/clients/filters.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {
FilterBuilder, FilterMappingFn, FilterOrderDirection, FilterOrderType, FilterType
FilterBuilder,
FilterMappingFn,
FilterOrderDirection,
FilterOrderType,
FilterType,
} from '../types'

export function getFilters(filters: FilterBuilder[]) {
Expand All @@ -9,11 +13,11 @@ export function getFilters(filters: FilterBuilder[]) {

function generateFilters(
filters: FilterBuilder[],
mappingFn: FilterMappingFn
mappingFn: FilterMappingFn,
): string[] {
return filters
.flatMap(([type, directions]) =>
getFilterOrders(directions).map(direction => mappingFn(type, direction))
getFilterOrders(directions).map((direction) => mappingFn(type, direction))
)
}

Expand All @@ -28,20 +32,20 @@ function generateFilters(

function subsquidFilterMapping(
filter: FilterType,
direction: FilterOrderDirection
direction: FilterOrderDirection,
): string {
return appendFilterDirection(filter, direction)
}

function appendFilterDirection(
filter: string,
direction: FilterOrderDirection
direction: FilterOrderDirection,
) {
return filter + '_' + direction
}

function getFilterOrders(
filterOrders: FilterOrderType
filterOrders: FilterOrderType,
): FilterOrderDirection[] {
if (!filterOrders) {
return ['ASC', 'DESC']
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export { fetchQuery, graphFetch } from './indexers'
export * from './rest'

// eslint-disable-next-line unicorn/prefer-export-from
export { SquidClient, getClient, getUrl }
export { getClient, getUrl, SquidClient }
18 changes: 13 additions & 5 deletions src/indexers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,30 @@ function getUrl(chain: Prefix, provider: Or<Provider, ''> = ''): string {

if (!result || provider === 'subquery') {
const message = chain
? `Indexer for chain ${chain} not found, allowed values are ${Object.keys(
INDEXERS
)}`
? `Indexer for chain ${chain} not found, allowed values are ${
Object.keys(
INDEXERS,
)
}`
: `Cannot use fetch for non-existinng chain, add parameter prefix when calling getClient or fetchQuery`
throw new ReferenceError(message)
}

return result
}

export function graphFetch<D>(baseURL: string, query: GraphQuery): Promise<GraphLike<D>> {
export function graphFetch<D>(
baseURL: string,
query: GraphQuery,
): Promise<GraphLike<D>> {
const opts = getOptions({ query, baseURL, path: '' })
return $fetch<GraphLike<D>>(baseURL, opts)
}

export function fetchQuery<D>(prefix: Prefix, query: GraphQuery): Promise<GraphLike<D>> {
export function fetchQuery<D>(
prefix: Prefix,
query: GraphQuery,
): Promise<GraphLike<D>> {
const baseURL = getUrl(prefix)
return graphFetch<D>(baseURL, query)
}
Expand Down
4 changes: 2 additions & 2 deletions src/indexers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { GraphLike, GraphRequest } from '../rest/types'

export const getOptions = ({
baseURL,
query
query,
}: GraphRequest): FetchOptions<'json'> => ({
baseURL,
method: 'POST',
body: query
body: query,
})

export const uwrapRequest = <T>(req: GraphLike<T>): T => {
Expand Down
10 changes: 7 additions & 3 deletions src/queryBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { query } from 'gql-query-builder'
import { KeyValue, FieldList, GraphQuery } from './types'
import { FieldList, GraphQuery, KeyValue } from './types'

function build(operation: string, fields: FieldList, variables?: KeyValue): GraphQuery {
function build(
operation: string,
fields: FieldList,
variables?: KeyValue,
): GraphQuery {
return query({
operation,
variables,
fields
fields,
})
}

Expand Down
5 changes: 4 additions & 1 deletion src/rest/ask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { GraphLike } from './types'

const GRAPHQL_PATH = '/graphql'

function askFor<T>(path: string, options?: QueryProps<T>): Promise<GraphLike<T>> {
function askFor<T>(
path: string,
options?: QueryProps<T>,
): Promise<GraphLike<T>> {
const request = pathToRequest(path, options)
const opts = getOptions(request)
return $fetch<GraphLike<T>>(GRAPHQL_PATH, opts)
Expand Down
3 changes: 2 additions & 1 deletion src/rest/indexers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import { Prefix } from './types'

export const getUrl = (chain: Prefix | ''): string => INDEXERS[chain]

export const getAvailableChains = (): Prefix[] => Object.keys(INDEXERS) as Prefix[]
export const getAvailableChains = (): Prefix[] =>
Object.keys(INDEXERS) as Prefix[]
13 changes: 10 additions & 3 deletions src/rest/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const pathMap: Record<string, ClientCall> = {
itemByOwner: 'itemListByOwner',
itemCollectedBy: 'itemListCollectedBy',
itemForSaleByCollection: 'itemListForSaleByCollectionId',
itemSoldBy: 'itemListSoldBy'
itemSoldBy: 'itemListSoldBy',
}

export const parsePath = (pathname: string): string[] => {
Expand All @@ -37,7 +37,11 @@ const supportChain = (chain: string | undefined): boolean => {
}

const urlOf = (path: string): $URL => new $URL(path)
const makeQuery = (call: string, id: string, options?: QueryProps<any>): GraphQuery => {
const makeQuery = (
call: string,
id: string,
options?: QueryProps<any>,
): GraphQuery => {
const client = getClient()
const method = getCall(call)
const fn: any | undefined = client[method]
Expand All @@ -50,7 +54,10 @@ const makeQuery = (call: string, id: string, options?: QueryProps<any>): GraphQu

// /bsx/item/:id
// TODO: should return GraphRequest
export function pathToRequest(path: string, options?: QueryProps<any>): GraphRequest {
export function pathToRequest(
path: string,
options?: QueryProps<any>,
): GraphRequest {
const { pathname } = urlOf(path) // query: options
const [chain, call, id] = parsePath(pathname)
if (!hasCall(call) || !supportChain(chain)) {
Expand Down
2 changes: 1 addition & 1 deletion src/rest/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GraphQuery, Or } from '../types'
export { GraphLike } from '../types'

export type GraphRequest = {
baseURL: string,
baseURL: string
query: GraphQuery
path: string
}
Expand Down
Loading