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

Provide parentType to addMany subscriptions #678

Closed
wants to merge 5 commits into from
Closed
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
5 changes: 5 additions & 0 deletions .changeset/rotten-timers-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'houdini': patch
---

Provide parentType to addMany subscriptions
107 changes: 106 additions & 1 deletion e2e/_api/graphql.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,41 @@ export const typeDefs = sourceFiles.map((filepath) =>
fs.readFileSync(path.resolve(filepath), 'utf-8')
)

// Example Cities/Libraries/Books data
// Assume a traditional relational database for storage - each table with unique ID.
let cityId = 1;
let libraryId = 1;
let bookId = 1;

// Allow the "database" to be persistent and mutable
let cities = [
{
id: cityId++, name: 'Alexandria', libraries: [
{
id: libraryId++, name: 'The Library of Alexandria', books: [
{ id: bookId++, title: 'Callimachus Pinakes' },
{ id: bookId++, title: 'Kutubkhana-i-lskandriyya' },
]
},
{
id: libraryId++, name: 'Bibliotheca Alexandrina', books: [
{ id: bookId++, title: 'Analyze your own personality' },
]
},
]
},
{
id: cityId++, name: 'Istanbul', libraries: [
{
id: libraryId++, name: 'The Imperial Library of Constantinople', books: [
{ id: bookId++, title: 'Homer' },
{ id: bookId++, title: 'The Hellenistic History' },
]
},
]
},
];

// example data
const data = [
{ id: '1', name: 'Bruce Willis', birthDate: new Date(1955, 2, 19) },
Expand Down Expand Up @@ -100,6 +135,9 @@ export const resolvers = {
__typename: 'User',
}
},
cities: () => {
return cities;
},
},

User: {
Expand Down Expand Up @@ -149,7 +187,7 @@ export const resolvers = {
try {
let data = await processFile(file)
return data
} catch (e) {}
} catch (e) { }
throw new GraphQLYogaError('ERROR', { code: 500 })
},
multipleUpload: async (_, { files }) => {
Expand All @@ -164,6 +202,73 @@ export const resolvers = {
}
return res
},
addCity: (_, args) => {
const city = {
id: cityId++,
name: args.name,
libraries: [],
}

cities.push(city);
return city;
},
addLibrary: (_, args) => {
const cityId = Number.parseInt(args.city);
const city = cities.find((city) => city.id === cityId);
if (!city) {
throw new GraphQLYogaError('City not found', { code: 404 })
}

const library = {
id: libraryId++,
name: args.name,
books: [],
}
city.libraries.push(library);
return library;
},
addBook: (_, args) => {
const libraryId = Number.parseInt(args.library);
const city = cities.find((city) => city.libraries.find((library) => library.id === libraryId));
if (!city) {
throw new GraphQLYogaError('City/Library not found', { code: 404 })
}
const library = city.libraries.find((library) => library.id === libraryId);

const book = {
id: bookId++,
title: args.title,
}
library.books.push(book);
return book;
},
deleteCity: (_, args) => {
const cityId = Number.parseInt(args.city);
const city = cities.find((city) => city.id === cityId);
cities = cities.filter((city) => city.id !== cityId);
return city;
},
deleteLibrary: (_, args) => {
const libraryId = Number.parseInt(args.library);
const city = cities.find((city) => city.libraries.find((library) => library.id === libraryId));
if (!city) {
throw new GraphQLYogaError('City/Library not found', { code: 404 })
}
const library = city.libraries.find((library) => library.id === libraryId);
city.libraries = city.libraries.filter((library) => library.id !== libraryId);
return library;
},
deleteBook: (_, args) => {
const bookId = Number.parseInt(args.book);
const city = cities.find((city) => city.libraries.find((library) => library.books.find((book) => book.id === bookId)));
if (!city) {
throw new GraphQLYogaError('City/Library/Book not found', { code: 404 })
}
const library = city.libraries.find((library) => library.books.find((book) => book.id === bookId));
const book = library.books.find((book) => book.id === bookId);
library.books = library.books.filter((book) => book.id !== bookId);
return book;
},
},

DateTime: new GraphQLScalarType({
Expand Down
39 changes: 39 additions & 0 deletions e2e/_api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ type Mutation {
updateUser(id: ID!, name: String, snapshot: String!, birthDate: DateTime, delay: Int): User!
singleUpload(file: File!): String!
multipleUpload(files: [File!]!): [String!]!
addCity(
name: String!
): City!
addLibrary(
city: ID!
name: String!
): Library!
addBook(
library: ID!
title: String!
): Book!
deleteCity(
city: ID!
): City!
deleteLibrary(
library: ID!
): Library!
deleteBook(
book: ID!
): Book!
}

interface Node {
Expand All @@ -52,6 +72,7 @@ type Query {
): UserConnection!
usersList(limit: Int = 4, offset: Int, snapshot: String!): [User!]!
session: String
cities: [City]!
}

type User implements Node {
Expand All @@ -73,3 +94,21 @@ type UserEdge {
cursor: String
node: User
}


type Book {
id: ID!
title: String!
}

type Library {
id: ID!
name: String!
books: [Book]!
}

type City {
id: ID!
name: String!
libraries: [Library]!
}
2 changes: 2 additions & 0 deletions e2e/sveltekit/src/lib/utils/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const routes = {
Pagination_fragment_backwards_cursor: '/pagination/fragment/backwards-cursor',
Pagination_fragment_offset: '/pagination/fragment/offset',

Stores_Nested_List: '/stores/nested-list',

Stores_subunsub_list: '/stores/subunsub-list',
Stores_subunsub_mutation: '/stores/subunsub-mutation',

Expand Down
98 changes: 98 additions & 0 deletions e2e/sveltekit/src/routes/stores/nested-list/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow!! I really appreciate this test. Super thorough!

import { browser } from '$app/environment';
import {
GQL_Cities,
GQL_AddCity,
GQL_AddLibrary,
GQL_AddBook,
GQL_DeleteCity,
GQL_DeleteLibrary,
GQL_DeleteBook
} from '$houdini';

$: browser && GQL_Cities.fetch();

const addCity = (event: Event) => {
const target = event?.target as HTMLInputElement;
GQL_AddCity.mutate({ name: target.value });
target.value = '';
};

const deleteCity = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteCity.mutate({ city: target.dataset.id });
};

const addLibrary = (event: Event) => {
const target = event?.target as HTMLInputElement;
if (!target.dataset.id) {
return;
}

GQL_AddLibrary.mutate({ city: target.dataset.id, name: target.value });
target.value = '';
};

const deleteLibrary = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteLibrary.mutate({ library: target.dataset.id });
};

const addBook = (event: Event) => {
const target = event?.target as HTMLInputElement;
if (!target.dataset.id) {
return;
}

GQL_AddBook.mutate({ library: target.dataset.id, title: target.value });
target.value = '';
};

const deleteBook = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteBook.mutate({ book: target.dataset.id });
};
</script>

<h1>Nested - List</h1>

<ul>
{#each $GQL_Cities.data?.cities ?? [] as city}
<li>
{city?.id}: {city?.name}
<button data-id={city?.id} on:click={deleteCity}>Delete</button>
<ul>
{#each city?.libraries ?? [] as library}
<li>
{library?.id}: {library?.name}
<button data-id={library?.id} on:click={deleteLibrary}>Delete</button>
<ul>
{#each library?.books ?? [] as book}
<li>
{book?.id}: {book?.title}
<button data-id={book?.id} on:click={deleteBook}>Delete</button>
</li>
{/each}
<li><input data-id={library?.id} on:change={addBook} /></li>
</ul>
</li>
{/each}
<li><input data-id={city?.id} on:change={addLibrary} /></li>
</ul>
</li>
{/each}
<li>
<input on:change={addCity} />
</li>
</ul>

<pre>{JSON.stringify($GQL_Cities?.data, null, 4)}</pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddBook($library: ID!, $title: String!) {
addBook(library: $library, title: $title) {
id
...Book_List_insert @append(parentID: $library)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddCity($name: String!) {
addCity(name: $name) {
id
...City_List_insert
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddLibrary($city: ID!, $name: String!) {
addLibrary(city: $city, name: $name) {
id
...Library_List_insert @append(parentID: $city)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteBook($book: ID!) {
deleteBook(book: $book) {
id @Book_delete
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteCity($city: ID!) {
deleteCity(city: $city) {
id @City_delete
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteLibrary($library: ID!) {
deleteLibrary(library: $library) {
id @Library_delete
}
}
14 changes: 14 additions & 0 deletions e2e/sveltekit/src/routes/stores/nested-list/QUERY.Cities.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query Cities {
cities @list(name: "City_List") {
id
name
libraries @list(name: "Library_List") {
id
name
books @list(name: "Book_List") {
id
title
}
}
}
}
2 changes: 2 additions & 0 deletions packages/houdini/src/runtime/cache/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ class CacheInternal {
selection: fields,
subscribers: currentSubscribers,
variables,
parentType: linkedType,
})

toNotify.push(...currentSubscribers)
Expand Down Expand Up @@ -545,6 +546,7 @@ class CacheInternal {
selection: fields,
subscribers: currentSubscribers,
variables,
parentType: linkedType,
})
}
}
Expand Down
Loading