240 lines
6.8 KiB
JavaScript
240 lines
6.8 KiB
JavaScript
/*
|
|
Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights
|
|
reserved.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
02110-1301 USA
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
global.debug = 0 ; // FIXME, currently used by parser & scanner
|
|
|
|
var assert = require("assert"),
|
|
mynode = require("../.."),
|
|
LoaderJob = require("./lib/LoaderJob.js").LoaderJob,
|
|
LoaderModule = require("./lib/LoaderModule.js").LoaderModule
|
|
;
|
|
|
|
function usage(flagHandler) {
|
|
var i, msg, option;
|
|
msg = "Usage: node dbloader [options]\n" +
|
|
" Options:\n" + flagHandler.helpText;
|
|
console.log(msg);
|
|
process.exit(1);
|
|
}
|
|
|
|
|
|
/* Define a command-line option.
|
|
If takesValue is false, then container[valueName] will hold valueIfSet if
|
|
option is set; if takesValue is true, container[valueName] will hold
|
|
the next command-line parameter after option.
|
|
*/
|
|
function Option(shortForm, longForm, helpText, callback) {
|
|
this.shortForm = shortForm;
|
|
this.longForm = longForm;
|
|
this.helpText = helpText;
|
|
this.callback = callback;
|
|
}
|
|
|
|
Option.prototype.isOption = true;
|
|
|
|
function FlagHandler() {
|
|
this.flags = {};
|
|
this.helpText = "";
|
|
}
|
|
|
|
FlagHandler.prototype.addOption = function(option) {
|
|
assert(option.isOption);
|
|
var shortFlag, longFlag, helpText;
|
|
helpText = "";
|
|
if(option.shortForm) {
|
|
shortFlag = option.shortForm;
|
|
this.flags[shortFlag] = option;
|
|
}
|
|
if(option.longForm) {
|
|
longFlag = option.longForm;
|
|
this.flags[longFlag] = option;
|
|
}
|
|
if(shortFlag && longFlag) {
|
|
helpText = " " + longFlag + "\n" +
|
|
" " + shortFlag + " " + option.helpText + "\n";
|
|
} else if(shortFlag) {
|
|
helpText = " " + shortFlag + " " + option.helpText + "\n";
|
|
} else if (longFlag) {
|
|
helpText = " " + longFlag + " " + option.helpText + "\n";
|
|
}
|
|
|
|
this.helpText += helpText;
|
|
};
|
|
|
|
FlagHandler.prototype.processArguments = function() {
|
|
var i, len, opt, nextArg, flag, consumed;
|
|
i = 2;
|
|
len = process.argv.length;
|
|
while(i < len) {
|
|
opt = process.argv[i];
|
|
nextArg = (i + 1 < len) ? process.argv[i+1] : null;
|
|
flag = this.flags[opt];
|
|
if(flag) {
|
|
consumed = flag.callback(nextArg);
|
|
if(consumed > 0) {
|
|
i += consumed;
|
|
} else {
|
|
usage(this);
|
|
}
|
|
} else {
|
|
usage(this);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
function parse_command_line() {
|
|
var i, len, handler, options;
|
|
handler = new FlagHandler();
|
|
options = {
|
|
"adapter" : "ndb",
|
|
"plugin" : new LoaderModule(handler)
|
|
};
|
|
handler.addOption(new Option(
|
|
"-n", "--ndb", "Use NDB adapter", function(nextArg) {
|
|
options.adapter = "ndb";
|
|
return 1;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-m", "--mysql", "Use MySQL adapter", function(nextArg) {
|
|
options.adapter = "mysql";
|
|
return 1;
|
|
}));
|
|
handler.addOption(new Option(
|
|
null, "--stats", "collect statistics", function(nextArg) {
|
|
options.stats = true;
|
|
return 1;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-d", "--debug", "enable debugging output", function(nextArg) {
|
|
unified_debug.on();
|
|
unified_debug.level_debug();
|
|
return 1;
|
|
}));
|
|
handler.addOption(new Option(
|
|
null, "-df", "enable debugging output from <source_file>", function(nextArg) {
|
|
unified_debug.on();
|
|
unified_debug.set_file_level(nextArg, 5);
|
|
return 2;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-c", null, "<ndb_connect_string>", function(nextArg) {
|
|
options.connect_string = nextArg;
|
|
return 2;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-f", null, "<control_file>", function(nextArg) {
|
|
options.control_file = nextArg;
|
|
return 2;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-e", null, "<load_data_command_text>", function(nextArg) {
|
|
options.control_text = nextArg;
|
|
return 2;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-j", null, "<javascript_plugin_file>", function(nextArg) {
|
|
/* Here is the code that actually loads the user's module: */
|
|
var modulePath;
|
|
options.plugin_file = nextArg;
|
|
modulePath = options.plugin_file;
|
|
// Assume the module path is relative to PWD unless it begins with / or .
|
|
if(modulePath[0] !== "." && modulePath[0] !== "/") {
|
|
modulePath = "./" + modulePath;
|
|
}
|
|
require(modulePath).init(options.plugin);
|
|
return 2;
|
|
}));
|
|
handler.addOption(new Option(
|
|
"-h", "--help", "show usage", function(nextArg) {
|
|
usage(handler);
|
|
process.exit(1);
|
|
}));
|
|
|
|
handler.processArguments();
|
|
|
|
if(! (options.control_file || options.control_text || options.plugin)) {
|
|
usage(handler);
|
|
}
|
|
return options;
|
|
}
|
|
|
|
|
|
function main() {
|
|
// Parse command-line options
|
|
var cmdOptions = parse_command_line();
|
|
|
|
// The User's custom plugin
|
|
var plugin = cmdOptions.plugin;
|
|
|
|
// Generate Loader Job
|
|
var job = new LoaderJob();
|
|
job.setPlugin(plugin);
|
|
|
|
if(cmdOptions.control_file) {
|
|
job.initializeFromFile(cmdOptions.control_file);
|
|
} else {
|
|
job.initializeFromSQL(cmdOptions.control_text);
|
|
}
|
|
|
|
// Create a TableMapping for the destination
|
|
var mappedConstructors = [ job.destination.createTableMapping() ];
|
|
|
|
// Add other mappings if defined by the plugin
|
|
var extMappings = job.plugin.createMappings();
|
|
if(Array.isArray(extMappings)) {
|
|
mappedConstructors = mappedConstructors.concat(extMappings);
|
|
}
|
|
|
|
// Set connection properties
|
|
var connectionProperties = new mynode.ConnectionProperties(cmdOptions.adapter);
|
|
|
|
if(cmdOptions.connect_string) {
|
|
connectionProperties.ndb_connectstring = cmdOptions.connect_string;
|
|
}
|
|
connectionProperties.database = job.destination.database;
|
|
|
|
// Connect to the database and start the controller
|
|
mynode.openSession(connectionProperties, mappedConstructors, function(err, session) {
|
|
if(err) throw err; /*JSON.stringify(err); process.exit(1);*/
|
|
job.run(session, function onComplete(error, stats) {
|
|
session.close().then(function() {
|
|
var exitCode = 0; // OK
|
|
if(error) {
|
|
console.log(error);
|
|
exitCode = 1; // Failure
|
|
} else {
|
|
console.log("Rows processed:", stats.rowsProcessed,
|
|
"Skipped", stats.rowsSkipped,
|
|
"Loaded:", stats.rowsComplete - stats.rowsError,
|
|
"Failed:", stats.rowsError);
|
|
if(stats.rowsError > 0) { exitCode = 2; } // Rejected Rows
|
|
}
|
|
process.exit(exitCode);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
main();
|
|
|