[๐Ÿš€Apollo] Cache - Customizing the behavior of cached fields

Jake_Youngยท2021๋…„ 9์›” 17์ผ
0
post-thumbnail

์ด ๋ฌธ์„œ๋Š” ์•„ํด๋กœ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • InMemoryCache์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ, read function๊ณผ merge function์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•  ์ˆ˜ ์žˆ๋‹ค.
const cache = new InMemoryCache({
  typePolicies: {
    Person: {
      fields: {
        name: {
          read(name) {
            // Return the cached name, transformed to upper case
            return name.toUpperCase();
          }
        }
      },
    },
  },
});

read function

  • ์‹ค์ œ ์ €์žฅ๋œ ์ •๋ณด๊ฐ€ ์•„๋‹ˆ๋ผ read function์„ ์ด์šฉํ•˜์—ฌ ๋ณ€ํ™˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.
// name ํ•„๋“œ์˜ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ "UNKNOWN NAME"์„ ์ฃผ๋Š” ํ•จ์ˆ˜
const cache = new InMemoryCache({
  typePolicies: {
    Person: {
      fields: {
        name: {
          read(name = "UNKNOWN NAME") {
            return name;
          }
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Person: {
      fields: {
        // If a field's TypePolicy would only include a read function,
        // you can optionally define the function like so, instead of
        // nesting it inside an object as shown in the example above.
        name(name: string, { args }) {
          if (args && typeof args.maxLength === "number") {
            return name.substring(0, args.maxLength);
          }
          return name;
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Person: {
      fields: {
        userId() {
          return localStorage.getItem("loggedInUserId");
        },
      },
    },
  },
});

merge function

const cache = new InMemoryCache({
  typePolicies: {
    Agenda: {
      fields: {
        tasks: {
          merge(existing = [], incoming: any[]) {
            return [...existing, ...incoming];
          },
        },
      },
    },
  },
});
Copy
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        author: {
          merge(existing, incoming) {
            // Better, but not quite correct.
            return { ...existing, ...incoming };
          },
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        author: {
          merge(existing, incoming) {
            // Equivalent to what happens if there is no custom merge function.
            return incoming;
          },
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        author: {
          // Short for always preferring incoming over existing data.
          merge: false,
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        author: {
          merge(existing, incoming, { mergeObjects }) {
            // Correct, thanks to invoking nested merge functions.
            return mergeObjects(existing, incoming);
          },
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        author: {
          // Short for options.mergeObjects(existing, incoming).
          merge: true,
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        // No longer necessary!
        // author: {
        //   merge: true,
        // },
      },
    },

    Author: {
      merge: true,
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        authors: {
          merge(existing: any[], incoming: any[], { readField, mergeObjects }) {
            const merged: any[] = existing ? existing.slice(0) : [];
            const authorNameToIndex: Record<string, number> = Object.create(null);
            if (existing) {
              existing.forEach((author, index) => {
                authorNameToIndex[readField<string>("name", author)] = index;
              });
            }
            incoming.forEach(author => {
              const name = readField<string>("name", author);
              const index = authorNameToIndex[name];
              if (typeof index === "number") {
                // Merge the new author data with the existing author data.
                merged[index] = mergeObjects(merged[index], author);
              } else {
                // First time we've seen this author in this array.
                authorNameToIndex[name] = merged.length;
                merged.push(author);
              }
            });
            return merged;
          },
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Book: {
      fields: {
        authors: {
          merge: mergeArrayByField<AuthorType>("name"),
        },
      },
    },
  },
});
const cache = new InMemoryCache({
  typePolicies: {
    Agenda: {
      fields: {
        tasks: {
          merge(existing: any[], incoming: any[], { args }) {
            const merged = existing ? existing.slice(0) : [];
            // Insert the incoming elements in the right places, according to args.
            const end = args.offset + Math.min(args.limit, incoming.length);
            for (let i = args.offset; i < end; ++i) {
              merged[i] = incoming[i - args.offset];
            }
            return merged;
          },

          read(existing: any[], { args }) {
            // If we read the field before any data has been written to the
            // cache, this function will return undefined, which correctly
            // indicates that the field is missing.
            const page = existing && existing.slice(
              args.offset,
              args.offset + args.limit,
            );
            // If we ask for a page outside the bounds of the existing array,
            // page.length will be 0, and we should return undefined instead of
            // the empty array.
            if (page && page.length > 0) {
              return page;
            }
          },
        },
      },
    },
  },
});
profile
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ํŒŒ์ด์ฌ ๊ทธ๋ฆฌ๊ณ  ์ปดํ“จํ„ฐ์™€ ๋„คํŠธ์›Œํฌ

0๊ฐœ์˜ ๋Œ“๊ธ€