140 lines
5.1 KiB
PL/PgSQL
140 lines
5.1 KiB
PL/PgSQL
-- =====================================================================================
|
||
-- 4. 创建聊天会话表 (ml_chat_rooms)
|
||
-- 用于优化聊天列表查询性能,维护用户与商家的会话状态
|
||
-- 依赖表: public.ak_users, public.ml_chat_messages
|
||
-- =====================================================================================
|
||
|
||
-- 1. 创建表结构
|
||
CREATE TABLE IF NOT EXISTS public.ml_chat_rooms (
|
||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
user_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, -- 消费者ID
|
||
merchant_id UUID NOT NULL, -- 商家ID/店铺ID
|
||
shop_name VARCHAR(100), -- 缓存店铺名称
|
||
shop_logo TEXT, -- 缓存店铺Logo
|
||
last_message TEXT, -- 最后一条消息内容预览
|
||
last_message_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), -- 最后一条消息时间
|
||
unread_count INTEGER DEFAULT 0, -- 未读消息数
|
||
is_top BOOLEAN DEFAULT FALSE, -- 是否置顶
|
||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
|
||
-- 确保同一个用户和同一个商家只有一个会话
|
||
UNIQUE(user_id, merchant_id)
|
||
);
|
||
|
||
COMMENT ON TABLE public.ml_chat_rooms IS '聊天会话列表表';
|
||
|
||
-- 2. 开启 RLS
|
||
ALTER TABLE public.ml_chat_rooms ENABLE ROW LEVEL SECURITY;
|
||
|
||
-- 3. RLS 策略
|
||
|
||
-- 策略:用户只能查自己的会话
|
||
CREATE POLICY ml_chat_rooms_select_policy ON public.ml_chat_rooms
|
||
FOR SELECT USING (
|
||
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
|
||
);
|
||
|
||
-- 策略:允许插入(通常由触发器或后端逻辑维护)
|
||
CREATE POLICY ml_chat_rooms_insert_policy ON public.ml_chat_rooms
|
||
FOR INSERT WITH CHECK (
|
||
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
|
||
);
|
||
|
||
-- 策略:允许更新(如清除未读数)
|
||
CREATE POLICY ml_chat_rooms_update_policy ON public.ml_chat_rooms
|
||
FOR UPDATE USING (
|
||
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
|
||
);
|
||
|
||
|
||
-- =====================================================================================
|
||
-- 4. 触发器函数:自动维护会话列表
|
||
-- =====================================================================================
|
||
|
||
CREATE OR REPLACE FUNCTION public.handle_new_chat_message()
|
||
RETURNS TRIGGER AS $$
|
||
DECLARE
|
||
v_user_id UUID;
|
||
v_merchant_id UUID;
|
||
v_shop_name TEXT;
|
||
v_shop_logo TEXT;
|
||
v_is_from_user BOOLEAN;
|
||
v_count_inc INTEGER;
|
||
BEGIN
|
||
-- 确定谁是用户,谁是商家
|
||
-- 假设 is_from_user 为 true 时,sender_id 是用户,receiver_id 是商家
|
||
-- 假设 is_from_user 为 false 时,sender_id 是商家,receiver_id 是用户
|
||
|
||
v_is_from_user := NEW.is_from_user;
|
||
|
||
IF v_is_from_user THEN
|
||
v_user_id := NEW.sender_id;
|
||
v_merchant_id := NEW.receiver_id;
|
||
v_count_inc := 0; -- 用户自己发的,未读数不变
|
||
ELSE
|
||
v_user_id := NEW.receiver_id;
|
||
v_merchant_id := NEW.sender_id;
|
||
v_count_inc := 1; -- 商家发的,用户未读数 +1
|
||
END IF;
|
||
|
||
-- 尝试更新用户的会话
|
||
UPDATE public.ml_chat_rooms
|
||
SET
|
||
last_message = NEW.content,
|
||
last_message_at = NEW.created_at,
|
||
updated_at = NOW(),
|
||
unread_count = unread_count + v_count_inc
|
||
WHERE user_id = v_user_id AND merchant_id = v_merchant_id;
|
||
|
||
-- 如果没有更新到任何行(说明会话不存在),则插入新会话
|
||
IF NOT FOUND THEN
|
||
-- 尝试从 ml_shops 表获取店铺信息(如果有的话)
|
||
BEGIN
|
||
SELECT shop_name, shop_logo INTO v_shop_name, v_shop_logo
|
||
FROM public.ml_shops
|
||
WHERE merchant_id = v_merchant_id
|
||
LIMIT 1;
|
||
EXCEPTION WHEN OTHERS THEN
|
||
-- 忽略错误,使用默认值
|
||
v_shop_name := '未知店铺';
|
||
v_shop_logo := '';
|
||
END;
|
||
|
||
-- 如果没查到,给个默认名
|
||
IF v_shop_name IS NULL THEN
|
||
v_shop_name := '店铺 ' || substr(v_merchant_id::text, 1, 8);
|
||
END IF;
|
||
|
||
INSERT INTO public.ml_chat_rooms (
|
||
user_id,
|
||
merchant_id,
|
||
last_message,
|
||
last_message_at,
|
||
unread_count,
|
||
shop_name,
|
||
shop_logo
|
||
)
|
||
VALUES (
|
||
v_user_id,
|
||
v_merchant_id,
|
||
NEW.content,
|
||
NEW.created_at,
|
||
v_count_inc,
|
||
v_shop_name,
|
||
v_shop_logo
|
||
);
|
||
END IF;
|
||
|
||
RETURN NEW;
|
||
END;
|
||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||
|
||
|
||
-- 5. 创建触发器
|
||
DROP TRIGGER IF EXISTS on_chat_message_inserted ON public.ml_chat_messages;
|
||
CREATE TRIGGER on_chat_message_inserted
|
||
AFTER INSERT ON public.ml_chat_messages
|
||
FOR EACH ROW
|
||
EXECUTE FUNCTION public.handle_new_chat_message();
|