Files
go-socket/packages/postgresql/postgresql.go
T

764 lines
24 KiB
Go

package postgresql
import (
"context"
"fmt"
"strings"
"time"
"go-socket/packages/convertions"
"go-socket/packages/types"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
var dbConn *pgxpool.Pool
func Init(ctx context.Context) {
var err error
dbConn, err = pgxpool.New(ctx, "postgres://master:secret@localhost:5432") // TODO change to env in production
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `CREATE EXTENSION IF NOT EXISTS "pgcrypto";`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT UNIQUE NOT NULL,
pass_hash TEXT NOT NULL,
pronouns TEXT DEFAULT NULL,
description TEXT DEFAULT NULL,
avatar TEXT DEFAULT NULL,
profile_bg TEXT DEFAULT NULL,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS user_connections (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
requestor_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
recipient_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
state SMALLINT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS direct_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sender_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
receiver_id UUID NOT NULL REFERENCES user_connections(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
content TEXT NOT NULL,
attached_file TEXT NOT NULL DEFAULT ''
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hubs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
icon_url TEXT,
background_url TEXT,
creator UUID NOT NULL REFERENCES users(id),
join_role SMALLINT,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295),
user_color_allowed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_roles (
id SMALLINT NOT NULL,
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL,
permissions BIGINT NOT NULL DEFAULT 0,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, hub_id)
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_channel (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT,
icon_url TEXT,
position SMALLINT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
roles_can_view_0 BIGINT NOT NULL DEFAULT 0,
roles_can_view_1 BIGINT NOT NULL DEFAULT 0,
roles_can_view_2 BIGINT NOT NULL DEFAULT 0,
roles_can_message_0 BIGINT NOT NULL DEFAULT 0,
roles_can_message_1 BIGINT NOT NULL DEFAULT 0,
roles_can_message_2 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_0 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_1 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_2 BIGINT NOT NULL DEFAULT 0
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_users (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL DEFAULT '',
roles_0 BIGINT NOT NULL DEFAULT 0,
roles_1 BIGINT NOT NULL DEFAULT 0,
roles_2 BIGINT NOT NULL DEFAULT 0,
is_muted BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, hub_id)
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_channel_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sender_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
receiver_id UUID NOT NULL REFERENCES hub_channel(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
content TEXT NOT NULL,
attached_file TEXT NOT NULL DEFAULT ''
)
`)
if err != nil {
panic(err)
}
}
func UserSave(ctx context.Context, user *types.User) error {
err := dbConn.QueryRow(ctx, `
INSERT INTO users (name, pass_hash, pronouns, rgba, created_at)
VALUES ($1, $2, $3, $4, $5)
RETURNING id
`, user.Name, user.PasswordHash, user.Pronouns, convertions.RgbaToUint32(user.Color), user.CreatedAt).
Scan(&user.Id)
return err
}
func UserDelete(ctx context.Context, id uuid.UUID) error {
_, err := dbConn.Exec(ctx, `
DELETE FROM users WHERE id = $1
`, id)
return err
}
func UserGetStandardInfoByName(ctx context.Context, user *types.User) error {
var rgba int64
err := dbConn.QueryRow(ctx, `
SELECT id, name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE name = $1
`, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarKey, &user.ProfileBgKey)
if err == nil {
user.Color = convertions.Uint32ToRgba(uint32(rgba))
}
return err
}
func UserGetById(ctx context.Context, user *types.User) error {
var rgba int64
err := dbConn.QueryRow(ctx, `
SELECT name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE id = $1
`, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarKey, &user.ProfileBgKey)
if err == nil {
user.Color = convertions.Uint32ToRgba(uint32(rgba))
}
return err
}
func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types.UserProfileUpdate) error {
setClauses := make([]string, 0, 3)
args := make([]any, 0, 4)
argIdx := 1
if updateList.Pronouns {
setClauses = append(setClauses, fmt.Sprintf("pronouns = $%d", argIdx))
args = append(args, user.Pronouns)
argIdx++
}
if updateList.Description {
setClauses = append(setClauses, fmt.Sprintf("description = $%d", argIdx))
args = append(args, user.Description)
argIdx++
}
if updateList.Color {
setClauses = append(setClauses, fmt.Sprintf("rgba = $%d", argIdx))
args = append(args, convertions.RgbaToUint32(user.Color))
argIdx++
}
if updateList.Avatar {
setClauses = append(setClauses, fmt.Sprintf("avatar = $%d", argIdx))
args = append(args, user.AvatarKey)
argIdx++
}
if updateList.ProfileBg {
setClauses = append(setClauses, fmt.Sprintf("profile_bg = $%d", argIdx))
args = append(args, user.ProfileBgKey)
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE users SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
args = append(args, user.Id)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func UserGetBelongingHubs(ctx context.Context, user *types.User) error {
rows, err := dbConn.Query(ctx, `
SELECT h.id, h.name, COALESCE(h.icon_url, ''), COALESCE(h.background_url, ''), h.creator, h.join_role, h.rgba, h.user_color_allowed, h.created_at
FROM hubs h
INNER JOIN hub_users hu ON hu.hub_id = h.id
WHERE hu.user_id = $1
`, user.Id)
if err != nil {
return err
}
defer rows.Close()
if user.Hubs == nil {
user.Hubs = make(map[uuid.UUID]*types.Hub)
}
for rows.Next() {
hub := types.NewHub()
var joinRoleId *int16
var rgba int64
if err = rows.Scan(&hub.Id, &hub.Name, &hub.IconUrl, &hub.BgUrl, &hub.Creator, &joinRoleId, &rgba, &hub.UserColorAllowed, &hub.CreatedAt); err != nil {
return fmt.Errorf("scanning hub row: %w", err)
}
hub.Color = convertions.Uint32ToRgba(uint32(rgba))
if joinRoleId != nil {
hub.JoinRole = &types.HubRole{Id: uint8(*joinRoleId)}
}
user.Hubs[hub.Id] = hub
}
return rows.Err()
}
func UserGetWhole(ctx context.Context, user *types.User) error {
if err := UserGetById(ctx, user); err != nil {
return err
}
if err := ConnectionsGetBelongingToUser(ctx, user); err != nil {
return err
}
if err := UserGetBelongingHubs(ctx, user); err != nil {
return err
}
return nil
}
func ConnectionSave(ctx context.Context, conn *types.Connection) error {
return dbConn.QueryRow(ctx, `
INSERT INTO user_connections (requestor_id, recipient_id, state, created_at) VALUES ($1, $2, $3, $4)
RETURNING id
`, conn.RequestorId, conn.RecipientId, conn.State, conn.CreatedAt).Scan(&conn.Id)
}
func ConnectionDelete(ctx context.Context, conn *types.Connection) error {
_, err := dbConn.Exec(ctx, `
DELETE FROM user_connections WHERE id = $1
`, conn.Id)
return err
}
func ConnectionGetById(ctx context.Context, id uuid.UUID) (*types.Connection, error) {
conn := types.NewConn()
err := dbConn.QueryRow(ctx, `
SELECT id, requestor_id, recipient_id, state, created_at
FROM user_connections
WHERE id = $1
`, id).Scan(&conn.Id, &conn.RequestorId, &conn.RecipientId, &conn.State, &conn.CreatedAt)
if err != nil {
return nil, err
}
return conn, nil
}
func ConnectionsGetBelongingToUser(ctx context.Context, user *types.User) error {
rows, err := dbConn.Query(ctx, `
SELECT id, requestor_id, recipient_id, state, created_at
FROM user_connections
WHERE requestor_id = $1 OR recipient_id = $1
`, user.Id)
if err != nil {
return err
}
defer rows.Close()
if user.Connections == nil {
user.Connections = make(map[uuid.UUID]*types.Connection)
}
for rows.Next() {
conn := types.NewConn()
if err = rows.Scan(&conn.Id, &conn.RequestorId, &conn.RecipientId, &conn.State, &conn.CreatedAt); err != nil {
return fmt.Errorf("scanning connection row: %w", err)
}
user.Connections[conn.Id] = conn
}
return rows.Err()
}
func ConnectionUpdateState(ctx context.Context, conn *types.Connection) error {
_, err := dbConn.Exec(ctx, `
UPDATE user_connections SET state = $1 WHERE id = $2
`, conn.State, conn.Id)
return err
}
func ConnectionMessageSave(ctx context.Context, message *types.Message) error {
if message.Id != (uuid.UUID{}) {
_, err := dbConn.Exec(ctx, `
INSERT INTO direct_messages (id, sender_id, receiver_id, created_at, content, attached_file) VALUES ($1, $2, $3, $4, $5, $6)
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile)
return err
}
return dbConn.QueryRow(ctx, `
INSERT INTO direct_messages (sender_id, receiver_id, created_at, content, attached_file) VALUES ($1, $2, $3, $4, $5)
RETURNING id
`, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile).Scan(&message.Id)
}
func ConnectionGetMessagesBefore(ctx context.Context, before time.Time, connection uuid.UUID, cap uint32) ([]*types.Message, error) {
rows, err := dbConn.Query(ctx, `
SELECT id, sender_id, receiver_id, created_at, content, attached_file
FROM (
SELECT id, sender_id, receiver_id, created_at, content, attached_file
FROM direct_messages
WHERE receiver_id = $1
AND created_at < $2
ORDER BY created_at DESC
LIMIT $3
) sub
ORDER BY created_at ASC
`, connection, before, cap)
if err != nil {
return nil, err
}
defer rows.Close()
messages := make([]*types.Message, 0, cap)
for rows.Next() {
msg := &types.Message{}
if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content, &msg.AttachedFile); err != nil {
return nil, err
}
messages = append(messages, msg)
}
return messages, rows.Err()
}
func HubGet(ctx context.Context, hub *types.Hub) error {
var joinRoleId *int16
var rgba int64
err := dbConn.QueryRow(ctx, `
SELECT name, COALESCE(icon_url, ''), COALESCE(background_url, ''), creator, join_role, rgba, user_color_allowed, created_at
FROM hubs WHERE id = $1
`, hub.Id).Scan(&hub.Name, &hub.IconUrl, &hub.BgUrl, &hub.Creator, &joinRoleId, &rgba, &hub.UserColorAllowed, &hub.CreatedAt)
if err != nil {
return err
}
hub.Color = convertions.Uint32ToRgba(uint32(rgba))
if joinRoleId != nil {
hub.JoinRole = &types.HubRole{Id: uint8(*joinRoleId)}
}
return nil
}
func HubGetWhole(ctx context.Context, hub *types.Hub) error {
if err := HubGet(ctx, hub); err != nil {
return err
}
if err := HubRolesGet(ctx, hub); err != nil {
return err
}
if err := HubChannelsGet(ctx, hub); err != nil {
return err
}
if err := HubUsersGet(ctx, hub); err != nil {
return err
}
return nil
}
func HubRolesGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT id, name, permissions, rgba, created_at FROM hub_roles WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
role := &types.HubRole{}
var id int16
var permissions, rgba int64
if err = rows.Scan(&id, &role.Name, &permissions, &rgba, &role.CreatedAt); err != nil {
return fmt.Errorf("scanning hub_role row: %w", err)
}
role.Id = uint8(id)
role.Permissions = types.Permissions(uint32(permissions))
role.Color = convertions.Uint32ToRgba(uint32(rgba))
hub.Roles[role.Id] = role
}
return rows.Err()
}
func HubUsersGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT user_id, name, roles_0, roles_1, roles_2, is_muted, created_at FROM hub_users WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
if hub.Users == nil {
hub.Users = make(map[uuid.UUID]*types.HubUser)
}
for rows.Next() {
user := types.NewHubUser()
var r0, r1, r2 int64
if err = rows.Scan(&user.OriginalId, &user.Name, &r0, &r1, &r2, &user.IsMuted, &user.CreatedAt); err != nil {
return fmt.Errorf("scanning hub_user row: %w", err)
}
user.Roles[0] = uint64(r0)
user.Roles[1] = uint64(r1)
user.Roles[2] = uint64(r2)
hub.Users[user.OriginalId] = user
}
return rows.Err()
}
func HubChannelsGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT id, name, COALESCE(description, ''), COALESCE(icon_url, ''), position, created_at,
roles_can_view_0, roles_can_view_1, roles_can_view_2,
roles_can_message_0, roles_can_message_1, roles_can_message_2,
roles_can_read_history_0, roles_can_read_history_1, roles_can_read_history_2
FROM hub_channel WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
if hub.Channels == nil {
hub.Channels = make(map[uuid.UUID]*types.HubChannel)
}
for rows.Next() {
channel := types.NewHubChannel()
var pos int16
var v0, v1, v2, m0, m1, m2, rh0, rh1, rh2 int64
if err = rows.Scan(
&channel.Id, &channel.Name, &channel.Description, &channel.IconUrl, &pos, &channel.CreatedAt,
&v0, &v1, &v2, &m0, &m1, &m2, &rh0, &rh1, &rh2,
); err != nil {
return fmt.Errorf("scanning hub_channel row: %w", err)
}
channel.Position = uint8(pos)
channel.RolesCanView = types.HubBoundRoles{uint64(v0), uint64(v1), uint64(v2)}
channel.RolesCanMessage = types.HubBoundRoles{uint64(m0), uint64(m1), uint64(m2)}
channel.RolesCanReadHistory = types.HubBoundRoles{uint64(rh0), uint64(rh1), uint64(rh2)}
hub.Channels[channel.Id] = channel
}
return rows.Err()
}
func HubSave(ctx context.Context, hub *types.Hub) error {
var joinRoleId *int16
if hub.JoinRole != nil {
id := int16(hub.JoinRole.Id)
joinRoleId = &id
}
_, err := dbConn.Exec(ctx, `
INSERT INTO hubs (id, name, icon_url, background_url, creator, join_role, rgba, user_color_allowed, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
`, hub.Id, hub.Name, hub.IconUrl, hub.BgUrl, hub.Creator, joinRoleId,
convertions.RgbaToUint32(hub.Color), hub.UserColorAllowed, hub.CreatedAt)
return err
}
func HubRoleSave(ctx context.Context, hubId uuid.UUID, role *types.HubRole) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_roles (id, hub_id, name, permissions, rgba, created_at)
VALUES ($1, $2, $3, $4, $5, $6)
`, int16(role.Id), hubId, role.Name, int64(role.Permissions),
convertions.RgbaToUint32(role.Color), role.CreatedAt)
return err
}
func HubChannelSave(ctx context.Context, hubId uuid.UUID, channel *types.HubChannel) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_channel (
id, hub_id, name, description, icon_url, position, created_at,
roles_can_view_0, roles_can_view_1, roles_can_view_2,
roles_can_message_0, roles_can_message_1, roles_can_message_2,
roles_can_read_history_0, roles_can_read_history_1, roles_can_read_history_2
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
`, channel.Id, hubId, channel.Name, channel.Description, channel.IconUrl, channel.Position, channel.CreatedAt,
int64(channel.RolesCanView[0]), int64(channel.RolesCanView[1]), int64(channel.RolesCanView[2]),
int64(channel.RolesCanMessage[0]), int64(channel.RolesCanMessage[1]), int64(channel.RolesCanMessage[2]),
int64(channel.RolesCanReadHistory[0]), int64(channel.RolesCanReadHistory[1]), int64(channel.RolesCanReadHistory[2]))
return err
}
func HubUserSave(ctx context.Context, hubId uuid.UUID, hubUser *types.HubUser) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_users (user_id, hub_id, name, roles_0, roles_1, roles_2, is_muted, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
`, hubUser.OriginalId, hubId, hubUser.Name,
int64(hubUser.Roles[0]), int64(hubUser.Roles[1]), int64(hubUser.Roles[2]),
hubUser.IsMuted, hubUser.CreatedAt)
return err
}
func HubChannelMessageSave(ctx context.Context, message *types.Message) error {
if message.Id != (uuid.UUID{}) {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_channel_messages (id, sender_id, receiver_id, created_at, content, attached_file)
VALUES ($1, $2, $3, $4, $5, $6)
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile)
return err
}
return dbConn.QueryRow(ctx, `
INSERT INTO hub_channel_messages (sender_id, receiver_id, created_at, content, attached_file)
VALUES ($1, $2, $3, $4, $5)
RETURNING id
`, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile).Scan(&message.Id)
}
func HubChannelMessageGet(ctx context.Context, message *types.Message) error {
return dbConn.QueryRow(ctx, `
SELECT sender_id, receiver_id, created_at, content, attached_file
FROM hub_channel_messages
WHERE id = $1
`, message.Id).Scan(&message.Sender, &message.Receiver, &message.CreatedAt, &message.Content, &message.AttachedFile)
}
func HubUpdate(ctx context.Context, hub *types.Hub, updateList *types.HubUpdate) error {
setClauses := make([]string, 0, 6)
args := make([]any, 0, 7)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, hub.Name)
argIdx++
}
if updateList.IconUrl {
setClauses = append(setClauses, fmt.Sprintf("icon_url = $%d", argIdx))
args = append(args, hub.IconUrl)
argIdx++
}
if updateList.BgUrl {
setClauses = append(setClauses, fmt.Sprintf("background_url = $%d", argIdx))
args = append(args, hub.BgUrl)
argIdx++
}
if updateList.JoinRole {
var joinRoleId *int16
if hub.JoinRole != nil {
id := int16(hub.JoinRole.Id)
joinRoleId = &id
}
setClauses = append(setClauses, fmt.Sprintf("join_role = $%d", argIdx))
args = append(args, joinRoleId)
argIdx++
}
if updateList.Color {
setClauses = append(setClauses, fmt.Sprintf("rgba = $%d", argIdx))
args = append(args, convertions.RgbaToUint32(hub.Color))
argIdx++
}
if updateList.UserColorAllowed {
setClauses = append(setClauses, fmt.Sprintf("user_color_allowed = $%d", argIdx))
args = append(args, hub.UserColorAllowed)
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hubs SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
args = append(args, hub.Id)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubRoleUpdate(ctx context.Context, hubId uuid.UUID, role *types.HubRole, updateList *types.HubRoleUpdate) error {
setClauses := make([]string, 0, 3)
args := make([]any, 0, 5)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, role.Name)
argIdx++
}
if updateList.Permissions {
setClauses = append(setClauses, fmt.Sprintf("permissions = $%d", argIdx))
args = append(args, int64(role.Permissions))
argIdx++
}
if updateList.Color {
setClauses = append(setClauses, fmt.Sprintf("rgba = $%d", argIdx))
args = append(args, convertions.RgbaToUint32(role.Color))
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_roles SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d AND hub_id = $%d", argIdx, argIdx+1)
args = append(args, int16(role.Id), hubId)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubChannelUpdate(ctx context.Context, channel *types.HubChannel, updateList *types.HubChannelUpdate) error {
setClauses := make([]string, 0, 13)
args := make([]any, 0, 15)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, channel.Name)
argIdx++
}
if updateList.Description {
setClauses = append(setClauses, fmt.Sprintf("description = $%d", argIdx))
args = append(args, channel.Description)
argIdx++
}
if updateList.IconUrl {
setClauses = append(setClauses, fmt.Sprintf("icon_url = $%d", argIdx))
args = append(args, channel.IconUrl)
argIdx++
}
if updateList.Position {
setClauses = append(setClauses, fmt.Sprintf("position = $%d", argIdx))
args = append(args, channel.Position)
argIdx++
}
if updateList.RolesCanView {
setClauses = append(setClauses, fmt.Sprintf("roles_can_view_0 = $%d, roles_can_view_1 = $%d, roles_can_view_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanView[0]), int64(channel.RolesCanView[1]), int64(channel.RolesCanView[2]))
argIdx += 3
}
if updateList.RolesCanMessage {
setClauses = append(setClauses, fmt.Sprintf("roles_can_message_0 = $%d, roles_can_message_1 = $%d, roles_can_message_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanMessage[0]), int64(channel.RolesCanMessage[1]), int64(channel.RolesCanMessage[2]))
argIdx += 3
}
if updateList.RolesCanReadHistory {
setClauses = append(setClauses, fmt.Sprintf("roles_can_read_history_0 = $%d, roles_can_read_history_1 = $%d, roles_can_read_history_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanReadHistory[0]), int64(channel.RolesCanReadHistory[1]), int64(channel.RolesCanReadHistory[2]))
argIdx += 3
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_channel SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
args = append(args, channel.Id)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubUserUpdate(ctx context.Context, hubId uuid.UUID, hubUser *types.HubUser, updateList *types.HubUserUpdate) error {
setClauses := make([]string, 0, 5)
args := make([]any, 0, 7)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, hubUser.Name)
argIdx++
}
if updateList.Roles {
setClauses = append(setClauses, fmt.Sprintf("roles_0 = $%d, roles_1 = $%d, roles_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(hubUser.Roles[0]), int64(hubUser.Roles[1]), int64(hubUser.Roles[2]))
argIdx += 3
}
if updateList.IsMuted {
setClauses = append(setClauses, fmt.Sprintf("is_muted = $%d", argIdx))
args = append(args, hubUser.IsMuted)
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_users SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE user_id = $%d AND hub_id = $%d", argIdx, argIdx+1)
args = append(args, hubUser.OriginalId, hubId)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubDelete(ctx context.Context, hubId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hubs WHERE id = $1`, hubId)
return err
}
func HubUserDelete(ctx context.Context, hubId uuid.UUID, userId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_users WHERE user_id = $1 AND hub_id = $2`, userId, hubId)
return err
}
func HubRoleDelete(ctx context.Context, hubId uuid.UUID, roleId uint8) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_roles WHERE id = $1 AND hub_id = $2`, int16(roleId), hubId)
return err
}
func HubChannelDelete(ctx context.Context, channelId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_channel WHERE id = $1`, channelId)
return err
}