mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
chore: squash inactive mysql sqlite migrations
This commit is contained in:
@@ -18,6 +18,8 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
last_login_at BIGINT,
|
||||
ldap_dn VARCHAR(1024),
|
||||
ldap_username VARCHAR(255),
|
||||
UNIQUE KEY users_email_key (email),
|
||||
UNIQUE KEY users_username_key (username)
|
||||
);
|
||||
@@ -118,6 +120,51 @@ CREATE TABLE IF NOT EXISTS management_tokens (
|
||||
UNIQUE KEY uq_management_tokens_user_name (user_id, name),
|
||||
KEY management_tokens_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL UNIQUE,
|
||||
avatar_url VARCHAR(500),
|
||||
bio TEXT,
|
||||
default_provider_id VARCHAR(36),
|
||||
theme VARCHAR(20) NOT NULL DEFAULT 'light',
|
||||
language VARCHAR(10) NOT NULL DEFAULT 'zh-CN',
|
||||
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
usage_alerts BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
announcement_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_preferences_default_provider_id_idx (default_provider_id),
|
||||
INDEX user_preferences_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
client_device_id VARCHAR(128) NOT NULL,
|
||||
device_label VARCHAR(120),
|
||||
device_type VARCHAR(20) NOT NULL DEFAULT 'unknown',
|
||||
browser_name VARCHAR(50),
|
||||
browser_version VARCHAR(50),
|
||||
os_name VARCHAR(50),
|
||||
os_version VARCHAR(50),
|
||||
device_model VARCHAR(100),
|
||||
ip_address VARCHAR(45),
|
||||
user_agent VARCHAR(1000),
|
||||
client_hints TEXT,
|
||||
refresh_token_hash VARCHAR(64) NOT NULL,
|
||||
prev_refresh_token_hash VARCHAR(64),
|
||||
rotated_at BIGINT,
|
||||
last_seen_at BIGINT NOT NULL,
|
||||
expires_at BIGINT NOT NULL,
|
||||
revoked_at BIGINT,
|
||||
revoke_reason VARCHAR(100),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_sessions_user_active_idx (user_id, revoked_at, expires_at),
|
||||
INDEX user_sessions_user_device_idx (user_id, client_device_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS billing_rules (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
global_model_id VARCHAR(64),
|
||||
@@ -479,6 +526,8 @@ CREATE TABLE IF NOT EXISTS user_oauth_links (
|
||||
extra_data TEXT,
|
||||
linked_at BIGINT NOT NULL,
|
||||
last_login_at BIGINT,
|
||||
UNIQUE KEY uq_user_oauth_links_provider_user (provider_type, provider_user_id),
|
||||
UNIQUE KEY uq_user_oauth_links_user_provider (user_id, provider_type),
|
||||
KEY user_oauth_links_provider_type_idx (provider_type),
|
||||
KEY user_oauth_links_user_id_idx (user_id)
|
||||
);
|
||||
@@ -724,6 +773,7 @@ CREATE TABLE IF NOT EXISTS `usage` (
|
||||
provider_endpoint_kind VARCHAR(64),
|
||||
has_format_conversion TINYINT(1) NOT NULL DEFAULT 0,
|
||||
is_stream TINYINT(1) NOT NULL DEFAULT 0,
|
||||
upstream_is_stream TINYINT(1),
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
@@ -789,3 +839,182 @@ CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
|
||||
KEY usage_settlement_snapshots_billing_status_idx (billing_status),
|
||||
KEY usage_settlement_snapshots_wallet_id_idx (wallet_id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_hour (hour_utc)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user_model (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_model (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_provider (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
fallback_count BIGINT NOT NULL DEFAULT 0,
|
||||
unique_models BIGINT NOT NULL DEFAULT 0,
|
||||
unique_providers BIGINT NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_date (`date`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_model (`date`, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_provider (`date`, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
api_key_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
api_key_name VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_api_key (`date`, api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
error_category VARCHAR(255) NOT NULL,
|
||||
provider_name VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
count BIGINT NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_error (`date`, error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
username VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_user_daily (`date`, user_id)
|
||||
);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
event_type VARCHAR(64) NOT NULL,
|
||||
user_id VARCHAR(64),
|
||||
api_key_id VARCHAR(64),
|
||||
description TEXT NOT NULL,
|
||||
ip_address VARCHAR(64),
|
||||
user_agent VARCHAR(512),
|
||||
request_id VARCHAR(128),
|
||||
event_metadata TEXT,
|
||||
status_code INT,
|
||||
error_message TEXT,
|
||||
created_at BIGINT NOT NULL,
|
||||
KEY audit_logs_created_at_idx (created_at),
|
||||
KEY audit_logs_event_type_idx (event_type),
|
||||
KEY audit_logs_request_id_idx (request_id),
|
||||
KEY audit_logs_user_id_idx (user_id)
|
||||
);
|
||||
@@ -1,44 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL UNIQUE,
|
||||
avatar_url VARCHAR(500),
|
||||
bio TEXT,
|
||||
default_provider_id VARCHAR(36),
|
||||
theme VARCHAR(20) NOT NULL DEFAULT 'light',
|
||||
language VARCHAR(10) NOT NULL DEFAULT 'zh-CN',
|
||||
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
usage_alerts BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
announcement_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_preferences_default_provider_id_idx (default_provider_id),
|
||||
INDEX user_preferences_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
client_device_id VARCHAR(128) NOT NULL,
|
||||
device_label VARCHAR(120),
|
||||
device_type VARCHAR(20) NOT NULL DEFAULT 'unknown',
|
||||
browser_name VARCHAR(50),
|
||||
browser_version VARCHAR(50),
|
||||
os_name VARCHAR(50),
|
||||
os_version VARCHAR(50),
|
||||
device_model VARCHAR(100),
|
||||
ip_address VARCHAR(45),
|
||||
user_agent VARCHAR(1000),
|
||||
client_hints TEXT,
|
||||
refresh_token_hash VARCHAR(64) NOT NULL,
|
||||
prev_refresh_token_hash VARCHAR(64),
|
||||
rotated_at BIGINT,
|
||||
last_seen_at BIGINT NOT NULL,
|
||||
expires_at BIGINT NOT NULL,
|
||||
revoked_at BIGINT,
|
||||
revoke_reason VARCHAR(100),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_sessions_user_active_idx (user_id, revoked_at, expires_at),
|
||||
INDEX user_sessions_user_device_idx (user_id, client_device_id)
|
||||
);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE users ADD COLUMN ldap_dn VARCHAR(1024);
|
||||
ALTER TABLE users ADD COLUMN ldap_username VARCHAR(255);
|
||||
@@ -1,3 +0,0 @@
|
||||
ALTER TABLE user_oauth_links
|
||||
ADD UNIQUE KEY uq_user_oauth_links_provider_user (provider_type, provider_user_id),
|
||||
ADD UNIQUE KEY uq_user_oauth_links_user_provider (user_id, provider_type);
|
||||
@@ -1,177 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_hour (hour_utc)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user_model (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_model (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_provider (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
fallback_count BIGINT NOT NULL DEFAULT 0,
|
||||
unique_models BIGINT NOT NULL DEFAULT 0,
|
||||
unique_providers BIGINT NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_date (`date`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_model (`date`, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_provider (`date`, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
api_key_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
api_key_name VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_api_key (`date`, api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
error_category VARCHAR(255) NOT NULL,
|
||||
provider_name VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
count BIGINT NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_error (`date`, error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
username VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_user_daily (`date`, user_id)
|
||||
);
|
||||
@@ -17,7 +17,9 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
metadata TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
last_login_at INTEGER
|
||||
last_login_at INTEGER,
|
||||
ldap_dn TEXT,
|
||||
ldap_username TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
@@ -114,6 +116,55 @@ CREATE TABLE IF NOT EXISTS management_tokens (
|
||||
UNIQUE (user_id, name)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON management_tokens (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL UNIQUE,
|
||||
avatar_url TEXT,
|
||||
bio TEXT,
|
||||
default_provider_id TEXT,
|
||||
theme TEXT NOT NULL DEFAULT 'light',
|
||||
language TEXT NOT NULL DEFAULT 'zh-CN',
|
||||
timezone TEXT NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
usage_alerts INTEGER NOT NULL DEFAULT 1,
|
||||
announcement_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx
|
||||
ON user_preferences (default_provider_id);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx
|
||||
ON user_preferences (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
client_device_id TEXT NOT NULL,
|
||||
device_label TEXT,
|
||||
device_type TEXT NOT NULL DEFAULT 'unknown',
|
||||
browser_name TEXT,
|
||||
browser_version TEXT,
|
||||
os_name TEXT,
|
||||
os_version TEXT,
|
||||
device_model TEXT,
|
||||
ip_address TEXT,
|
||||
user_agent TEXT,
|
||||
client_hints TEXT,
|
||||
refresh_token_hash TEXT NOT NULL,
|
||||
prev_refresh_token_hash TEXT,
|
||||
rotated_at INTEGER,
|
||||
last_seen_at INTEGER NOT NULL,
|
||||
expires_at INTEGER NOT NULL,
|
||||
revoked_at INTEGER,
|
||||
revoke_reason TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx
|
||||
ON user_sessions (user_id, revoked_at, expires_at);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx
|
||||
ON user_sessions (user_id, client_device_id);
|
||||
CREATE TABLE IF NOT EXISTS billing_rules (
|
||||
id TEXT PRIMARY KEY,
|
||||
global_model_id TEXT,
|
||||
@@ -478,6 +529,10 @@ CREATE TABLE IF NOT EXISTS user_oauth_links (
|
||||
linked_at INTEGER NOT NULL,
|
||||
last_login_at INTEGER
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_provider_user
|
||||
ON user_oauth_links (provider_type, provider_user_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_user_provider
|
||||
ON user_oauth_links (user_id, provider_type);
|
||||
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON user_oauth_links (provider_type);
|
||||
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON user_oauth_links (user_id);
|
||||
CREATE TABLE IF NOT EXISTS proxy_nodes (
|
||||
@@ -741,6 +796,7 @@ CREATE TABLE IF NOT EXISTS "usage" (
|
||||
provider_endpoint_kind TEXT,
|
||||
has_format_conversion INTEGER NOT NULL DEFAULT 0,
|
||||
is_stream INTEGER NOT NULL DEFAULT 0,
|
||||
upstream_is_stream INTEGER,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -808,3 +864,180 @@ CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx
|
||||
ON usage_settlement_snapshots (billing_status);
|
||||
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx
|
||||
ON usage_settlement_snapshots (wallet_id);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
fallback_count INTEGER NOT NULL DEFAULT 0,
|
||||
unique_models INTEGER NOT NULL DEFAULT 0,
|
||||
unique_providers INTEGER NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id TEXT PRIMARY KEY,
|
||||
api_key_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
api_key_name TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
error_category TEXT NOT NULL,
|
||||
provider_name TEXT,
|
||||
model TEXT,
|
||||
count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
username TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", user_id)
|
||||
);
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id TEXT PRIMARY KEY,
|
||||
event_type TEXT NOT NULL,
|
||||
user_id TEXT,
|
||||
api_key_id TEXT,
|
||||
description TEXT NOT NULL,
|
||||
ip_address TEXT,
|
||||
user_agent TEXT,
|
||||
request_id TEXT,
|
||||
event_metadata TEXT,
|
||||
status_code INTEGER,
|
||||
error_message TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON audit_logs (created_at);
|
||||
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON audit_logs (event_type);
|
||||
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON audit_logs (request_id);
|
||||
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON audit_logs (user_id);
|
||||
@@ -1,48 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL UNIQUE,
|
||||
avatar_url TEXT,
|
||||
bio TEXT,
|
||||
default_provider_id TEXT,
|
||||
theme TEXT NOT NULL DEFAULT 'light',
|
||||
language TEXT NOT NULL DEFAULT 'zh-CN',
|
||||
timezone TEXT NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
usage_alerts INTEGER NOT NULL DEFAULT 1,
|
||||
announcement_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx
|
||||
ON user_preferences (default_provider_id);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx
|
||||
ON user_preferences (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
client_device_id TEXT NOT NULL,
|
||||
device_label TEXT,
|
||||
device_type TEXT NOT NULL DEFAULT 'unknown',
|
||||
browser_name TEXT,
|
||||
browser_version TEXT,
|
||||
os_name TEXT,
|
||||
os_version TEXT,
|
||||
device_model TEXT,
|
||||
ip_address TEXT,
|
||||
user_agent TEXT,
|
||||
client_hints TEXT,
|
||||
refresh_token_hash TEXT NOT NULL,
|
||||
prev_refresh_token_hash TEXT,
|
||||
rotated_at INTEGER,
|
||||
last_seen_at INTEGER NOT NULL,
|
||||
expires_at INTEGER NOT NULL,
|
||||
revoked_at INTEGER,
|
||||
revoke_reason TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx
|
||||
ON user_sessions (user_id, revoked_at, expires_at);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx
|
||||
ON user_sessions (user_id, client_device_id);
|
||||
@@ -1,2 +0,0 @@
|
||||
ALTER TABLE users ADD COLUMN ldap_dn TEXT;
|
||||
ALTER TABLE users ADD COLUMN ldap_username TEXT;
|
||||
@@ -1,5 +0,0 @@
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_provider_user
|
||||
ON user_oauth_links (provider_type, provider_user_id);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_user_provider
|
||||
ON user_oauth_links (user_id, provider_type);
|
||||
@@ -1,175 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
fallback_count INTEGER NOT NULL DEFAULT 0,
|
||||
unique_models INTEGER NOT NULL DEFAULT 0,
|
||||
unique_providers INTEGER NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id TEXT PRIMARY KEY,
|
||||
api_key_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
api_key_name TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
error_category TEXT NOT NULL,
|
||||
provider_name TEXT,
|
||||
model TEXT,
|
||||
count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
username TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", user_id)
|
||||
);
|
||||
@@ -18,6 +18,8 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
last_login_at BIGINT,
|
||||
ldap_dn VARCHAR(1024),
|
||||
ldap_username VARCHAR(255),
|
||||
UNIQUE KEY users_email_key (email),
|
||||
UNIQUE KEY users_username_key (username)
|
||||
);
|
||||
@@ -118,3 +120,48 @@ CREATE TABLE IF NOT EXISTS management_tokens (
|
||||
UNIQUE KEY uq_management_tokens_user_name (user_id, name),
|
||||
KEY management_tokens_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL UNIQUE,
|
||||
avatar_url VARCHAR(500),
|
||||
bio TEXT,
|
||||
default_provider_id VARCHAR(36),
|
||||
theme VARCHAR(20) NOT NULL DEFAULT 'light',
|
||||
language VARCHAR(10) NOT NULL DEFAULT 'zh-CN',
|
||||
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
usage_alerts BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
announcement_notifications BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_preferences_default_provider_id_idx (default_provider_id),
|
||||
INDEX user_preferences_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
client_device_id VARCHAR(128) NOT NULL,
|
||||
device_label VARCHAR(120),
|
||||
device_type VARCHAR(20) NOT NULL DEFAULT 'unknown',
|
||||
browser_name VARCHAR(50),
|
||||
browser_version VARCHAR(50),
|
||||
os_name VARCHAR(50),
|
||||
os_version VARCHAR(50),
|
||||
device_model VARCHAR(100),
|
||||
ip_address VARCHAR(45),
|
||||
user_agent VARCHAR(1000),
|
||||
client_hints TEXT,
|
||||
refresh_token_hash VARCHAR(64) NOT NULL,
|
||||
prev_refresh_token_hash VARCHAR(64),
|
||||
rotated_at BIGINT,
|
||||
last_seen_at BIGINT NOT NULL,
|
||||
expires_at BIGINT NOT NULL,
|
||||
revoked_at BIGINT,
|
||||
revoke_reason VARCHAR(100),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
INDEX user_sessions_user_active_idx (user_id, revoked_at, expires_at),
|
||||
INDEX user_sessions_user_device_idx (user_id, client_device_id)
|
||||
);
|
||||
|
||||
@@ -64,6 +64,8 @@ CREATE TABLE IF NOT EXISTS user_oauth_links (
|
||||
extra_data TEXT,
|
||||
linked_at BIGINT NOT NULL,
|
||||
last_login_at BIGINT,
|
||||
UNIQUE KEY uq_user_oauth_links_provider_user (provider_type, provider_user_id),
|
||||
UNIQUE KEY uq_user_oauth_links_user_provider (user_id, provider_type),
|
||||
KEY user_oauth_links_provider_type_idx (provider_type),
|
||||
KEY user_oauth_links_user_id_idx (user_id)
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS `usage` (
|
||||
provider_endpoint_kind VARCHAR(64),
|
||||
has_format_conversion TINYINT(1) NOT NULL DEFAULT 0,
|
||||
is_stream TINYINT(1) NOT NULL DEFAULT 0,
|
||||
upstream_is_stream TINYINT(1),
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
@@ -83,3 +84,182 @@ CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
|
||||
KEY usage_settlement_snapshots_billing_status_idx (billing_status),
|
||||
KEY usage_settlement_snapshots_wallet_id_idx (wallet_id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_hour (hour_utc)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_user_model (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_model (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
hour_utc BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_hourly_provider (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
fallback_count BIGINT NOT NULL DEFAULT 0,
|
||||
unique_models BIGINT NOT NULL DEFAULT 0,
|
||||
unique_providers BIGINT NOT NULL DEFAULT 0,
|
||||
is_complete TINYINT(1) NOT NULL DEFAULT 0,
|
||||
aggregated_at BIGINT,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_date (`date`)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
model VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_model (`date`, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
provider_name VARCHAR(255) NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_provider (`date`, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
api_key_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
api_key_name VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_api_key (`date`, api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
`date` BIGINT NOT NULL,
|
||||
error_category VARCHAR(255) NOT NULL,
|
||||
provider_name VARCHAR(255),
|
||||
model VARCHAR(255),
|
||||
count BIGINT NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_daily_error (`date`, error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
`date` BIGINT NOT NULL,
|
||||
total_requests BIGINT NOT NULL DEFAULT 0,
|
||||
success_requests BIGINT NOT NULL DEFAULT 0,
|
||||
error_requests BIGINT NOT NULL DEFAULT 0,
|
||||
input_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
output_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
|
||||
total_cost DOUBLE NOT NULL DEFAULT 0,
|
||||
username VARCHAR(255),
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
UNIQUE KEY uq_stats_user_daily (`date`, user_id)
|
||||
);
|
||||
|
||||
@@ -17,7 +17,9 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
metadata TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
last_login_at INTEGER
|
||||
last_login_at INTEGER,
|
||||
ldap_dn TEXT,
|
||||
ldap_username TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
@@ -114,3 +116,52 @@ CREATE TABLE IF NOT EXISTS management_tokens (
|
||||
UNIQUE (user_id, name)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON management_tokens (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_preferences (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL UNIQUE,
|
||||
avatar_url TEXT,
|
||||
bio TEXT,
|
||||
default_provider_id TEXT,
|
||||
theme TEXT NOT NULL DEFAULT 'light',
|
||||
language TEXT NOT NULL DEFAULT 'zh-CN',
|
||||
timezone TEXT NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
email_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
usage_alerts INTEGER NOT NULL DEFAULT 1,
|
||||
announcement_notifications INTEGER NOT NULL DEFAULT 1,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx
|
||||
ON user_preferences (default_provider_id);
|
||||
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx
|
||||
ON user_preferences (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
client_device_id TEXT NOT NULL,
|
||||
device_label TEXT,
|
||||
device_type TEXT NOT NULL DEFAULT 'unknown',
|
||||
browser_name TEXT,
|
||||
browser_version TEXT,
|
||||
os_name TEXT,
|
||||
os_version TEXT,
|
||||
device_model TEXT,
|
||||
ip_address TEXT,
|
||||
user_agent TEXT,
|
||||
client_hints TEXT,
|
||||
refresh_token_hash TEXT NOT NULL,
|
||||
prev_refresh_token_hash TEXT,
|
||||
rotated_at INTEGER,
|
||||
last_seen_at INTEGER NOT NULL,
|
||||
expires_at INTEGER NOT NULL,
|
||||
revoked_at INTEGER,
|
||||
revoke_reason TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx
|
||||
ON user_sessions (user_id, revoked_at, expires_at);
|
||||
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx
|
||||
ON user_sessions (user_id, client_device_id);
|
||||
|
||||
@@ -63,5 +63,9 @@ CREATE TABLE IF NOT EXISTS user_oauth_links (
|
||||
linked_at INTEGER NOT NULL,
|
||||
last_login_at INTEGER
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_provider_user
|
||||
ON user_oauth_links (provider_type, provider_user_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_user_provider
|
||||
ON user_oauth_links (user_id, provider_type);
|
||||
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON user_oauth_links (provider_type);
|
||||
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON user_oauth_links (user_id);
|
||||
|
||||
@@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS "usage" (
|
||||
provider_endpoint_kind TEXT,
|
||||
has_format_conversion INTEGER NOT NULL DEFAULT 0,
|
||||
is_stream INTEGER NOT NULL DEFAULT 0,
|
||||
upstream_is_stream INTEGER,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
@@ -85,3 +86,180 @@ CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx
|
||||
ON usage_settlement_snapshots (billing_status);
|
||||
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx
|
||||
ON usage_settlement_snapshots (wallet_id);
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, user_id, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
hour_utc INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE (hour_utc, provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL UNIQUE,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
actual_total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
fallback_count INTEGER NOT NULL DEFAULT 0,
|
||||
unique_models INTEGER NOT NULL DEFAULT 0,
|
||||
unique_providers INTEGER NOT NULL DEFAULT 0,
|
||||
is_complete INTEGER NOT NULL DEFAULT 0,
|
||||
aggregated_at INTEGER,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_model (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
model TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
avg_response_time_ms REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_provider (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", provider_name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
|
||||
id TEXT PRIMARY KEY,
|
||||
api_key_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
api_key_name TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", api_key_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_daily_error (
|
||||
id TEXT PRIMARY KEY,
|
||||
"date" INTEGER NOT NULL,
|
||||
error_category TEXT NOT NULL,
|
||||
provider_name TEXT,
|
||||
model TEXT,
|
||||
count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", error_category, provider_name, model)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS stats_user_daily (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
"date" INTEGER NOT NULL,
|
||||
total_requests INTEGER NOT NULL DEFAULT 0,
|
||||
success_requests INTEGER NOT NULL DEFAULT 0,
|
||||
error_requests INTEGER NOT NULL DEFAULT 0,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
total_cost REAL NOT NULL DEFAULT 0,
|
||||
username TEXT,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
UNIQUE ("date", user_id)
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS `usage` (
|
||||
`provider_endpoint_kind` VARCHAR(64),
|
||||
`has_format_conversion` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`is_stream` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`upstream_is_stream` TINYINT(1),
|
||||
`input_tokens` BIGINT NOT NULL DEFAULT 0,
|
||||
`output_tokens` BIGINT NOT NULL DEFAULT 0,
|
||||
`input_output_total_tokens` BIGINT NOT NULL DEFAULT 0,
|
||||
|
||||
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS public.usage (
|
||||
provider_endpoint_kind character varying(64),
|
||||
has_format_conversion boolean DEFAULT false NOT NULL,
|
||||
is_stream boolean DEFAULT false NOT NULL,
|
||||
upstream_is_stream boolean,
|
||||
input_tokens bigint DEFAULT 0 NOT NULL,
|
||||
output_tokens bigint DEFAULT 0 NOT NULL,
|
||||
input_output_total_tokens bigint DEFAULT 0 NOT NULL,
|
||||
|
||||
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS "usage" (
|
||||
provider_endpoint_kind TEXT,
|
||||
has_format_conversion INTEGER NOT NULL DEFAULT 0,
|
||||
is_stream INTEGER NOT NULL DEFAULT 0,
|
||||
upstream_is_stream INTEGER,
|
||||
input_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
output_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
input_output_total_tokens INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
@@ -114,6 +114,11 @@ name = "is_stream"
|
||||
type = "bool"
|
||||
default = false
|
||||
|
||||
[[table.usage.columns]]
|
||||
name = "upstream_is_stream"
|
||||
type = "bool"
|
||||
nullable = true
|
||||
|
||||
[[table.usage.columns]]
|
||||
name = "input_tokens"
|
||||
type = "int64"
|
||||
|
||||
@@ -478,24 +478,16 @@ fn split_baseline_sources_match_executable_migrations() {
|
||||
|
||||
#[test]
|
||||
fn mysql_and_sqlite_migrations_do_not_use_postgres_jsonb() {
|
||||
let mysql_sources = [
|
||||
include_str!("../../../migrations/mysql/20260403000000_baseline.sql"),
|
||||
include_str!("../../../migrations/mysql/20260504000000_add_audit_logs.sql"),
|
||||
include_str!("../../../migrations/mysql/20260504010000_add_auth_user_runtime_tables.sql"),
|
||||
include_str!("../../../migrations/mysql/20260504020000_add_ldap_user_columns.sql"),
|
||||
include_str!("../../../migrations/mysql/20260504030000_add_user_oauth_link_uniques.sql"),
|
||||
include_str!("../../../migrations/mysql/20260504040000_add_stats_aggregation_tables.sql"),
|
||||
];
|
||||
let sqlite_sources = [
|
||||
include_str!("../../../migrations/sqlite/20260403000000_baseline.sql"),
|
||||
include_str!("../../../migrations/sqlite/20260504000000_add_audit_logs.sql"),
|
||||
include_str!("../../../migrations/sqlite/20260504010000_add_auth_user_runtime_tables.sql"),
|
||||
include_str!("../../../migrations/sqlite/20260504020000_add_ldap_user_columns.sql"),
|
||||
include_str!("../../../migrations/sqlite/20260504030000_add_user_oauth_link_uniques.sql"),
|
||||
include_str!("../../../migrations/sqlite/20260504040000_add_stats_aggregation_tables.sql"),
|
||||
];
|
||||
let mysql_sources = super::mysql::MIGRATOR
|
||||
.iter()
|
||||
.filter(|migration| migration.migration_type.is_up_migration())
|
||||
.map(|migration| migration.sql.as_ref());
|
||||
let sqlite_sources = super::sqlite::MIGRATOR
|
||||
.iter()
|
||||
.filter(|migration| migration.migration_type.is_up_migration())
|
||||
.map(|migration| migration.sql.as_ref());
|
||||
|
||||
for source in mysql_sources.into_iter().chain(sqlite_sources) {
|
||||
for source in mysql_sources.chain(sqlite_sources) {
|
||||
assert!(
|
||||
!source.to_ascii_lowercase().contains("jsonb"),
|
||||
"Postgres jsonb must stay out of MySQL/SQLite migrations"
|
||||
@@ -503,6 +495,33 @@ fn mysql_and_sqlite_migrations_do_not_use_postgres_jsonb() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_and_sqlite_migrations_are_baseline_only_until_enabled() {
|
||||
let mysql_versions = super::mysql::MIGRATOR
|
||||
.iter()
|
||||
.filter(|migration| migration.migration_type.is_up_migration())
|
||||
.map(|migration| migration.version)
|
||||
.collect::<Vec<_>>();
|
||||
let sqlite_versions = super::sqlite::MIGRATOR
|
||||
.iter()
|
||||
.filter(|migration| migration.migration_type.is_up_migration())
|
||||
.map(|migration| migration.version)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(mysql_versions, vec![20260403000000]);
|
||||
assert_eq!(sqlite_versions, vec![20260403000000]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fresh_usage_schema_projects_upstream_stream_mode_for_all_drivers() {
|
||||
let mysql_baseline = include_str!("../../../migrations/mysql/20260403000000_baseline.sql");
|
||||
let sqlite_baseline = include_str!("../../../migrations/sqlite/20260403000000_baseline.sql");
|
||||
|
||||
assert!(EMPTY_DATABASE_SNAPSHOT_SQL.contains("upstream_is_stream boolean"));
|
||||
assert!(mysql_baseline.contains("upstream_is_stream TINYINT(1)"));
|
||||
assert!(sqlite_baseline.contains("upstream_is_stream INTEGER"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn api_format_normalization_migration_preserves_duplicate_endpoint_transports() {
|
||||
let Some(server) = ManagedPostgresServer::try_start()
|
||||
@@ -1088,6 +1107,17 @@ async fn sqlite_migrations_create_core_config_tables() {
|
||||
total_adjusted_exists, 1,
|
||||
"missing sqlite wallets.total_adjusted"
|
||||
);
|
||||
|
||||
let upstream_is_stream_exists: i64 =
|
||||
sqlx::query_scalar("SELECT COUNT(*) FROM pragma_table_info('usage') WHERE name = ?")
|
||||
.bind("upstream_is_stream")
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("sqlite usage column query should succeed");
|
||||
assert_eq!(
|
||||
upstream_is_stream_exists, 1,
|
||||
"missing sqlite usage.upstream_is_stream"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1258,6 +1288,23 @@ WHERE table_schema = DATABASE()
|
||||
total_adjusted_exists, 1,
|
||||
"missing mysql wallets.total_adjusted"
|
||||
);
|
||||
|
||||
let upstream_is_stream_exists: i64 = sqlx::query_scalar(
|
||||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'usage'
|
||||
AND column_name = 'upstream_is_stream'
|
||||
"#,
|
||||
)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("mysql usage column query should succeed");
|
||||
assert_eq!(
|
||||
upstream_is_stream_exists, 1,
|
||||
"missing mysql usage.upstream_is_stream"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -34,6 +34,7 @@ SELECT
|
||||
provider_endpoint_kind,
|
||||
has_format_conversion,
|
||||
is_stream,
|
||||
upstream_is_stream,
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
total_tokens,
|
||||
@@ -89,6 +90,7 @@ INSERT INTO `usage` (
|
||||
provider_endpoint_kind,
|
||||
has_format_conversion,
|
||||
is_stream,
|
||||
upstream_is_stream,
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
total_tokens,
|
||||
@@ -122,7 +124,8 @@ INSERT INTO `usage` (
|
||||
updated_at_unix_secs
|
||||
) VALUES (
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
user_id = VALUES(user_id),
|
||||
@@ -142,6 +145,7 @@ ON DUPLICATE KEY UPDATE
|
||||
provider_endpoint_kind = VALUES(provider_endpoint_kind),
|
||||
has_format_conversion = VALUES(has_format_conversion),
|
||||
is_stream = VALUES(is_stream),
|
||||
upstream_is_stream = VALUES(upstream_is_stream),
|
||||
input_tokens = VALUES(input_tokens),
|
||||
output_tokens = VALUES(output_tokens),
|
||||
total_tokens = VALUES(total_tokens),
|
||||
@@ -736,6 +740,7 @@ fn bind_upsert<'q>(
|
||||
.bind(usage.provider_endpoint_kind.as_deref())
|
||||
.bind(usage.has_format_conversion.unwrap_or(false))
|
||||
.bind(usage.is_stream.unwrap_or(false))
|
||||
.bind(usage_upstream_is_stream(usage))
|
||||
.bind(to_i64(input_tokens, "input_tokens")?)
|
||||
.bind(to_i64(output_tokens, "output_tokens")?)
|
||||
.bind(to_i64(total_tokens, "total_tokens")?)
|
||||
@@ -845,6 +850,10 @@ fn map_usage_row(row: &MySqlRow) -> Result<StoredRequestUsageAudit, DataLayerErr
|
||||
.map(|raw| serde_json::from_str(&raw))
|
||||
.transpose()
|
||||
.map_err(|err| DataLayerError::UnexpectedValue(err.to_string()))?;
|
||||
let upstream_is_stream = row
|
||||
.try_get::<Option<bool>, _>("upstream_is_stream")
|
||||
.map_sql_err()?;
|
||||
merge_usage_stream_metadata(&mut audit.request_metadata, upstream_is_stream);
|
||||
audit.candidate_id = row.try_get("candidate_id").map_sql_err()?;
|
||||
audit.candidate_index = row
|
||||
.try_get::<Option<i64>, _>("candidate_index")
|
||||
@@ -865,6 +874,29 @@ fn to_i64(value: u64, field: &str) -> Result<i64, DataLayerError> {
|
||||
i64::try_from(value).map_err(|_| DataLayerError::InvalidInput(format!("{field} overflow")))
|
||||
}
|
||||
|
||||
fn usage_upstream_is_stream(usage: &UpsertUsageRecord) -> bool {
|
||||
usage
|
||||
.request_metadata
|
||||
.as_ref()
|
||||
.and_then(serde_json::Value::as_object)
|
||||
.and_then(|metadata| metadata.get("upstream_is_stream"))
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or_else(|| usage.is_stream.unwrap_or(false))
|
||||
}
|
||||
|
||||
fn merge_usage_stream_metadata(metadata: &mut Option<serde_json::Value>, upstream: Option<bool>) {
|
||||
let Some(upstream) = upstream else {
|
||||
return;
|
||||
};
|
||||
let value = metadata.get_or_insert_with(|| serde_json::json!({}));
|
||||
let Some(object) = value.as_object_mut() else {
|
||||
return;
|
||||
};
|
||||
object
|
||||
.entry("upstream_is_stream")
|
||||
.or_insert(serde_json::Value::Bool(upstream));
|
||||
}
|
||||
|
||||
fn row_i32(row: &MySqlRow, field: &str) -> Result<i32, DataLayerError> {
|
||||
let value: i64 = row.try_get(field).map_sql_err()?;
|
||||
i32::try_from(value).map_err(|_| DataLayerError::UnexpectedValue(format!("{field} overflow")))
|
||||
@@ -954,6 +986,17 @@ mod tests {
|
||||
Some(provider_key_id.as_str())
|
||||
);
|
||||
assert_eq!(record.total_tokens, 7);
|
||||
assert_eq!(
|
||||
record.request_metadata.as_ref().unwrap()["upstream_is_stream"],
|
||||
true
|
||||
);
|
||||
let upstream_is_stream: Option<bool> =
|
||||
sqlx::query_scalar("SELECT upstream_is_stream FROM `usage` WHERE request_id = ?")
|
||||
.bind(format!("request-{suffix}"))
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("usage stream mode should load");
|
||||
assert_eq!(upstream_is_stream, Some(true));
|
||||
|
||||
let stats = sqlx::query_as::<_, (i64, i64, f64, Option<i64>)>(
|
||||
"SELECT total_requests, total_tokens, total_cost_usd, last_used_at FROM api_keys WHERE id = ?",
|
||||
@@ -1196,7 +1239,10 @@ VALUES (?, ?, ?, 1, 1)
|
||||
route_kind: Some("completion".to_string()),
|
||||
execution_path: Some("remote".to_string()),
|
||||
local_execution_runtime_miss_reason: None,
|
||||
request_metadata: Some(serde_json::json!({ "trace_id": "trace-1" })),
|
||||
request_metadata: Some(serde_json::json!({
|
||||
"trace_id": "trace-1",
|
||||
"upstream_is_stream": true,
|
||||
})),
|
||||
finalized_at_unix_secs: Some(updated_at),
|
||||
created_at_unix_ms: Some(updated_at),
|
||||
updated_at_unix_secs: updated_at,
|
||||
|
||||
@@ -34,6 +34,7 @@ SELECT
|
||||
provider_endpoint_kind,
|
||||
has_format_conversion,
|
||||
is_stream,
|
||||
upstream_is_stream,
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
total_tokens,
|
||||
@@ -89,6 +90,7 @@ INSERT INTO "usage" (
|
||||
provider_endpoint_kind,
|
||||
has_format_conversion,
|
||||
is_stream,
|
||||
upstream_is_stream,
|
||||
input_tokens,
|
||||
output_tokens,
|
||||
total_tokens,
|
||||
@@ -122,7 +124,8 @@ INSERT INTO "usage" (
|
||||
updated_at_unix_secs
|
||||
) VALUES (
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?
|
||||
)
|
||||
ON CONFLICT (request_id) DO UPDATE SET
|
||||
user_id = excluded.user_id,
|
||||
@@ -142,6 +145,7 @@ ON CONFLICT (request_id) DO UPDATE SET
|
||||
provider_endpoint_kind = excluded.provider_endpoint_kind,
|
||||
has_format_conversion = excluded.has_format_conversion,
|
||||
is_stream = excluded.is_stream,
|
||||
upstream_is_stream = excluded.upstream_is_stream,
|
||||
input_tokens = excluded.input_tokens,
|
||||
output_tokens = excluded.output_tokens,
|
||||
total_tokens = excluded.total_tokens,
|
||||
@@ -738,6 +742,7 @@ fn bind_upsert<'q>(
|
||||
.bind(usage.provider_endpoint_kind.as_deref())
|
||||
.bind(i64::from(usage.has_format_conversion.unwrap_or(false)))
|
||||
.bind(i64::from(usage.is_stream.unwrap_or(false)))
|
||||
.bind(i64::from(usage_upstream_is_stream(usage)))
|
||||
.bind(to_i64(input_tokens, "input_tokens")?)
|
||||
.bind(to_i64(output_tokens, "output_tokens")?)
|
||||
.bind(to_i64(total_tokens, "total_tokens")?)
|
||||
@@ -841,6 +846,11 @@ fn map_usage_row(row: &SqliteRow) -> Result<StoredRequestUsageAudit, DataLayerEr
|
||||
.map(|raw| serde_json::from_str(&raw))
|
||||
.transpose()
|
||||
.map_err(|err| DataLayerError::UnexpectedValue(err.to_string()))?;
|
||||
let upstream_is_stream = row
|
||||
.try_get::<Option<i64>, _>("upstream_is_stream")
|
||||
.map_sql_err()?
|
||||
.map(|value| value != 0);
|
||||
merge_usage_stream_metadata(&mut audit.request_metadata, upstream_is_stream);
|
||||
audit.candidate_id = row.try_get("candidate_id").map_sql_err()?;
|
||||
audit.candidate_index = row
|
||||
.try_get::<Option<i64>, _>("candidate_index")
|
||||
@@ -861,6 +871,29 @@ fn to_i64(value: u64, field: &str) -> Result<i64, DataLayerError> {
|
||||
i64::try_from(value).map_err(|_| DataLayerError::InvalidInput(format!("{field} overflow")))
|
||||
}
|
||||
|
||||
fn usage_upstream_is_stream(usage: &UpsertUsageRecord) -> bool {
|
||||
usage
|
||||
.request_metadata
|
||||
.as_ref()
|
||||
.and_then(serde_json::Value::as_object)
|
||||
.and_then(|metadata| metadata.get("upstream_is_stream"))
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
.unwrap_or_else(|| usage.is_stream.unwrap_or(false))
|
||||
}
|
||||
|
||||
fn merge_usage_stream_metadata(metadata: &mut Option<serde_json::Value>, upstream: Option<bool>) {
|
||||
let Some(upstream) = upstream else {
|
||||
return;
|
||||
};
|
||||
let value = metadata.get_or_insert_with(|| serde_json::json!({}));
|
||||
let Some(object) = value.as_object_mut() else {
|
||||
return;
|
||||
};
|
||||
object
|
||||
.entry("upstream_is_stream")
|
||||
.or_insert(serde_json::Value::Bool(upstream));
|
||||
}
|
||||
|
||||
fn row_i32(row: &SqliteRow, field: &str) -> Result<i32, DataLayerError> {
|
||||
let value: i64 = row.try_get(field).map_sql_err()?;
|
||||
i32::try_from(value).map_err(|_| DataLayerError::UnexpectedValue(format!("{field} overflow")))
|
||||
@@ -916,6 +949,17 @@ mod tests {
|
||||
record.request_metadata.as_ref().unwrap()["trace_id"],
|
||||
"trace-1"
|
||||
);
|
||||
assert_eq!(
|
||||
record.request_metadata.as_ref().unwrap()["upstream_is_stream"],
|
||||
true
|
||||
);
|
||||
let upstream_is_stream: Option<i64> =
|
||||
sqlx::query_scalar("SELECT upstream_is_stream FROM \"usage\" WHERE request_id = ?")
|
||||
.bind("request-1")
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.expect("usage stream mode should load");
|
||||
assert_eq!(upstream_is_stream, Some(1));
|
||||
|
||||
let loaded = repository
|
||||
.find_by_request_id("request-1")
|
||||
@@ -1216,7 +1260,10 @@ VALUES ('provider-key-1', 'provider-1', 'Provider Key One', 1, 1);
|
||||
route_kind: Some("completion".to_string()),
|
||||
execution_path: Some("remote".to_string()),
|
||||
local_execution_runtime_miss_reason: None,
|
||||
request_metadata: Some(serde_json::json!({ "trace_id": "trace-1" })),
|
||||
request_metadata: Some(serde_json::json!({
|
||||
"trace_id": "trace-1",
|
||||
"upstream_is_stream": true,
|
||||
})),
|
||||
finalized_at_unix_secs: Some(updated_at),
|
||||
created_at_unix_ms: Some(updated_at),
|
||||
updated_at_unix_secs: updated_at,
|
||||
|
||||
Reference in New Issue
Block a user