@@ -214,55 +214,81 @@ defmodule CodexPooler.Accounting.PricingResolution do
214214 timestamp ,
215215 batch_usage?
216216 ) do
217- snapshot = pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp )
218-
219- case snapshot do
217+ case pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) ||
218+ fallback_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
220219 % PricingSnapshot { } = snapshot ->
221220 priced_snapshot ( snapshot , requested_tier , actual_tier , service_tier , batch_usage? )
222221
223222 nil ->
224- case fallback_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
225- % PricingSnapshot { } = fallback ->
226- priced_snapshot ( fallback , requested_tier , actual_tier , service_tier , batch_usage? )
227-
228- nil ->
229- case suffix_inference_pricing_snapshot (
230- identifiers ,
231- service_tier ,
232- price_bucket ,
233- timestamp
234- ) ||
235- fallback_suffix_inference_pricing_snapshot (
236- identifiers ,
237- service_tier ,
238- price_bucket ,
239- timestamp
240- ) do
241- { % PricingSnapshot { } = inferred , alias_metadata } ->
242- priced_snapshot (
243- inferred ,
244- requested_tier ,
245- actual_tier ,
246- service_tier ,
247- batch_usage? ,
248- alias_metadata
249- )
250-
251- nil ->
252- missing_pricing_snapshot (
253- model ,
254- identifiers ,
255- requested_tier ,
256- actual_tier ,
257- service_tier ,
258- timestamp ,
259- batch_usage?
260- )
261- end
262- end
223+ lookup_inferred_service_tier (
224+ model ,
225+ identifiers ,
226+ requested_tier ,
227+ actual_tier ,
228+ service_tier ,
229+ price_bucket ,
230+ timestamp ,
231+ batch_usage?
232+ )
263233 end
264234 end
265235
236+ @ spec lookup_inferred_service_tier (
237+ Model . t ( ) ,
238+ [ String . t ( ) ] ,
239+ String . t ( ) | nil ,
240+ String . t ( ) | nil ,
241+ String . t ( ) ,
242+ String . t ( ) ,
243+ DateTime . t ( ) ,
244+ boolean ( )
245+ ) :: map ( )
246+ defp lookup_inferred_service_tier (
247+ model ,
248+ identifiers ,
249+ requested_tier ,
250+ actual_tier ,
251+ service_tier ,
252+ price_bucket ,
253+ timestamp ,
254+ batch_usage?
255+ ) do
256+ case inferred_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
257+ { % PricingSnapshot { } = inferred , alias_metadata } ->
258+ priced_snapshot (
259+ inferred ,
260+ requested_tier ,
261+ actual_tier ,
262+ service_tier ,
263+ batch_usage? ,
264+ alias_metadata
265+ )
266+
267+ nil ->
268+ missing_pricing_snapshot (
269+ model ,
270+ identifiers ,
271+ requested_tier ,
272+ actual_tier ,
273+ service_tier ,
274+ timestamp ,
275+ batch_usage?
276+ )
277+ end
278+ end
279+
280+ @ spec inferred_pricing_snapshot ( [ String . t ( ) ] , String . t ( ) , String . t ( ) , DateTime . t ( ) ) ::
281+ { PricingSnapshot . t ( ) , map ( ) } | nil
282+ defp inferred_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
283+ suffix_inference_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) ||
284+ fallback_suffix_inference_pricing_snapshot (
285+ identifiers ,
286+ service_tier ,
287+ price_bucket ,
288+ timestamp
289+ )
290+ end
291+
266292 defp pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
267293 Repo . one (
268294 from ps in PricingSnapshot ,
@@ -291,7 +317,7 @@ defmodule CodexPooler.Accounting.PricingResolution do
291317 String . t ( ) ,
292318 String . t ( ) ,
293319 DateTime . t ( )
294- ) :: { % PricingSnapshot { } , map ( ) } | nil
320+ ) :: { PricingSnapshot . t ( ) , map ( ) } | nil
295321 defp fallback_suffix_inference_pricing_snapshot (
296322 identifiers ,
297323 service_tier ,
@@ -315,7 +341,7 @@ defmodule CodexPooler.Accounting.PricingResolution do
315341 do: nil
316342
317343 @ spec suffix_inference_pricing_snapshot ( [ String . t ( ) ] , String . t ( ) , String . t ( ) , DateTime . t ( ) ) ::
318- { % PricingSnapshot { } , map ( ) } | nil
344+ { PricingSnapshot . t ( ) , map ( ) } | nil
319345 defp suffix_inference_pricing_snapshot ( identifiers , service_tier , price_bucket , timestamp ) do
320346 candidates = suffix_inference_candidates ( identifiers )
321347 candidate_identifiers = candidates |> Enum . map ( & & 1 . to ) |> Enum . uniq ( )
@@ -393,41 +419,86 @@ defmodule CodexPooler.Accounting.PricingResolution do
393419
394420 1 .. ( segment_count - 1 )
395421 |> Enum . reduce_while ( { [ ] , 0 } , fn distance , { candidates , arbitrary_trim_count } ->
396- trimmed_segment = Enum . at ( segments , - distance )
397-
398- arbitrary_trim_count =
399- if date_or_version_suffix? ( trimmed_segment ) ,
400- do: arbitrary_trim_count ,
401- else: arbitrary_trim_count + 1
402-
403- if arbitrary_trim_count > 1 do
404- { :halt , { candidates , arbitrary_trim_count } }
405- else
406- candidate_identifier =
407- segments
408- |> Enum . take ( segment_count - distance )
409- |> Enum . join ( "-" )
410-
411- candidate =
412- if blank? ( candidate_identifier ) or candidate_identifier == original_identifier do
413- nil
414- else
415- % {
416- from: original_identifier ,
417- to: candidate_identifier ,
418- distance: distance
419- }
420- end
421-
422- candidates = if candidate , do: [ candidate | candidates ] , else: candidates
423-
424- { :cont , { candidates , arbitrary_trim_count } }
425- end
422+ suffix_inference_candidate_step (
423+ segments ,
424+ original_identifier ,
425+ segment_count ,
426+ distance ,
427+ candidates ,
428+ arbitrary_trim_count
429+ )
426430 end )
427431 |> elem ( 0 )
428432 |> Enum . reverse ( )
429433 end
430434
435+ @ spec suffix_inference_candidate_step (
436+ [ String . t ( ) ] ,
437+ String . t ( ) ,
438+ pos_integer ( ) ,
439+ pos_integer ( ) ,
440+ [ suffix_candidate ( ) ] ,
441+ non_neg_integer ( )
442+ ) :: { :cont | :halt , { [ suffix_candidate ( ) ] , non_neg_integer ( ) } }
443+ defp suffix_inference_candidate_step (
444+ segments ,
445+ original_identifier ,
446+ segment_count ,
447+ distance ,
448+ candidates ,
449+ arbitrary_trim_count
450+ ) do
451+ arbitrary_trim_count =
452+ if date_or_version_suffix? ( Enum . at ( segments , - distance ) ) ,
453+ do: arbitrary_trim_count ,
454+ else: arbitrary_trim_count + 1
455+
456+ if arbitrary_trim_count > 1 do
457+ { :halt , { candidates , arbitrary_trim_count } }
458+ else
459+ candidate_identifier =
460+ segments
461+ |> Enum . take ( segment_count - distance )
462+ |> Enum . join ( "-" )
463+
464+ candidates =
465+ maybe_prepend_suffix_candidate (
466+ candidates ,
467+ candidate_identifier ,
468+ original_identifier ,
469+ distance
470+ )
471+
472+ { :cont , { candidates , arbitrary_trim_count } }
473+ end
474+ end
475+
476+ @ spec maybe_prepend_suffix_candidate (
477+ [ suffix_candidate ( ) ] ,
478+ String . t ( ) ,
479+ String . t ( ) ,
480+ pos_integer ( )
481+ ) :: [ suffix_candidate ( ) ]
482+ defp maybe_prepend_suffix_candidate (
483+ candidates ,
484+ candidate_identifier ,
485+ original_identifier ,
486+ distance
487+ ) do
488+ if blank? ( candidate_identifier ) or candidate_identifier == original_identifier do
489+ candidates
490+ else
491+ [
492+ % {
493+ from: original_identifier ,
494+ to: candidate_identifier ,
495+ distance: distance
496+ }
497+ | candidates
498+ ]
499+ end
500+ end
501+
431502 @ spec date_or_version_suffix? ( term ( ) ) :: boolean ( )
432503 defp date_or_version_suffix? ( segment ) when is_binary ( segment ) do
433504 Regex . match? ( ~r/ \A (?:v)?\d +(?:[._]\d +)*\z / i , String . trim ( segment ) )
@@ -443,7 +514,7 @@ defmodule CodexPooler.Accounting.PricingResolution do
443514 end
444515 end
445516
446- @ spec nearest_suffix_inference_match ( [ map ( ) ] ) :: { % PricingSnapshot { } , map ( ) } | nil
517+ @ spec nearest_suffix_inference_match ( [ map ( ) ] ) :: { PricingSnapshot . t ( ) , map ( ) } | nil
447518 defp nearest_suffix_inference_match ( [ ] ) , do: nil
448519
449520 defp nearest_suffix_inference_match ( matches ) do
0 commit comments