Files
makemeahanzi/server/migration.js
2015-12-24 18:53:54 -05:00

150 lines
4.5 KiB
JavaScript

"use strict";
const addFrequencyField = (glyph) => {
const data = cjklib.getCharacterData(glyph.character);
glyph.metadata.frequency = data.frequency;
Glyphs.save(glyph);
}
const addSimplifiedAndTraditionalFields = (glyph) => {
const data = cjklib.getCharacterData(glyph.character);
glyph.simplified = data.simplified;
glyph.traditional = data.traditional;
Glyphs.save(glyph);
}
const checkStrokeExtractorStability = (glyph) => {
const strokes = stroke_extractor.getStrokes(
glyph.stages.path, glyph.stages.bridges);
if (!_.isEqual(strokes.strokes.sort(), glyph.stages.strokes.sort())) {
console.log(`Different strokes for ${glyph.character}`);
}
}
const convertOldPathSchemaToSVGPath = (path) => {
const terms = [];
for (let segment of path) {
assert('LMQZ'.indexOf(segment.type) >= 0, segment.type);
terms.push(segment.type);
if (segment.x1 !== undefined) {
terms.push(segment.x1);
terms.push(segment.y1);
}
if (segment.x !== undefined) {
terms.push(segment.x);
terms.push(segment.y);
}
}
return terms.join(' ');
}
const migrateOldGlyphSchemaToNew = (glyph) => {
const codepoint = parseInt(glyph.name.substr(3), 16);
const character = String.fromCodePoint(codepoint);
const data = cjklib.getCharacterData(character);
assert(glyph.manual && glyph.manual.verified !== undefined,
`Glyph ${character} was not verified.`);
const result = {
character: character,
codepoint: codepoint,
metadata: {
definition: undefined,
frequency: data.frequency,
kangxi_index: data.kangxi_index,
pinyin: undefined,
strokes: undefined,
},
stages: {
path: convertOldPathSchemaToSVGPath(glyph.path),
bridges: glyph.manual.bridges,
strokes: glyph.derived.strokes,
analysis: undefined,
order: undefined,
verified: undefined,
},
simplified: data.simplified,
traditional: data.traditional,
};
assert(result.stages.path !== undefined);
assert(result.stages.bridges !== undefined);
assert(result.stages.strokes !== undefined);
return result;
}
const setAnalysisStageToReady = (glyph) => {
const data = cjklib.getCharacterData(glyph.character);
if (data && data.strokes === glyph.stages.strokes.length) {
glyph.stages.analysis = {sentinel: true};
} else {
console.log(`Different stroke count for ${glyph.character}. Expected: ` +
`${data.strokes}, got: ${glyph.stages.strokes.length}.`);
}
}
const completionCallback = undefined;
const perGlyphCallback = undefined;
const loadFromOldSchemaJSON = (filename) => {
const fs = Npm.require('fs');
const path = Npm.require('path');
const filepath = path.join(getPWD(), 'public', filename);
fs.readFile(filepath, 'utf8', Meteor.bindEnvironment((error, data) => {
if (error) throw error;
const lines = data.split('\n').filter((x) => x.length > 0);
console.log(`Loaded ${lines.length} old-schema glyphs.`);
let migrated = 0;
for (var line of lines) {
try {
const old_glyph = JSON.parse(line);
const new_glyph = migrateOldGlyphSchemaToNew(old_glyph);
setAnalysisStageToReady(new_glyph);
Glyphs.save(new_glyph);
migrated += 1;
} catch (error) {
console.error(error);
}
}
console.log(`Successfully migrated ${migrated} glyphs.`);
}));
}
// Runs the given per-glyph callback for each glyph in the database.
// When all the glyphs are migrated, runs the completion callback.
const runMigration = () => {
console.log('Running migration...');
if (perGlyphCallback) {
const codepoints =
Glyphs.find({}, {fields: {codepoint: 1}, sort: {codepoint: 1}}).fetch();
for (let i = 0; i < codepoints.length; i++) {
const glyph = Glyphs.findOne({codepoint: codepoints[i].codepoint});
assert(glyph, 'Glyphs changed during migration!');
perGlyphCallback(glyph);
if ((i + 1) % 1000 === 0) {
console.log(`Migrated ${i + 1} glyphs.`);
}
}
}
if (completionCallback) {
completionCallback();
}
console.log('Migration complete.');
}
Meteor.methods({
'loadFromOldSchemaJSON': (filename) => {
cjklib.promise.then(
Meteor.bindEnvironment(() => loadFromOldSchemaJSON(filename)))
.catch(console.error.bind(console));
},
});
Meteor.startup(() => {
if (!perGlyphCallback && !completionCallback) {
return;
}
console.log('Preparing for migration...');
cjklib.promise.then(Meteor.bindEnvironment(runMigration))
.catch(console.error.bind(console));
});