Remove deprecated relationship change log migration and enhance error handling in FalukantService for partner retrieval
This commit is contained in:
@@ -1,105 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** Log-Tabelle für alle Änderungen an relationship und marriage_proposals (keine Einträge werden gelöscht).
|
|
||||||
* Hilft zu analysieren, warum z.B. Werbungen um einen Partner über Nacht verschwinden. */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
async up(queryInterface, Sequelize) {
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
CREATE TABLE IF NOT EXISTS falukant_log.relationship_change_log (
|
|
||||||
id serial PRIMARY KEY,
|
|
||||||
changed_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
table_name character varying(64) NOT NULL,
|
|
||||||
operation character varying(16) NOT NULL,
|
|
||||||
record_id integer,
|
|
||||||
payload_old jsonb,
|
|
||||||
payload_new jsonb
|
|
||||||
);
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
CREATE INDEX IF NOT EXISTS relationship_change_log_changed_at_idx
|
|
||||||
ON falukant_log.relationship_change_log (changed_at);
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
CREATE INDEX IF NOT EXISTS relationship_change_log_table_operation_idx
|
|
||||||
ON falukant_log.relationship_change_log (table_name, operation);
|
|
||||||
`);
|
|
||||||
|
|
||||||
const triggerFunction = `
|
|
||||||
CREATE OR REPLACE FUNCTION falukant_log.log_relationship_change()
|
|
||||||
RETURNS TRIGGER AS $$
|
|
||||||
DECLARE
|
|
||||||
v_record_id INTEGER;
|
|
||||||
v_payload_old JSONB;
|
|
||||||
v_payload_new JSONB;
|
|
||||||
BEGIN
|
|
||||||
IF TG_OP = 'INSERT' THEN
|
|
||||||
v_record_id := NEW.id;
|
|
||||||
v_payload_old := NULL;
|
|
||||||
v_payload_new := to_jsonb(NEW);
|
|
||||||
ELSIF TG_OP = 'UPDATE' THEN
|
|
||||||
v_record_id := NEW.id;
|
|
||||||
v_payload_old := to_jsonb(OLD);
|
|
||||||
v_payload_new := to_jsonb(NEW);
|
|
||||||
ELSIF TG_OP = 'DELETE' THEN
|
|
||||||
v_record_id := OLD.id;
|
|
||||||
v_payload_old := to_jsonb(OLD);
|
|
||||||
v_payload_new := NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
INSERT INTO falukant_log.relationship_change_log (
|
|
||||||
table_name,
|
|
||||||
operation,
|
|
||||||
record_id,
|
|
||||||
payload_old,
|
|
||||||
payload_new
|
|
||||||
) VALUES (
|
|
||||||
TG_TABLE_NAME,
|
|
||||||
TG_OP,
|
|
||||||
v_record_id,
|
|
||||||
v_payload_old,
|
|
||||||
v_payload_new
|
|
||||||
);
|
|
||||||
|
|
||||||
IF TG_OP = 'DELETE' THEN
|
|
||||||
RETURN OLD;
|
|
||||||
ELSE
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
`;
|
|
||||||
await queryInterface.sequelize.query(triggerFunction);
|
|
||||||
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.relationship;
|
|
||||||
CREATE TRIGGER trg_log_relationship_change
|
|
||||||
AFTER INSERT OR UPDATE OR DELETE ON falukant_data.relationship
|
|
||||||
FOR EACH ROW
|
|
||||||
EXECUTE FUNCTION falukant_log.log_relationship_change();
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.marriage_proposals;
|
|
||||||
CREATE TRIGGER trg_log_relationship_change
|
|
||||||
AFTER INSERT OR UPDATE OR DELETE ON falukant_data.marriage_proposals
|
|
||||||
FOR EACH ROW
|
|
||||||
EXECUTE FUNCTION falukant_log.log_relationship_change();
|
|
||||||
`);
|
|
||||||
},
|
|
||||||
|
|
||||||
async down(queryInterface, Sequelize) {
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.relationship;
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.marriage_proposals;
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP FUNCTION IF EXISTS falukant_log.log_relationship_change();
|
|
||||||
`);
|
|
||||||
await queryInterface.sequelize.query(`
|
|
||||||
DROP TABLE IF EXISTS falukant_log.relationship_change_log;
|
|
||||||
`);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -3158,6 +3158,7 @@ class FalukantService extends BaseService {
|
|||||||
const step7Start = Date.now();
|
const step7Start = Date.now();
|
||||||
const ownAge = calcAge(character.birthdate);
|
const ownAge = calcAge(character.birthdate);
|
||||||
if (ownAge >= 12 && family.relationships.length === 0) {
|
if (ownAge >= 12 && family.relationships.length === 0) {
|
||||||
|
try {
|
||||||
family.possiblePartners = await this.getPossiblePartners(character.id);
|
family.possiblePartners = await this.getPossiblePartners(character.id);
|
||||||
if (family.possiblePartners.length === 0) {
|
if (family.possiblePartners.length === 0) {
|
||||||
// Asynchron erstellen, nicht blockieren
|
// Asynchron erstellen, nicht blockieren
|
||||||
@@ -3169,6 +3170,12 @@ class FalukantService extends BaseService {
|
|||||||
ownAge
|
ownAge
|
||||||
).catch(err => console.error('[getFamily] Error creating partners (async):', err));
|
).catch(err => console.error('[getFamily] Error creating partners (async):', err));
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Fehler beim Laden nicht an Frontend durchreichen – Seite bleibt nutzbar, Log für Analyse
|
||||||
|
console.error('[getFamily] getPossiblePartners failed (characterId=%s):', character.id, err?.message || err);
|
||||||
|
if (err?.stack) console.error('[getFamily] getPossiblePartners stack:', err.stack);
|
||||||
|
family.possiblePartners = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
timings.step7_possible_partners = Date.now() - step7Start;
|
timings.step7_possible_partners = Date.now() - step7Start;
|
||||||
|
|
||||||
@@ -3399,33 +3406,44 @@ class FalukantService extends BaseService {
|
|||||||
{
|
{
|
||||||
model: FalukantCharacter,
|
model: FalukantCharacter,
|
||||||
as: 'proposedCharacter',
|
as: 'proposedCharacter',
|
||||||
|
required: false,
|
||||||
attributes: ['id', 'firstName', 'lastName', 'gender', 'regionId', 'birthdate'],
|
attributes: ['id', 'firstName', 'lastName', 'gender', 'regionId', 'birthdate'],
|
||||||
include: [
|
include: [
|
||||||
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'] },
|
{ model: FalukantPredefineFirstname, as: 'definedFirstName', attributes: ['name'], required: false },
|
||||||
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'] },
|
{ model: FalukantPredefineLastname, as: 'definedLastName', attributes: ['name'], required: false },
|
||||||
{ model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'] },
|
{ model: TitleOfNobility, as: 'nobleTitle', attributes: ['labelTr'], required: false },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
return proposals
|
const valid = [];
|
||||||
.filter(proposal => proposal.proposedCharacter !== null)
|
for (const proposal of proposals) {
|
||||||
.map(proposal => {
|
if (proposal.proposedCharacter == null) {
|
||||||
const birthdate = new Date(proposal.proposedCharacter.birthdate);
|
console.warn('[getPossiblePartners] Proposal id=%s filtered out (proposedCharacterId=%s missing)', proposal.id, proposal.proposedCharacterId);
|
||||||
const age = calcAge(birthdate);
|
continue;
|
||||||
return {
|
}
|
||||||
|
const pc = proposal.proposedCharacter;
|
||||||
|
const birthdate = pc.birthdate ? new Date(pc.birthdate) : null;
|
||||||
|
const age = birthdate ? calcAge(birthdate) : 0;
|
||||||
|
const name = `${pc.definedFirstName?.name ?? ''} ${pc.definedLastName?.name ?? ''}`.trim() || null;
|
||||||
|
if (!name) {
|
||||||
|
console.warn('[getPossiblePartners] Proposal id=%s filtered out (proposedCharacterId=%s has no name)', proposal.id, pc.id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
valid.push({
|
||||||
id: proposal.id,
|
id: proposal.id,
|
||||||
requesterCharacterId: proposal.requesterCharacterId,
|
requesterCharacterId: proposal.requesterCharacterId,
|
||||||
proposedCharacterId: proposal.proposedCharacter.id,
|
proposedCharacterId: pc.id,
|
||||||
proposedCharacterName: `${proposal.proposedCharacter.definedFirstName?.name} ${proposal.proposedCharacter.definedLastName?.name}`,
|
proposedCharacterName: name,
|
||||||
proposedCharacterGender: proposal.proposedCharacter.gender,
|
proposedCharacterGender: pc.gender,
|
||||||
proposedCharacterRegionId: proposal.proposedCharacter.regionId,
|
proposedCharacterRegionId: pc.regionId,
|
||||||
proposedCharacterAge: age,
|
proposedCharacterAge: age,
|
||||||
proposedCharacterNobleTitle: proposal.proposedCharacter.nobleTitle?.labelTr || null,
|
proposedCharacterNobleTitle: pc.nobleTitle?.labelTr ?? null,
|
||||||
cost: proposal.cost,
|
cost: proposal.cost,
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
async createPossiblePartners(requestingCharacterId, requestingCharacterGender, requestingRegionId, requestingCharacterTitleOfNobility, ownAge) {
|
async createPossiblePartners(requestingCharacterId, requestingCharacterGender, requestingRegionId, requestingCharacterTitleOfNobility, ownAge) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -387,6 +387,77 @@ const syncDatabase = async () => {
|
|||||||
console.warn('⚠️ Konnte Vocab-Trainer Tabellen nicht sicherstellen:', e?.message || e);
|
console.warn('⚠️ Konnte Vocab-Trainer Tabellen nicht sicherstellen:', e?.message || e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relationship-/Marriage-Proposal-Änderungen loggen (keine Einträge löschen; ohne db:migrate)
|
||||||
|
console.log("Ensuring relationship change log (falukant) exists...");
|
||||||
|
try {
|
||||||
|
await sequelize.query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS falukant_log.relationship_change_log (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
changed_at timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
table_name character varying(64) NOT NULL,
|
||||||
|
operation character varying(16) NOT NULL,
|
||||||
|
record_id integer,
|
||||||
|
payload_old jsonb,
|
||||||
|
payload_new jsonb
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
await sequelize.query(`
|
||||||
|
CREATE INDEX IF NOT EXISTS relationship_change_log_changed_at_idx
|
||||||
|
ON falukant_log.relationship_change_log (changed_at);
|
||||||
|
`);
|
||||||
|
await sequelize.query(`
|
||||||
|
CREATE INDEX IF NOT EXISTS relationship_change_log_table_operation_idx
|
||||||
|
ON falukant_log.relationship_change_log (table_name, operation);
|
||||||
|
`);
|
||||||
|
await sequelize.query(`
|
||||||
|
CREATE OR REPLACE FUNCTION falukant_log.log_relationship_change()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
v_record_id INTEGER;
|
||||||
|
v_payload_old JSONB;
|
||||||
|
v_payload_new JSONB;
|
||||||
|
BEGIN
|
||||||
|
IF TG_OP = 'INSERT' THEN
|
||||||
|
v_record_id := NEW.id;
|
||||||
|
v_payload_old := NULL;
|
||||||
|
v_payload_new := to_jsonb(NEW);
|
||||||
|
ELSIF TG_OP = 'UPDATE' THEN
|
||||||
|
v_record_id := NEW.id;
|
||||||
|
v_payload_old := to_jsonb(OLD);
|
||||||
|
v_payload_new := to_jsonb(NEW);
|
||||||
|
ELSIF TG_OP = 'DELETE' THEN
|
||||||
|
v_record_id := OLD.id;
|
||||||
|
v_payload_old := to_jsonb(OLD);
|
||||||
|
v_payload_new := NULL;
|
||||||
|
END IF;
|
||||||
|
INSERT INTO falukant_log.relationship_change_log (
|
||||||
|
table_name, operation, record_id, payload_old, payload_new
|
||||||
|
) VALUES (
|
||||||
|
TG_TABLE_NAME, TG_OP, v_record_id, v_payload_old, v_payload_new
|
||||||
|
);
|
||||||
|
IF TG_OP = 'DELETE' THEN RETURN OLD; ELSE RETURN NEW; END IF;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
`);
|
||||||
|
await sequelize.query(`
|
||||||
|
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.relationship;
|
||||||
|
CREATE TRIGGER trg_log_relationship_change
|
||||||
|
AFTER INSERT OR UPDATE OR DELETE ON falukant_data.relationship
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION falukant_log.log_relationship_change();
|
||||||
|
`);
|
||||||
|
await sequelize.query(`
|
||||||
|
DROP TRIGGER IF EXISTS trg_log_relationship_change ON falukant_data.marriage_proposals;
|
||||||
|
CREATE TRIGGER trg_log_relationship_change
|
||||||
|
AFTER INSERT OR UPDATE OR DELETE ON falukant_data.marriage_proposals
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION falukant_log.log_relationship_change();
|
||||||
|
`);
|
||||||
|
console.log("✅ relationship_change_log und Trigger sind vorhanden.");
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('⚠️ relationship_change_log/Trigger konnten nicht sichergestellt werden:', e?.message || e);
|
||||||
|
}
|
||||||
|
|
||||||
// Vorab: Stelle kritische Spalten sicher, damit Index-Erstellung nicht fehlschlägt
|
// Vorab: Stelle kritische Spalten sicher, damit Index-Erstellung nicht fehlschlägt
|
||||||
console.log("Pre-ensure Taxi columns (traffic_light) ...");
|
console.log("Pre-ensure Taxi columns (traffic_light) ...");
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user