// SPDX-License-Identifier: AGPL-3.0-or-later import type {ConnectionType} from '@fluxer/constants/src/ConnectionConstants'; import type {UserID} from '../BrandedTypes'; import {deleteOneOrMany, fetchMany, fetchOne, upsertOne} from '../database/CassandraQueryExecution'; import {Db, type DbOp} from '../database/CassandraTypes'; import type {UserConnectionRow} from '../database/types/ConnectionTypes'; import {UserConnections} from '../Tables'; import {type CreateConnectionParams, IConnectionRepository, type UpdateConnectionParams} from './IConnectionRepository'; const FETCH_CONNECTIONS_BY_USER_CQL = UserConnections.selectCql({ where: UserConnections.where.eq('user_id'), }); const FETCH_CONNECTION_BY_ID_CQL = UserConnections.selectCql({ where: [ UserConnections.where.eq('user_id'), UserConnections.where.eq('connection_type'), UserConnections.where.eq('connection_id'), ], limit: 1, }); const COUNT_CONNECTIONS_CQL = UserConnections.selectCountCql({ where: UserConnections.where.eq('user_id'), }); export class ConnectionRepository extends IConnectionRepository { async findByUserId(userId: UserID): Promise> { return fetchMany(FETCH_CONNECTIONS_BY_USER_CQL, {user_id: userId}); } async findById( userId: UserID, connectionType: ConnectionType, connectionId: string, ): Promise { return fetchOne(FETCH_CONNECTION_BY_ID_CQL, { user_id: userId, connection_type: connectionType, connection_id: connectionId, }); } async findByTypeAndIdentifier( userId: UserID, connectionType: ConnectionType, identifier: string, ): Promise { const connections = await this.findByUserId(userId); return ( connections.find( (c) => c.connection_type === connectionType && c.identifier.toLowerCase() === identifier.toLowerCase(), ) ?? null ); } async create(params: CreateConnectionParams): Promise { const now = new Date(); const row: UserConnectionRow = { user_id: params.user_id, connection_id: params.connection_id, connection_type: params.connection_type, identifier: params.identifier, name: params.name, verified: params.verified ?? false, visibility_flags: params.visibility_flags, sort_order: params.sort_order, verification_token: params.verification_token, verified_at: params.verified_at ?? null, last_verified_at: params.last_verified_at ?? null, created_at: now, version: 1, }; await upsertOne(UserConnections.upsertAll(row)); return row; } async update( userId: UserID, connectionType: ConnectionType, connectionId: string, params: UpdateConnectionParams, ): Promise { const patch: Record> = {}; if (params.name !== undefined) { patch['name'] = Db.set(params.name); } if (params.visibility_flags !== undefined) { patch['visibility_flags'] = Db.set(params.visibility_flags); } if (params.sort_order !== undefined) { patch['sort_order'] = Db.set(params.sort_order); } if (params.verified !== undefined) { patch['verified'] = Db.set(params.verified); } if (params.verified_at !== undefined) { patch['verified_at'] = Db.set(params.verified_at); } if (params.last_verified_at !== undefined) { patch['last_verified_at'] = Db.set(params.last_verified_at); } if (Object.keys(patch).length > 0) { await upsertOne( UserConnections.patchByPk( {user_id: userId, connection_type: connectionType, connection_id: connectionId}, patch, ), ); } } async delete(userId: UserID, connectionType: ConnectionType, connectionId: string): Promise { await deleteOneOrMany( UserConnections.deleteByPk({user_id: userId, connection_type: connectionType, connection_id: connectionId}), ); } async count(userId: UserID): Promise { const result = await fetchOne<{ count: bigint; }>(COUNT_CONNECTIONS_CQL, {user_id: userId}); return result ? Number(result.count) : 0; } }