Skip to content

Instantly share code, notes, and snippets.

@bc-jasond
Created September 2, 2019 05:43
Show Gist options
  • Save bc-jasond/499580dc656c484c89289b4be7c3f6f3 to your computer and use it in GitHub Desktop.
Save bc-jasond/499580dc656c484c89289b4be7c3f6f3 to your computer and use it in GitHub Desktop.
dubaniewi.cz content model migration script
// ESM - remove after ECMAScript Module support is past Experimental node v14 ?
require = require('esm')(module/*, options*/);
const {
NODE_TYPE_LI,
NODE_TYPE_P,
NODE_TYPE_A,
NODE_TYPE_BOLD,
NODE_TYPE_CODE,
NODE_TYPE_ITALIC,
NODE_TYPE_LINK,
NODE_TYPE_SITEINFO,
NODE_TYPE_STRIKE,
NODE_TYPE_TEXT,
SELECTION_ACTION_SITEINFO,
SELECTION_ACTION_LINK,
SELECTION_ACTION_ITALIC,
SELECTION_ACTION_STRIKETHROUGH,
SELECTION_ACTION_CODE,
SELECTION_ACTION_BOLD,
SELECTION_LINK_URL,
} = require('../frontend/src/common/constants');
const {
Selection,
} = require('../frontend/src/pages/edit/edit-selection-helpers');
const { fromJS, List } = require('immutable');
const {
getKnex,
} = require('./mysql');
async function mang() {
const id = 8;
const knex = await getKnex();
const [{ user_id, title, canonical, abstract }] = await knex('post')
.where('id', id);
const [newPostId] = await knex
.insert({ user_id, title, canonical, abstract })
.into('post');
const contentNodes = await knex('content_node')
.where('post_id', id)
.orderBy(['parent_id', 'position']);
// keyed off of parent_id
const formattingNodes = {};
// nodes with Selection()
const pAndLiNodes = {};
// all other nodes, sections, etc.
const sectionAndParentNodes = [];
// first loop
// - add formatting & legacy text nodes to an object keyed on 'parent_id' for later Selection() processing
for (let i = 0; i < contentNodes.length; i++) {
const node = fromJS({ ...contentNodes[i] });
if ([
NODE_TYPE_A,
NODE_TYPE_CODE,
NODE_TYPE_SITEINFO,
NODE_TYPE_ITALIC,
NODE_TYPE_STRIKE,
NODE_TYPE_BOLD,
NODE_TYPE_LINK,
NODE_TYPE_TEXT
].includes(node.get('type'))) {
if (!formattingNodes[node.get('parent_id')]) {
formattingNodes[node.get('parent_id')] = [];
}
formattingNodes[node.get('parent_id')][node.get('position')] = node;
continue;
}
if ([NODE_TYPE_P, NODE_TYPE_LI].includes(node.get('type'))) {
pAndLiNodes[node.get('id')] = node;
continue;
}
sectionAndParentNodes.push(node);
}
// next loop - add sections and parent nodes (everything but P and LI) to document, add text content where no Selection() is necessary
for (let i = 0; i < sectionAndParentNodes.length; i++) {
const node = sectionAndParentNodes[i];
const nodeInsertValues = { ...node.toJS(), post_id: newPostId };
nodeInsertValues.content = nodeInsertValues.content || '';
if (formattingNodes[node.get('id')] && formattingNodes[node.get('id')].length === 1 && formattingNodes[node.get('id')][0].get('type') === NODE_TYPE_TEXT) {
nodeInsertValues.content = formattingNodes[node.get('id')][0].get('content');
delete formattingNodes[node.get('id')];
}
nodeInsertValues.meta = JSON.stringify(nodeInsertValues.meta);
await knex('content_node')
.insert(nodeInsertValues)
}
// next loop - for P and LI create Selection() records where necessary
for (let nodeWithSelectionId in pAndLiNodes) {
let parent = pAndLiNodes[nodeWithSelectionId];
const siblings = formattingNodes[nodeWithSelectionId];
let currentMeta = parent.get('meta');
let currentSelections = currentMeta.get('selections', List());
let currentSelection = new Selection();
let currentEndOffset = 0;
for (let i = 0; i < siblings.length; i++) {
let current = siblings[i];
if (
current.get('type') === NODE_TYPE_TEXT
// text node is only child of P or LI
&& siblings.length === 1
) {
// just add TEXT node content to parent node - no Selection() mapping needed
parent = parent.set('content', current.get('content'));
// already updated this node
continue;
}
// Selection() needed
while (current.get('type') !== NODE_TYPE_TEXT) {
switch (current.get('type')) {
case NODE_TYPE_SITEINFO:
currentSelection = currentSelection.set(SELECTION_ACTION_SITEINFO, true);
break;
case NODE_TYPE_A:
currentSelection = currentSelection
.set(SELECTION_ACTION_LINK, true)
.set(SELECTION_LINK_URL, current.get('content'));
break;
case NODE_TYPE_ITALIC:
currentSelection = currentSelection.set(SELECTION_ACTION_ITALIC, true);
break;
case NODE_TYPE_STRIKE:
currentSelection = currentSelection.set(SELECTION_ACTION_STRIKETHROUGH, true);
break;
case NODE_TYPE_CODE:
currentSelection = currentSelection.set(SELECTION_ACTION_CODE, true);
break;
case NODE_TYPE_BOLD:
currentSelection = currentSelection.set(SELECTION_ACTION_BOLD, true);
}
const currentChildren = formattingNodes[current.get('id')];
// assuming 1 child here...
if (currentChildren) {
current = currentChildren.shift();
} else {
// CODE used to have 'content' too!, need to let the loop happen for formatting but, then break;
break;
}
}
const parentContent = parent.get('content') || '';
const currentContent = current.get('content') || '';
currentEndOffset = currentEndOffset += currentContent.length;
currentSelection = currentSelection.set('end', currentEndOffset);
currentSelections = currentSelections.push(currentSelection);
parent = parent
.set('content', `${parentContent}${currentContent}`)
.set('meta', currentMeta.set('selections', currentSelections))
currentSelection = new Selection({ start: currentEndOffset });
}
const insertValues = { ...parent.toJS(), post_id: newPostId };
insertValues.meta = JSON.stringify(insertValues.meta);
await knex('content_node')
.insert(insertValues);
}
console.log('KTHXBYE')
}
mang();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment