mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Preserve usage provider identity
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
-- Usage is a historical fact table. Backfill nullable provider_id snapshots
|
||||
-- from the unique provider name where the catalog row still exists.
|
||||
|
||||
UPDATE `usage` AS usage_rows
|
||||
JOIN providers
|
||||
ON providers.name = TRIM(usage_rows.provider_name)
|
||||
SET usage_rows.provider_id = providers.id
|
||||
WHERE usage_rows.provider_id IS NULL
|
||||
AND TRIM(COALESCE(usage_rows.provider_name, '')) <> ''
|
||||
AND LOWER(TRIM(COALESCE(usage_rows.provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending');
|
||||
@@ -4427,21 +4427,6 @@ END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
DO $mig$ BEGIN
|
||||
ALTER TABLE ONLY public.usage
|
||||
ADD CONSTRAINT usage_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE SET NULL;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN NULL;
|
||||
WHEN duplicate_table THEN NULL;
|
||||
WHEN invalid_table_definition THEN NULL;
|
||||
END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- Usage is a historical fact table. Keep the provider_id snapshot even if the
|
||||
-- provider catalog row is deleted, and backfill rows that can still be matched
|
||||
-- by the unique provider name.
|
||||
|
||||
UPDATE public.usage AS usage_rows
|
||||
SET provider_id = providers.id
|
||||
FROM public.providers AS providers
|
||||
WHERE usage_rows.provider_id IS NULL
|
||||
AND BTRIM(COALESCE(usage_rows.provider_name, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE(usage_rows.provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
AND providers.name = BTRIM(usage_rows.provider_name);
|
||||
|
||||
ALTER TABLE ONLY public.usage
|
||||
DROP CONSTRAINT IF EXISTS usage_provider_id_fkey;
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Usage is a historical fact table. Backfill nullable provider_id snapshots
|
||||
-- from the unique provider name where the catalog row still exists.
|
||||
|
||||
UPDATE "usage"
|
||||
SET provider_id = (
|
||||
SELECT providers.id
|
||||
FROM providers
|
||||
WHERE providers.name = TRIM("usage".provider_name)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE provider_id IS NULL
|
||||
AND TRIM(COALESCE(provider_name, '')) <> ''
|
||||
AND LOWER(TRIM(COALESCE(provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM providers
|
||||
WHERE providers.name = TRIM("usage".provider_name)
|
||||
);
|
||||
@@ -627,21 +627,6 @@ END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
DO $mig$ BEGIN
|
||||
ALTER TABLE ONLY public.usage
|
||||
ADD CONSTRAINT usage_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE SET NULL;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN NULL;
|
||||
WHEN duplicate_table THEN NULL;
|
||||
WHEN invalid_table_definition THEN NULL;
|
||||
END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -552,21 +552,6 @@ END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
DO $mig$ BEGIN
|
||||
ALTER TABLE ONLY public.usage
|
||||
ADD CONSTRAINT usage_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE SET NULL;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN NULL;
|
||||
WHEN duplicate_table THEN NULL;
|
||||
WHEN invalid_table_definition THEN NULL;
|
||||
END $mig$;
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -7,7 +7,7 @@ use tracing::info;
|
||||
// Generated by build.rs from schema/bootstrap/postgres.
|
||||
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
|
||||
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260520000000;
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260520010000;
|
||||
|
||||
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
|
||||
SELECT COUNT(*)::BIGINT
|
||||
|
||||
@@ -311,6 +311,7 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
|
||||
20260519120000,
|
||||
20260519130000,
|
||||
20260520000000,
|
||||
20260520010000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -631,6 +632,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260519120000,
|
||||
20260519130000,
|
||||
20260520000000,
|
||||
20260520010000,
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -653,6 +655,7 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260519120000,
|
||||
20260519130000,
|
||||
20260520000000,
|
||||
20260520010000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -1175,6 +1178,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
|
||||
20260519120000,
|
||||
20260519130000,
|
||||
20260520000000,
|
||||
20260520010000,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -983,6 +983,30 @@ fn usage_provider_display_name(item: &StoredRequestUsageAudit) -> Option<String>
|
||||
}
|
||||
}
|
||||
|
||||
fn usage_provider_id(item: &StoredRequestUsageAudit) -> Option<String> {
|
||||
let provider_id = item.provider_id.as_deref()?.trim();
|
||||
if provider_id.is_empty() || usage_reserved_provider_label(provider_id) {
|
||||
None
|
||||
} else {
|
||||
Some(provider_id.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn usage_provider_aggregation_identity(
|
||||
item: &StoredRequestUsageAudit,
|
||||
) -> Option<(String, Option<String>, String)> {
|
||||
let display_name = usage_provider_display_name(item);
|
||||
if let Some(provider_id) = usage_provider_id(item) {
|
||||
return Some((provider_id, display_name, "provider_id".to_string()));
|
||||
}
|
||||
let display_name = display_name?;
|
||||
Some((
|
||||
display_name.clone(),
|
||||
Some(display_name),
|
||||
"legacy_name".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UsageReadRepository for InMemoryUsageReadRepository {
|
||||
async fn find_by_id(
|
||||
@@ -1167,14 +1191,14 @@ impl UsageReadRepository for InMemoryUsageReadRepository {
|
||||
|| item.created_at_unix_ms >= query.created_until_unix_secs
|
||||
|| matches!(item.status.as_str(), "pending" | "streaming")
|
||||
|| (query.exclude_reserved_provider_labels
|
||||
&& usage_provider_display_name(item).is_none())
|
||||
&& usage_provider_aggregation_identity(item).is_none())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let provider_display_name =
|
||||
let provider_identity =
|
||||
if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider) {
|
||||
match usage_provider_display_name(item) {
|
||||
match usage_provider_aggregation_identity(item) {
|
||||
Some(value) => Some(value),
|
||||
None => continue,
|
||||
}
|
||||
@@ -1184,19 +1208,11 @@ impl UsageReadRepository for InMemoryUsageReadRepository {
|
||||
|
||||
let group_key = match query.group_by {
|
||||
UsageAuditAggregationGroupBy::Model => item.model.clone(),
|
||||
UsageAuditAggregationGroupBy::Provider => {
|
||||
let display_name = provider_display_name
|
||||
.as_deref()
|
||||
.expect("provider display name is set for provider aggregation");
|
||||
item.provider_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|provider_id| {
|
||||
!provider_id.is_empty() && !usage_reserved_provider_label(provider_id)
|
||||
})
|
||||
.unwrap_or(display_name)
|
||||
.to_string()
|
||||
}
|
||||
UsageAuditAggregationGroupBy::Provider => provider_identity
|
||||
.as_ref()
|
||||
.expect("provider identity is set for provider aggregation")
|
||||
.0
|
||||
.clone(),
|
||||
UsageAuditAggregationGroupBy::ApiFormat => item
|
||||
.api_format
|
||||
.clone()
|
||||
@@ -1211,7 +1227,17 @@ impl UsageReadRepository for InMemoryUsageReadRepository {
|
||||
&& (bucket.display_name.is_none()
|
||||
|| bucket.display_name.as_deref() == Some("Unknown"))
|
||||
{
|
||||
bucket.display_name = provider_display_name;
|
||||
bucket.display_name = provider_identity
|
||||
.as_ref()
|
||||
.and_then(|(_, display_name, _)| display_name.clone());
|
||||
}
|
||||
if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider)
|
||||
&& (bucket.secondary_name.is_none()
|
||||
|| bucket.secondary_name.as_deref() == Some("legacy_name"))
|
||||
{
|
||||
bucket.secondary_name = provider_identity
|
||||
.as_ref()
|
||||
.map(|(_, _, identity_source)| identity_source.clone());
|
||||
}
|
||||
bucket.request_count = bucket.request_count.saturating_add(1);
|
||||
bucket.total_tokens = bucket.total_tokens.saturating_add(item.total_tokens);
|
||||
@@ -3149,6 +3175,12 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn provider_aggregation_skips_unknown_provider_labels() {
|
||||
let valid_provider = sample_usage("req-valid-provider", 300);
|
||||
|
||||
let mut legacy_provider = sample_usage("req-legacy-provider", 250);
|
||||
legacy_provider.provider_id = None;
|
||||
legacy_provider.provider_name = "Legacy Provider".to_string();
|
||||
|
||||
let mut unknown = sample_usage("req-unknown-provider", 100);
|
||||
unknown.provider_id = None;
|
||||
unknown.provider_name = "unknown".to_string();
|
||||
@@ -3158,7 +3190,8 @@ mod tests {
|
||||
typo_unknown.provider_name = "unknow".to_string();
|
||||
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![
|
||||
sample_usage("req-valid-provider", 300),
|
||||
valid_provider,
|
||||
legacy_provider,
|
||||
unknown,
|
||||
typo_unknown,
|
||||
]);
|
||||
@@ -3174,9 +3207,29 @@ mod tests {
|
||||
.await
|
||||
.expect("aggregation should succeed");
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
assert_eq!(rows[0].group_key, "provider-1");
|
||||
assert_eq!(rows[0].display_name.as_deref(), Some("OpenAI"));
|
||||
assert_eq!(rows.len(), 2);
|
||||
let provider_id_row = rows
|
||||
.iter()
|
||||
.find(|row| row.group_key == "provider-1")
|
||||
.expect("provider_id row should be present");
|
||||
assert_eq!(provider_id_row.display_name.as_deref(), Some("OpenAI"));
|
||||
assert_eq!(
|
||||
provider_id_row.secondary_name.as_deref(),
|
||||
Some("provider_id")
|
||||
);
|
||||
|
||||
let legacy_name_row = rows
|
||||
.iter()
|
||||
.find(|row| row.group_key == "Legacy Provider")
|
||||
.expect("legacy provider name row should be present");
|
||||
assert_eq!(
|
||||
legacy_name_row.display_name.as_deref(),
|
||||
Some("Legacy Provider")
|
||||
);
|
||||
assert_eq!(
|
||||
legacy_name_row.secondary_name.as_deref(),
|
||||
Some("legacy_name")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -3193,11 +3246,15 @@ mod tests {
|
||||
pending_provider.provider_id = None;
|
||||
pending_provider.provider_name = "pending".to_string();
|
||||
|
||||
let mut id_only_provider = sample_usage("req-id-only-provider", 350);
|
||||
id_only_provider.provider_name = "unknown".to_string();
|
||||
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![
|
||||
sample_usage("req-valid-provider", 400),
|
||||
unknown,
|
||||
typo_unknown,
|
||||
pending_provider,
|
||||
id_only_provider,
|
||||
]);
|
||||
|
||||
let model_rows = repository
|
||||
@@ -3212,7 +3269,7 @@ mod tests {
|
||||
.expect("model aggregation should succeed");
|
||||
assert_eq!(model_rows.len(), 1);
|
||||
assert_eq!(model_rows[0].group_key, "gpt-4.1");
|
||||
assert_eq!(model_rows[0].request_count, 1);
|
||||
assert_eq!(model_rows[0].request_count, 2);
|
||||
|
||||
let api_format_rows = repository
|
||||
.aggregate_usage_audits(&UsageAuditAggregationQuery {
|
||||
@@ -3226,7 +3283,7 @@ mod tests {
|
||||
.expect("api format aggregation should succeed");
|
||||
assert_eq!(api_format_rows.len(), 1);
|
||||
assert_eq!(api_format_rows[0].group_key, "openai:chat");
|
||||
assert_eq!(api_format_rows[0].request_count, 1);
|
||||
assert_eq!(api_format_rows[0].request_count, 2);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -1488,8 +1488,16 @@ const REBUILD_PROVIDER_API_KEY_CODEX_WINDOW_USAGE_STATS_SQL: &str =
|
||||
include_str!("queries/rebuild_provider_api_key_codex_window_usage_stats_sql.sql");
|
||||
|
||||
const LIST_USAGE_AUDITS_PREFIX: &str = include_str!("queries/list_usage_audits_prefix.sql");
|
||||
const USAGE_RESERVED_PROVIDER_LABELS_FILTER_SQL: &str = " AND BTRIM(COALESCE(\"usage\".provider_name, '')) <> '' AND lower(BTRIM(COALESCE(\"usage\".provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending')";
|
||||
const USAGE_PROVIDER_IDENTITY_FILTER_SQL: &str = " AND BTRIM(COALESCE(\"usage\".provider_id, '')) <> '' AND lower(BTRIM(COALESCE(\"usage\".provider_id, ''))) NOT IN ('unknown', 'unknow', 'pending')";
|
||||
const USAGE_PROVIDER_IDENTITY_FILTER_SQL: &str = r#" AND (
|
||||
(
|
||||
BTRIM(COALESCE("usage".provider_id, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE("usage".provider_id, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
)
|
||||
OR (
|
||||
BTRIM(COALESCE("usage".provider_name, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE("usage".provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
)
|
||||
)"#;
|
||||
const USAGE_RAW_PROVIDER_GROUP_KEY_SQL: &str = r#"CASE
|
||||
WHEN BTRIM(COALESCE("usage".provider_id, '')) = ''
|
||||
OR lower(BTRIM(COALESCE("usage".provider_id, ''))) IN ('unknown', 'unknow', 'pending')
|
||||
@@ -1502,13 +1510,33 @@ const USAGE_RAW_PROVIDER_DISPLAY_NAME_SQL: &str = r#"CASE
|
||||
THEN NULL
|
||||
ELSE BTRIM("usage".provider_name)
|
||||
END"#;
|
||||
const USAGE_PROVIDER_IDENTITY_SOURCE_SQL: &str = r#"CASE
|
||||
WHEN BTRIM(COALESCE("usage".provider_id, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE("usage".provider_id, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
THEN 'provider_id'
|
||||
WHEN BTRIM(COALESCE("usage".provider_name, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE("usage".provider_name, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
THEN 'legacy_name'
|
||||
ELSE NULL
|
||||
END"#;
|
||||
const USAGE_PROVIDER_IDENTITY_JOIN_SQL: &str = r#" LEFT JOIN providers AS provider_by_id
|
||||
ON BTRIM(COALESCE("usage".provider_id, '')) <> ''
|
||||
AND lower(BTRIM(COALESCE("usage".provider_id, ''))) NOT IN ('unknown', 'unknow', 'pending')
|
||||
AND provider_by_id.id = BTRIM("usage".provider_id)"#;
|
||||
const USAGE_RESOLVED_PROVIDER_GROUP_KEY_SQL: &str = r#"COALESCE(
|
||||
provider_by_id.id,
|
||||
BTRIM("usage".provider_id)
|
||||
CASE
|
||||
WHEN BTRIM(COALESCE("usage".provider_id, '')) = ''
|
||||
OR lower(BTRIM(COALESCE("usage".provider_id, ''))) IN ('unknown', 'unknow', 'pending')
|
||||
THEN NULL
|
||||
ELSE BTRIM("usage".provider_id)
|
||||
END,
|
||||
CASE
|
||||
WHEN BTRIM(COALESCE("usage".provider_name, '')) = ''
|
||||
OR lower(BTRIM(COALESCE("usage".provider_name, ''))) IN ('unknown', 'unknow', 'pending')
|
||||
THEN NULL
|
||||
ELSE BTRIM("usage".provider_name)
|
||||
END
|
||||
)"#;
|
||||
const USAGE_RESOLVED_PROVIDER_DISPLAY_NAME_SQL: &str = r#"COALESCE(
|
||||
provider_by_id.name,
|
||||
@@ -1558,9 +1586,9 @@ fn usage_audit_aggregation_sql_fragments(
|
||||
filtered_extra_where: "",
|
||||
group_key_expr: "provider_group_key",
|
||||
display_name_expr: "provider_display_name",
|
||||
secondary_name_expr: "NULL::varchar",
|
||||
secondary_name_expr: "provider_identity_source",
|
||||
aggregate_display_name_expr: "MAX(display_name)",
|
||||
aggregate_secondary_name_expr: "NULL::varchar",
|
||||
aggregate_secondary_name_expr: "CASE WHEN COUNT(*) FILTER (WHERE secondary_name = 'provider_id') > 0 THEN 'provider_id' WHEN COUNT(*) FILTER (WHERE secondary_name = 'legacy_name') > 0 THEN 'legacy_name' ELSE NULL END",
|
||||
avg_response_time_expr: "AVG(response_time_ms::DOUBLE PRECISION)",
|
||||
success_count_expr: "COALESCE(SUM(success_flag), 0)::BIGINT",
|
||||
},
|
||||
@@ -6687,10 +6715,10 @@ ORDER BY request_count DESC, group_key ASC
|
||||
) -> Result<Vec<StoredUsageAuditAggregation>, DataLayerError> {
|
||||
let fragments = usage_audit_aggregation_sql_fragments(query.group_by);
|
||||
let provider_extra_where =
|
||||
if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider) {
|
||||
if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider)
|
||||
|| query.exclude_reserved_provider_labels
|
||||
{
|
||||
USAGE_PROVIDER_IDENTITY_FILTER_SQL
|
||||
} else if query.exclude_reserved_provider_labels {
|
||||
USAGE_RESERVED_PROVIDER_LABELS_FILTER_SQL
|
||||
} else {
|
||||
""
|
||||
};
|
||||
@@ -6702,6 +6730,7 @@ WITH filtered_usage AS (
|
||||
"usage".user_id AS user_id,
|
||||
{provider_group_key_expr} AS provider_group_key,
|
||||
{provider_display_name_expr} AS provider_display_name,
|
||||
{provider_identity_source_expr} AS provider_identity_source,
|
||||
COALESCE("usage".api_format, 'unknown') AS api_format_group_key,
|
||||
GREATEST(COALESCE("usage".input_tokens, 0), 0) AS input_tokens,
|
||||
GREATEST(COALESCE("usage".output_tokens, 0), 0) AS output_tokens,
|
||||
@@ -6835,6 +6864,7 @@ LIMIT $3
|
||||
provider_identity_join = fragments.provider_identity_join,
|
||||
provider_group_key_expr = fragments.provider_group_key_expr,
|
||||
provider_display_name_expr = fragments.provider_display_name_expr,
|
||||
provider_identity_source_expr = USAGE_PROVIDER_IDENTITY_SOURCE_SQL,
|
||||
group_key_expr = fragments.group_key_expr,
|
||||
display_name_expr = fragments.display_name_expr,
|
||||
secondary_name_expr = fragments.secondary_name_expr,
|
||||
|
||||
@@ -464,16 +464,24 @@ fn usage_sql_aggregate_usage_audits_supports_daily_model_and_provider_aggregates
|
||||
#[test]
|
||||
fn usage_sql_provider_aggregation_excludes_unknown_provider_labels() {
|
||||
let source = include_str!("mod.rs");
|
||||
assert!(source.contains(
|
||||
r#"const USAGE_PROVIDER_IDENTITY_FILTER_SQL: &str = " AND BTRIM(COALESCE(\"usage\".provider_id, '')) <> ''"#
|
||||
));
|
||||
assert!(source.contains("const USAGE_PROVIDER_IDENTITY_FILTER_SQL"));
|
||||
assert!(source.contains("const USAGE_PROVIDER_IDENTITY_SOURCE_SQL"));
|
||||
assert!(source.contains(r#"BTRIM(COALESCE("usage".provider_id, '')) <> ''"#));
|
||||
assert!(source.contains(r#"BTRIM(COALESCE("usage".provider_name, '')) <> ''"#));
|
||||
assert!(source.contains("LEFT JOIN providers AS provider_by_id"));
|
||||
assert!(source.contains("provider_by_id.id = BTRIM(\"usage\".provider_id)"));
|
||||
assert!(source.contains("COALESCE(\n provider_by_id.id,\n CASE"));
|
||||
assert!(
|
||||
source.contains("COALESCE(\n provider_by_id.id,\n BTRIM(\"usage\".provider_id)")
|
||||
source.contains(
|
||||
"ELSE BTRIM(\"usage\".provider_id)\n END,\n CASE\n WHEN BTRIM(COALESCE(\"usage\".provider_name, ''))"
|
||||
)
|
||||
);
|
||||
assert!(source.contains("COALESCE(\n provider_by_id.name,"));
|
||||
assert!(!source.contains("provider_by_name.name = BTRIM(\"usage\".provider_name)"));
|
||||
assert!(source.contains("{provider_identity_source_expr} AS provider_identity_source"));
|
||||
assert!(source.contains(r#"secondary_name_expr: "provider_identity_source""#));
|
||||
assert!(source
|
||||
.contains("COUNT(*) FILTER (WHERE secondary_name = 'provider_id') > 0 THEN 'provider_id'"));
|
||||
assert!(source.contains(
|
||||
"if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider) {\n return self.aggregate_usage_audits_raw(query).await;"
|
||||
));
|
||||
|
||||
@@ -223,10 +223,19 @@ WHERE request_id = ?
|
||||
AND status IN ('streaming', 'success')
|
||||
"#;
|
||||
|
||||
const SQLITE_PROVIDER_NAME_IS_NOT_RESERVED: &str = r#"
|
||||
provider_name IS NOT NULL
|
||||
AND TRIM(provider_name) <> ''
|
||||
AND LOWER(TRIM(provider_name)) NOT IN ('unknown', 'unknow', 'pending')
|
||||
const SQLITE_PROVIDER_IDENTITY_IS_NOT_RESERVED: &str = r#"
|
||||
(
|
||||
(
|
||||
provider_id IS NOT NULL
|
||||
AND TRIM(provider_id) <> ''
|
||||
AND LOWER(TRIM(provider_id)) NOT IN ('unknown', 'unknow', 'pending')
|
||||
)
|
||||
OR (
|
||||
provider_name IS NOT NULL
|
||||
AND TRIM(provider_name) <> ''
|
||||
AND LOWER(TRIM(provider_name)) NOT IN ('unknown', 'unknow', 'pending')
|
||||
)
|
||||
)
|
||||
"#;
|
||||
|
||||
const SQLITE_USAGE_CACHE_CREATION_TOKENS_EXPR: &str = r#"
|
||||
@@ -617,6 +626,23 @@ THEN TRIM(provider_id) ELSE TRIM(provider_name) END"
|
||||
}
|
||||
}
|
||||
|
||||
fn sqlite_usage_aggregation_secondary_expr(group_by: UsageAuditAggregationGroupBy) -> &'static str {
|
||||
match group_by {
|
||||
UsageAuditAggregationGroupBy::Provider => {
|
||||
"CASE WHEN SUM(CASE WHEN provider_id IS NOT NULL \
|
||||
AND TRIM(provider_id) <> '' \
|
||||
AND LOWER(TRIM(provider_id)) NOT IN ('unknown', 'unknow', 'pending') \
|
||||
THEN 1 ELSE 0 END) > 0 THEN 'provider_id' \
|
||||
WHEN SUM(CASE WHEN provider_name IS NOT NULL \
|
||||
AND TRIM(provider_name) <> '' \
|
||||
AND LOWER(TRIM(provider_name)) NOT IN ('unknown', 'unknow', 'pending') \
|
||||
THEN 1 ELSE 0 END) > 0 THEN 'legacy_name' \
|
||||
ELSE NULL END"
|
||||
}
|
||||
_ => "NULL",
|
||||
}
|
||||
}
|
||||
|
||||
fn sqlite_aggregate_u64(row: &SqliteRow, field: &str) -> Result<u64, DataLayerError> {
|
||||
Ok(row.try_get::<i64, _>(field).map_sql_err()?.max(0) as u64)
|
||||
}
|
||||
@@ -682,7 +708,7 @@ fn decode_sqlite_usage_aggregation_row(
|
||||
Ok(StoredUsageAuditAggregation {
|
||||
group_key: row.try_get::<String, _>("group_key").map_sql_err()?,
|
||||
display_name: row.try_get("display_name").map_sql_err()?,
|
||||
secondary_name: None,
|
||||
secondary_name: row.try_get("secondary_name").map_sql_err()?,
|
||||
request_count: sqlite_aggregate_u64(row, "request_count")?,
|
||||
total_tokens: sqlite_aggregate_u64(row, "total_tokens")?,
|
||||
output_tokens: sqlite_aggregate_u64(row, "output_tokens")?,
|
||||
@@ -1323,8 +1349,9 @@ FROM "usage"
|
||||
}
|
||||
|
||||
let group_expr = sqlite_usage_aggregation_group_expr(query.group_by);
|
||||
let secondary_expr = sqlite_usage_aggregation_secondary_expr(query.group_by);
|
||||
let display_expr = if matches!(query.group_by, UsageAuditAggregationGroupBy::Provider) {
|
||||
"NULLIF(TRIM(provider_name), '')"
|
||||
"CASE WHEN provider_name IS NOT NULL AND TRIM(provider_name) <> '' AND LOWER(TRIM(provider_name)) NOT IN ('unknown', 'unknow', 'pending') THEN TRIM(provider_name) ELSE NULL END"
|
||||
} else {
|
||||
"NULL"
|
||||
};
|
||||
@@ -1348,6 +1375,7 @@ FROM "usage"
|
||||
SELECT
|
||||
{group_expr} AS group_key,
|
||||
{display_expr} AS display_name,
|
||||
{secondary_expr} AS secondary_name,
|
||||
COUNT(*) AS request_count,
|
||||
COALESCE(SUM(MAX(COALESCE(total_tokens, 0), 0)), 0) AS total_tokens,
|
||||
COALESCE(SUM(MAX(COALESCE(output_tokens, 0), 0)), 0) AS output_tokens,
|
||||
@@ -1368,6 +1396,7 @@ FROM "usage"
|
||||
"#,
|
||||
effective_input_expr = SQLITE_USAGE_EFFECTIVE_INPUT_TOKENS_EXPR,
|
||||
total_input_context_expr = SQLITE_USAGE_TOTAL_INPUT_CONTEXT_EXPR,
|
||||
secondary_expr = secondary_expr,
|
||||
cache_creation_expr = SQLITE_USAGE_CACHE_CREATION_TOKENS_EXPR
|
||||
));
|
||||
let mut has_where = false;
|
||||
@@ -1383,7 +1412,7 @@ FROM "usage"
|
||||
builder.push("status NOT IN ('pending', 'streaming')");
|
||||
if query.exclude_reserved_provider_labels {
|
||||
push_sqlite_usage_where(&mut builder, &mut has_where);
|
||||
builder.push(SQLITE_PROVIDER_NAME_IS_NOT_RESERVED);
|
||||
builder.push(SQLITE_PROVIDER_IDENTITY_IS_NOT_RESERVED);
|
||||
}
|
||||
if matches!(query.group_by, UsageAuditAggregationGroupBy::User) {
|
||||
push_sqlite_usage_where(&mut builder, &mut has_where);
|
||||
|
||||
Reference in New Issue
Block a user