Skip to content

Commit

Permalink
feat: add dynamic operations with fields starting with with
Browse files Browse the repository at this point in the history
  • Loading branch information
adrian-ub committed Sep 21, 2024
1 parent 8240f06 commit f24ff49
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 47 deletions.
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,10 @@ const series = defineCollection({
{
description: ['html', 'markdown'],
},
{
operation: 'posts',
variables: {
first: {
name: 'first',
required: true,
value: 20,
type: 'Int',
},
},
fields: [{
edges: [{
node: ['slug', 'title', 'publishedAt', { coverImage: ['url'] }],
}],
}],
},
],
withPosts: {
fields: ['slug', 'title', 'publishedAt', { coverImage: ['url'] }],
},
}),
schema: z.object({
slug: z.string(),
Expand Down
19 changes: 3 additions & 16 deletions examples/hashnode/src/content/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,10 @@ const series = defineCollection({
{
description: ['html', 'markdown'],
},
{
operation: 'posts',
variables: {
first: {
name: 'first',
required: true,
value: 20,
type: 'Int',
},
},
fields: [{
edges: [{
node: ['slug', 'title', 'publishedAt', { coverImage: ['url'] }],
}],
}],
},
],
withPosts: {
fields: ['slug', 'title', 'publishedAt', { coverImage: ['url'] }],
},
}),
schema: z.object({
slug: z.string(),
Expand Down
70 changes: 55 additions & 15 deletions src/hashnode/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,39 @@ import * as gql from 'gql-query-builder'
import { GraphQLClient } from 'graphql-request'
import type { Loader } from 'astro/loaders'

import type IQueryBuilderOptions from 'gql-query-builder/build/IQueryBuilderOptions'
import { flattenEdges } from '../utils/flatten-edges'

export interface HashnodeLoaderOptions {
type QueryBuilderOptionsWithOperation = Omit<IQueryBuilderOptions, 'operation'>
export type HashnodeLoaderOptions = QueryBuilderOptionsWithOperation & {
operation: 'seriesList' | 'posts' | 'staticPages'
endpoint?: string
publicationHost: string
fields: Array<string | object>
variables?: Array<object>
[key: `with${string}`]: QueryBuilderOptionsWithOperation
}
type HashnodeLoaderOptionsWithOperation = HashnodeLoaderOptions & { operation: string }

function getFieldsWithOperation(fields: HashnodeLoaderOptions): IQueryBuilderOptions[] {
const result = []

for (const key in fields) {
if (key.startsWith('with')) {
result.push({
operation: key.slice(4).toLowerCase(),
variables: fields[key as `with${string}`].variables,
fields: fields[key as `with${string}`].fields,
})
}
}

return result
}

async function fetchAllData(
client: GraphQLClient,
{ fields, variables, operation }: Pick<HashnodeLoaderOptions, 'variables' | 'fields' | 'operation'>,
options: HashnodeLoaderOptionsWithOperation,
): Promise<any[]> {
const { fields, variables = [], operation, publicationHost } = options
const publication = 'publication'

let data: object[] = []
Expand All @@ -24,8 +43,7 @@ async function fetchAllData(

// Loop through all pages of data
while (hasNextPage) {
// build the query
const query = gql.query({
const queryOptions = {
operation: publication,
fields: [{
operation,
Expand All @@ -48,17 +66,43 @@ async function fetchAllData(
}, {
edges: [
{
node: ['id', ...fields],
node: [
'id',
...fields ?? [],
...getFieldsWithOperation(options).map(({ operation, fields, variables }) => {
return {
operation,
variables: {
first: {
name: 'first',
required: true,
value: 20,
type: 'Int',
},
...variables,
},
fields: [{
edges: [{
node: [...(fields ?? [])],
}],
}],
}
}),
],
},
],
}],
}],
variables: {
...variables,
host: publicationHost,
// if endCursor exists, add it to the variables otherwise, don't
...(endCursor && { after: endCursor }),
},
})
}

// build the query
const query = gql.query(queryOptions)

// make the request with query and variables
const res = await client.request<{
Expand All @@ -84,7 +128,8 @@ async function fetchAllData(
return data
}

export function HashnodeLoader({ endpoint = 'https://gql.hashnode.com', fields, variables = [], publicationHost, operation }: HashnodeLoaderOptions): Loader {
export function HashnodeLoader(options: HashnodeLoaderOptions): Loader {
const { endpoint = 'https://gql.hashnode.com', fields, operation } = options
if (!endpoint) {
throw new Error('Hashnode requires an endpoint')
}
Expand All @@ -95,18 +140,13 @@ export function HashnodeLoader({ endpoint = 'https://gql.hashnode.com', fields,

const client = new GraphQLClient(endpoint)

const connectionVariables = {
...variables,
host: publicationHost,
}

return {
name: 'astro-loader-hashnode',
load: async ({ logger, store, parseData }) => {
logger.info(`Loading ${operation} data from Hashnode`)
store.clear()

const data = await fetchAllData(client, { fields, variables: connectionVariables, operation })
const data = await fetchAllData(client, options)

for (const item of data) {
const parsedData = await parseData({ id: item, data: item })
Expand Down

0 comments on commit f24ff49

Please sign in to comment.