package com.imutil.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.imutil.entity.UsageStat; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import java.time.OffsetDateTime; /** * 用量统计 Mapper *
* 提供按小时窗口的聚合 upsert(PG ON CONFLICT 幂等,可重复跑)。
* 两个数据源各自 upsert 指定列,避免互相覆盖:
* - im_message → im_msg_count / im_dau
* - api_call_log → api_call_count
*
* @author imutil
*/
public interface UsageStatMapper extends BaseMapper
* 仅更新 im_msg_count / im_dau,不触碰已有 api_call_count。
*
* @param start 窗口起点(含)
* @param end 窗口终点(不含)
* @param statTime 统计时刻(=窗口起点整点,作为 usage_stat.stat_time)
* @return 受影响租户数
*/
@Insert("INSERT INTO usage_stat (tenant_id, stat_time, stat_level, im_msg_count, im_dau, " +
"api_call_count, trtc_duration_sec, trtc_max_concurrent_room, created_at) " +
"SELECT tenant_id, #{statTime}, 1, count(*), count(DISTINCT from_account), 0, 0, 0, now() " +
"FROM im_message WHERE created_at >= #{start} AND created_at < #{end} " +
"GROUP BY tenant_id " +
"ON CONFLICT (tenant_id, stat_time, stat_level) DO UPDATE SET " +
"im_msg_count = EXCLUDED.im_msg_count, im_dau = EXCLUDED.im_dau")
int aggregateMsgHour(@Param("start") OffsetDateTime start,
@Param("end") OffsetDateTime end,
@Param("statTime") OffsetDateTime statTime);
/**
* 从 api_call_log 聚合某小时窗口的腾讯 API 调用次数,upsert 到 usage_stat(stat_level=1 小时)
*
* 仅更新 api_call_count,不触碰已有 im_msg_count / im_dau。
*
* @return 受影响租户数
*/
@Insert("INSERT INTO usage_stat (tenant_id, stat_time, stat_level, im_msg_count, im_dau, " +
"api_call_count, trtc_duration_sec, trtc_max_concurrent_room, created_at) " +
"SELECT tenant_id, #{statTime}, 1, 0, 0, count(*), 0, 0, now() " +
"FROM api_call_log WHERE called_at >= #{start} AND called_at < #{end} " +
"GROUP BY tenant_id " +
"ON CONFLICT (tenant_id, stat_time, stat_level) DO UPDATE SET " +
"api_call_count = EXCLUDED.api_call_count")
int aggregateApiCallHour(@Param("start") OffsetDateTime start,
@Param("end") OffsetDateTime end,
@Param("statTime") OffsetDateTime statTime);
}