Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphQL + KotlinでN+1問題 を対応する / GraphQL + Kotlin with N+1 problem

Shiraji
October 09, 2019

GraphQL + KotlinでN+1問題 を対応する / GraphQL + Kotlin with N+1 problem

Shiraji

October 09, 2019
Tweet

More Decks by Shiraji

Other Decks in Programming

Transcript

  1. w 4&-&$5 '30.ESVHXIFSFJEJO    / 1SPCMFN w 4&-&$5

    '30.DPNQBOZXIFSFJE w 4&-&$5 '30.DPNQBOZXIFSFJE w 4&-&$5 '30.DPNQBOZXIFSFJE
  2. / XJUIHSBQIRMKBWBTUBSUFS val context = GraphQLContext(httpServletRequest, httpServletResponse) context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_companies_by_drugs_id”,

    DataLoader.newDataLoader<Long, Company> { companyIds, _ -> CompletableFuture.supplyAsync { // SELECT * FROM company where company_id in (1, 2, 3) drugService.getCompanyByIds(companyIds) }d }c )b )a return context
  3. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompany(drug: Drug): Company {a companyService.getCompanyById(drug.companyId) }a }b
  4. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompany(drug: Drug, env: DataFetchingEnvironment): Company {a companyService.getCompanyById(drug.companyId) }a }b
  5. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompanies(drug: Drug, env: DataFetchingEnvironment): CompletableFuture<List<Company>>? {a companyService.getCompanyById(drug.companyId) }a }b
  6. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompanies(drug: Drug, env: DataFetchingEnvironment): CompletableFuture<List<Company>>? {a }a }b
  7. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompanies(drug: Drug, env: DataFetchingEnvironment): CompletableFuture<List<Company>>? {a return env .getDataLoader<Long, List<Company>>(“key_companies_by_drugs_id”) }a }b
  8. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompanies(drug: Drug, env: DataFetchingEnvironment): CompletableFuture<List<Company>>? {a return env .getDataLoader<Long, List<Company>>(“key_companies_by_drugs_id”) .load(drug.companyId) }a }b
  9. / XJUIHSBQIRMKBWBTUBSUFS @Component class DrugResolver : GraphQLResolver<Drug> { @Suppress("unused") fun

    getCompanies(drug: Drug, env: DataFetchingEnvironment): CompletableFuture<List<Company>>? {a return env .getDataLoader<Long, List<Company>>(“key_companies_by_drugs_id”) .load(drug.companyId) }a }b val context = GraphQLContext(httpServletRequest, httpServletResponse) context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_companies_by_drugs_id”, DataLoader.newDataLoader<Long, Company> { companyIds, _ -> CompletableFuture.supplyAsync { // SELECT * FROM company where company_id in (1, 2, 3) drugService.getCompanyByIds(companyIds) }d }c )b )a return context
  10. "TTPDJBUFLFZXJUIWBMVF val context = GraphQLContext(httpServletRequest, httpServletResponse) context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_companies_by_drugs_id”, DataLoader.newDataLoader<Long,

    Company> { companyIds, _ -> CompletableFuture.supplyAsync { // SELECT * FROM company where company_id in (1, 2, 3) drugService.getCompanyByIds(companyIds) }d }c )b )a return context w 0SEFSNBUUFS w DPNQBOZ*ET    <$PNQBOZ JE $PNQBOZ JE $PNQBOZ JE > w DPNQBOZ*ET    <$PNQBOZ JE OVMM $PNQBOZ JE >
  11. $PNQMFYSFMBUJPOT type Drug { id: ID! company: Company! kinkiDrugs: [Drug!]

    } w 0OFESVHIBTNVMUJQMF,JOLJESVHT w %SVHTNJHIUIBWFTBNF,JOLJESVHT
  12. w 4&-&$5 '30.ESVHXIFSFJEJO     w 4&-&$5 '30.LJOLJ@ESVHXIFSFESVH@B@JEJO

        w 4&-&$5 '30.ESVHXIFSFJEJO    $PNQMFYSFMBUJPOT
  13. JE ESVH@B@JE ESVH@C@JE       

         w 4&-&$5 '30.LJOLJ@ESVHXIFSF ESVH@B@JEJO     w :FT ESVH@C@JEJT    CVUEVQMJDBUFE LJOLJ@ESVH $PNQMFYSFMBUJPOT
  14. "TTPDJBUFLFZXJUIWBMVF val context = GraphQLContext(httpServletRequest, httpServletResponse) context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_companies_by_drugs_id”, DataLoader.newDataLoader<Long,

    Company> { companyIds, _ -> CompletableFuture.supplyAsync { // SELECT * FROM company where company_id in (1, 2, 3) drugService.getCompanyByIds(companyIds) }d }c )b )a return context w 0SEFSNBUUFS w DPNQBOZ*ET    <$PNQBOZ JE $PNQBOZ JE $PNQBOZ JE > w DPNQBOZ*ET    <$PNQBOZ JE OVMM $PNQBOZ JE >
  15. context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_kinki_drugs_by_drugs_id”, DataLoader.newMappedDataLoader<Long, Drug> { drugIds, _ -> CompletableFuture.supplyAsync

    { // SELECT * FROM kinki_drug where drug_a_id in (1, 2, 3) val kinkis = kinkiDrugService.getKinkiDrugs(drugsIds) // SELECT * FROM drug where id in (4, 5, 6) val drugs = drugService.getDrugs(kinkis.map { it.drugBId }) }d }c )b )a
  16. context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_kinki_drugs_by_drugs_id”, DataLoader.newMappedDataLoader<Long, Drug> { drugIds, _ -> CompletableFuture.supplyAsync

    { // SELECT * FROM kinki_drug where drug_a_id in (1, 2, 3) val kinkis = kinkiDrugService.getKinkiDrugs(drugsIds) // SELECT * FROM drug where id in (4, 5, 6) val drugs = drugService.getDrugs(kinkis.map { it.drugBId }) // Create Map<KinkiDrug, List<Drug>> val kinkiMap = kinkis.associateWith { kinkiDrug -> drugs.filter { it.id == kinkiDrug.drugBId } }x }d }c )b )a
  17. context.setDataLoaderRegistry( DataLoaderRegistry().register( “key_kinki_drugs_by_drugs_id”, DataLoader.newMappedDataLoader<Long, Drug> { drugIds, _ -> CompletableFuture.supplyAsync

    { // SELECT * FROM kinki_drug where drug_a_id in (1, 2, 3) val kinkis = kinkiDrugService.getKinkiDrugs(drugsIds) // SELECT * FROM drug where id in (4, 5, 6) val drugs = drugService.getDrugs(kinkis.map { it.drugBId }) // Create Map<KinkiDrug, List<Drug>> val kinkiMap = kinkis.associateWith { kinkiDrug -> drugs.filter { it.id == kinkiDrug.drugBId } }x // Create Map<Long, List<Drug>> drugIds.associateWith { drugId -> kinkiMap.filter { entry -> entry.key.drugAId == drugId }.values.flatten() } }d }c )b )a
  18. @Component class DrugDataLoader : MappedBatchLoader<Long, List<Drug>> { override fun load(ids:

    Set<Long>?): CompletionStage<Map<Long, List<Drug>>> { return CompletableFuture.supplyAsync { // do whatever you want }a }b }c .BLFDVTUPN#BUDI-PBEFS
  19. 4USJOH,FZ /BWJHBUJPO context.setDataLoaderRegistry( DataLoaderRegistry().register( // Use class name DrugDataLoader::class.qualifiedName, DataLoader.newMappedDataLoader(drugDataLoader)

    )b )a @Component class DrugDataLoader : MappedBatchLoader<Long, List<Drug>> { override fun load(ids: Set<Long>?): CompletionStage<Map<Long, List<Drug>>> { return CompletableFuture.supplyAsync { // do whatever you want }a }b }c @Suppress("unused") fun getKinkiDrugs(drug: Drug, environment: DataFetchingEnvironment): CompletableFuture<List<Drug>>? { return environment // Use class name .getDataLoader<Long, List<Drug>>(DrugDataLoader::class.qualifiedName) .load(drug.id) }b
  20. @Component class DrugDataLoader : MappedBatchLoader<Long, List<Drug>> { override fun load(ids:

    Set<Long>?): CompletionStage<Map<Long, List<Drug>>> { return CompletableFuture.supplyAsync { // do whatever you want }a }b }c .BLFDVTUPN#BUDI-PBEFS .PDLBOEUFTUMPBENFUIPE
  21. 4USJOH,FZ /BWJHBUJPO val context = GraphQLContext(httpServletRequest, httpServletResponse) context.setDataLoaderRegistry( DataLoaderRegistry().register( cDrugDataLoader::class.qualifiedName,

    // cache survive until drugDataLoader DataLoader.newMappedDataLoader(drugDataLoader) )b )a return context @Component class DrugDataLoader : MappedBatchLoader<Long, List<Drug>> { // keep cache here override fun load(ids: Set<Long>?): CompletionStage<Map<Long, List<Drug>>> { return CompletableFuture.supplyAsync { // do whatever you want }a }b }c