convert flattens the upstream map into table-shaped rows for the configured providers. If any configured provider is absent from the upstream payload, every missing provider is reported and the function returns an error so the caller doesn't ship an incomplete seed.
(upstream map[string]upstreamProvider, providers []string)
| 134 | // every missing provider is reported and the function returns an error so the |
| 135 | // caller doesn't ship an incomplete seed. |
| 136 | func convert(upstream map[string]upstreamProvider, providers []string) ([]priceRow, error) { |
| 137 | var ( |
| 138 | rows []priceRow |
| 139 | missing []string |
| 140 | ) |
| 141 | for _, providerID := range providers { |
| 142 | provider, ok := upstream[providerID] |
| 143 | if !ok || len(provider.Models) == 0 { |
| 144 | missing = append(missing, providerID) |
| 145 | continue |
| 146 | } |
| 147 | for modelID, m := range provider.Models { |
| 148 | if !m.Cost.hasPricing() { |
| 149 | continue |
| 150 | } |
| 151 | rows = append(rows, priceRow{ |
| 152 | Provider: providerID, |
| 153 | Model: modelID, |
| 154 | InputPrice: toMicros(m.Cost.Input), |
| 155 | OutputPrice: toMicros(m.Cost.Output), |
| 156 | CacheReadPrice: toMicros(m.Cost.CacheRead), |
| 157 | CacheWritePrice: toMicros(m.Cost.CacheWrite), |
| 158 | }) |
| 159 | } |
| 160 | } |
| 161 | if len(missing) > 0 { |
| 162 | return nil, xerrors.Errorf("providers missing or empty in upstream: %v", missing) |
| 163 | } |
| 164 | |
| 165 | sort.Slice(rows, func(i, j int) bool { |
| 166 | if rows[i].Provider != rows[j].Provider { |
| 167 | return rows[i].Provider < rows[j].Provider |
| 168 | } |
| 169 | return rows[i].Model < rows[j].Model |
| 170 | }) |
| 171 | return rows, nil |
| 172 | } |
| 173 | |
| 174 | // validate checks invariants on the converted rows. Catches upstream |
| 175 | // changes that produce structurally valid but semantically broken seed |