Last active
June 27, 2024 15:16
-
-
Save nickdbush/a377ae8a3acc7c6b35984f8b2ac7c4e6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package altdata | |
| import ( | |
| "context" | |
| "github.com/google/uuid" | |
| "golang.org/x/sync/errgroup" | |
| ) | |
| type LoaderFn[Data any] func(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]Data, error) | |
| type ApplierFn[Target any, Data any] func(*Target, Data) | |
| type Resolver[Target any, Data any] struct { | |
| loader LoaderFn[Data] | |
| applier ApplierFn[Target, Data] | |
| } | |
| type ResolveFn[Target any] func(context.Context, []uuid.UUID) (func(uuid.UUID, *Target), error) | |
| func Resolve[Target any, Data any](loader LoaderFn[Data], applier ApplierFn[Target, Data]) ResolveFn[Target] { | |
| return func(ctx context.Context, ids []uuid.UUID) (func(uuid.UUID, *Target), error) { | |
| results, err := loader(ctx, ids) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return func(id uuid.UUID, target *Target) { | |
| applier(target, results[id]) | |
| }, nil | |
| } | |
| } | |
| func ResolveAsync[Target any]( | |
| ctx context.Context, | |
| ids []uuid.UUID, | |
| resolvers ...ResolveFn[Target], | |
| ) ([]Target, error) { | |
| entities := make([]Target, len(ids)) | |
| group, ctx := errgroup.WithContext(ctx) | |
| appliers := make(chan func(uuid.UUID, *Target), len(resolvers)) | |
| for _, resolver := range resolvers { | |
| group.Go(func() error { | |
| applier, err := resolver(ctx, ids) | |
| if err != nil { | |
| return err | |
| } | |
| appliers <- applier | |
| return nil | |
| }) | |
| } | |
| if err := group.Wait(); err != nil { | |
| return nil, err | |
| } | |
| for _ = range resolvers { | |
| applier := <-appliers | |
| for i, entity := range entities { | |
| id := ids[i] | |
| applier(id, &entity) | |
| } | |
| } | |
| return entities, nil | |
| } | |
| func OffersLoader(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID][]Offer, error) { | |
| return map[uuid.UUID][]Offer{ | |
| ids[0]: {}, | |
| }, nil | |
| } | |
| func ProfileLoader(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]Photo, error) { | |
| return map[uuid.UUID]Photo{ | |
| ids[0]: { | |
| ID: uuid.New(), | |
| }, | |
| }, nil | |
| } | |
| type Offer struct { | |
| ID uuid.UUID | |
| } | |
| type Photo struct { | |
| ID uuid.UUID | |
| } | |
| type User struct { | |
| ID uuid.UUID | |
| Offers []Offer | |
| Profile Photo | |
| } | |
| func GetUserSummaries(ctx context.Context, ids []uuid.UUID) ([]User, error) { | |
| offersResolver := Resolve(OffersLoader, func(data *User, offers []Offer) { | |
| data.Offers = offers | |
| }) | |
| profileResolver := Resolve(ProfileLoader, func(user *User, profile Photo) { | |
| user.Profile = profile | |
| }) | |
| return ResolveAsync(ctx, ids, offersResolver, profileResolver) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment