Professional Documents
Culture Documents
/usr/bin/env node
const fs = require('fs');
const readline = require('readline');
// FIXME handle broken pipe error and add tests. See Python version.
function show_exception(e) {
let [error_type, error_msg] = rbql.exception_to_error_info(e);
if (error_format == 'hr') {
show_error_plain_text(error_type, error_msg);
} else {
report_error_json(error_type, error_msg);
}
}
function show_warning(msg) {
if (interactive_mode) {
console.log('\x1b[33;1mWarning:\x1b[0m ' + msg);
} else {
console.error('Warning: ' + msg);
}
}
function normalize_delim(delim) {
if (delim == 'TAB')
return '\t';
if (delim == '\\t')
return '\t';
return delim;
}
function get_default_policy(delim) {
if ([';', ','].indexOf(delim) != -1) {
return 'quoted';
} else if (delim == ' ') {
return 'whitespace';
} else {
return 'simple';
}
}
rbql-js supports two modes: non-interactive (with "--query" option) and interactive
(without "--query" option)
Interactive mode shows source table preview which makes query editing much easier.
Usage example:
$ rbql-js --input input.csv
Non-interactive mode supports source tables in stdin. Usage example:
$ rbql-js --query "select a1, a2 order by a1" --delim , < input.csv
`;
let epilog = `
Description of the available CSV split policies:
* "simple" - RBQL uses simple split() function and doesn't perform special
handling of double quote characters
* "quoted" - Separator can be escaped inside double-quoted fields. Double quotes
inside double-quoted fields must be doubled
* "quoted_rfc" - Same as "quoted", but also allows newlines inside double-quoted
fields, see RFC-4180: https://tools.ietf.org/html/rfc4180
* "whitespace" - Works only with whitespace separator, multiple consecutive
whitespaces are treated as a single whitespace
* "monocolumn" - RBQL doesn't perform any split at all, each line is a single-
element record, i.e. only "a1" and "NR" are available
`;
if (args['version']) {
console.log(rbql.version);
process.exit(0);
}
if (args.encoding == 'latin-1')
args.encoding = 'binary';
error_format = args['error-format'];
if (args.hasOwnProperty('query')) {
interactive_mode = false;
if (!args.hasOwnProperty('delim')) {
throw new GenericError('Separator must be provided with "--delim"
option in non-interactive mode');
}
await run_with_js(args);
} else {
interactive_mode = true;
if (error_format == 'json') {
throw new GenericError('json error format is not compatible with
interactive mode');
}
await run_interactive_loop(args);
}
}
function main() {
var scheme = {
'--input': {'help': 'Read csv table from FILE instead of stdin. Required in
interactive mode', 'metavar': 'FILE'},
'--query': {'help': 'Query string in rbql. Run in interactive mode if
empty', 'metavar': 'QUERY'},
'--output': {'help': 'Write output table to FILE instead of stdout',
'metavar': 'FILE'},
'--delim': {'help': 'Delimiter character or multicharacter string, e.g. ","
or "###". Can be autodetected in interactive mode', 'metavar': 'DELIM'},
'--policy': {'help': 'Split policy, see the explanation below. Supported
values: "simple", "quoted", "quoted_rfc", "whitespace", "monocolumn". Can be
autodetected in interactive mode', 'metavar': 'POLICY'},
'--with-headers': {'boolean': true, 'help': 'Indicates that input (and
join) table has header'},
'--comment-prefix': {'help': 'Ignore lines in input and join tables that
start with the comment PREFIX, e.g. "#" or ">>"', 'metavar': 'PREFIX'},
'--encoding': {'default': 'utf-8', 'help': 'Manually set csv encoding',
'metavar': 'ENCODING'},
'--out-format': {'default': 'input', 'help': 'Output format. Supported
values: ' + out_format_names.map(v => `"${v}"`).join(', '), 'metavar': 'FORMAT'},
'--out-delim': {'help': 'Output delim. Use with "out-policy". Overrides
out-format', 'metavar': 'DELIM'},
'--out-policy': {'help': 'Output policy. Use with "out-delim". Overrides
out-format', 'metavar': 'POLICY'},
'--error-format': {'default': 'hr', 'help': 'Errors and warnings format.
[hr|json]', 'hidden': true},
'--version': {'boolean': true, 'help': 'Print RBQL version and exit'},
'--init-source-file': {'help': 'Path to init source file to use instead of
~/.rbql_init_source.js', 'hidden': true}
};
let args = cli_parser.parse_cmd_args(process.argv, scheme, tool_description,
epilog);
do_main(args).then(() => {}).catch(error_info => { show_exception(error_info);
process.exit(1); });
}