@sprocketbot/gql-stores
This package wraps @urql/core as an alternative to @urql/svelte.
Instead of the context based approach taken by urql; this package uses a store approach to make operations easier to abstract outside of your components.
Examples
Simple Query
People.store.ts
import {Client} from "@urql/core";
export const client = new Client({url: "https://graphqlzero.almansi.me/api"});
type PeopleQueryValue = {
users: {
data: {
id: string;
name: string;
}[];
};
};
const query = gql<PeopleQueryValue>`
query {
users {
data {
name
id
}
}
}
`;
export const PeopleQuery = new QueryStore(client, query, {});
+page.svelte
<script lang="ts">
import {PeopleQuery} from "./People.store";
</script>
<ul>
{#if $PeopleQuery.fetching}
<li>Loading...</li>
{:else if $PeopleQuery.success}
{#each $PeopleQuery.data.users.data as person}
<li>{person.name}</li>
{/each}
{/if}
</ul>
{#if $PeopleQuery.errors}
{#if $PeopleQuery.errors.message}
{$PeopleQuery.errors.message}
{/if}
{#if $PeopleQuery.errors.graphQLErrors}
{#each $PeopleQuery.errors.graphQLErrors as err}
<p>{err.message}</p>
{/each}
{/if}
{/if}
Paginated Query
Posts.store.ts
import {Client} from "@urql/core";
export const client = new Client({url: "https://graphqlzero.almansi.me/api"});
export type PostsValue = {
posts: {
links: {
prev?: {page: number};
next?: {page: number};
};
data: {
id: number;
user: {id: number; name: string};
title: string;
body: string;
}[];
};
};
export type PostsVariables = {
page: number;
};
const query = gql<PostsValue, PostsVariables>`
query ($page: Int!) {
posts(options: {paginate: {limit: 5, page: $page}}) {
links {
prev {
page
}
next {
page
}
}
data {
user {
id
name
}
title
body
id
}
}
}
`;
export const Posts = new QueryStore(client, query, {page: 1});
+page.svelte
<script lang="ts">
import {Posts} from "./Posts.store";
function prevPage() {
const data = $Posts.data
if (!data || !data.posts.links.prev) return;
Posts.variables = { page: data.posts.links.prev.page}
}
function nextPage() {
const data = $Posts.data
if (!data || !data.posts.links.next) return;
Posts.variables = { page: data.posts.links.next.page}
}
</script>
{#if $Posts.fetching && !$Posts.data}
Loading...
{:else if $Posts.data}
<div>
<button
disabled={!$Posts.data.posts.links.prev || $Posts.fetching}
on:click={prevPage}
>
{`< ${$Posts.data.posts.links.prev?.page ?? " "} -`}
</button>
<span>{$Posts.variables.page}</span>
<button
disabled={!$Posts.data.posts.links.next || $Posts.fetching}
on:click={nextPage}
>
{`- ${$Posts.data.posts.links.next?.page ?? " "} >`}
</button>
</div>
{#each $Posts.data.posts.data as post}
<div>
<h2>{post.title}</h2>
<h4>{post.user.name}</h4>
<p>{post.body}</p>
</div>
{/each}
{/if}
Mutation
CreateUser.mutation.ts
import {Mutation} from "$lib/Mutation";
import {gql} from "@urql/core";
import {client} from "../client";
export type CreatePersonValue = {
createUser: {
name: string;
email: string;
id: number;
};
};
export type CreatePersonVariables = {
input: {
name: string;
username: string;
email: string;
};
};
const mutation = gql<CreatePersonValue, CreatePersonVariables>`
mutation ($input: CreateUserInput!) {
createUser(input: $input) {
name
email
id
}
}
`;
export const CreatePerson = Mutation(client, mutation);
let createUserInput: CreatePersonVariables["input"] = {
name: "Dave",
username: "dave4",
email: "dave@dave.com"
};
const createPerson = await CreatePerson({ input: createUserInput })