|
@@ -29,194 +29,145 @@ AI日记的辅助AI应用,用户(User)、日记、聊天消息、动态、互
|
|
|
|
|
|
# UML类图
|
|
|
```plantuml
|
|
|
-@startuml AI日记系统数据库设计
|
|
|
-
|
|
|
-class _User {
|
|
|
- .. 系统预留字段 ..
|
|
|
- + objectId: String
|
|
|
- + username: String
|
|
|
- + email: String
|
|
|
- + emailVerified: bool
|
|
|
- + authData: Object
|
|
|
- + password: String
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- .. 自定义字段 ..
|
|
|
- + nickname: String
|
|
|
- + avatar: File
|
|
|
- + bio: String
|
|
|
- + lastActiveAt: Date
|
|
|
- + privacySettings: Object
|
|
|
-}
|
|
|
-
|
|
|
-class Diary {
|
|
|
- + objectId: String
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + title: String
|
|
|
- + content: String
|
|
|
- + author: Pointer<_User>
|
|
|
- + mood: String
|
|
|
- + tags: Array
|
|
|
- + isPublic: bool
|
|
|
- + location: GeoPoint
|
|
|
- + weather: Object
|
|
|
- + aiAnalysis: Object
|
|
|
+@startuml
|
|
|
+' 设置主题
|
|
|
+skinparam class {
|
|
|
+ BackgroundColor White
|
|
|
+ ArrowColor #0078D7
|
|
|
+ BorderColor #0078D7
|
|
|
}
|
|
|
|
|
|
-class ChatMessage {
|
|
|
- + objectId: String
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + sender: Pointer<_User>
|
|
|
- + receiver: Pointer<_User>
|
|
|
- + content: String
|
|
|
- + diaryRef: Pointer<Diary>
|
|
|
- + isRead: bool
|
|
|
- + messageType: String
|
|
|
- + attachments: Array<File>
|
|
|
+' 用户表(使用Parse预留表)
|
|
|
+class _User {
|
|
|
+ + objectId: String [PK]
|
|
|
+ + username: String
|
|
|
+ + email: String
|
|
|
+ + authData: Object
|
|
|
+ + emailVerified: bool
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + profilePicture: File
|
|
|
+ + lastActiveAt: Date
|
|
|
}
|
|
|
|
|
|
-class Moment {
|
|
|
- + objectId: String
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + creator: Pointer<_User>
|
|
|
- + content: String
|
|
|
- + images: Array<File>
|
|
|
- + refDiary: Pointer<Diary>
|
|
|
- + location: GeoPoint
|
|
|
- + tags: Array
|
|
|
- + interactionCount: Number
|
|
|
+' 动态表
|
|
|
+class Dynamic {
|
|
|
+ + objectId: String [PK]
|
|
|
+ + content: String
|
|
|
+ + images: Array<File>
|
|
|
+ + location: GeoPoint
|
|
|
+ + mood: String
|
|
|
+ + tags: Array<String>
|
|
|
+ + isPublic: bool
|
|
|
+ + likeCount: Number
|
|
|
+ + commentCount: Number
|
|
|
+ + shareCount: Number
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + author: Pointer<_User>
|
|
|
}
|
|
|
|
|
|
+' 互动表(包含点赞、评论、分享)
|
|
|
class Interaction {
|
|
|
- + objectId: String
|
|
|
- + createdAt: Date
|
|
|
- + updatedAt: Date
|
|
|
- + type: String
|
|
|
- + fromUser: Pointer<_User>
|
|
|
- + toUser: Pointer<_User>
|
|
|
- + targetType: String
|
|
|
- + targetId: Pointer
|
|
|
- + content: String
|
|
|
- + status: String
|
|
|
+ + objectId: String [PK]
|
|
|
+ + type: String // 'like'|'comment'|'share'
|
|
|
+ + content: String // 评论内容
|
|
|
+ + createdAt: Date
|
|
|
+ + updatedAt: Date
|
|
|
+ + user: Pointer<_User>
|
|
|
+ + diary: Pointer<Dynamic>
|
|
|
+ + targetUser: Pointer<_User> // 互动目标用户(分享给谁/回复谁)
|
|
|
}
|
|
|
|
|
|
' 关系定义
|
|
|
-_User "1" *-- "many" Diary : 创作
|
|
|
-_User "1" *-- "many" ChatMessage : 发送
|
|
|
-_User "1" *-- "many" Moment : 发布
|
|
|
-_User "1" *-- "many" Interaction : 发起
|
|
|
-
|
|
|
-Diary "1" *-- "many" ChatMessage : 关联
|
|
|
-Diary "1" *-- "many" Moment : 引用
|
|
|
-Diary "1" *-- "many" Interaction : 接收
|
|
|
-
|
|
|
-Moment "1" *-- "many" Interaction : 接收
|
|
|
-
|
|
|
+_User "1" --> "*" Dynamic : 发布
|
|
|
+_User "1" --> "*" Interaction : 发起
|
|
|
+Dynamic "1" --> "*" Interaction : 拥有
|
|
|
+_User "1" --> "*" Interaction : 接收互动(targetUser)
|
|
|
@enduml
|
|
|
```
|
|
|
# SQL语句
|
|
|
|
|
|
### 建表语句
|
|
|
```sql
|
|
|
-<!-- -- 注意:实际使用ParseServer时_User表已存在,此处仅为演示字段结构 -->
|
|
|
+-- 用户表(基于ParseServer的_User表结构扩展)
|
|
|
CREATE TABLE "_User" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "username" VARCHAR(255) UNIQUE NOT NULL,
|
|
|
- "email" VARCHAR(255) UNIQUE,
|
|
|
- "emailVerified" BOOLEAN DEFAULT false,
|
|
|
- "authData" JSONB,
|
|
|
- "password" VARCHAR(255),
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "nickname" VARCHAR(100),
|
|
|
- "avatar" VARCHAR(255), -- Parse.File存储路径
|
|
|
- "bio" TEXT,
|
|
|
- "lastActiveAt" TIMESTAMP WITH TIME ZONE,
|
|
|
- "privacySettings" JSONB
|
|
|
-);
|
|
|
-
|
|
|
-CREATE TABLE "Diary" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "title" VARCHAR(200) NOT NULL,
|
|
|
- "content" TEXT NOT NULL,
|
|
|
- "author" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "mood" VARCHAR(50),
|
|
|
- "tags" JSONB DEFAULT '[]'::JSONB,
|
|
|
- "isPublic" BOOLEAN DEFAULT false,
|
|
|
- "location" JSONB, -- {latitude: xx, longitude: xx}
|
|
|
- "weather" JSONB,
|
|
|
- "aiAnalysis" JSONB
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "username" VARCHAR(50) UNIQUE NOT NULL,
|
|
|
+ "email" VARCHAR(255) UNIQUE,
|
|
|
+ "authData" JSONB,
|
|
|
+ "emailVerified" BOOLEAN DEFAULT false,
|
|
|
+ "profilePicture" TEXT, -- Parse.File存储的URL
|
|
|
+ "lastActiveAt" TIMESTAMP WITH TIME ZONE,
|
|
|
+ "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
|
);
|
|
|
|
|
|
-CREATE TABLE "ChatMessage" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "sender" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "receiver" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "content" TEXT,
|
|
|
- "diaryRef" VARCHAR(36) REFERENCES "Diary"("objectId"),
|
|
|
- "isRead" BOOLEAN DEFAULT false,
|
|
|
- "messageType" VARCHAR(20) DEFAULT 'text',
|
|
|
- "attachments" JSONB DEFAULT '[]'::JSONB
|
|
|
-);
|
|
|
-
|
|
|
-CREATE TABLE "Moment" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "creator" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "content" TEXT,
|
|
|
- "images" JSONB DEFAULT '[]'::JSONB, -- Parse.File路径数组
|
|
|
- "refDiary" VARCHAR(36) REFERENCES "Diary"("objectId"),
|
|
|
- "location" JSONB,
|
|
|
- "tags" JSONB DEFAULT '[]'::JSONB,
|
|
|
- "interactionCount" INTEGER DEFAULT 0
|
|
|
+-- 动态表
|
|
|
+CREATE TABLE "Dynamic" (
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "content" TEXT NOT NULL,
|
|
|
+ "images" JSONB, -- 存储File URL数组
|
|
|
+ "location" JSONB, -- {latitude: xx, longitude: yy}
|
|
|
+ "mood" VARCHAR(20),
|
|
|
+ "tags" JSONB, -- 字符串数组
|
|
|
+ "isPublic" BOOLEAN DEFAULT true,
|
|
|
+ "likeCount" INTEGER DEFAULT 0,
|
|
|
+ "commentCount" INTEGER DEFAULT 0,
|
|
|
+ "shareCount" INTEGER DEFAULT 0,
|
|
|
+ "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "author" VARCHAR(36) NOT NULL REFERENCES "_User"("objectId")
|
|
|
);
|
|
|
|
|
|
+-- 互动表
|
|
|
CREATE TABLE "Interaction" (
|
|
|
- "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
- "createdAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "updatedAt" TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
|
- "type" VARCHAR(20) NOT NULL, -- like/comment/share
|
|
|
- "fromUser" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "toUser" VARCHAR(36) REFERENCES "_User"("objectId"),
|
|
|
- "targetType" VARCHAR(20) NOT NULL, -- Diary/Moment
|
|
|
- "targetId" VARCHAR(36), -- 多态关联
|
|
|
- "content" TEXT,
|
|
|
- "status" VARCHAR(20) DEFAULT 'unread'
|
|
|
+ "objectId" VARCHAR(36) PRIMARY KEY,
|
|
|
+ "type" VARCHAR(10) CHECK ("type" IN ('like', 'comment', 'share')),
|
|
|
+ "content" TEXT,
|
|
|
+ "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ "user" VARCHAR(36) NOT NULL REFERENCES "_User"("objectId"),
|
|
|
+ "diary" VARCHAR(36) NOT NULL REFERENCES "Dynamic"("objectId"),
|
|
|
+ "targetUser" VARCHAR(36) REFERENCES "_User"("objectId")
|
|
|
);
|
|
|
-```
|
|
|
|
|
|
-### 测试数据插入语句
|
|
|
-```sql
|
|
|
--- 插入测试用户
|
|
|
-INSERT INTO "_User" ("objectId", "username", "email", "nickname", "createdAt") VALUES
|
|
|
-('usr001', 'alice123', 'alice@example.com', 'Alice', NOW()),
|
|
|
-('usr002', 'bob456', 'bob@example.com', 'Bob', NOW());
|
|
|
-
|
|
|
--- 插入日记
|
|
|
-INSERT INTO "Diary" ("objectId", "title", "content", "author", "createdAt") VALUES
|
|
|
-('d001', '美好的一天', '今天天气晴朗...', 'usr001', NOW()),
|
|
|
-('d002', '项目总结', '完成了数据库设计...', 'usr002', NOW());
|
|
|
-
|
|
|
--- 插入动态
|
|
|
-INSERT INTO "Moment" ("objectId", "creator", "content", "refDiary", "createdAt") VALUES
|
|
|
-('m001', 'usr001', '分享我的日记', 'd001', NOW()),
|
|
|
-('m002', 'usr002', '技术分享', 'd002', NOW());
|
|
|
-
|
|
|
--- 插入互动
|
|
|
-INSERT INTO "Interaction" ("objectId", "type", "fromUser", "toUser", "targetType", "targetId", "content") VALUES
|
|
|
-('i001', 'like', 'usr002', 'usr001', 'Diary', 'd001', NULL),
|
|
|
-('i002', 'comment', 'usr001', 'usr002', 'Moment', 'm002', '写得真好!');
|
|
|
-
|
|
|
--- 插入聊天消息
|
|
|
-INSERT INTO "ChatMessage" ("objectId", "sender", "receiver", "content", "diaryRef") VALUES
|
|
|
-('msg001', 'usr001', 'usr002', '你好,看了你的日记', 'd002'),
|
|
|
-('msg002', 'usr002', 'usr001', '谢谢关注!', 'd002');
|
|
|
+-- 创建更新时间触发器函数
|
|
|
+CREATE OR REPLACE FUNCTION update_timestamp()
|
|
|
+RETURNS TRIGGER AS $$
|
|
|
+BEGIN
|
|
|
+ NEW."updatedAt" = CURRENT_TIMESTAMP;
|
|
|
+ RETURN NEW;
|
|
|
+END;
|
|
|
+$$ LANGUAGE plpgsql;
|
|
|
+
|
|
|
+-- 为每张表添加更新时间触发器
|
|
|
+CREATE TRIGGER update_user_timestamp
|
|
|
+BEFORE UPDATE ON "_User"
|
|
|
+FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
+
|
|
|
+CREATE TRIGGER update_diary_timestamp
|
|
|
+BEFORE UPDATE ON "Diary"
|
|
|
+FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
+
|
|
|
+CREATE TRIGGER update_interaction_timestamp
|
|
|
+BEFORE UPDATE ON "Interaction"
|
|
|
+FOR EACH ROW EXECUTE FUNCTION update_timestamp();
|
|
|
+
|
|
|
+-- 测试数据插入
|
|
|
+INSERT INTO "_User" ("objectId", "username", "email", "emailVerified", "profilePicture", "lastActiveAt")
|
|
|
+VALUES
|
|
|
+ ('usr001', 'testUser1', 'user1@example.com', true, 'https://example.com/pic1.jpg', NOW()),
|
|
|
+ ('usr002', 'testUser2', 'user2@example.com', true, 'https://example.com/pic2.jpg', NOW());
|
|
|
+
|
|
|
+INSERT INTO "Dynamic" ("objectId", "content", "images", "location", "mood", "tags", "isPublic", "author")
|
|
|
+VALUES
|
|
|
+ ('d001', '今天天气真好!', '["https://example.com/img1.jpg"]', '{"latitude": 39.9042, "longitude": 116.4074}', 'happy', '["天气","户外"]', true, 'usr001'),
|
|
|
+ ('d002', '学习PostgreSQL很有趣', '[]', NULL, 'excited', '["学习","数据库"]', true, 'usr002');
|
|
|
+
|
|
|
+INSERT INTO "Interaction" ("objectId", "type", "content", "user", "diary", "targetUser")
|
|
|
+VALUES
|
|
|
+ ('i001', 'like', NULL, 'usr002', 'd001', NULL),
|
|
|
+ ('i002', 'comment', '我也觉得天气不错!', 'usr002', 'd001', NULL),
|
|
|
+ ('i003', 'share', NULL, 'usr001', 'd002', 'usr002');
|
|
|
```
|