const BaseRepository = require('../../../src/database/repository'); const logger = require('../../../src/utils/logger'); /** * Base Financial Repository * * Extends core BaseRepository to handle pg_ prefixed plugin tables. * All financial plugin repositories should extend this class. * * Features: * - Uses pg_ prefix to identify plugin tables in main schema * - Inherits all BaseRepository methods (findOne, findAll, create, etc.) * - Multi-tenant support via site_id * - Database abstraction (works with any supported database) */ class BaseFinancialRepository extends BaseRepository { constructor(tableName) { super(tableName); this.schema = 'public'; // Use main schema with pg_ prefixed tables } /** * Get database connection * @returns {Object} Database connection */ getConnection() { if (global.dbConnection && typeof global.dbConnection.getConnection === 'function') { return global.dbConnection.getConnection(); } throw new Error('No database connection available'); } /** * Check if connection is Supabase client * @param {Object} connection * @returns {boolean} */ isSupabase(connection) { return connection && typeof connection.from === 'function' && typeof connection.auth === 'object'; } /** * Override findAll to handle pg_ prefixed tables in main schema */ async findAll(criteria = {}, options = {}) { const connection = this.getConnection(); if (this.isSupabase(connection)) { // Supabase style - use pg_ prefixed tables in public schema let query = connection.from(this.tableName).select('*'); // Apply criteria if (Object.keys(criteria).length > 0) { query = query.match(criteria); } // Apply ordering if (options.orderBy) { const ascending = options.orderDirection === 'asc' || options.orderDirection === 'ASC'; query = query.order(options.orderBy, { ascending }); } // Apply limit if (options.limit) query = query.limit(options.limit); const { data, error } = await query; if (error) throw error; return data || []; } else { // Knex style - for other databases return super.findAll(criteria, options); } } /** * Override findOne to handle pg_ prefixed tables in main schema */ async findOne(criteria) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const { data, error } = await connection .from(this.tableName) .select('*') .match(criteria) .limit(1); if (error) throw error; return data && data[0]; } else { return super.findOne(criteria); } } /** * Override create to handle pg_ prefixed tables in main schema */ async create(data) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const { data: result, error } = await connection .from(this.tableName) .insert([data]) .select(); if (error) throw error; return result && result[0]; } else { return super.create(data); } } /** * Override updateById to handle pg_ prefixed tables in main schema */ async updateById(id, updateData) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const { data, error } = await connection .from(this.tableName) .update(updateData) .eq('id', id) .select(); if (error) throw error; return data && data[0]; } else { return super.updateById(id, updateData); } } /** * Override deleteById to handle pg_ prefixed tables in main schema */ async deleteById(id) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const { error } = await connection .from(this.tableName) .delete() .eq('id', id); if (error) throw error; return true; } else { return super.deleteById(id); } } /** * Override count to handle pg_ prefixed tables in main schema */ async count(criteria = {}) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const { count, error } = await connection .from(this.tableName) .select('*', { count: 'exact', head: true }) .match(criteria); if (error) throw error; return count || 0; } else { return super.count(criteria); } } /** * Override findWhere to handle pg_ prefixed tables in main schema */ async findWhere(conditions, options = {}) { const connection = this.getConnection(); if (this.isSupabase(connection)) { let query = connection.from(this.tableName).select('*'); // Apply conditions for (const [field, condition] of Object.entries(conditions)) { if (condition.eq !== undefined) query = query.eq(field, condition.eq); if (condition.neq !== undefined) query = query.neq(field, condition.neq); if (condition.gt !== undefined) query = query.gt(field, condition.gt); if (condition.gte !== undefined) query = query.gte(field, condition.gte); if (condition.lt !== undefined) query = query.lt(field, condition.lt); if (condition.lte !== undefined) query = query.lte(field, condition.lte); if (condition.like !== undefined) query = query.like(field, condition.like); if (condition.in !== undefined) query = query.in(field, condition.in); } // Apply ordering if (options.orderBy) { const ascending = options.orderDirection === 'asc' || options.orderDirection === 'ASC'; query = query.order(options.orderBy, { ascending }); } // Apply limit if (options.limit) query = query.limit(options.limit); const { data, error } = await query; if (error) throw error; return data || []; } else { return super.findWhere(conditions, options); } } /** * Override paginate to handle pg_ prefixed tables in main schema */ async paginate(criteria = {}, page = 1, limit = 10, options = {}) { const connection = this.getConnection(); if (this.isSupabase(connection)) { const offset = (page - 1) * limit; let query = connection .from(this.tableName) .select('*', { count: 'exact' }) .match(criteria); query = query.range(offset, offset + limit - 1); const { data, error, count } = await query; if (error) throw error; const total = typeof count === 'number' ? count : (data ? data.length : 0); const totalPages = Math.ceil(total / limit); return { data: data || [], pagination: { page, limit, total, totalPages, hasNext: page < totalPages, hasPrev: page > 1 } }; } else { return super.paginate(criteria, page, limit, options); } } } module.exports = BaseFinancialRepository;