Skip to content
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
70 changes: 70 additions & 0 deletions __tests__/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,18 @@ describe('archive queries', () => {
}
`;

const featuredArchivesQuery = `
query FeaturedArchives($subjectType: String!, $subjectId: String!) {
featuredArchives(subjectType: $subjectType, subjectId: $subjectId) {
id
scopeType
scopeId
periodType
periodStart
}
}
`;

beforeEach(async () => {
await materializePeriodArchives({
con,
Expand Down Expand Up @@ -704,6 +716,52 @@ describe('archive queries', () => {
]);
});

it('should return all relevant archives for a featured post', async () => {
const res = await client.query(featuredArchivesQuery, {
variables: {
subjectType: ArchiveSubjectType.Post,
subjectId: 'post-6',
},
});

expect(res.errors).toBeFalsy();
expect(res.data.featuredArchives).toEqual([
{
id: expect.any(String),
scopeType: ArchiveScopeType.Global,
scopeId: null,
periodType: ArchivePeriodType.Month,
periodStart: marchPeriodStart.toISOString(),
},
{
id: expect.any(String),
scopeType: ArchiveScopeType.Source,
scopeId: 'source-a',
periodType: ArchivePeriodType.Month,
periodStart: marchPeriodStart.toISOString(),
},
{
id: expect.any(String),
scopeType: ArchiveScopeType.Tag,
scopeId: 'webdev',
periodType: ArchivePeriodType.Month,
periodStart: marchPeriodStart.toISOString(),
},
]);
});

it('should return an empty list when no archives exist for the requested subject type', async () => {
const res = await client.query(featuredArchivesQuery, {
variables: {
subjectType: ArchiveSubjectType.User,
subjectId: 'author-good',
},
});

expect(res.errors).toBeFalsy();
expect(res.data.featuredArchives).toEqual([]);
});

it('should validate that tag archives require a scopeId', async () =>
testQueryErrorCode(
client,
Expand Down Expand Up @@ -739,4 +797,16 @@ describe('archive queries', () => {
'GRAPHQL_VALIDATION_FAILED',
'month must not be set for yearly archives',
));

it('should accept other archive subject types even when no results exist', async () => {
const res = await client.query(featuredArchivesQuery, {
variables: {
subjectType: ArchiveSubjectType.Squad,
subjectId: 'source-a',
},
});

expect(res.errors).toBeFalsy();
expect(res.data.featuredArchives).toEqual([]);
});
});
5 changes: 5 additions & 0 deletions src/common/schema/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,8 @@ export const archiveIndexQuerySchema = z
});
}
});

export const featuredArchivesQuerySchema = z.object({
subjectType: archiveSubjectTypeSchema,
subjectId: z.string().min(1),
});
46 changes: 46 additions & 0 deletions src/schema/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { ArchivePeriodType, getArchivePeriodStart } from '../common/archive';
import {
archiveIndexQuerySchema,
archiveQuerySchema,
featuredArchivesQuerySchema,
} from '../common/schema/archive';
import { ArchiveItem } from '../entity/ArchiveItem';
import graphorm from '../graphorm';

type GQLArchive = {
Expand All @@ -21,6 +23,7 @@ type GQLArchive = {

type ArchiveQueryArgs = z.infer<typeof archiveQuerySchema>;
type ArchiveIndexQueryArgs = z.infer<typeof archiveIndexQuerySchema>;
type FeaturedArchivesQueryArgs = z.infer<typeof featuredArchivesQuerySchema>;

export const typeDefs = /* GraphQL */ `
type ArchiveItem {
Expand Down Expand Up @@ -60,6 +63,9 @@ export const typeDefs = /* GraphQL */ `
periodType: String
year: Int
): [Archive!]! @cacheControl(maxAge: 3600)

featuredArchives(subjectType: String!, subjectId: String!): [Archive!]!
@cacheControl(maxAge: 3600)
}
`;

Expand Down Expand Up @@ -193,5 +199,45 @@ export const resolvers: IResolvers<unknown, BaseContext> = {
true,
);
},
featuredArchives: async (
_,
args: FeaturedArchivesQueryArgs,
ctx: Context,
info,
): Promise<GQLArchive[]> => {
const validatedArgsResult = featuredArchivesQuerySchema.safeParse(args);

if (!validatedArgsResult.success) {
throw new ValidationError(validatedArgsResult.error.issues[0].message);
}

const validatedArgs = validatedArgsResult.data;

return graphorm.query<GQLArchive>(
ctx,
info,
(builder) => {
builder.queryBuilder = builder.queryBuilder
.innerJoin(
ArchiveItem,
'archiveItem',
`"archiveItem"."archiveId" = ${builder.alias}.id`,
)
.andWhere(`${builder.alias}."subjectType" = :subjectType`, {
subjectType: validatedArgs.subjectType,
})
.andWhere('"archiveItem"."subjectId" = :subjectId', {
subjectId: validatedArgs.subjectId,
})
.distinct(true)
.orderBy(`${builder.alias}."periodStart"`, 'DESC')
.addOrderBy(`${builder.alias}."scopeType"`, 'ASC')
.addOrderBy(`${builder.alias}."scopeId"`, 'ASC');

return builder;
},
true,
);
},
},
};
Loading