diff --git a/server/database-storage.ts b/server/database-storage.ts index 74d5973..3364e81 100644 --- a/server/database-storage.ts +++ b/server/database-storage.ts @@ -386,23 +386,39 @@ export class DatabaseStorage implements IStorage { // DNS Record management async getDnsRecord(id: string): Promise { - const [record] = await db.select({ - id: dnsRecords.id, - domainId: dnsRecords.domainId, - name: dnsRecords.name, - type: dnsRecords.type, - content: dnsRecords.content, - ttl: dnsRecords.ttl, - isActive: dnsRecords.isActive, - isAutoIP: dnsRecords.isAutoIP, - notes: dnsRecords.notes, - providerId: dnsRecords.providerId, - lastUpdated: dnsRecords.lastUpdated, - createdAt: dnsRecords.createdAt - }) - .from(dnsRecords) - .where(eq(dnsRecords.id, id)); - return record; + // Use raw SQL to select only columns that actually exist in the database + const query = ` + SELECT + id, domain_id, name, type, content, ttl, + is_active, auto_update, notes, last_updated, created_at + FROM dns_records + WHERE id = $1 + `; + + const result = await db.execute(query, [id]); + + if (!result || result.length === 0) { + return undefined; + } + + const record = result[0]; + + // Map the result to match our schema expectations + return { + id: record.id, + domainId: record.domain_id, + name: record.name, + type: record.type, + content: record.content, + ttl: record.ttl, + isActive: record.is_active, + isAutoIP: record.auto_update, // Map auto_update to isAutoIP + notes: record.notes, + lastUpdated: record.last_updated, + createdAt: record.created_at, + proxied: null, // Add missing fields with null values + providerId: null + }; } async getDnsRecordsByDomain(domainId: string): Promise { @@ -491,43 +507,97 @@ export class DatabaseStorage implements IStorage { } async updateDnsRecord(id: string, recordData: Partial): Promise { - // Filter out the proxied field if it exists and map isAutoIP to autoUpdate - const { proxied, isAutoIP, ...filteredDataRaw } = recordData as any; + // Filter out fields that don't exist in the database + const { proxied, isAutoIP, providerId, ...validFields } = recordData as any; - // Create a proper data object with the correct field names - const updateData: any = { - ...filteredDataRaw, - lastUpdated: new Date() - }; + // Build the SET clause parts and parameters for the SQL query + const setClauses = []; + const params = [id]; // First parameter is the id for the WHERE clause + let paramIndex = 2; // Start from $2 since $1 is the id - // Map isAutoIP to autoUpdate if it exists + // Add each field to the SET clauses + Object.entries(validFields).forEach(([key, value]) => { + // Convert camelCase to snake_case for database + const dbField = key.replace(/([A-Z])/g, '_$1').toLowerCase(); + setClauses.push(`${dbField} = $${paramIndex}`); + params.push(value); + paramIndex++; + }); + + // Handle isAutoIP separately (maps to auto_update in database) if (isAutoIP !== undefined) { - updateData.autoUpdate = isAutoIP; + setClauses.push(`auto_update = $${paramIndex}`); + params.push(isAutoIP); + paramIndex++; } - const [updatedRecord] = await db.update(dnsRecords) - .set(updateData) - .where(eq(dnsRecords.id, id)) - .returning({ - id: dnsRecords.id, - domainId: dnsRecords.domainId, - name: dnsRecords.name, - type: dnsRecords.type, - content: dnsRecords.content, - ttl: dnsRecords.ttl, - isActive: dnsRecords.isActive, - autoUpdate: dnsRecords.autoUpdate, - notes: dnsRecords.notes, - lastUpdated: dnsRecords.lastUpdated, - createdAt: dnsRecords.createdAt - }); + // Always update last_updated + setClauses.push(`last_updated = $${paramIndex}`); + params.push(new Date()); - if (!updatedRecord) return undefined; + // If no fields to update other than last_updated, return the existing record + if (setClauses.length === 1) { + // Get the record first to return it + const existingRecord = await this.getDnsRecord(id); + if (!existingRecord) return undefined; + + // Update just the last_updated field + const query = ` + UPDATE dns_records + SET last_updated = $2 + WHERE id = $1 + RETURNING id, domain_id, name, type, content, ttl, + is_active, auto_update, notes, last_updated, created_at + `; + + const result = await db.execute(query, [id, new Date()]); + if (!result || result.length === 0) return undefined; + + // Map result to expected format + const updatedRecord = result[0]; + return { + id: updatedRecord.id, + domainId: updatedRecord.domain_id, + name: updatedRecord.name, + type: updatedRecord.type, + content: updatedRecord.content, + ttl: updatedRecord.ttl, + isActive: updatedRecord.is_active, + isAutoIP: updatedRecord.auto_update, + notes: updatedRecord.notes, + lastUpdated: updatedRecord.last_updated, + createdAt: updatedRecord.created_at, + proxied: null, + providerId: null + }; + } - // Return the record with frontend-expected field names + // Build and execute the query with all fields + const query = ` + UPDATE dns_records + SET ${setClauses.join(', ')} + WHERE id = $1 + RETURNING id, domain_id, name, type, content, ttl, + is_active, auto_update, notes, last_updated, created_at + `; + + const result = await db.execute(query, params); + if (!result || result.length === 0) return undefined; + + // Map result to expected format + const updatedRecord = result[0]; return { - ...updatedRecord, - isAutoIP: updatedRecord.autoUpdate, + id: updatedRecord.id, + domainId: updatedRecord.domain_id, + name: updatedRecord.name, + type: updatedRecord.type, + content: updatedRecord.content, + ttl: updatedRecord.ttl, + isActive: updatedRecord.is_active, + isAutoIP: updatedRecord.auto_update, + notes: updatedRecord.notes, + lastUpdated: updatedRecord.last_updated, + createdAt: updatedRecord.created_at, proxied: null, providerId: null };