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

Allow for required arguments on paginated fragments #1253

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
6 changes: 6 additions & 0 deletions .changeset/neat-cameras-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'houdini-svelte': patch
'houdini': patch
---

Add support for required arguments in paginated fragments
9 changes: 6 additions & 3 deletions e2e/_api/graphql.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ export const resolvers = {
usersConnection: (user, args) => {
return connectionFromArray(getUserSnapshot(user.snapshot), args)
},
usersConnectionSnapshot: (user, args) => {
return connectionFromArray(getUserSnapshot(args.snapshot), args)
},
userSearch: (_, args) => {
const allUsers = [...getUserSnapshot(args.snapshot)]

Expand All @@ -270,11 +273,11 @@ export const resolvers = {
enumValue: () => 'Value1',
testField: (user, args) => {
if (args.someParam) {
return "Hello world";
return 'Hello world'
}

return null;
}
return null
},
},

Mutation: {
Expand Down
1 change: 1 addition & 0 deletions e2e/_api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ type User implements Node {
friendsConnection(after: String, before: String, first: Int, last: Int): UserConnection!
"This is the same list as what's used globally. its here to tests fragments"
usersConnection(after: String, before: String, first: Int, last: Int): UserConnection!
usersConnectionSnapshot(after: String, before: String, first: Int, last: Int, snapshot: String!): UserConnection!
"This is the same list as what's used globally. its here to tests fragments"
userSearch(filter: UserNameFilter!, snapshot: String!): [User!]!
friendsList(limit: Int, offset: Int): [User!]!
Expand Down
1 change: 1 addition & 0 deletions e2e/kit/src/lib/utils/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const routes = {
Pagination_fragment_backwards_cursor: '/pagination/fragment/backwards-cursor',
Pagination_fragment_bidirectional_cursor: '/pagination/fragment/bidirectional-cursor',
Pagination_fragment_offset: '/pagination/fragment/offset',
Pagination_fragment_required_arguments: '/pagination/fragment/required-arguments',

nested_argument_fragments: '/nested-argument-fragments',
nested_argument_fragments_masking: '/nested-argument-fragments-masking',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
import { graphql, paginatedFragment } from '$houdini';

$: queryResult = graphql(`
query UserFragmentRequiredArgsQuery(
$snapshot: String! = "pagination-fragment-required-arguments"
) @load {
user(id: "1", snapshot: $snapshot) {
id
name

...TestFragment @with(snapshot: $snapshot)
}
}
`);

$: fragmentResult = paginatedFragment(
$queryResult.data?.user ?? null,
graphql(`
fragment TestFragment on User @arguments(snapshot: { type: "String!" }) {
usersConnectionSnapshot(first: 2, snapshot: $snapshot) @paginate {
edges {
node {
id
name
}
}
}
}
`)
);
</script>

<div id="result">
{$fragmentResult.data?.usersConnectionSnapshot.edges.map(({ node }) => node?.name).join(', ')}
</div>

<div id="pageInfo">
{JSON.stringify($fragmentResult.pageInfo)}
</div>

<button id="next" on:click={() => fragmentResult.loadNextPage()}>next</button>
48 changes: 48 additions & 0 deletions e2e/kit/src/routes/pagination/fragment/required-arguments/spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { test } from '@playwright/test';
import { routes } from '../../../../lib/utils/routes.js';
import {
expectToContain,
expect_0_gql,
expect_1_gql,
expect_to_be,
goto
} from '../../../../lib/utils/testsHelper.js';

test.describe('forwards cursor paginatedFragment with required arguments', () => {
test('loadNextPage', async ({ page }) => {
await goto(page, routes.Pagination_fragment_required_arguments);
await expect_to_be(page, 'Bruce Willis, Samuel Jackson');

// wait for the api response
await expect_1_gql(page, 'button[id=next]');

// make sure we got the new content
await expect_to_be(page, 'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks');
});

test('page info tracks connection state', async ({ page }) => {
await goto(page, routes.Pagination_fragment_required_arguments);

const data = [
'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks',
'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford',
'Bruce Willis, Samuel Jackson, Morgan Freeman, Tom Hanks, Will Smith, Harrison Ford, Eddie Murphy, Clint Eastwood'
];

// load the next 3 pages
for (let i = 0; i < 3; i++) {
// wait for the request to resolve
await expect_1_gql(page, 'button[id=next]');

// check the page info
await expect_to_be(page, data[i]);
}

// make sure we have all of the data loaded
await expect_to_be(page, data[2]);

await expectToContain(page, `"hasNextPage":false`);

await expect_0_gql(page, 'button[id=next]');
});
});
3 changes: 2 additions & 1 deletion packages/houdini-svelte/src/plugin/artifactData.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ describe('load', () => {
"id": "ID"
},

"types": {}
"types": {},
"defaults": {}
},

"policy": "CacheOrNetwork",
Expand Down
11 changes: 9 additions & 2 deletions packages/houdini-svelte/src/runtime/stores/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,20 @@ This will result in duplicate queries. If you are trying to ensure there is alwa
// we might not want to actually wait for the fetch to resolve
const fakeAwait = clientStarted && isBrowser && !need_to_block

// spreading the default variables frist so that if the user provides one of these params themselves,
// those params get overwritten with the correct value
const usedVariables = {
...this.artifact.input?.defaults,
...params.variables,
}

// we want to try to load cached data before we potentially fake the await
// this makes sure that the UI feels snappy as we click between cached pages
// (no loaders)
if (policy !== CachePolicy.NetworkOnly && fakeAwait) {
await this.observer.send({
fetch: context.fetch,
variables: params.variables,
variables: usedVariables,
metadata: params.metadata,
session: context.session,
policy: CachePolicy.CacheOnly,
Expand All @@ -181,7 +188,7 @@ This will result in duplicate queries. If you are trying to ensure there is alwa
// since CacheOrNetwork behaves the same as CacheAndNetwork
const request = this.observer.send({
fetch: context.fetch,
variables: params.variables,
variables: usedVariables,
metadata: params.metadata,
session: context.session,
policy: policy,
Expand Down
12 changes: 9 additions & 3 deletions packages/houdini/src/codegen/generators/artifacts/inputs.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import * as graphql from 'graphql'
import * as recast from 'recast'

import { unwrapType } from '../../../lib'
import type { Config } from '../../../lib/config'
import { variableValue } from '../../../runtime/cache/cache'
import type { InputObject } from '../../../runtime/lib/types'

const AST = recast.types.builders

export function inputObject(
config: Config,
inputs: readonly graphql.VariableDefinitionNode[]
Expand All @@ -27,6 +25,14 @@ export function inputObject(
}
}, {}),
types: {},
defaults: inputs.reduce((fields, input) => {
return {
...fields,
[input.variable.name.value]: input.defaultValue
? variableValue(input.defaultValue, {})
: undefined,
}
}, {}),
}

// walk through every type referenced and add it to the list
Expand Down
Loading
Loading