fix: only write AI model prices that changed (#27923)

Previously, the AI Gateway price seeder rewrote every row of
`ai_model_prices` on each server start, because `ON CONFLICT` fires on a
key conflict rather than on a value difference. `updated_at` therefore
recorded when the server last restarted rather than when a price last
changed.

Guard the `DO UPDATE` branch so a conflicting row is only rewritten when
one of its four prices differs. The comparison uses `IS DISTINCT FROM`
rather than `<>` because the price columns are nullable, and `<>` yields
NULL when either side is NULL, which would skip the update and leave a
stale price in place.

Related to
https://linear.app/codercom/issue/AIGOV-567/experimental-cli-command-to-set-prices-for-unpriced-ai-models

> [!NOTE]
> Initially generated by Claude Opus 5, modified and reviewed by
@ssncferreira
This commit is contained in:
Susana Ferreira
2026-08-10 16:33:48 +01:00
committed by GitHub
parent 27414788f7
commit 5efa7abe7d
4 changed files with 137 additions and 3 deletions
+14
View File
@@ -3459,11 +3459,25 @@ ON CONFLICT (provider, model) DO UPDATE SET
cache_read_price = EXCLUDED.cache_read_price,
cache_write_price = EXCLUDED.cache_write_price,
updated_at = NOW()
WHERE (
ai_model_prices.input_price,
ai_model_prices.output_price,
ai_model_prices.cache_read_price,
ai_model_prices.cache_write_price
) IS DISTINCT FROM (
EXCLUDED.input_price,
EXCLUDED.output_price,
EXCLUDED.cache_read_price,
EXCLUDED.cache_write_price
)
`
// Upsert a batch of (provider, model) rows from a JSON array. Each element
// must have provider, model, and the four price fields; null prices are
// written as SQL NULL.
// A conflicting row is only rewritten when a price differs, so updated_at
// records when a price last changed. Prices are nullable and a NULL on
// either side counts as a difference.
func (q *sqlQuerier) UpsertAIModelPrices(ctx context.Context, seed json.RawMessage) error {
_, err := q.db.ExecContext(ctx, upsertAIModelPrices, seed)
return err