703 lines
16 KiB
GLSL
Executable File
703 lines
16 KiB
GLSL
Executable File
#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
|
|
|
import db.sqlite
|
|
import db.pg
|
|
import time
|
|
// import lib.biz.planner.models
|
|
|
|
// Enums for better type safety
|
|
pub enum ChatType {
|
|
direct_message
|
|
group_chat
|
|
project_chat
|
|
team_chat
|
|
customer_chat
|
|
support_chat
|
|
announcement
|
|
}
|
|
|
|
pub enum ChatStatus {
|
|
active
|
|
inactive
|
|
archived
|
|
deleted
|
|
}
|
|
|
|
pub enum ChatVisibility {
|
|
private
|
|
public
|
|
restricted
|
|
}
|
|
|
|
pub enum MessageType {
|
|
text
|
|
image
|
|
file
|
|
audio
|
|
video
|
|
system
|
|
notification
|
|
}
|
|
|
|
pub enum MessagePriority {
|
|
low
|
|
normal
|
|
high
|
|
urgent
|
|
}
|
|
|
|
pub enum MessageDeliveryStatus {
|
|
pending
|
|
sent
|
|
delivered
|
|
read
|
|
failed
|
|
}
|
|
|
|
pub enum MemberRole {
|
|
owner
|
|
admin
|
|
moderator
|
|
member
|
|
guest
|
|
}
|
|
|
|
pub enum MemberStatus {
|
|
active
|
|
inactive
|
|
banned
|
|
left
|
|
}
|
|
|
|
// Parameter structs using @[params]
|
|
@[params]
|
|
pub struct ChatNewArgs {
|
|
pub mut:
|
|
name string
|
|
description ?string
|
|
chat_type ChatType
|
|
visibility ChatVisibility = .private
|
|
owner_id int
|
|
project_id ?int
|
|
team_id ?int
|
|
customer_id ?int
|
|
task_id ?int
|
|
issue_id ?int
|
|
milestone_id ?int
|
|
sprint_id ?int
|
|
agenda_id ?int
|
|
created_by int
|
|
}
|
|
|
|
@[params]
|
|
pub struct MessageNewArgs {
|
|
pub mut:
|
|
chat_id int
|
|
sender_id int
|
|
content string
|
|
message_type MessageType = .text
|
|
thread_id ?int
|
|
reply_to_id ?int
|
|
priority MessagePriority = .normal
|
|
scheduled_at ?u32
|
|
expires_at ?u32
|
|
created_by int
|
|
}
|
|
|
|
@[params]
|
|
pub struct ChatMemberNewArgs {
|
|
pub mut:
|
|
chat_id int
|
|
user_id int
|
|
role MemberRole = .member
|
|
invited_by ?int
|
|
}
|
|
|
|
@[params]
|
|
pub struct ChatListArgs {
|
|
pub mut:
|
|
chat_type ChatType = ChatType.direct_message // default value, will be ignored if not set
|
|
status ChatStatus = ChatStatus.active // default value, will be ignored if not set
|
|
owner_id int
|
|
limit int = 50
|
|
offset int
|
|
}
|
|
|
|
@[params]
|
|
pub struct ChatSearchArgs {
|
|
pub mut:
|
|
search_term string
|
|
limit int = 20
|
|
}
|
|
|
|
// Chat model for ORM - simplified version with ORM attributes
|
|
@[table: 'chat']
|
|
pub struct ChatORM {
|
|
pub mut:
|
|
id int @[primary; sql: serial]
|
|
name string
|
|
description ?string
|
|
chat_type ChatType
|
|
status ChatStatus
|
|
visibility ChatVisibility
|
|
owner_id int
|
|
project_id ?int
|
|
team_id ?int
|
|
customer_id ?int
|
|
task_id ?int
|
|
issue_id ?int
|
|
milestone_id ?int
|
|
sprint_id ?int
|
|
agenda_id ?int
|
|
last_activity u32
|
|
message_count int
|
|
file_count int
|
|
archived_at u32
|
|
created_at u32
|
|
updated_at u32
|
|
created_by int
|
|
updated_by int
|
|
version int
|
|
deleted_at u32
|
|
}
|
|
|
|
// Message model for ORM
|
|
@[table: 'message']
|
|
pub struct MessageORM {
|
|
pub mut:
|
|
id int @[primary; sql: serial]
|
|
chat_id int
|
|
sender_id int
|
|
content string
|
|
message_type MessageType
|
|
thread_id ?int
|
|
reply_to_id ?int
|
|
edited_at u32
|
|
edited_by ?int
|
|
deleted_at u32
|
|
deleted_by ?int
|
|
pinned bool
|
|
pinned_at u32
|
|
pinned_by ?int
|
|
forwarded_from ?int
|
|
scheduled_at u32
|
|
delivery_status MessageDeliveryStatus
|
|
priority MessagePriority
|
|
expires_at u32
|
|
system_message bool
|
|
bot_message bool
|
|
external_id ?string
|
|
created_at u32
|
|
updated_at u32
|
|
created_by int
|
|
updated_by int
|
|
version int
|
|
}
|
|
|
|
// ChatMember model for ORM
|
|
@[table: 'chat_member']
|
|
pub struct ChatMemberORM {
|
|
pub mut:
|
|
id int @[primary; sql: serial]
|
|
user_id int
|
|
chat_id int
|
|
role MemberRole
|
|
joined_at u32
|
|
last_read_at u32
|
|
last_read_message_id ?int
|
|
status MemberStatus
|
|
invited_by ?int
|
|
muted bool
|
|
muted_until u32
|
|
custom_title ?string
|
|
created_at u32
|
|
updated_at u32
|
|
}
|
|
|
|
// ChatRepository using V ORM
|
|
pub struct ChatRepository {
|
|
mut:
|
|
db sqlite.DB
|
|
}
|
|
|
|
// PostgreSQL version
|
|
pub struct ChatRepositoryPG {
|
|
mut:
|
|
db pg.DB
|
|
}
|
|
|
|
// Initialize SQLite database with ORM
|
|
pub fn new_chat_repository(db_path string) !ChatRepository {
|
|
mut db := sqlite.connect(db_path)!
|
|
|
|
// Create tables using ORM
|
|
sql db {
|
|
create table ChatORM
|
|
create table MessageORM
|
|
create table ChatMemberORM
|
|
}!
|
|
|
|
return ChatRepository{
|
|
db: db
|
|
}
|
|
}
|
|
|
|
// Initialize PostgreSQL database with ORM
|
|
pub fn new_chat_repository_pg(host string, port int, user string, password string, dbname string) !ChatRepositoryPG {
|
|
mut db := pg.connect(host: host, port: port, user: user, password: password, dbname: dbname)!
|
|
|
|
// Create tables using ORM
|
|
sql db {
|
|
create table ChatORM
|
|
create table MessageORM
|
|
create table ChatMemberORM
|
|
}!
|
|
|
|
return ChatRepositoryPG{
|
|
db: db
|
|
}
|
|
}
|
|
|
|
// Create a new chat using ORM
|
|
pub fn (mut repo ChatRepository) create_chat(args_ ChatNewArgs) !ChatORM {
|
|
mut args := args_
|
|
now := u32(time.now().unix())
|
|
mut chat := ChatORM{
|
|
name: args.name
|
|
description: args.description
|
|
chat_type: args.chat_type
|
|
status: .active
|
|
visibility: args.visibility
|
|
owner_id: args.owner_id
|
|
project_id: args.project_id
|
|
team_id: args.team_id
|
|
customer_id: args.customer_id
|
|
task_id: args.task_id
|
|
issue_id: args.issue_id
|
|
milestone_id: args.milestone_id
|
|
sprint_id: args.sprint_id
|
|
agenda_id: args.agenda_id
|
|
created_by: args.created_by
|
|
updated_by: args.created_by
|
|
created_at: now
|
|
updated_at: now
|
|
deleted_at: 0
|
|
last_activity: 0
|
|
message_count: 0
|
|
file_count: 0
|
|
archived_at: 0
|
|
version: 1
|
|
}
|
|
|
|
// Insert using ORM
|
|
sql repo.db {
|
|
insert chat into ChatORM
|
|
}!
|
|
|
|
// Get the last inserted ID
|
|
chat.id = repo.db.last_id()
|
|
|
|
return chat
|
|
}
|
|
|
|
// Get chat by ID using ORM
|
|
pub fn (repo ChatRepository) get_chat(id int) !ChatORM {
|
|
chat := sql repo.db {
|
|
select from ChatORM where id == id && deleted_at == 0
|
|
}!
|
|
|
|
if chat.len == 0 {
|
|
return error('Chat not found')
|
|
}
|
|
|
|
return chat[0]
|
|
}
|
|
|
|
// Update chat using ORM
|
|
pub fn (mut repo ChatRepository) update_chat(mut chat ChatORM, updated_by int) ! {
|
|
chat.updated_at = u32(time.now().unix())
|
|
chat.updated_by = updated_by
|
|
chat.version++
|
|
|
|
sql repo.db {
|
|
update ChatORM set name = chat.name, description = chat.description, status = chat.status,
|
|
updated_at = chat.updated_at, updated_by = chat.updated_by, version = chat.version
|
|
where id == chat.id
|
|
}!
|
|
}
|
|
|
|
// Delete chat (soft delete) using ORM
|
|
pub fn (mut repo ChatRepository) delete_chat(id int, deleted_by int) ! {
|
|
now := u32(time.now().unix())
|
|
|
|
sql repo.db {
|
|
update ChatORM set deleted_at = now, updated_by = deleted_by, updated_at = now where id == id
|
|
}!
|
|
}
|
|
|
|
// List chats with filtering using ORM
|
|
pub fn (repo ChatRepository) list_chats(args_ ChatListArgs) ![]ChatORM {
|
|
mut args := args_
|
|
mut chats := []ChatORM{}
|
|
|
|
if args.owner_id > 0 {
|
|
chats = sql repo.db {
|
|
select from ChatORM where owner_id == args.owner_id && deleted_at == 0 order by updated_at desc limit args.limit offset args.offset
|
|
}!
|
|
} else {
|
|
chats = sql repo.db {
|
|
select from ChatORM where deleted_at == 0 order by updated_at desc limit args.limit offset args.offset
|
|
}!
|
|
}
|
|
|
|
return chats
|
|
}
|
|
|
|
// Search chats by name using ORM
|
|
pub fn (repo ChatRepository) search_chats(args_ ChatSearchArgs) ![]ChatORM {
|
|
mut args := args_
|
|
chats := sql repo.db {
|
|
select from ChatORM where name like '%${args.search_term}%' && deleted_at == 0 order by updated_at desc limit args.limit
|
|
}!
|
|
|
|
return chats
|
|
}
|
|
|
|
// Get chats by project using ORM
|
|
pub fn (repo ChatRepository) get_chats_by_project(project_id int) ![]ChatORM {
|
|
chats := sql repo.db {
|
|
select from ChatORM where project_id == project_id && deleted_at == 0 order by updated_at desc
|
|
}!
|
|
|
|
return chats
|
|
}
|
|
|
|
// Get chats by team using ORM
|
|
pub fn (repo ChatRepository) get_chats_by_team(team_id int) ![]ChatORM {
|
|
chats := sql repo.db {
|
|
select from ChatORM where team_id == team_id && deleted_at == 0 order by updated_at desc
|
|
}!
|
|
|
|
return chats
|
|
}
|
|
|
|
// Count total chats using ORM
|
|
pub fn (repo ChatRepository) count_chats() !int {
|
|
result := sql repo.db {
|
|
select count from ChatORM where deleted_at == 0
|
|
}!
|
|
|
|
return result
|
|
}
|
|
|
|
// Add member to chat using ORM
|
|
pub fn (mut repo ChatRepository) add_chat_member(args_ ChatMemberNewArgs) !ChatMemberORM {
|
|
mut args := args_
|
|
now := u32(time.now().unix())
|
|
mut member := ChatMemberORM{
|
|
user_id: args.user_id
|
|
chat_id: args.chat_id
|
|
role: args.role
|
|
invited_by: args.invited_by
|
|
joined_at: now
|
|
created_at: now
|
|
updated_at: now
|
|
last_read_at: 0
|
|
status: .active
|
|
muted: false
|
|
muted_until: 0
|
|
}
|
|
|
|
sql repo.db {
|
|
insert member into ChatMemberORM
|
|
}!
|
|
|
|
// Get the last inserted ID
|
|
member.id = repo.db.last_id()
|
|
|
|
return member
|
|
}
|
|
|
|
// Get chat members using ORM
|
|
pub fn (repo ChatRepository) get_chat_members(chat_id int) ![]ChatMemberORM {
|
|
members := sql repo.db {
|
|
select from ChatMemberORM where chat_id == chat_id && status == MemberStatus.active order by joined_at
|
|
}!
|
|
|
|
return members
|
|
}
|
|
|
|
// Remove member from chat using ORM
|
|
pub fn (mut repo ChatRepository) remove_chat_member(chat_id int, user_id int) ! {
|
|
now := u32(time.now().unix())
|
|
sql repo.db {
|
|
update ChatMemberORM set status = MemberStatus.inactive, updated_at = now where
|
|
chat_id == chat_id && user_id == user_id
|
|
}!
|
|
}
|
|
|
|
// Send message using ORM
|
|
pub fn (mut repo ChatRepository) send_message(args_ MessageNewArgs) !MessageORM {
|
|
mut args := args_
|
|
now := u32(time.now().unix())
|
|
mut message := MessageORM{
|
|
chat_id: args.chat_id
|
|
sender_id: args.sender_id
|
|
content: args.content
|
|
message_type: args.message_type
|
|
thread_id: args.thread_id
|
|
reply_to_id: args.reply_to_id
|
|
priority: args.priority
|
|
scheduled_at: args.scheduled_at or { 0 }
|
|
expires_at: args.expires_at or { 0 }
|
|
created_by: args.created_by
|
|
updated_by: args.created_by
|
|
created_at: now
|
|
updated_at: now
|
|
deleted_at: 0
|
|
edited_at: 0
|
|
pinned: false
|
|
pinned_at: 0
|
|
delivery_status: .sent
|
|
system_message: false
|
|
bot_message: false
|
|
version: 1
|
|
}
|
|
|
|
sql repo.db {
|
|
insert message into MessageORM
|
|
}!
|
|
|
|
// Get the last inserted ID
|
|
message.id = repo.db.last_id()
|
|
|
|
// Update chat message count and last activity
|
|
sql repo.db {
|
|
update ChatORM set message_count = message_count + 1, last_activity = now, updated_at = now
|
|
where id == args.chat_id
|
|
}!
|
|
|
|
return message
|
|
}
|
|
|
|
// Get messages for chat using ORM
|
|
pub fn (repo ChatRepository) get_messages(chat_id int, limit int, offset int) ![]MessageORM {
|
|
messages := sql repo.db {
|
|
select from MessageORM where chat_id == chat_id && deleted_at == 0 order by created_at desc limit limit offset offset
|
|
}!
|
|
|
|
return messages
|
|
}
|
|
|
|
// Get message by ID using ORM
|
|
pub fn (repo ChatRepository) get_message(id int) !MessageORM {
|
|
message := sql repo.db {
|
|
select from MessageORM where id == id && deleted_at == 0
|
|
}!
|
|
|
|
if message.len == 0 {
|
|
return error('Message not found')
|
|
}
|
|
|
|
return message[0]
|
|
}
|
|
|
|
// Edit message using ORM
|
|
pub fn (mut repo ChatRepository) edit_message(id int, new_content string, edited_by int) ! {
|
|
now := u32(time.now().unix())
|
|
|
|
sql repo.db {
|
|
update MessageORM set content = new_content, edited_at = now, edited_by = edited_by,
|
|
updated_at = now where id == id
|
|
}!
|
|
}
|
|
|
|
// Delete message using ORM
|
|
pub fn (mut repo ChatRepository) delete_message(id int, deleted_by int) ! {
|
|
now := u32(time.now().unix())
|
|
|
|
sql repo.db {
|
|
update MessageORM set deleted_at = now, deleted_by = deleted_by, updated_at = now
|
|
where id == id
|
|
}!
|
|
}
|
|
|
|
// Pin message using ORM
|
|
pub fn (mut repo ChatRepository) pin_message(id int, pinned_by int) ! {
|
|
now := u32(time.now().unix())
|
|
|
|
sql repo.db {
|
|
update MessageORM set pinned = true, pinned_at = now, pinned_by = pinned_by, updated_at = now
|
|
where id == id
|
|
}!
|
|
}
|
|
|
|
// Get pinned messages using ORM
|
|
pub fn (repo ChatRepository) get_pinned_messages(chat_id int) ![]MessageORM {
|
|
messages := sql repo.db {
|
|
select from MessageORM where chat_id == chat_id && pinned == true && deleted_at == 0 order by pinned_at desc
|
|
}!
|
|
|
|
return messages
|
|
}
|
|
|
|
// Mark messages as read using ORM
|
|
pub fn (mut repo ChatRepository) mark_as_read(chat_id int, user_id int, message_id int) ! {
|
|
now := u32(time.now().unix())
|
|
|
|
sql repo.db {
|
|
update ChatMemberORM set last_read_at = now, last_read_message_id = message_id where
|
|
chat_id == chat_id && user_id == user_id
|
|
}!
|
|
}
|
|
|
|
// Get unread count using ORM
|
|
pub fn (repo ChatRepository) get_unread_count(chat_id int, user_id int) !int {
|
|
// Get user's last read message ID
|
|
member := sql repo.db {
|
|
select from ChatMemberORM where chat_id == chat_id && user_id == user_id
|
|
}!
|
|
|
|
if member.len == 0 {
|
|
return 0
|
|
}
|
|
|
|
last_read_id := member[0].last_read_message_id or { 0 }
|
|
|
|
// Count messages after last read
|
|
result := sql repo.db {
|
|
select count from MessageORM where chat_id == chat_id && id > last_read_id && deleted_at == 0
|
|
&& system_message == false
|
|
}!
|
|
|
|
return result
|
|
}
|
|
|
|
// Delete all data from repository (removes all records from all tables)
|
|
pub fn (mut repo ChatRepository) delete_all() ! {
|
|
sql repo.db {
|
|
delete from MessageORM where id > 0
|
|
}!
|
|
|
|
sql repo.db {
|
|
delete from ChatMemberORM where id > 0
|
|
}!
|
|
|
|
sql repo.db {
|
|
delete from ChatORM where id > 0
|
|
}!
|
|
}
|
|
|
|
// Delete all data from PostgreSQL repository (removes all records from all tables)
|
|
pub fn (mut repo ChatRepositoryPG) delete_all() ! {
|
|
sql repo.db {
|
|
delete from MessageORM where id > 0
|
|
}!
|
|
|
|
sql repo.db {
|
|
delete from ChatMemberORM where id > 0
|
|
}!
|
|
|
|
sql repo.db {
|
|
delete from ChatORM where id > 0
|
|
}!
|
|
}
|
|
|
|
// Example usage function
|
|
pub fn example_usage() ! {
|
|
// Initialize repository
|
|
mut repo := new_chat_repository('chat_example.db')!
|
|
|
|
// Create a new chat using the new parameter struct
|
|
mut chat := repo.create_chat(
|
|
name: 'Project Alpha Discussion'
|
|
chat_type: .project_chat
|
|
owner_id: 1
|
|
created_by: 1
|
|
)!
|
|
println('Created chat: ${chat.name} with ID: ${chat.id}')
|
|
|
|
// Add members to chat using the new parameter struct
|
|
member1 := repo.add_chat_member(
|
|
chat_id: chat.id
|
|
user_id: 2
|
|
role: .member
|
|
invited_by: 1
|
|
)!
|
|
member2 := repo.add_chat_member(
|
|
chat_id: chat.id
|
|
user_id: 3
|
|
role: .moderator
|
|
invited_by: 1
|
|
)!
|
|
println('Added members: ${member1.user_id}, ${member2.user_id}')
|
|
|
|
// Send messages using the new parameter struct
|
|
msg1 := repo.send_message(
|
|
chat_id: chat.id
|
|
sender_id: 1
|
|
content: 'Welcome to the project chat!'
|
|
message_type: .text
|
|
created_by: 1
|
|
)!
|
|
msg2 := repo.send_message(
|
|
chat_id: chat.id
|
|
sender_id: 2
|
|
content: 'Thanks for adding me!'
|
|
message_type: .text
|
|
created_by: 2
|
|
)!
|
|
println('Sent messages: ${msg1.id}, ${msg2.id}')
|
|
|
|
// Debug: Check what's in the database
|
|
all_messages := sql repo.db {
|
|
select from MessageORM
|
|
}!
|
|
println('Debug: Total messages in DB: ${all_messages.len}')
|
|
for i, msg in all_messages {
|
|
println(' DB Message ${i + 1}: ID=${msg.id}, chat_id=${msg.chat_id}, content="${msg.content}", deleted_at=${msg.deleted_at}')
|
|
}
|
|
|
|
// Get messages
|
|
messages := repo.get_messages(chat.id, 10, 0)!
|
|
println('Retrieved ${messages.len} messages')
|
|
for i, msg in messages {
|
|
println(' Message ${i + 1}: "${msg.content}" from user ${msg.sender_id}')
|
|
}
|
|
|
|
// Mark as read
|
|
repo.mark_as_read(chat.id, 2, msg2.id)!
|
|
|
|
// Get unread count
|
|
unread := repo.get_unread_count(chat.id, 3)!
|
|
println('User 3 has ${unread} unread messages')
|
|
|
|
// Search chats using the new parameter struct
|
|
found_chats := repo.search_chats(
|
|
search_term: 'Alpha'
|
|
limit: 5
|
|
)!
|
|
println('Found ${found_chats.len} chats matching "Alpha"')
|
|
for i, found_chat in found_chats {
|
|
println(' Chat ${i + 1}: "${found_chat.name}" (ID: ${found_chat.id})')
|
|
}
|
|
|
|
// Pin a message
|
|
repo.pin_message(msg1.id, 1)!
|
|
|
|
// Get pinned messages
|
|
pinned := repo.get_pinned_messages(chat.id)!
|
|
println('Found ${pinned.len} pinned messages')
|
|
for i, pinned_msg in pinned {
|
|
println(' Pinned message ${i + 1}: "${pinned_msg.content}"')
|
|
}
|
|
|
|
// Test the delete_all method
|
|
// println('Testing delete_all method...')
|
|
// repo.delete_all()!
|
|
// println('All data deleted successfully!')
|
|
}
|
|
|
|
// Run the example
|
|
example_usage() or { panic(err) }
|