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

org.jooq.impl.AbstractRowAsField Maven / Gradle / Ivy

There is a newer version: 3.19.15
Show newest version
/*
 * 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.
 *
 * Other licenses:
 * -----------------------------------------------------------------------------
 * Commercial licenses for this work are available. These replace the above
 * Apache-2.0 license and offer limited warranties, support, maintenance, and
 * commercial database integrations.
 *
 * For more information, please visit: https://www.jooq.org/legal/licensing
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq.impl;

import static java.lang.Boolean.TRUE;
import static org.jooq.impl.DSL.jsonArray;
import static org.jooq.impl.DSL.jsonObject;
import static org.jooq.impl.DSL.jsonbArray;
import static org.jooq.impl.DSL.jsonbObject;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.DSL.xmlelement;
import static org.jooq.impl.Multiset.returningClob;
import static org.jooq.impl.Names.N_RECORD;
import static org.jooq.impl.RowAsField.NO_NATIVE_SUPPORT;
import static org.jooq.impl.Tools.emulateMultiset;
import static org.jooq.impl.Tools.fieldNameString;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.row0;
import static org.jooq.impl.Tools.sanitiseName;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONTENT;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_ROW_CONTENT;

import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Fields;
import org.jooq.Name;
import org.jooq.Record;
import org.jooq.Row;
import org.jooq.SelectField;

/**
 * @author Lukas Eder
 */
abstract class AbstractRowAsField
extends
    AbstractField
implements
    AutoAlias>
{

    AbstractRowAsField(Name name, DataType type) {
        super(name, type);
    }

    abstract Fields fields0();
    abstract Class getRecordType();

    @SuppressWarnings("unchecked")
    final AbstractRow emulatedFields(Configuration configuration) {
        return (AbstractRow) row0(map(fields0().fields(), x -> x.as(sanitiseName(configuration, getUnqualifiedName().unquotedName() + configuration.settings().getNamePathSeparator() + x.getName())), Field[]::new));
    }

    @Override
    final int projectionSize() {
        int result = 0;

        for (Field field : fields0().fields())
            result += ((AbstractField) field).projectionSize();

        return result;
    }

    @Override
    public final boolean declaresFields() {
        return true;
    }

    @Override
    public final void accept(Context ctx) {

        // [#12021] If a RowField is nested somewhere in MULTISET, we must apply
        //          the MULTISET emulation as well, here
        if (forceMultisetContent(ctx, () -> getDataType().getRow().size() > 1))
            acceptMultisetContent(ctx, getDataType().getRow(), this, this::acceptDefault);
        else
            acceptDefault(ctx);
    }

    static final boolean forceMultisetContent(
        Context ctx,
        BooleanSupplier degreeCheck
    ) {
        return

            // All types of row expressions must be emulated using MULTISET
            // emulations if nested in some sort of MULTISET content
            TRUE.equals(ctx.data(DATA_MULTISET_CONTENT))

            // Row expressions of degree > 1 must also be emulated using MULTISET
            // emulations if nested in scalar subqueries, except for predicand
            // subqueries, where row subqueries are usually supported, e.g.
            // (a, b) IN (SELECT x, y)
            || ctx.subquery()
                    && NO_NATIVE_SUPPORT.contains(ctx.dialect())
                    && !ctx.predicandSubquery()
                    && !ctx.derivedTableSubquery()
                    && !ctx.setOperationSubquery()
                    && degreeCheck.getAsBoolean();
    }

    static final boolean forceRowContent(Context ctx) {
        return

            // [#15991] All types of row expressions must be emulated using ROW
            // emulations if nested in some sort of ROW content
            TRUE.equals(ctx.data(DATA_ROW_CONTENT));
    }

    static final void acceptMultisetContent(Context ctx, Row row, Field field, Consumer> acceptDefault) {
        Object previous = ctx.data(DATA_MULTISET_CONTENT);

        try {
            ctx.data(DATA_MULTISET_CONTENT, true);
            Name alias = field.getUnqualifiedName();

            switch (emulateMultiset(ctx.configuration())) {
                case JSON:
                    switch (ctx.family()) {
















                        default:
                            ctx.visit(alias(ctx, alias, returningClob(ctx, jsonArray(row.fields()).nullOnNull())));
                            break;
                    }

                    break;

                case JSONB:
                    switch (ctx.family()) {
















                        default:
                            ctx.visit(alias(ctx, alias, returningClob(ctx, jsonbArray(row.fields()).nullOnNull())));
                            break;
                    }

                    break;

                case XML:
                    switch (ctx.family()) {









                        default:
                            ctx.visit(alias(ctx, alias, xmlelement(N_RECORD,
                                map(row.fields(), (f, i) -> xmlelement(fieldNameString(i), f)))
                            ));

                            break;
                    }

                    break;

                // case ARRAY:
                case NATIVE:
                default:
                    acceptDefault.accept(ctx);
                    break;
            }
        }
        finally {
            ctx.data(DATA_MULTISET_CONTENT, previous);
        }
    }

    @Override
    public final SelectField autoAlias(Context ctx, SelectField s) {

        // [#13843] Re-aliasing only applies if at least ROW() projection is supported natively
        if (RowAsField.NO_NATIVE_SUPPORT.contains(ctx.dialect()))
            return s;

        // [#13843] Within MULTISET(), re-aliasing isn't required, while it leads to new edge cases
        else if (forceMultisetContent(ctx, () -> getDataType().getRow().size() > 1))
            return s;

        // [#13843] With native support, re-alias the table as field projection
        else
            return new FieldAlias<>(DSL.field(s), getUnqualifiedName());
    }

    private static final Field alias(Context ctx, Name alias, Field field) {
        return ctx.declareFields() ? field.as(alias) : field;
    }

    abstract void acceptDefault(Context ctx);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy