Skip to content

Instantly share code, notes, and snippets.

@nickdbush
Last active June 27, 2024 15:16
Show Gist options
  • Select an option

  • Save nickdbush/a377ae8a3acc7c6b35984f8b2ac7c4e6 to your computer and use it in GitHub Desktop.

Select an option

Save nickdbush/a377ae8a3acc7c6b35984f8b2ac7c4e6 to your computer and use it in GitHub Desktop.
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