All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cinchapi.concourse.export.cli.ExportCli Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2022 Cinchapi Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cinchapi.concourse.export.cli;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import com.beust.jcommander.Parameter;
import com.cinchapi.ccl.syntax.AbstractSyntaxTree;
import com.cinchapi.ccl.syntax.OrderTree;
import com.cinchapi.ccl.syntax.PageTree;
import com.cinchapi.common.base.AnyObjects;
import com.cinchapi.common.base.CheckedExceptions;
import com.cinchapi.common.describe.Empty;
import com.cinchapi.concourse.cli.CommandLineInterface;
import com.cinchapi.concourse.cli.Options;
import com.cinchapi.concourse.export.Exporter;
import com.cinchapi.concourse.export.Exporters;
import com.cinchapi.concourse.lang.ConcourseCompiler;
import com.cinchapi.concourse.lang.paginate.Page;
import com.cinchapi.concourse.lang.sort.Order;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

/**
 * A CLI that uses the export framework to export data from Concourse to an
 * output stream.
 *
 * @author Jeff Nelson
 */
public final class ExportCli extends CommandLineInterface {

    /**
     * The set of records from which to export data.
     */
    @Nullable
    protected Set records = null;

    /**
     * The file to which the exported data is stored.
     */
    @Nullable
    protected Path file = null;

    /**
     * The condition that determines which records to export.
     */
    @Nullable
    protected String condition = null;

    /**
     * The order of the exported data.
     */
    @Nullable
    protected Order order = null;

    /**
     * The page of the data to export.
     */
    @Nullable
    protected Page page = null;

    /**
     * The set of keys to include in the data export for each exported record.
     */
    @Nullable
    protected Set keys = null;

    /**
     * A flag that determines of the record id should be included with the
     * exported data.
     */
    protected boolean excludeRecordId = getOptions().excludeRecordId;

    /**
     * Construct a new instance.
     * 
     * @param args
     */
    public ExportCli(String[] args) {
        super(args);
        init();
    }

    /**
     * Initialize the CLI based on the arguments that are provided.
     */
    private void init() {
        ExportOptions opts = (ExportOptions) options;

        // file
        if(!Empty.ness().describes(opts.file)) {
            file = Paths.get(opts.file);
            File $file = file.toFile();
            $file.getParentFile().mkdirs();
            try {
                $file.createNewFile();
            }
            catch (IOException e) {
                CheckedExceptions.wrapAsRuntimeException(e);
            }
        }

        // records
        if(!Empty.ness().describes(opts.records)) {
            records = AnyObjects.split(opts.records, ',').stream()
                    .map(Long::parseLong)
                    .collect(Collectors.toCollection(LinkedHashSet::new));
        }

        // keys
        if(!Empty.ness().describes(opts.keys)) {
            keys = AnyObjects.split(opts.keys, ',').stream()
                    .collect(Collectors.toCollection(LinkedHashSet::new));
        }

        // order
        if(!Empty.ness().describes(opts.order)) {
            if(!opts.order.toLowerCase().startsWith("order by")) {
                opts.order = "ORDER BY " + opts.order;
            }
            try {
                AbstractSyntaxTree ast = ConcourseCompiler.get()
                        .parse(opts.order);
                OrderTree tree = (OrderTree) ast;
                order = Order.from(tree);
            }
            catch (Exception e) {
                throw new IllegalArgumentException(
                        "Invalid order CCL statement");
            }
        }

        // page
        String $page = "";
        if(!Empty.ness().describes(opts.page)) {
            $page += "PAGE " + opts.page + " ";
        }
        if(!Empty.ness().describes(opts.size)) {
            $page += "SIZE " + opts.size;
        }
        if(!Empty.ness().describes($page)) {
            try {
                AbstractSyntaxTree ast = ConcourseCompiler.get().parse($page);
                PageTree tree = (PageTree) ast;
                page = Page.from(tree);
            }
            catch (Exception e) {
                throw new IllegalArgumentException(
                        "Invalid page or size argument");
            }
        }

        excludeRecordId = opts.excludeRecordId;
        condition = opts.condition;
    }

    @Override
    protected void doTask() {
        Map>> data;
        if(!Empty.ness().describes(records) && !Empty.ness().describes(keys)
                && !Empty.ness().describes(order)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, records, order, page);
        }
        else if(!Empty.ness().describes(condition)
                && !Empty.ness().describes(keys)
                && !Empty.ness().describes(order)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, condition, order, page);
        }
        else if(!Empty.ness().describes(records)
                && !Empty.ness().describes(keys)
                && !Empty.ness().describes(order)) {
            data = concourse.select(keys, records, order);
        }
        else if(!Empty.ness().describes(records)
                && !Empty.ness().describes(keys)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, records, page);
        }
        else if(!Empty.ness().describes(condition)
                && !Empty.ness().describes(keys)
                && !Empty.ness().describes(order)) {
            data = concourse.select(keys, condition, order);
        }
        else if(!Empty.ness().describes(records)
                && !Empty.ness().describes(page)
                && !Empty.ness().describes(order)) {
            data = concourse.select(records, page, order);
        }
        else if(!Empty.ness().describes(page) && !Empty.ness().describes(order)
                && !Empty.ness().describes(condition)) {
            data = concourse.select(condition, page, order);
        }
        else if(!Empty.ness().describes(condition)
                && !Empty.ness().describes(keys)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, condition, page);
        }
        else if(!Empty.ness().describes(keys) && !Empty.ness().describes(order)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, concourse.inventory(), order, page);
        }
        else if(!Empty.ness().describes(records)
                && !Empty.ness().describes(keys)) {
            data = concourse.select(keys, records);
        }
        else if(!Empty.ness().describes(condition)
                && !Empty.ness().describes(keys)) {
            data = concourse.select(keys, condition);
        }
        else if(!Empty.ness().describes(page)
                && !Empty.ness().describes(records)) {
            data = concourse.select(records, page);
        }
        else if(!Empty.ness().describes(order)
                && !Empty.ness().describes(records)) {
            data = concourse.select(records, order);
        }
        else if(!Empty.ness().describes(page)
                && !Empty.ness().describes(condition)) {
            data = concourse.select(condition, page);
        }
        else if(!Empty.ness().describes(order)
                && !Empty.ness().describes(condition)) {
            data = concourse.select(condition, order);
        }
        else if(!Empty.ness().describes(keys)
                && !Empty.ness().describes(order)) {
            data = concourse.select(keys, concourse.inventory(), order);
        }
        else if(!Empty.ness().describes(keys)
                && !Empty.ness().describes(page)) {
            data = concourse.select(keys, concourse.inventory(), page);
        }
        else if(!Empty.ness().describes(order)
                && !Empty.ness().describes(page)) {
            data = concourse.select(concourse.inventory(), order, page);
        }
        else if(!Empty.ness().describes(records)) {
            data = concourse.select(records);
        }
        else if(!Empty.ness().describes(condition)) {
            data = concourse.select(condition);
        }
        else if(!Empty.ness().describes(order)) {
            data = concourse.select(concourse.inventory(), order);
        }
        else if(!Empty.ness().describes(page)) {
            data = concourse.select(concourse.inventory(), page);
        }
        else if(!Empty.ness().describes(keys)) {
            data = concourse.select(keys, concourse.inventory());
        }
        else {
            data = concourse.select(concourse.inventory());
        }
        Exporter> exporter = file != null ? Exporters.csv(file)
                : Exporters.csv(); // TODO: add support for workbooks?
        if(!excludeRecordId) {
            data.forEach((id, object) -> {
                object.put("id", ImmutableSet.of(id));
            });
        }
        exporter.export(data.values());
    }

    @Override
    protected ExportOptions getOptions() {
        return new ExportOptions();
    }

    /**
     * Export specific {@link Options}.
     * 
     * @author jnelson
     */
    private static class ExportOptions extends Options {
        @Parameter(names = { "-r",
                "--records" }, description = "Comma separated list of records to export", variableArity = true)
        public List records = Lists.newArrayList();

        @Parameter(names = { "--condition",
                "--where" }, description = "CCL condition statement that describes how to find the records to export")
        public String condition = null;

        @Parameter(names = { "-o",
                "--order" }, description = "CCL order statement that describes how to sort the exported data")
        public String order = null;

        @Parameter(names = {
                "--page" }, description = "The data page to export (default: the first page)")
        public Integer page = null;

        @Parameter(names = {
                "--size" }, description = "The maximum number of records to include on the exported page (default: export all data)")
        public Integer size = null;

        @Parameter(names = { "-f",
                "--file" }, description = "File to which the data should be exported.")
        public String file = null;

        @Parameter(names = "--exclude-record-id", description = "Flag to not display the primary key when exporting.")
        public boolean excludeRecordId = false;

        @Parameter(names = { "-k", "--keys",
                "--select" }, description = "Comma separated list of keys to select from each record. By default, all of a record's keys are selected", variableArity = true)
        public List keys = Lists.newArrayList();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy