<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const db = require('../models/database').db;
const Migration = require('../models/Migration');
const { compareSemanticVersion } = require('../util');
const { log } = require('../log');

// file needed to run database transaction
const requiredFile = [];

/**
 * @param migrationItems extracted from registerMigration.js
 * @returns {Array} of migration pair
 */
function printMigrationList(migrationItems) {
	const list = [];
	for (const item of migrationItems) {
		list.push(`${item.fromVersion} -> ${item.toVersion}`);
	}
	return list;
}

/**
 * Create an array of unique versions;
 * @param migrationItems extracted from registerMigration.js
 * @returns {*[]} array of unique versions
 */
function getUniqueKeyOfMigrationList(migrationItems) {
	const vertex = [];

	for (const m of migrationItems) {
		// disallow down migration
		if (compareSemanticVersion(m.fromVersion, m.toVersion) === 1) {
			throw new Error('Should not downgrade, please check registerMigration.js');
		} else {
			vertex.push(m.fromVersion);
			vertex.push(m.toVersion);
		}
	}

	return [...new Set(vertex)];
}

/**
 * create an adjacency list (OBJECT) of the migrations
 * @param migrationItems extracted from registerMigration.js
 * @returns {{}}
 */
function createMigrationList(migrationItems) {
	const migrationList = {};

	const uniqueKey = getUniqueKeyOfMigrationList(migrationItems);

	uniqueKey.forEach(key => {
		migrationList[key] = [];
	});

	for (const m of migrationItems) {
		migrationList[m.fromVersion].push(m);
	}

	return migrationList;
}

/**
 * If current version or version user wants to migrate is not in the migrationList, throw an Error
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param adjListArray adjacency list of version graph
 */
function checkIfFromAndToExist(curr, to, adjListArray) {
	if (!(curr in adjListArray)) {
		throw new Error('Did not find version in migration list');
	}
	if (!(to in adjListArray)) {
		throw new Error('Did not find version in migration list');
	}
}

/**
 * Do a breath first search traversal to find the shortest path
 * from the current version to the version user want to migrate
 * It also works for down migration.
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param adjListArray adjacency list of version graph
 * @returns {Array} return an array of indexes to the version that we want to migrate to
 */
function findPathToMigrate(curr, to, adjListArray) {
	const queue = [];
	const path = [];
	const visited = []; // When there is a cycle, make sure it is not infinite.

	checkIfFromAndToExist(curr, to, adjListArray);

	for (const vertex of Object.keys(adjListArray)) {
		visited[vertex] = false;
		path[vertex] = -1;
	}

	queue.push(curr);
	visited[curr] = true;

	while (queue.length > 0) {
		const currentVertexID = queue.shift();
		const currentVertex = adjListArray[currentVertexID];
		const edges = currentVertex.length;
		for (let i = 0; i < edges; i++) {
			const target = currentVertex[i];
			if (!visited[target.toVersion]) {
				visited[target.toVersion] = true;
				path[target.toVersion] = currentVertexID;
				queue.push(target.toVersion);
			}
		}
	}
	return path;
}

/**
 * Based on the path array, recursively find the correct file to the version wanted to update
 * and add it to the requiredFile array
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param path array that store the indexes to the version that we want to migrate to
 */
function getRequiredFileToMigrate(curr, to, path) {
	if (curr === to) {
		requiredFile.push();
	} else if (path[to] === -1) {
		throw new Error('No path found');
	} else {
		getRequiredFileToMigrate(curr, path[to], path);
		requiredFile.push({
			fromVersion: path[to],
			toVersion: to
		});
	}
}

/**
 * Open a database transaction and migrate the database by calling up() method.
 * Insert row into migration folder
 * @param neededFile name of file needed to migrate
 * @param list is the migration list
 */
async function migrateDatabaseTransaction(neededFile, list) {
	await db.tx(async t => {
		neededFile.forEach(file => {
			for (const items of Object.keys(list)) {
				if (file.fromVersion === items) {
					list[items].forEach(async item => {
						if (item.toVersion === file.toVersion) {
							await item.up(t);
							const migration = new Migration(undefined, file.fromVersion, file.toVersion);
							try {
								await migration.insert(t);
							} catch (err) {
								log.error(`Error while migrating database: ${err}`, err);
							}<commit_msg>Moved up method into try catch to catch error<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const db = require('../models/database').db;
const Migration = require('../models/Migration');
const { compareSemanticVersion } = require('../util');
const { log } = require('../log');

// file needed to run database transaction
const requiredFile = [];

/**
 * @param migrationItems extracted from registerMigration.js
 * @returns {Array} of migration pair
 */
function printMigrationList(migrationItems) {
	const list = [];
	for (const item of migrationItems) {
		list.push(`${item.fromVersion} -> ${item.toVersion}`);
	}
	return list;
}

/**
 * Create an array of unique versions;
 * @param migrationItems extracted from registerMigration.js
 * @returns {*[]} array of unique versions
 */
function getUniqueKeyOfMigrationList(migrationItems) {
	const vertex = [];

	for (const m of migrationItems) {
		// disallow down migration
		if (compareSemanticVersion(m.fromVersion, m.toVersion) === 1) {
			throw new Error('Should not downgrade, please check registerMigration.js');
		} else {
			vertex.push(m.fromVersion);
			vertex.push(m.toVersion);
		}
	}

	return [...new Set(vertex)];
}

/**
 * create an adjacency list (OBJECT) of the migrations
 * @param migrationItems extracted from registerMigration.js
 * @returns {{}}
 */
function createMigrationList(migrationItems) {
	const migrationList = {};

	const uniqueKey = getUniqueKeyOfMigrationList(migrationItems);

	uniqueKey.forEach(key => {
		migrationList[key] = [];
	});

	for (const m of migrationItems) {
		migrationList[m.fromVersion].push(m);
	}

	return migrationList;
}

/**
 * If current version or version user wants to migrate is not in the migrationList, throw an Error
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param adjListArray adjacency list of version graph
 */
function checkIfFromAndToExist(curr, to, adjListArray) {
	if (!(curr in adjListArray)) {
		throw new Error('Did not find version in migration list');
	}
	if (!(to in adjListArray)) {
		throw new Error('Did not find version in migration list');
	}
}

/**
 * Do a breath first search traversal to find the shortest path
 * from the current version to the version user want to migrate
 * It also works for down migration.
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param adjListArray adjacency list of version graph
 * @returns {Array} return an array of indexes to the version that we want to migrate to
 */
function findPathToMigrate(curr, to, adjListArray) {
	const queue = [];
	const path = [];
	const visited = []; // When there is a cycle, make sure it is not infinite.

	checkIfFromAndToExist(curr, to, adjListArray);

	for (const vertex of Object.keys(adjListArray)) {
		visited[vertex] = false;
		path[vertex] = -1;
	}

	queue.push(curr);
	visited[curr] = true;

	while (queue.length > 0) {
		const currentVertexID = queue.shift();
		const currentVertex = adjListArray[currentVertexID];
		const edges = currentVertex.length;
		for (let i = 0; i < edges; i++) {
			const target = currentVertex[i];
			if (!visited[target.toVersion]) {
				visited[target.toVersion] = true;
				path[target.toVersion] = currentVertexID;
				queue.push(target.toVersion);
			}
		}
	}
	return path;
}

/**
 * Based on the path array, recursively find the correct file to the version wanted to update
 * and add it to the requiredFile array
 * @param curr current version of the database
 * @param to version want to migrate to
 * @param path array that store the indexes to the version that we want to migrate to
 */
function getRequiredFileToMigrate(curr, to, path) {
	if (curr === to) {
		requiredFile.push();
	} else if (path[to] === -1) {
		throw new Error('No path found');
	} else {
		getRequiredFileToMigrate(curr, path[to], path);
		requiredFile.push({
			fromVersion: path[to],
			toVersion: to
		});
	}
}

/**
 * Open a database transaction and migrate the database by calling up() method.
 * Insert row into migration folder
 * @param neededFile name of file needed to migrate
 * @param list is the migration list
 */
async function migrateDatabaseTransaction(neededFile, list) {
	await db.tx(async t => {
		neededFile.forEach(file => {
			for (const items of Object.keys(list)) {
				if (file.fromVersion === items) {
					list[items].forEach(async item => {
						if (item.toVersion === file.toVersion) {
							try {
								await item.up(t);
								const migration = new Migration(undefined, file.fromVersion, file.toVersion);
								await migration.insert(t);
							} catch (err) {
								log.error(`Error while migrating database: ${err}`, err);
							}
{'fraction_non_alphanumeric': 0.11609171658748192, 'fraction_numerical': 0.0018591200165255113, 'mean_word_length': 3.8487731597396095, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5513461', 'n_tokens_mistral': 3088, 'n_tokens_neox': 2832, 'n_words': 1018}