feat(vocab): add support for answer alternatives in core patterns and update related logic
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
'use strict';
|
||||
|
||||
const SHORT_ANSWER = 'Ich ruhe mich später kurz aus.';
|
||||
const ALTERNATIVE_ANSWER = 'Ich ruhe mich später aus.';
|
||||
const COMBINED_ANSWER = `${SHORT_ANSWER} / ${ALTERNATIVE_ANSWER}`;
|
||||
const TARGET = 'Magpahuway ko gamay unya.';
|
||||
const NORMALIZED_COMBINED_ANSWER = 'ich ruhe mich später kurz aus ich ruhe mich später aus';
|
||||
const NORMALIZED_TARGET = 'magpahuway ko gamay unya';
|
||||
|
||||
module.exports = {
|
||||
async up(queryInterface) {
|
||||
await queryInterface.sequelize.transaction(async (transaction) => {
|
||||
await queryInterface.sequelize.query(`
|
||||
UPDATE community.vocab_course_lesson
|
||||
SET core_patterns = (
|
||||
SELECT JSONB_AGG(
|
||||
CASE
|
||||
WHEN pattern.value->>'target' = :target AND pattern.value->>'gloss' = :shortAnswer
|
||||
THEN pattern.value || JSONB_BUILD_OBJECT('alternatives', JSONB_BUILD_ARRAY(:alternativeAnswer))
|
||||
ELSE pattern.value
|
||||
END
|
||||
)
|
||||
FROM JSONB_ARRAY_ELEMENTS(core_patterns) AS pattern(value)
|
||||
)
|
||||
WHERE JSONB_TYPEOF(core_patterns) = 'array'
|
||||
AND core_patterns @> JSONB_BUILD_ARRAY(JSONB_BUILD_OBJECT('target', :target, 'gloss', :shortAnswer));
|
||||
`, {
|
||||
replacements: { target: TARGET, shortAnswer: SHORT_ANSWER, alternativeAnswer: ALTERNATIVE_ANSWER },
|
||||
transaction
|
||||
});
|
||||
|
||||
await queryInterface.sequelize.query(`
|
||||
WITH stale AS (
|
||||
SELECT id, user_id, course_id, lesson_id, direction, correct_count, wrong_count, lapse_count,
|
||||
stage, interval_days, last_reviewed_at, next_due_at
|
||||
FROM community.vocab_srs_item
|
||||
WHERE learning = :shortAnswer
|
||||
AND reference = :target
|
||||
)
|
||||
UPDATE community.vocab_srs_item AS canonical
|
||||
SET correct_count = canonical.correct_count + stale.correct_count,
|
||||
wrong_count = canonical.wrong_count + stale.wrong_count,
|
||||
lapse_count = canonical.lapse_count + stale.lapse_count,
|
||||
stage = GREATEST(canonical.stage, stale.stage),
|
||||
interval_days = GREATEST(canonical.interval_days, stale.interval_days),
|
||||
last_reviewed_at = GREATEST(canonical.last_reviewed_at, stale.last_reviewed_at),
|
||||
next_due_at = LEAST(canonical.next_due_at, stale.next_due_at),
|
||||
updated_at = NOW()
|
||||
FROM stale
|
||||
WHERE canonical.user_id = stale.user_id
|
||||
AND canonical.id <> stale.id
|
||||
AND canonical.item_key = ENCODE(DIGEST(CONCAT_WS(
|
||||
'|',
|
||||
stale.course_id::text,
|
||||
COALESCE(stale.lesson_id::text, 'course'),
|
||||
UPPER(stale.direction),
|
||||
:normalizedCombinedAnswer,
|
||||
:normalizedTarget
|
||||
), 'sha1'), 'hex');
|
||||
`, {
|
||||
replacements: {
|
||||
target: TARGET,
|
||||
shortAnswer: SHORT_ANSWER,
|
||||
normalizedCombinedAnswer: NORMALIZED_COMBINED_ANSWER,
|
||||
normalizedTarget: NORMALIZED_TARGET
|
||||
},
|
||||
transaction
|
||||
});
|
||||
|
||||
await queryInterface.sequelize.query(`
|
||||
DELETE FROM community.vocab_srs_item AS stale
|
||||
WHERE stale.learning = :shortAnswer
|
||||
AND stale.reference = :target
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM community.vocab_srs_item canonical
|
||||
WHERE canonical.user_id = stale.user_id
|
||||
AND canonical.id <> stale.id
|
||||
AND canonical.item_key = ENCODE(DIGEST(CONCAT_WS(
|
||||
'|',
|
||||
stale.course_id::text,
|
||||
COALESCE(stale.lesson_id::text, 'course'),
|
||||
UPPER(stale.direction),
|
||||
:normalizedCombinedAnswer,
|
||||
:normalizedTarget
|
||||
), 'sha1'), 'hex')
|
||||
);
|
||||
`, {
|
||||
replacements: {
|
||||
target: TARGET,
|
||||
shortAnswer: SHORT_ANSWER,
|
||||
normalizedCombinedAnswer: NORMALIZED_COMBINED_ANSWER,
|
||||
normalizedTarget: NORMALIZED_TARGET
|
||||
},
|
||||
transaction
|
||||
});
|
||||
|
||||
await queryInterface.sequelize.query(`
|
||||
UPDATE community.vocab_srs_item
|
||||
SET learning = :combinedAnswer,
|
||||
item_key = ENCODE(DIGEST(CONCAT_WS(
|
||||
'|',
|
||||
course_id::text,
|
||||
COALESCE(lesson_id::text, 'course'),
|
||||
UPPER(direction),
|
||||
:normalizedCombinedAnswer,
|
||||
:normalizedTarget
|
||||
), 'sha1'), 'hex'),
|
||||
updated_at = NOW()
|
||||
WHERE learning = :shortAnswer
|
||||
AND reference = :target
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM community.vocab_srs_item duplicate
|
||||
WHERE duplicate.user_id = vocab_srs_item.user_id
|
||||
AND duplicate.item_key = ENCODE(DIGEST(CONCAT_WS(
|
||||
'|',
|
||||
vocab_srs_item.course_id::text,
|
||||
COALESCE(vocab_srs_item.lesson_id::text, 'course'),
|
||||
UPPER(vocab_srs_item.direction),
|
||||
:normalizedCombinedAnswer,
|
||||
:normalizedTarget
|
||||
), 'sha1'), 'hex')
|
||||
AND duplicate.id <> vocab_srs_item.id
|
||||
);
|
||||
`, {
|
||||
replacements: {
|
||||
target: TARGET,
|
||||
shortAnswer: SHORT_ANSWER,
|
||||
combinedAnswer: COMBINED_ANSWER,
|
||||
normalizedCombinedAnswer: NORMALIZED_COMBINED_ANSWER,
|
||||
normalizedTarget: NORMALIZED_TARGET
|
||||
},
|
||||
transaction
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async down() {
|
||||
// The alternative is valid course content and should not be removed.
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user