Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Latest commit

 

History

History
261 lines (204 loc) · 8.99 KB

File metadata and controls

261 lines (204 loc) · 8.99 KB
theme layout highlighter lineNumbers info drawings background download
apple-basic
intro
shiki
true
## Slidev Starter Template Dataloadery | Co to je? K čemu to používat? Learn more at [Sli.dev](https://sli.dev)
persist
true
Dmitrij Tkačenko | 8.12.2021

Field Resolvers a
Dataloaders
v Qestu

Co to je? K čemu to používat?


layout: section

Field Resolvers


Motivace

  • dotahujeme relace na základě contextu nadřazeného resolveru
  • relace se starají samy o sebe
  • strom skládáme postupně
  • lazy loading
  • nejen na relace - dobré i třeba na deprecated fields, nebo jednoduché fieldy s nějakou logikou
@ObjectType()
class Recipe {
  @Field()
  title: string;

  @Field({ deprecationReason: "Use `title` instead" })
  get name(): string {
    return this.title;
  }
}

layout: statement

Ukázka z DPD

👉 VSCode


InvoiceResolver...

@Query(() => PaginatedInvoiceResponse)
async invoices(@Args() invoicesArgs: InvoicesArgs, @Ctx() { container }: GraphqlContext): Promise<PaginatedInvoiceResponse> {
    const { items, total } = await container.invoiceService.getAllInvoices(invoicesArgs)

    return {
        items: items.map((i) => mapInvoiceEntityToObjectType(i)),
        total,
    }
}

@Query(() => InvoiceResponse)
async invoice(@Args() { id }: InvoiceArgs, @Ctx() { container }: GraphqlContext): Promise<InvoiceResponse | null> {
    const invoice = await container.invoiceRepository.findOne({ where: { id }, relations: ['rewards', 'pickupPoint'] })

    if (!invoice) {
        throw new BaseApolloError(new InvoiceNotFound(`The invoice with the id of: "${id}" was not found!`, id))
    }

    return mapInvoiceEntityToObjectType(invoice)
}
  • a rozdíl dotazování do DB

Používat?

  • za mě ano
  • menší chybovost
  • větší přehlednost
  • jednoduše se můžeme zbavit nadbytečných dotazů do DB

Diskuze 🗣


layout: section

Dataloaders


layout: quote

"DataLoader is a generic utility to be used as part of your application's data fetching layer to provide a simplified and consistent API over various remote data sources such as databases or web services via batching and caching."

@Fb, @leebyron


layout: fact

2,271,547

Stažení týdně


Motivace

Získat unifikované API pro získávání dat z různých nezávislých zdrojů. Zároveň mít vyřešenou optimalizaci.

batching

  • dotahuji seznam stejných typů hodnot ze stejné DB v různých částech dotazu
  • do vstupu pošlu seznam klíčů (typicky IDs)
  • na výstupu Promise se seznamem odpovídajících hodnot

caching

  • dotahuji stejnou hodnotu z DB jednou
  • identifikace podle klíče
  • cache per request

obě techniky se navzájem kombinují


Ukázka z dokumentace

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
    name: { type: GraphQLString },
    bestFriend: {
      type: UserType,
      resolve: user => userLoader.load(user.bestFriendID)
    },
    friends: {
      args: {
        first: { type: GraphQLInt }
      },
      type: new GraphQLList(UserType),
      resolve: async (user, { first }) => {
        const rows = await queryLoader.load([
          'SELECT toID FROM friends WHERE fromID=? LIMIT ?', user.id, first
        ])
        return rows.map(row => userLoader.load(row.toID))
      }
    }
  })
})
  • bez Dataloaderu až 13 DB dotazů
  • s Dataloadery max 4

layout: statement

Ukázka z DPD

👉 VSCode


@FieldResolver()
async pickupPoint(@Root() invoice: Invoice, @Ctx() { container }: GraphqlContext): Promise<PickupPointResponse | null> {
    if (!invoice.pickupPointPudoId) {
        return null
    }
    const pp = await container.pickupPointRepository.findOneOrFail({
        where: {
            pudoId: invoice.pickupPointPudoId,
        },
    })
    return mapPickupPointEntityToObjectType(pp)
}

// VS

@FieldResolver()
async pickupPoint(@Root() invoice: Invoice, @Ctx() { loaders }: GraphqlContext): Promise<PickupPointResponse | null> {
    if (!invoice.pickupPointPudoId) {
        return null
    }
    const pp = await loaders.pickupPointByPudo.load(invoice.pickupPointPudoId)
    return mapPickupPointEntityToObjectType(pp)
}

Používat?

  • za mě v daný moment nemusíme
    • nemáme zatím více datových zdrojů
    • z FE nejsou moc hluboké dotazy "zatím"
  • pokud budem dodržovat field resolvery, tak se dá jednoduše a postupně doimplementovat
  • hybrid mod? Nechat to na pocitu, popřípadě na potřebách z FE

Diskuze 🗣


Díky 🙏

*Pro stažení PDF klikněte na v dolní liště.