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

Implement Optimistic Effects #1415

Merged
merged 7 commits into from
Sep 4, 2023
Merged

Conversation

charlesBochet
Copy link
Member

@charlesBochet charlesBochet commented Sep 1, 2023

I'm introducing a new pattern called optimistic effects.

Optimistic Effect is a way to declare that query result cache should be updated when some mutations are performed and native apollo cache is failing to update them.

Problem

The typical use case is the following:

Let's imagine a query: GetPeopleQuery({ where: { name { like { '%toto%'} }})

Apollo does not know whenever it needs to add or remove rows from the query cache whenever

  • a person is renamed to 'toto' for example (this person should be added to the query cache
  • a person is renamed from 'toto' to something else
  • a person is created with the name 'toto'
  • (apollo does handle the person deletion using cache.evict())

Proposed Solution

When performing a query, you can registerOptimisticEffect() in the query and attach it to a typename. This optimistic effect can precisely describe what to do when an entity is added or modified (kind of mimicking the backend behavior). Usually, you want to read the existing query cache, and update it.

Ex: OptimisticEffect Declaration:

function optimisticEffectResolver({
  cache,
  entities,
  variables,
}: {
  cache: ApolloCache<Company>;
  entities: Company[];
  variables: GetCompaniesQueryVariables;
}) {
  const existingData = cache.readQuery<GetCompaniesQuery>({
    query: GET_COMPANIES,
    variables: { orderBy: variables.orderBy, where: variables.where },
  });

  if (!existingData) {
    return;
  }

  cache.writeQuery({
    query: GET_COMPANIES,
    variables: { orderBy: variables.orderBy, where: variables.where },
    data: {
      people: [...entities, ...existingData.companies],
    },
  });
}

export function getCompaniesOptimisticEffect(
  variables: GetCompaniesQueryVariables,
) {
  return {
    key: 'generic-entity-table-data-companies',
    variables: variables,
    typename: 'Company',
    resolver: optimisticEffectResolver,
  };
}

Register:

useGetRequest({
    variables: { orderBy, where: whereFilters },
    onCompleted: (data: any) => {
      const entities = data[getRequestResultKey] ?? [];
      setEntityTableData(entities, filterDefinitionArray);
      registerOptimisticEffect(
        getCompaniesOptimisticEffect({ orderBy, where: whereFilters }),
      );
    },
  });

Once registered, an optimistic effect is kept in memory.

Then, while performing a mutation, you can call triggerOptimisticEffects(typename) and all registered effect tied to this typename will be triggered

Example:
triggerOptimisticEffects('Company', [data?.createOneCompany]);

@ergomake
Copy link

ergomake bot commented Sep 1, 2023

Hi 👋

Here's a preview environment 🚀

https://front-twentyhq-twenty-1415.env.ergomake.link

Environment Summary 📑

Container Source URL
front Dockerfile https://front-twentyhq-twenty-1415.env.ergomake.link
server Dockerfile https://server-twentyhq-twenty-1415.env.ergomake.link
postgres Dockerfile [not exposed - internal service]

Here are your environment's logs.

For questions or comments, join Discord.

Click here to disable Ergomake.

@charlesBochet charlesBochet merged commit a46210b into main Sep 4, 2023
@charlesBochet charlesBochet deleted the 1339-timebox-optimistic-rendering branch September 4, 2023 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants