diff --git a/src/tools/scene_tag_revision_fix.js b/src/tools/scene_tag_revision_fix.js new file mode 100644 index 0000000..b8497d5 --- /dev/null +++ b/src/tools/scene_tag_revision_fix.js @@ -0,0 +1,80 @@ +import { MerkleJson } from 'merkle-json'; + +import knex from '../knex.js'; + +const mj = new MerkleJson(); + +function curateTag(tag) { + if (Object.hasOwn(tag, 'actorId')) { + return { + id: tag.id, + actorId: tag.actorId, + }; + } + + if (typeof tag === 'number') { + return { + id: tag, + // can't restore actorId, don't set to null to hint at missing data + }; + } + + throw new Error(`Unrecognized tag delta: ${JSON.stringify(tag)}`); +} + +async function init() { + const revisions = await knex('scenes_revisions'); + + // console.log(revisions); + + const fixedRevisions = revisions.map((revision) => { + if (revision.base.tags.length === 0 && !revision.deltas.some((delta) => delta.key === 'tags')) { + return null; + } + + const newDeltas = revision.deltas.map((delta) => { + if (delta.key !== 'tags') { + return delta; + } + + return { + ...delta, + value: delta.value.map((tag) => curateTag(tag)), + }; + }); + + const newBase = { + ...revision.base, + tags: revision.base.tags.map((tag) => curateTag(tag)), + }; + + return { + ...revision, + deltas: newDeltas, + base: newBase, + }; + }).filter(Boolean); + + const entries = fixedRevisions.map((revision) => ({ + id: revision.id, + base: JSON.stringify(revision.base), + deltas: JSON.stringify(revision.deltas), + hash: mj.hash({ + base: revision.base, + deltas: revision.deltas, + }), + })); + + console.log(entries); + + await knex('scenes_revisions') + .insert(entries) + .onConflict('id') + .merge(['base', 'deltas', 'hash']); + + console.log(`Fixed ${entries.length} revisions`); + + await knex.destroy(); +} + +init();