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

org.ehrbase.aql.sql.queryimpl.FunctionBasedNodePredicateCall Maven / Gradle / Ivy

There is a newer version: 2.12.0
Show newest version
/*
 * Copyright (c) 2019 vitasystems GmbH and Hannover Medical School.
 *
 * This file is part of project EHRbase
 *
 * 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
 *
 *     https://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 org.ehrbase.aql.sql.queryimpl;

import static org.ehrbase.aql.sql.queryimpl.AqlRoutines.jsonpathItemAsText;
import static org.ehrbase.aql.sql.queryimpl.QueryImplConstants.AQL_NODE_ITERATIVE_MARKER;
import static org.ehrbase.aql.sql.queryimpl.QueryImplConstants.AQL_NODE_NAME_PREDICATE_MARKER;
import static org.ehrbase.aql.sql.queryimpl.value_field.Functions.apply;
import static org.ehrbase.jooq.pg.Routines.aqlNodeNamePredicate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.ehrbase.aql.sql.queryimpl.attribute.FieldResolutionContext;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.JSONB;
import org.jooq.TableField;
import org.jooq.impl.DSL;

/**
 * Created by christian on 5/9/2018.
 * build expression to call node name resolution on jsonb
 * specifically deals with function based sql encoding (used for composition attributes at this stage)
 * The function call syntax is:
 * ehr.aql_node_name_predicate(,'','the path of node to check for name/value predicate')
 */
public class FunctionBasedNodePredicateCall {

    private final List itemPathArray;
    private final FieldResolutionContext fieldContext;

    public FunctionBasedNodePredicateCall(FieldResolutionContext fieldContext, List itemPathArray) {
        this.fieldContext = fieldContext;
        this.itemPathArray = itemPathArray;
    }

    public Field resolve(Object function, TableField... tableFields) {
        List expression = new ArrayList<>();
        expression.addAll(patchItemArray(itemPathArray));

        while (expression.contains(AQL_NODE_NAME_PREDICATE_MARKER)) {
            expression = resolveNodePredicateCall(expression, function, tableFields);
        }

        return DSL.field(expression.get(0));
    }

    /**
     * substitute with the node/name predicate function
     * @param itemPathArray
     * @return
     */
    private List resolveNodePredicateCall(
            List itemPathArray, Object function, TableField... tableFields) {
        Configuration configuration = fieldContext.getContext().configuration();
        int startList;

        List expression = new ArrayList<>();

        Field nodeField;

        if (!itemPathArray.get(0).replace("\"", "").startsWith(QueryImplConstants.AQL_NODE_NAME_PREDICATE_FUNCTION)) {
            nodeField = DSL.field(apply(function, tableFields).toString()).cast(JSONB.class);
            startList = 0;
        } else {
            nodeField = DSL.field(itemPathArray.get(0));
            startList = 1;
        }

        int markerPos = ArrayUtils.indexOf(
                itemPathArray.toArray(new String[] {}), QueryImplConstants.AQL_NODE_NAME_PREDICATE_MARKER, startList);

        if (markerPos < 0) // not found
        markerPos = itemPathArray.size();

        expression.add(aqlNodeNamePredicate(
                        DSL.field(jsonpathItemAsText(
                                        configuration,
                                        nodeField,
                                        itemPathArray
                                                .subList(startList, markerPos)
                                                .toArray(new String[] {})))
                                .cast(JSONB.class),
                        DSL.val(itemPathArray.get(markerPos + 1).replace("'", "")),
                        DSL.val(""))
                .toString());

        // Locate end tag (end of array or next marker)
        int endPos = itemPathArray.size();

        expression.addAll(Arrays.asList(rightPathExpression(itemPathArray, markerPos, endPos)));

        // end of iteration, wrap up
        String[] extractPathArguments = expression.subList(1, expression.size()).toArray(new String[] {});

        if (!expression.contains(QueryImplConstants.AQL_NODE_NAME_PREDICATE_MARKER)
                && extractPathArguments.length > 0) {
            List resultList = new ArrayList<>();
            resultList.add(DSL.field(jsonpathItemAsText(
                            configuration, DSL.field(expression.get(0)).cast(JSONB.class), extractPathArguments))
                    .toString());
            expression = resultList;
        }

        return expression;
    }

    private String[] rightPathExpression(List itemPathArray, int from, int to) {
        return itemPathArray
                .subList(
                        // test if the starting item is an index, then skip it as it is mutually exclusive with node
                        // name predicate node selection
                        itemPathArray.get(from + 2).matches("'[0-9]*'|#") ? from + 3 : from + 2, to)
                .toArray(new String[] {});
    }

    /**
     * remove json array marker and replace it with a dummy index '0'
     *
     * @return
     */
    private List patchItemArray(List itemPathArray) {

        List items = new ArrayList<>();

        for (String item : itemPathArray) {
            if (item.equals(AQL_NODE_ITERATIVE_MARKER)) items.add("0");
            else items.add(item);
        }

        return items;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy