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

io.inversion.rql.Term Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015-2018 Rocket Partners, LLC
 * https://github.com/inversion-api
 *
 * 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 io.inversion.rql;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

public class Term implements Comparable {

    public final List terms  = new ArrayList<>();
    public       Term       parent = null;
    public       char       quote  = 0;
    public       String     token  = null;

    protected Term() {

    }

    protected Term(String token) {
        withToken(token);
    }

    protected Term(Term parent, String token) {
        withParent(parent);
        withToken(token);
    }

    public static Term term(Term parent, String token, Object... terms) {
        Term newTerm       = new Term(parent, token);
        List deconstructed = deconstructed(new ArrayList<>(), terms);
        for (Object aTerm : deconstructed) {
            if (aTerm instanceof Term) {
                newTerm.withTerm((Term) aTerm);
            } else {
                newTerm.withTerm(new Term(newTerm, aTerm.toString()));
            }
        }

        return newTerm;
    }

    static List deconstructed(List found, Object... terms) {
        if (terms.length == 1 && terms[0].getClass().isArray())
            terms = (Object[]) terms[0];

        for (Object o : terms) {
            if (o instanceof Collection) {
                ((Collection) o).forEach(o2 -> deconstructed(found, o2));
            } else if (o.getClass().isArray()) {
                Object[] arr = (Object[]) o;
                for (Object o2 : arr) {
                    deconstructed(found, o2);
                }
            } else {
                found.add(o);
            }
        }
        return found;
    }

    public Term copy() {
        Term copy = new Term();

        copy.quote = quote;
        copy.token = token;

        terms.forEach(child -> copy.withTerm(child.copy()));

        return copy;
    }

    @Override
    public int compareTo(Term o) {
        int val = token.compareTo(o.token);
        if (val == 0) {
            for (int i = 0; i < terms.size(); i++) {
                if (o.terms.size() <= i)
                    return 1;

                val = terms.get(i).compareTo(o.terms.get(i));

                if (val != 0)
                    break;
            }
        }
        return val;
    }

    public String getToken(int childIndex) {
        if (terms.size() > childIndex)
            return terms.get(childIndex).getToken();
        return null;
    }

    public String getToken() {
        if (token == null)
            return "NULL";

        return token;
    }

    public boolean hasToken(String... tokens) {
        if (token == null)
            return false;

        for (int i = 0; tokens != null && i < tokens.length; i++) {
            if (token.equalsIgnoreCase(tokens[i]))
                return true;
        }
        return false;
    }

    public boolean hasChildLeafToken(String... tokens) {
        if (token == null)
            return false;

        for (Term child : terms) {
            if (child.isLeaf() && child.hasToken(tokens))
                return true;
        }
        return false;
    }

    public Term withToken(String token) {
        quote = 0;
        if (token != null) {
            token = token.trim();

            if (token.length() > 1) {
                char start = token.charAt(0);
                if (token.charAt(token.length() - 1) == start && (start == '\'' || start == '"' || start == '`')) {
                    quote = start;
                    token = token.substring(1, token.length() - 1);
                }
            }
        }

        if (quote == '`') //replace mysql style with ansi sql style
            quote = '"';

        this.token = token;
        return this;
    }

    public Term getParent() {
        return parent;
    }

    public Term withParent(Term parent) {
        if (this.parent != parent) {
            this.parent = parent;
            if (parent != null) {
                parent.withTerm(this);
            }
        }
        this.parent = parent;

        return this;
    }

    public boolean isLeaf() {
        return terms.size() == 0;
    }

    public boolean isLeaf(int childIndex) {
        if (childIndex >= terms.size())
            return false;

        return getTerm(childIndex).isLeaf();
    }

    public int size() {
        return terms.size();
    }

    public int indexOf(Term child) {
        return terms.indexOf(child);
    }

    public int getNumTerms() {
        return terms.size();
    }

    public List getTerms() {
        return terms;
    }

    public Term getTerm(int index) {
        if (terms.size() > index)
            return terms.get(index);

        return null;
    }

    public Term replaceTerm(Term oldTerm, Term newTerm) {
        terms.remove(newTerm);//make sure not in there twice

        int idx = terms.indexOf(oldTerm);
        if (idx < 0)
            terms.add(newTerm);
        else
            terms.set(idx, newTerm);
        return this;
    }

    public Term withTerms(Term... terms) {
        for (Term term : terms) {
            withTerm(term);
        }
        return this;
    }

    public Term withTerm(Term term) {
        if (term == this)
            throw new RuntimeException("A term can not be a child of itself");

        if (!terms.contains(term)) {
            terms.add(term);
            if (term.getParent() != this)
                term.withParent(this);
        }
        return this;
    }

    public Term withTerm(String token, Object... terms) {
        withTerm(term(this, token, terms));
        return this;
    }

    public Term withTerm(int index, Term term) {
        if (term == this)
            throw new RuntimeException("A term can not be a child of itself");

        terms.remove(term);
        terms.add(index, term);

        if (term.getParent() != this)
            term.withParent(this);

        return this;
    }

    public void removeTerm(Term term) {
        terms.remove(term);
    }

    public void clear() {
        terms.clear();
    }

    public boolean isQuoted() {
        return quote != 0;
    }

    public char getQuote() {
        return quote;
    }

    public String toString() {
        StringBuilder buff;
        if (quote > 0) {
            buff = new StringBuilder().append(quote).append(getToken()).append(quote);
        } else {
            buff = new StringBuilder(getToken());
        }
        if (terms.size() > 0) {
            buff.append("(");

            for (int i = 0; i < terms.size(); i++) {
                buff.append(terms.get(i).toString());
                if (i < terms.size() - 1)
                    buff.append(",");
            }

            buff.append(")");
        }

        return buff.toString();
    }

    /**
     * Returns a stream containing all Terms recursively.
     *
     * @return this term and all children recursively
     */
    public Stream stream() {
        List list = new ArrayList<>();
        collect(list);
        return list.stream();
    }

    void collect(List list) {
        list.add(this);
        for (Term child : terms) {
            child.collect(list);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy