feat(vocab): add logic to aggregate and clean up duplicate SRS items based on answer patterns
This commit is contained in:
@@ -95,6 +95,90 @@ module.exports = {
|
|||||||
transaction
|
transaction
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await queryInterface.sequelize.query(`
|
||||||
|
WITH candidates AS (
|
||||||
|
SELECT id, user_id,
|
||||||
|
ENCODE(DIGEST(CONCAT_WS(
|
||||||
|
'|',
|
||||||
|
course_id::text,
|
||||||
|
COALESCE(lesson_id::text, 'course'),
|
||||||
|
UPPER(direction),
|
||||||
|
:normalizedCombinedAnswer,
|
||||||
|
:normalizedTarget
|
||||||
|
), 'sha1'), 'hex') AS new_item_key,
|
||||||
|
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
|
||||||
|
), ranked AS (
|
||||||
|
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id, new_item_key ORDER BY id) AS position
|
||||||
|
FROM candidates
|
||||||
|
), aggregates AS (
|
||||||
|
SELECT user_id, new_item_key, MIN(id) AS keeper_id,
|
||||||
|
SUM(correct_count) AS correct_count,
|
||||||
|
SUM(wrong_count) AS wrong_count,
|
||||||
|
SUM(lapse_count) AS lapse_count,
|
||||||
|
MAX(stage) AS stage,
|
||||||
|
MAX(interval_days) AS interval_days,
|
||||||
|
MAX(last_reviewed_at) AS last_reviewed_at,
|
||||||
|
MIN(next_due_at) AS next_due_at
|
||||||
|
FROM ranked
|
||||||
|
GROUP BY user_id, new_item_key
|
||||||
|
)
|
||||||
|
UPDATE community.vocab_srs_item AS keeper
|
||||||
|
SET correct_count = aggregates.correct_count,
|
||||||
|
wrong_count = aggregates.wrong_count,
|
||||||
|
lapse_count = aggregates.lapse_count,
|
||||||
|
stage = aggregates.stage,
|
||||||
|
interval_days = aggregates.interval_days,
|
||||||
|
last_reviewed_at = aggregates.last_reviewed_at,
|
||||||
|
next_due_at = aggregates.next_due_at,
|
||||||
|
updated_at = NOW()
|
||||||
|
FROM aggregates
|
||||||
|
WHERE keeper.id = aggregates.keeper_id;
|
||||||
|
`, {
|
||||||
|
replacements: {
|
||||||
|
target: TARGET,
|
||||||
|
shortAnswer: SHORT_ANSWER,
|
||||||
|
normalizedCombinedAnswer: NORMALIZED_COMBINED_ANSWER,
|
||||||
|
normalizedTarget: NORMALIZED_TARGET
|
||||||
|
},
|
||||||
|
transaction
|
||||||
|
});
|
||||||
|
|
||||||
|
await queryInterface.sequelize.query(`
|
||||||
|
WITH candidates AS (
|
||||||
|
SELECT id, user_id,
|
||||||
|
ENCODE(DIGEST(CONCAT_WS(
|
||||||
|
'|',
|
||||||
|
course_id::text,
|
||||||
|
COALESCE(lesson_id::text, 'course'),
|
||||||
|
UPPER(direction),
|
||||||
|
:normalizedCombinedAnswer,
|
||||||
|
:normalizedTarget
|
||||||
|
), 'sha1'), 'hex') AS new_item_key
|
||||||
|
FROM community.vocab_srs_item
|
||||||
|
WHERE learning = :shortAnswer
|
||||||
|
AND reference = :target
|
||||||
|
), ranked AS (
|
||||||
|
SELECT id, ROW_NUMBER() OVER (PARTITION BY user_id, new_item_key ORDER BY id) AS position
|
||||||
|
FROM candidates
|
||||||
|
)
|
||||||
|
DELETE FROM community.vocab_srs_item AS duplicate
|
||||||
|
USING ranked
|
||||||
|
WHERE duplicate.id = ranked.id
|
||||||
|
AND ranked.position > 1;
|
||||||
|
`, {
|
||||||
|
replacements: {
|
||||||
|
target: TARGET,
|
||||||
|
shortAnswer: SHORT_ANSWER,
|
||||||
|
normalizedCombinedAnswer: NORMALIZED_COMBINED_ANSWER,
|
||||||
|
normalizedTarget: NORMALIZED_TARGET
|
||||||
|
},
|
||||||
|
transaction
|
||||||
|
});
|
||||||
|
|
||||||
await queryInterface.sequelize.query(`
|
await queryInterface.sequelize.query(`
|
||||||
UPDATE community.vocab_srs_item
|
UPDATE community.vocab_srs_item
|
||||||
SET learning = :combinedAnswer,
|
SET learning = :combinedAnswer,
|
||||||
|
|||||||
Reference in New Issue
Block a user