// Load will load all related entities for the supplied struct, or slice, as // long as the struct type and callback handlers have been registered. // Note: A collection is expected to be of the same type, mixed type slices will // have incorrect data, or may even panic. func Load(context *ctx.Context, data interface{}, required []string) (map[string]map[string]interface{}, error) { if required == nil { context.Lock() defer context.Unlock() return preloadedEntities(context), nil } ids, err := idsFromData(data, required...) if err != nil { return nil, err } // At this point the ids map is ready for hydration. return hydrateEntitiesFromMap(context, ids) }
// hydrateEntitiesFromMap will take an entity ids map, and return the results // for each of the entity types and their ids. This requires a handler for the // entity types to have been registered previously. func hydrateEntitiesFromMap(context *ctx.Context, ids map[string]map[string]bool) (map[string]map[string]interface{}, error) { context.Lock() entities := preloadedEntities(context) context.Unlock() if len(ids) == 0 { return entities, nil } resultChan := make(chan entityCollectionResult) for name, idMap := range ids { // Turn the map of ids into a slice. idSlice := make([]string, len(idMap)) i := 0 for id := range idMap { idSlice[i] = id i++ } // Go get the entity collection go singleEntityCollection(context, resultChan, name, idSlice) } var firstErr error // Loops over the ids again, for the correct count. for _ = range ids { // Retrieve a result off the result chan. result := <-resultChan // An error should be assigned to the firstErr is it's empty. if result.err != nil { if firstErr == nil { firstErr = result.err } continue } // Results get assigned back to the entities being returned. if existingEntities, ok := entities[result.name]; ok { for key, value := range result.results { existingEntities[key] = value } entities[result.name] = existingEntities } else { entities[result.name] = result.results } } return entities, firstErr }