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

Iteratorでページネーションを実現する

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for sonatard sonatard
September 24, 2024

 Iteratorでページネーションを実現する

Avatar for sonatard

sonatard

September 24, 2024
Tweet

More Decks by sonatard

Other Decks in Programming

Transcript

  1. 3 %#ͷϖʔδωʔγϣϯΛߟ͑ͯΈΔ w TQBOOFSDQBDLBHFͰ$MPVE4QBOOFSͷૢ࡞Λϥοϓ͍ͯ͠Δ w ҎԼ͸*UFSBUPSΛ࢖͏લͷίʔυ cursorInfo = offset.NewCursorInfo() for

    { stmt := statement.ByCursor[domain.User](cursorInfo) users, pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if !pageInfo.HasNextPage { break } cursorInfo.Cursor = pageInfo.EndCursor }
  2. 4 cursorInfo := offset.NewCursorInfo() for { stmt := statement.ByCursor[domain.User](cursorInfo) users,

    pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if !pageInfo.HasNextPage { break } cursorInfo.Cursor = pageInfo.EndCursor } ࣍ͷϖʔδ͕ͳ͚Ε͹GPS͔Βൈ͚Δ ࣍ͷϖʔδͷ$VSTPSΛߋ৽͢Δ
  3. 5 cursorInfo := offset.NewCursorInfo() for { stmt := statement.ByCursor[domain.User](cursorInfo) users,

    pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if !pageInfo.HasNextPage { break } cursorInfo.Cursor = pageInfo.EndCursor } CSFBLΛ๨ΕͨΓɺ৚݅Λؒҧ͑Δ
  4. 6 cursorInfo := offset.NewCursorInfo() for { stmt := statement.ByCursor[domain.User](cursorInfo) users,

    pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if !pageInfo.HasNextPage { break } // cursorInfo.Cursor = pageInfo.EndCursor } $VSTPSͷߋ৽Λ๨ΕΔ
  5. 7 cursorInfo := offset.NewCursorInfo() for { stmt := statement.ByCursor[domain.User](cursorInfo) users,

    pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if users.Invalid() { continue } if !pageInfo.HasNextPage { break } cursorInfo.Cursor = pageInfo.EndCursor } $VSTPSͷߋ৽Λ๨ΕͯDPOUJOVF
  6. 8 cursorInfo := offset.NewCursorInfo() for { stmt := statement.ByCursor[domain.User](cursorInfo) users,

    pageInfo, err := spannerc.GetMulti(ctx, stmt) if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if users.Invalid() { continue } if !pageInfo.HasNextPage { break } cursorInfo.Cursor = pageInfo.EndCursor } ࠓ·Ͱ͸ՄೳͳൣғͰ-JOUͰରԠ͍ͯͨ͠
  7. 9 stmt := statement.ByCursor[domain.User](offset.NewCursorInfo()) for users, err := range spannerc.GetMultiIter(ctx,

    stmt) { if err != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if users.Invalid() { continue } } ϧʔϓͷϖʔδωʔγϣϯॲཧ΍ऴྃ৚݅ (FU.VMUJ*UFSʹӅṭ͞Ε͍ͯΔ 6TFSʹؔ࿈͢ΔॲཧͷΈΛॻ͚͹Α͘ͳͬͨ QBHF*OGPม਺΁ͷΞΫηε͕ෆཁʹͳͬͨ
  8. 10 func GetMultiIter[T any](ctx context.Context, stmt offset.StatementWithCursor[T]) iter.Seq2[[]*T, error] {

    return func(yield func([]*T, error) bool) { for { stmt.Statement.Params["offset"] = stmt.CursorInfo.Offset() ts, pageInfo, err := GetMulti[T](ctx, stmt) if !yield(ts, err) { return } if err != nil { return } if !pageInfo.HasNextPage { break } stmt.CursorInfo.Cursor = pageInfo.EndCursor } } } (FU.VMUJ*UFSͷ࣮૷
  9. 11 for users, err := range statement.ByCursor[domain.User](offset.NewCursorInfo()).All(ctx) { if err

    != nil { return nil, nil, fmt.Errorf(": %w", err) } // usersʹԿ͔͠Βͷॲཧ if users.Invalid() { continue } } ͓·͚ ͜Μͳ࣮૷ʹͨ͠ΒΑΓ(Pͷ*UFSBUPSΒ͍͠
  10. 12 *UFSBUPSͷ࢖͍ॴ w ·ͱΊ w ϧʔϓΛந৅Խ͢Δ༻్Ͱ࢖͑Δ w 'PSͷதͰ͋Δ৚݅ͰCSFBL΍DPOUJOVFΛ͍ͯ͠ΔͷͰ͋Ε͹γϯϓϧʹͰ͖Δ w Ͳ͜·Ͱ*UFSBUPSʹ͍ͯ͘͠ʁ

    w *UFSBUPS͸௚ײతʹಡΈͮΒ͍ͷͰɺͪΐͬͱͨ͜͠ͱͰ*UFSBUPSΛ࢖͍͗͢Δͱٯʹ ίʔυ͕ಡΈͮΒ͘ͳΔ͔΋ w ϧʔϓʹ໌֬ͳ՝୊͕͋Δɺ৑௕ͳॲཧΛ͍ͭ΋࣮૷͠ͳ͚Ε͹ͳΒͳ͍৔߹ͳͲɺ ༻๏༻ྔΛकͬͯਖ਼͓͘͠࢖͍͍ͩ͘͞ɻ
  11. 13 *UFSBUPSͷ࢖͍ॴ w ͓·͚ w %BUBCBTFपลͰ͸EBUBCBTFTRMQBDLBHFͳͲͰJP&0'ͳͲͷϋϯυϦϯά΋*UFSBUPS ͰෆཁʹͰ͖Δ w JP3FBEFSͳͲ΋ಉ༷ʁ w

    ͔͠͠JPQBDLBHFͷΠϯλʔϑΣʔε͕มΘΔͷ͸؆୯Ͱ͸ͳͦ͞͏ w ࠓޙඪ४ϥΠϒϥϦ͕ͲͷΑ͏ʹ*UFSBUPSʹରԠ͍͔ͯ͘͠΋ཁ஫໨