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

com.atlan.model.discovery.LinkableQuery Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
// Generated by delombok at Thu Oct 10 18:56:32 UTC 2024
/* SPDX-License-Identifier: Apache-2.0
   Copyright 2023 Atlan Pte. Ltd. */
package com.atlan.model.discovery;

import com.atlan.AtlanClient;
import com.atlan.exception.AtlanException;
import com.atlan.model.admin.AtlanGroup;
import com.atlan.model.admin.AtlanUser;
import com.atlan.model.assets.Connection;
import com.atlan.model.assets.GlossaryTerm;
import com.atlan.model.enums.CertificateStatus;
import com.atlan.serde.Removable;
import com.atlan.serde.Serde;
import com.atlan.util.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Class to compose compound queries combining various conditions, that can be used
 * to generate links (URLs) for the discovery page in Atlan.
 */
public class LinkableQuery {
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LinkableQuery.class);
    private AtlanClient client;

    /**
     * Begin building a linkable query.
     *
     * @param client connectivity to the Atlan tenant for which to build the query.
     * @return a builder upon which the query can be composed
     */
    public static LinkableQueryBuilder builder(AtlanClient client) {
        return _internal().client(client);
    }

    /**
     * Only assets with one of these certificate statuses will be included.
     * To include assets with no certificate, use {@code null} as a value in the list.
     */
    private List certificateStatuses;
    /**
     * Asset hierarchy (connector type, connection qualifiedName) to limit assets.
     */
    private AssetHierarchy hierarchy;
    /**
     * Owners by which to limit assets.
     */
    private Owners owners;
    /**
     * Criteria based on properties that exist across all asset types, that must be present on every asset.
     */
    private List properties;
    // TODO: Specialized filters (dbt, table/view, etc)
    /**
     * Criteria based on matching one or more of the provided tags (and optionally a value), that must
     * be present on every asset.
     */
    private List tags;
    /**
     * Terms by which to limit assets.
     */
    private Terms terms;
    /**
     * List of types by which to limit the assets.
     */
    private List typeNames;

    /**
     * Convert the linkable query into a string.
     */
    @Override
    public String toString() {
        FilterParams fp = new FilterParams(this);
        try {
            return Serde.allInclusiveMapper.writeValueAsString(fp);
        } catch (JsonProcessingException e) {
            log.error("Unable to convert parameters to a linkable query.", e);
            return "";
        }
    }

    /**
     * Convert this linkable query into an actual link (URL).
     * @return the URL (without tenant domain / hostname) for accessing this limited set of assets
     */
    public String getUrl() {
        String params = toString();
        // Note: needs to be double-url-encoded
        String encoded = StringUtils.encodeContent(StringUtils.encodeContent(params));
        return "/assets?searchAndFilterCriteria=" + encoded;
    }

    /**
     * Convert this linkable query into an actual link (URL).
     * Note: this will not work if the code is running in the tenant itself (e.g. via a custom package).
     * @return the full URL (including tenant domain) for accessing this limited set of assets in the tenant
     */
    public String getFullUrl() {
        return client.getBaseUrl() + getUrl();
    }


    static final class AssetHierarchy {
        /**
         * Name of the connector type to limit assets by.
         */
        String connectorName;
        /**
         * Unique name of the connection to limit assets by.
         */
        String connectionQualifiedName;
        /**
         * Name of the attribute within the lowest level of the asset hierarchy to limit assets by.
         * For example, if you want to limit assets by schema, use {@code schemaQualifiedName}, but if
         * you only want to limit assets by database use {@code databaseQualifiedName}.
         */
        String attributeName;
        /**
         * Qualified name prefix that matches the provided {@code attributeName} by which to limit assets.
         */
        String attributeValue;


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static abstract class AssetHierarchyBuilder> {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String connectorName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String connectionQualifiedName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String attributeName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String attributeValue;

            /**
             * Name of the connector type to limit assets by.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B connectorName(final String connectorName) {
                this.connectorName = connectorName;
                return self();
            }

            /**
             * Unique name of the connection to limit assets by.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B connectionQualifiedName(final String connectionQualifiedName) {
                this.connectionQualifiedName = connectionQualifiedName;
                return self();
            }

            /**
             * Name of the attribute within the lowest level of the asset hierarchy to limit assets by.
             * For example, if you want to limit assets by schema, use {@code schemaQualifiedName}, but if
             * you only want to limit assets by database use {@code databaseQualifiedName}.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B attributeName(final String attributeName) {
                this.attributeName = attributeName;
                return self();
            }

            /**
             * Qualified name prefix that matches the provided {@code attributeName} by which to limit assets.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B attributeValue(final String attributeValue) {
                this.attributeValue = attributeValue;
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected abstract B self();

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public abstract C build();

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public java.lang.String toString() {
                return "LinkableQuery.AssetHierarchy.AssetHierarchyBuilder(connectorName=" + this.connectorName + ", connectionQualifiedName=" + this.connectionQualifiedName + ", attributeName=" + this.attributeName + ", attributeValue=" + this.attributeValue + ")";
            }
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private static final class AssetHierarchyBuilderImpl extends LinkableQuery.AssetHierarchy.AssetHierarchyBuilder {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private AssetHierarchyBuilderImpl() {
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected LinkableQuery.AssetHierarchy.AssetHierarchyBuilderImpl self() {
                return this;
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public LinkableQuery.AssetHierarchy build() {
                return new LinkableQuery.AssetHierarchy(this);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected AssetHierarchy(final LinkableQuery.AssetHierarchy.AssetHierarchyBuilder b) {
            this.connectorName = b.connectorName;
            this.connectionQualifiedName = b.connectionQualifiedName;
            this.attributeName = b.attributeName;
            this.attributeValue = b.attributeValue;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static LinkableQuery.AssetHierarchy.AssetHierarchyBuilder builder() {
            return new LinkableQuery.AssetHierarchy.AssetHierarchyBuilderImpl();
        }

        /**
         * Name of the connector type to limit assets by.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getConnectorName() {
            return this.connectorName;
        }

        /**
         * Unique name of the connection to limit assets by.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getConnectionQualifiedName() {
            return this.connectionQualifiedName;
        }

        /**
         * Name of the attribute within the lowest level of the asset hierarchy to limit assets by.
         * For example, if you want to limit assets by schema, use {@code schemaQualifiedName}, but if
         * you only want to limit assets by database use {@code databaseQualifiedName}.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getAttributeName() {
            return this.attributeName;
        }

        /**
         * Qualified name prefix that matches the provided {@code attributeName} by which to limit assets.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getAttributeValue() {
            return this.attributeValue;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof LinkableQuery.AssetHierarchy)) return false;
            final LinkableQuery.AssetHierarchy other = (LinkableQuery.AssetHierarchy) o;
            final java.lang.Object this$connectorName = this.getConnectorName();
            final java.lang.Object other$connectorName = other.getConnectorName();
            if (this$connectorName == null ? other$connectorName != null : !this$connectorName.equals(other$connectorName)) return false;
            final java.lang.Object this$connectionQualifiedName = this.getConnectionQualifiedName();
            final java.lang.Object other$connectionQualifiedName = other.getConnectionQualifiedName();
            if (this$connectionQualifiedName == null ? other$connectionQualifiedName != null : !this$connectionQualifiedName.equals(other$connectionQualifiedName)) return false;
            final java.lang.Object this$attributeName = this.getAttributeName();
            final java.lang.Object other$attributeName = other.getAttributeName();
            if (this$attributeName == null ? other$attributeName != null : !this$attributeName.equals(other$attributeName)) return false;
            final java.lang.Object this$attributeValue = this.getAttributeValue();
            final java.lang.Object other$attributeValue = other.getAttributeValue();
            if (this$attributeValue == null ? other$attributeValue != null : !this$attributeValue.equals(other$attributeValue)) return false;
            return true;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $connectorName = this.getConnectorName();
            result = result * PRIME + ($connectorName == null ? 43 : $connectorName.hashCode());
            final java.lang.Object $connectionQualifiedName = this.getConnectionQualifiedName();
            result = result * PRIME + ($connectionQualifiedName == null ? 43 : $connectionQualifiedName.hashCode());
            final java.lang.Object $attributeName = this.getAttributeName();
            result = result * PRIME + ($attributeName == null ? 43 : $attributeName.hashCode());
            final java.lang.Object $attributeValue = this.getAttributeValue();
            result = result * PRIME + ($attributeValue == null ? 43 : $attributeValue.hashCode());
            return result;
        }
    }


    @SuppressWarnings("cast")
    static final class Owners {
        /**
         * List of UUIDs of owners to limit assets by.
         */
        List ownerIds;
        /**
         * Listing of details for the owners that are specified, keyed by the username.
         */
        Map selectedOwners;
        /**
         * List of usernames of owners to limit assets by.
         */
        List ownerUsers;
        /**
         * Listing of details for the owners that are specified, keyed by the group alias.
         */
        Map selectedGroups;
        /**
         * List of group aliases of owners to limit assets by.
         */
        List ownerGroups;
        /**
         * If true, include assets with no owners, otherwise only include assets with selected owners.
         */
        Boolean empty;


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static abstract class OwnersBuilder> {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList ownerIds;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList selectedOwners$key;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList selectedOwners$value;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList ownerUsers;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList selectedGroups$key;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList selectedGroups$value;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList ownerGroups;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private Boolean empty;

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerId(final String ownerId) {
                if (this.ownerIds == null) this.ownerIds = new java.util.ArrayList();
                this.ownerIds.add(ownerId);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerIds(final java.util.Collection ownerIds) {
                if (ownerIds == null) {
                    throw new java.lang.NullPointerException("ownerIds cannot be null");
                }
                if (this.ownerIds == null) this.ownerIds = new java.util.ArrayList();
                this.ownerIds.addAll(ownerIds);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearOwnerIds() {
                if (this.ownerIds != null) this.ownerIds.clear();
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B selectedOwner(final String selectedOwnerKey, final OwnerDetails selectedOwnerValue) {
                if (this.selectedOwners$key == null) {
                    this.selectedOwners$key = new java.util.ArrayList();
                    this.selectedOwners$value = new java.util.ArrayList();
                }
                this.selectedOwners$key.add(selectedOwnerKey);
                this.selectedOwners$value.add(selectedOwnerValue);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B selectedOwners(final java.util.Map selectedOwners) {
                if (selectedOwners == null) {
                    throw new java.lang.NullPointerException("selectedOwners cannot be null");
                }
                if (this.selectedOwners$key == null) {
                    this.selectedOwners$key = new java.util.ArrayList();
                    this.selectedOwners$value = new java.util.ArrayList();
                }
                for (final java.util.Map.Entry $lombokEntry : selectedOwners.entrySet()) {
                    this.selectedOwners$key.add($lombokEntry.getKey());
                    this.selectedOwners$value.add($lombokEntry.getValue());
                }
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearSelectedOwners() {
                if (this.selectedOwners$key != null) {
                    this.selectedOwners$key.clear();
                    this.selectedOwners$value.clear();
                }
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerUser(final String ownerUser) {
                if (this.ownerUsers == null) this.ownerUsers = new java.util.ArrayList();
                this.ownerUsers.add(ownerUser);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerUsers(final java.util.Collection ownerUsers) {
                if (ownerUsers == null) {
                    throw new java.lang.NullPointerException("ownerUsers cannot be null");
                }
                if (this.ownerUsers == null) this.ownerUsers = new java.util.ArrayList();
                this.ownerUsers.addAll(ownerUsers);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearOwnerUsers() {
                if (this.ownerUsers != null) this.ownerUsers.clear();
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B selectedGroup(final String selectedGroupKey, final AtlanGroup selectedGroupValue) {
                if (this.selectedGroups$key == null) {
                    this.selectedGroups$key = new java.util.ArrayList();
                    this.selectedGroups$value = new java.util.ArrayList();
                }
                this.selectedGroups$key.add(selectedGroupKey);
                this.selectedGroups$value.add(selectedGroupValue);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B selectedGroups(final java.util.Map selectedGroups) {
                if (selectedGroups == null) {
                    throw new java.lang.NullPointerException("selectedGroups cannot be null");
                }
                if (this.selectedGroups$key == null) {
                    this.selectedGroups$key = new java.util.ArrayList();
                    this.selectedGroups$value = new java.util.ArrayList();
                }
                for (final java.util.Map.Entry $lombokEntry : selectedGroups.entrySet()) {
                    this.selectedGroups$key.add($lombokEntry.getKey());
                    this.selectedGroups$value.add($lombokEntry.getValue());
                }
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearSelectedGroups() {
                if (this.selectedGroups$key != null) {
                    this.selectedGroups$key.clear();
                    this.selectedGroups$value.clear();
                }
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerGroup(final String ownerGroup) {
                if (this.ownerGroups == null) this.ownerGroups = new java.util.ArrayList();
                this.ownerGroups.add(ownerGroup);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B ownerGroups(final java.util.Collection ownerGroups) {
                if (ownerGroups == null) {
                    throw new java.lang.NullPointerException("ownerGroups cannot be null");
                }
                if (this.ownerGroups == null) this.ownerGroups = new java.util.ArrayList();
                this.ownerGroups.addAll(ownerGroups);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearOwnerGroups() {
                if (this.ownerGroups != null) this.ownerGroups.clear();
                return self();
            }

            /**
             * If true, include assets with no owners, otherwise only include assets with selected owners.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B empty(final Boolean empty) {
                this.empty = empty;
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected abstract B self();

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public abstract C build();

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public java.lang.String toString() {
                return "LinkableQuery.Owners.OwnersBuilder(ownerIds=" + this.ownerIds + ", selectedOwners$key=" + this.selectedOwners$key + ", selectedOwners$value=" + this.selectedOwners$value + ", ownerUsers=" + this.ownerUsers + ", selectedGroups$key=" + this.selectedGroups$key + ", selectedGroups$value=" + this.selectedGroups$value + ", ownerGroups=" + this.ownerGroups + ", empty=" + this.empty + ")";
            }
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private static final class OwnersBuilderImpl extends LinkableQuery.Owners.OwnersBuilder {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private OwnersBuilderImpl() {
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected LinkableQuery.Owners.OwnersBuilderImpl self() {
                return this;
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public LinkableQuery.Owners build() {
                return new LinkableQuery.Owners(this);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected Owners(final LinkableQuery.Owners.OwnersBuilder b) {
            java.util.List ownerIds;
            switch (b.ownerIds == null ? 0 : b.ownerIds.size()) {
            case 0: 
                ownerIds = java.util.Collections.emptyList();
                break;
            case 1: 
                ownerIds = java.util.Collections.singletonList(b.ownerIds.get(0));
                break;
            default: 
                ownerIds = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.ownerIds));
            }
            this.ownerIds = ownerIds;
            java.util.Map selectedOwners;
            switch (b.selectedOwners$key == null ? 0 : b.selectedOwners$key.size()) {
            case 0: 
                selectedOwners = java.util.Collections.emptyMap();
                break;
            case 1: 
                selectedOwners = java.util.Collections.singletonMap(b.selectedOwners$key.get(0), b.selectedOwners$value.get(0));
                break;
            default: 
                selectedOwners = new java.util.LinkedHashMap(b.selectedOwners$key.size() < 1073741824 ? 1 + b.selectedOwners$key.size() + (b.selectedOwners$key.size() - 3) / 3 : java.lang.Integer.MAX_VALUE);
                for (int $i = 0; $i < b.selectedOwners$key.size(); $i++) selectedOwners.put(b.selectedOwners$key.get($i), (OwnerDetails) b.selectedOwners$value.get($i));
                selectedOwners = java.util.Collections.unmodifiableMap(selectedOwners);
            }
            this.selectedOwners = selectedOwners;
            java.util.List ownerUsers;
            switch (b.ownerUsers == null ? 0 : b.ownerUsers.size()) {
            case 0: 
                ownerUsers = java.util.Collections.emptyList();
                break;
            case 1: 
                ownerUsers = java.util.Collections.singletonList(b.ownerUsers.get(0));
                break;
            default: 
                ownerUsers = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.ownerUsers));
            }
            this.ownerUsers = ownerUsers;
            java.util.Map selectedGroups;
            switch (b.selectedGroups$key == null ? 0 : b.selectedGroups$key.size()) {
            case 0: 
                selectedGroups = java.util.Collections.emptyMap();
                break;
            case 1: 
                selectedGroups = java.util.Collections.singletonMap(b.selectedGroups$key.get(0), b.selectedGroups$value.get(0));
                break;
            default: 
                selectedGroups = new java.util.LinkedHashMap(b.selectedGroups$key.size() < 1073741824 ? 1 + b.selectedGroups$key.size() + (b.selectedGroups$key.size() - 3) / 3 : java.lang.Integer.MAX_VALUE);
                for (int $i = 0; $i < b.selectedGroups$key.size(); $i++) selectedGroups.put(b.selectedGroups$key.get($i), (AtlanGroup) b.selectedGroups$value.get($i));
                selectedGroups = java.util.Collections.unmodifiableMap(selectedGroups);
            }
            this.selectedGroups = selectedGroups;
            java.util.List ownerGroups;
            switch (b.ownerGroups == null ? 0 : b.ownerGroups.size()) {
            case 0: 
                ownerGroups = java.util.Collections.emptyList();
                break;
            case 1: 
                ownerGroups = java.util.Collections.singletonList(b.ownerGroups.get(0));
                break;
            default: 
                ownerGroups = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.ownerGroups));
            }
            this.ownerGroups = ownerGroups;
            this.empty = b.empty;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static LinkableQuery.Owners.OwnersBuilder builder() {
            return new LinkableQuery.Owners.OwnersBuilderImpl();
        }

        /**
         * List of UUIDs of owners to limit assets by.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public List getOwnerIds() {
            return this.ownerIds;
        }

        /**
         * Listing of details for the owners that are specified, keyed by the username.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Map getSelectedOwners() {
            return this.selectedOwners;
        }

        /**
         * List of usernames of owners to limit assets by.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public List getOwnerUsers() {
            return this.ownerUsers;
        }

        /**
         * Listing of details for the owners that are specified, keyed by the group alias.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Map getSelectedGroups() {
            return this.selectedGroups;
        }

        /**
         * List of group aliases of owners to limit assets by.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public List getOwnerGroups() {
            return this.ownerGroups;
        }

        /**
         * If true, include assets with no owners, otherwise only include assets with selected owners.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Boolean getEmpty() {
            return this.empty;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof LinkableQuery.Owners)) return false;
            final LinkableQuery.Owners other = (LinkableQuery.Owners) o;
            final java.lang.Object this$empty = this.getEmpty();
            final java.lang.Object other$empty = other.getEmpty();
            if (this$empty == null ? other$empty != null : !this$empty.equals(other$empty)) return false;
            final java.lang.Object this$ownerIds = this.getOwnerIds();
            final java.lang.Object other$ownerIds = other.getOwnerIds();
            if (this$ownerIds == null ? other$ownerIds != null : !this$ownerIds.equals(other$ownerIds)) return false;
            final java.lang.Object this$selectedOwners = this.getSelectedOwners();
            final java.lang.Object other$selectedOwners = other.getSelectedOwners();
            if (this$selectedOwners == null ? other$selectedOwners != null : !this$selectedOwners.equals(other$selectedOwners)) return false;
            final java.lang.Object this$ownerUsers = this.getOwnerUsers();
            final java.lang.Object other$ownerUsers = other.getOwnerUsers();
            if (this$ownerUsers == null ? other$ownerUsers != null : !this$ownerUsers.equals(other$ownerUsers)) return false;
            final java.lang.Object this$selectedGroups = this.getSelectedGroups();
            final java.lang.Object other$selectedGroups = other.getSelectedGroups();
            if (this$selectedGroups == null ? other$selectedGroups != null : !this$selectedGroups.equals(other$selectedGroups)) return false;
            final java.lang.Object this$ownerGroups = this.getOwnerGroups();
            final java.lang.Object other$ownerGroups = other.getOwnerGroups();
            if (this$ownerGroups == null ? other$ownerGroups != null : !this$ownerGroups.equals(other$ownerGroups)) return false;
            return true;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $empty = this.getEmpty();
            result = result * PRIME + ($empty == null ? 43 : $empty.hashCode());
            final java.lang.Object $ownerIds = this.getOwnerIds();
            result = result * PRIME + ($ownerIds == null ? 43 : $ownerIds.hashCode());
            final java.lang.Object $selectedOwners = this.getSelectedOwners();
            result = result * PRIME + ($selectedOwners == null ? 43 : $selectedOwners.hashCode());
            final java.lang.Object $ownerUsers = this.getOwnerUsers();
            result = result * PRIME + ($ownerUsers == null ? 43 : $ownerUsers.hashCode());
            final java.lang.Object $selectedGroups = this.getSelectedGroups();
            result = result * PRIME + ($selectedGroups == null ? 43 : $selectedGroups.hashCode());
            final java.lang.Object $ownerGroups = this.getOwnerGroups();
            result = result * PRIME + ($ownerGroups == null ? 43 : $ownerGroups.hashCode());
            return result;
        }
    }


    static final class Terms {
        /**
         * Whether to include assets with no terms assigned (true) or not (false).
         */
        Boolean empty;
        /**
         * Comparison operator to use for matching the terms specified.
         */
        String operator;
        /**
         * Details of the terms to use for matching.
         */
        List terms;


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static abstract class TermsBuilder> {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private Boolean empty;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String operator;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private java.util.ArrayList terms;

            /**
             * Whether to include assets with no terms assigned (true) or not (false).
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B empty(final Boolean empty) {
                this.empty = empty;
                return self();
            }

            /**
             * Comparison operator to use for matching the terms specified.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B operator(final String operator) {
                this.operator = operator;
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B term(final TermDetails term) {
                if (this.terms == null) this.terms = new java.util.ArrayList();
                this.terms.add(term);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B terms(final java.util.Collection terms) {
                if (terms == null) {
                    throw new java.lang.NullPointerException("terms cannot be null");
                }
                if (this.terms == null) this.terms = new java.util.ArrayList();
                this.terms.addAll(terms);
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B clearTerms() {
                if (this.terms != null) this.terms.clear();
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected abstract B self();

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public abstract C build();

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public java.lang.String toString() {
                return "LinkableQuery.Terms.TermsBuilder(empty=" + this.empty + ", operator=" + this.operator + ", terms=" + this.terms + ")";
            }
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private static final class TermsBuilderImpl extends LinkableQuery.Terms.TermsBuilder {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private TermsBuilderImpl() {
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected LinkableQuery.Terms.TermsBuilderImpl self() {
                return this;
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public LinkableQuery.Terms build() {
                return new LinkableQuery.Terms(this);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected Terms(final LinkableQuery.Terms.TermsBuilder b) {
            this.empty = b.empty;
            this.operator = b.operator;
            java.util.List terms;
            switch (b.terms == null ? 0 : b.terms.size()) {
            case 0: 
                terms = java.util.Collections.emptyList();
                break;
            case 1: 
                terms = java.util.Collections.singletonList(b.terms.get(0));
                break;
            default: 
                terms = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.terms));
            }
            this.terms = terms;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static LinkableQuery.Terms.TermsBuilder builder() {
            return new LinkableQuery.Terms.TermsBuilderImpl();
        }

        /**
         * Whether to include assets with no terms assigned (true) or not (false).
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Boolean getEmpty() {
            return this.empty;
        }

        /**
         * Comparison operator to use for matching the terms specified.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getOperator() {
            return this.operator;
        }

        /**
         * Details of the terms to use for matching.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public List getTerms() {
            return this.terms;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof LinkableQuery.Terms)) return false;
            final LinkableQuery.Terms other = (LinkableQuery.Terms) o;
            final java.lang.Object this$empty = this.getEmpty();
            final java.lang.Object other$empty = other.getEmpty();
            if (this$empty == null ? other$empty != null : !this$empty.equals(other$empty)) return false;
            final java.lang.Object this$operator = this.getOperator();
            final java.lang.Object other$operator = other.getOperator();
            if (this$operator == null ? other$operator != null : !this$operator.equals(other$operator)) return false;
            final java.lang.Object this$terms = this.getTerms();
            final java.lang.Object other$terms = other.getTerms();
            if (this$terms == null ? other$terms != null : !this$terms.equals(other$terms)) return false;
            return true;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $empty = this.getEmpty();
            result = result * PRIME + ($empty == null ? 43 : $empty.hashCode());
            final java.lang.Object $operator = this.getOperator();
            result = result * PRIME + ($operator == null ? 43 : $operator.hashCode());
            final java.lang.Object $terms = this.getTerms();
            result = result * PRIME + ($terms == null ? 43 : $terms.hashCode());
            return result;
        }
    }


    static final class OwnerDetails {
        /**
         * First name of the user.
         */
        String firstName;
        /**
         * UUID of the user.
         */
        String id;
        /**
         * Username of the user.
         */
        String username;
        /**
         * Surname of the user.
         */
        String lastName;
        /**
         * Whether the user is active (true) or deactivated (false).
         */
        Boolean enabled;
        /**
         * Email address of the user.
         */
        String email;

        public static OwnerDetails from(AtlanUser user) {
            if (user == null) return null;
            return builder().firstName(user.getFirstName()).id(user.getId()).username(user.getUsername()).lastName(user.getLastName()).enabled(user.getEnabled()).email(user.getEmail()).build();
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static abstract class OwnerDetailsBuilder> {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String firstName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String id;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String username;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String lastName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private Boolean enabled;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String email;

            /**
             * First name of the user.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B firstName(final String firstName) {
                this.firstName = firstName;
                return self();
            }

            /**
             * UUID of the user.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B id(final String id) {
                this.id = id;
                return self();
            }

            /**
             * Username of the user.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B username(final String username) {
                this.username = username;
                return self();
            }

            /**
             * Surname of the user.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B lastName(final String lastName) {
                this.lastName = lastName;
                return self();
            }

            /**
             * Whether the user is active (true) or deactivated (false).
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B enabled(final Boolean enabled) {
                this.enabled = enabled;
                return self();
            }

            /**
             * Email address of the user.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B email(final String email) {
                this.email = email;
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected abstract B self();

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public abstract C build();

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public java.lang.String toString() {
                return "LinkableQuery.OwnerDetails.OwnerDetailsBuilder(firstName=" + this.firstName + ", id=" + this.id + ", username=" + this.username + ", lastName=" + this.lastName + ", enabled=" + this.enabled + ", email=" + this.email + ")";
            }
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private static final class OwnerDetailsBuilderImpl extends LinkableQuery.OwnerDetails.OwnerDetailsBuilder {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private OwnerDetailsBuilderImpl() {
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected LinkableQuery.OwnerDetails.OwnerDetailsBuilderImpl self() {
                return this;
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public LinkableQuery.OwnerDetails build() {
                return new LinkableQuery.OwnerDetails(this);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected OwnerDetails(final LinkableQuery.OwnerDetails.OwnerDetailsBuilder b) {
            this.firstName = b.firstName;
            this.id = b.id;
            this.username = b.username;
            this.lastName = b.lastName;
            this.enabled = b.enabled;
            this.email = b.email;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static LinkableQuery.OwnerDetails.OwnerDetailsBuilder builder() {
            return new LinkableQuery.OwnerDetails.OwnerDetailsBuilderImpl();
        }

        /**
         * First name of the user.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getFirstName() {
            return this.firstName;
        }

        /**
         * UUID of the user.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getId() {
            return this.id;
        }

        /**
         * Username of the user.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getUsername() {
            return this.username;
        }

        /**
         * Surname of the user.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getLastName() {
            return this.lastName;
        }

        /**
         * Whether the user is active (true) or deactivated (false).
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Boolean getEnabled() {
            return this.enabled;
        }

        /**
         * Email address of the user.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getEmail() {
            return this.email;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof LinkableQuery.OwnerDetails)) return false;
            final LinkableQuery.OwnerDetails other = (LinkableQuery.OwnerDetails) o;
            final java.lang.Object this$enabled = this.getEnabled();
            final java.lang.Object other$enabled = other.getEnabled();
            if (this$enabled == null ? other$enabled != null : !this$enabled.equals(other$enabled)) return false;
            final java.lang.Object this$firstName = this.getFirstName();
            final java.lang.Object other$firstName = other.getFirstName();
            if (this$firstName == null ? other$firstName != null : !this$firstName.equals(other$firstName)) return false;
            final java.lang.Object this$id = this.getId();
            final java.lang.Object other$id = other.getId();
            if (this$id == null ? other$id != null : !this$id.equals(other$id)) return false;
            final java.lang.Object this$username = this.getUsername();
            final java.lang.Object other$username = other.getUsername();
            if (this$username == null ? other$username != null : !this$username.equals(other$username)) return false;
            final java.lang.Object this$lastName = this.getLastName();
            final java.lang.Object other$lastName = other.getLastName();
            if (this$lastName == null ? other$lastName != null : !this$lastName.equals(other$lastName)) return false;
            final java.lang.Object this$email = this.getEmail();
            final java.lang.Object other$email = other.getEmail();
            if (this$email == null ? other$email != null : !this$email.equals(other$email)) return false;
            return true;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $enabled = this.getEnabled();
            result = result * PRIME + ($enabled == null ? 43 : $enabled.hashCode());
            final java.lang.Object $firstName = this.getFirstName();
            result = result * PRIME + ($firstName == null ? 43 : $firstName.hashCode());
            final java.lang.Object $id = this.getId();
            result = result * PRIME + ($id == null ? 43 : $id.hashCode());
            final java.lang.Object $username = this.getUsername();
            result = result * PRIME + ($username == null ? 43 : $username.hashCode());
            final java.lang.Object $lastName = this.getLastName();
            result = result * PRIME + ($lastName == null ? 43 : $lastName.hashCode());
            final java.lang.Object $email = this.getEmail();
            result = result * PRIME + ($email == null ? 43 : $email.hashCode());
            return result;
        }
    }


    @SuppressWarnings("cast")
    static final class TermDetails {
        /**
         * UUID of the term.
         */
        String guid;
        /**
         * Unique name of the term.
         */
        String qualifiedName;
        /**
         * Type of the term.
         */
        final String typeName = GlossaryTerm.TYPE_NAME;
        /**
         * Attributes of the term.
         */
        Map attributes;


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static abstract class TermDetailsBuilder> {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String guid;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private String qualifiedName;
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private Map attributes;

            /**
             * UUID of the term.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B guid(final String guid) {
                this.guid = guid;
                return self();
            }

            /**
             * Unique name of the term.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B qualifiedName(final String qualifiedName) {
                this.qualifiedName = qualifiedName;
                return self();
            }

            /**
             * Attributes of the term.
             * @return {@code this}.
             */
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public B attributes(final Map attributes) {
                this.attributes = attributes;
                return self();
            }

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected abstract B self();

            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public abstract C build();

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public java.lang.String toString() {
                return "LinkableQuery.TermDetails.TermDetailsBuilder(guid=" + this.guid + ", qualifiedName=" + this.qualifiedName + ", attributes=" + this.attributes + ")";
            }
        }


        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private static final class TermDetailsBuilderImpl extends LinkableQuery.TermDetails.TermDetailsBuilder {
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            private TermDetailsBuilderImpl() {
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            protected LinkableQuery.TermDetails.TermDetailsBuilderImpl self() {
                return this;
            }

            @java.lang.Override
            @java.lang.SuppressWarnings("all")
            @lombok.Generated
            public LinkableQuery.TermDetails build() {
                return new LinkableQuery.TermDetails(this);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected TermDetails(final LinkableQuery.TermDetails.TermDetailsBuilder b) {
            this.guid = b.guid;
            this.qualifiedName = b.qualifiedName;
            this.attributes = b.attributes;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public static LinkableQuery.TermDetails.TermDetailsBuilder builder() {
            return new LinkableQuery.TermDetails.TermDetailsBuilderImpl();
        }

        /**
         * UUID of the term.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getGuid() {
            return this.guid;
        }

        /**
         * Unique name of the term.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getQualifiedName() {
            return this.qualifiedName;
        }

        /**
         * Type of the term.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getTypeName() {
            return this.typeName;
        }

        /**
         * Attributes of the term.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Map getAttributes() {
            return this.attributes;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public boolean equals(final java.lang.Object o) {
            if (o == this) return true;
            if (!(o instanceof LinkableQuery.TermDetails)) return false;
            final LinkableQuery.TermDetails other = (LinkableQuery.TermDetails) o;
            final java.lang.Object this$guid = this.getGuid();
            final java.lang.Object other$guid = other.getGuid();
            if (this$guid == null ? other$guid != null : !this$guid.equals(other$guid)) return false;
            final java.lang.Object this$qualifiedName = this.getQualifiedName();
            final java.lang.Object other$qualifiedName = other.getQualifiedName();
            if (this$qualifiedName == null ? other$qualifiedName != null : !this$qualifiedName.equals(other$qualifiedName)) return false;
            final java.lang.Object this$typeName = this.getTypeName();
            final java.lang.Object other$typeName = other.getTypeName();
            if (this$typeName == null ? other$typeName != null : !this$typeName.equals(other$typeName)) return false;
            final java.lang.Object this$attributes = this.getAttributes();
            final java.lang.Object other$attributes = other.getAttributes();
            if (this$attributes == null ? other$attributes != null : !this$attributes.equals(other$attributes)) return false;
            return true;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public int hashCode() {
            final int PRIME = 59;
            int result = 1;
            final java.lang.Object $guid = this.getGuid();
            result = result * PRIME + ($guid == null ? 43 : $guid.hashCode());
            final java.lang.Object $qualifiedName = this.getQualifiedName();
            result = result * PRIME + ($qualifiedName == null ? 43 : $qualifiedName.hashCode());
            final java.lang.Object $typeName = this.getTypeName();
            result = result * PRIME + ($typeName == null ? 43 : $typeName.hashCode());
            final java.lang.Object $attributes = this.getAttributes();
            result = result * PRIME + ($attributes == null ? 43 : $attributes.hashCode());
            return result;
        }
    }


    private static final class FilterParams {
        private final Map filters = new LinkedHashMap<>();
        private final Map postFilters = new LinkedHashMap<>();

        FilterParams(LinkableQuery query) {
            if (query.certificateStatuses != null) {
                List list = new ArrayList<>();
                for (CertificateStatus status : query.certificateStatuses) {
                    if (status == null) {
                        list.add(Removable.NULL);
                    } else {
                        list.add(status.getValue());
                    }
                }
                filters.put("certificateStatus", list);
            }
            if (query.hierarchy != null) {
                filters.put("hierarchy", query.hierarchy);
            }
            if (query.properties != null) {
                Map propertyMap = new LinkedHashMap<>();
                for (DiscoveryFilter filter : query.properties) {
                    propertyMap.put(filter.filterKey, List.of(filter));
                }
                filters.put("properties", propertyMap);
            }
            if (query.tags != null) {
                filters.put("__traitNames", Map.of("classifications", query.tags));
            }
            if (query.typeNames != null) {
                List types = new ArrayList<>();
                for (String typeName : query.typeNames) {
                    types.add(new TypeName(typeName));
                }
                postFilters.put("typeName", types);
            }
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Map getFilters() {
            return this.filters;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public Map getPostFilters() {
            return this.postFilters;
        }
    }


    private static final class TypeName {
        String id;
        String label;

        TypeName(String typeName) {
            this.id = typeName;
            this.label = StringUtils.getTitleCase(typeName);
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getId() {
            return this.id;
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public String getLabel() {
            return this.label;
        }
    }


    public static abstract class LinkableQueryBuilder> {
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private AtlanClient client;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private java.util.ArrayList certificateStatuses;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private AssetHierarchy hierarchy;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private Owners owners;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private java.util.ArrayList properties;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private java.util.ArrayList tags;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private Terms terms;
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private java.util.ArrayList typeNames;

        /**
         * Limit assets to a given connection.
         * @param connection for which to limit assets
         * @return the query builder, limited to assets from the specific connection
         */
        public B forConnection(Connection connection) {
            String qn = connection.getQualifiedName();
            return hierarchy(AssetHierarchy.builder().connectionQualifiedName(connection.getQualifiedName()).connectorName(Connection.getConnectorTypeFromQualifiedName(qn).getValue()).attributeName("").attributeValue("").build());
        }

        /**
         * Limit assets to a specified subset of those in a connection.
         * @param qualifiedNamePrefix full qualifiedName prefix that all assets in the subset should start with
         * @param denormalizedAttributeName name of the denormalized attribute where the prefix can be found on all assets (for example, {@code schemaQualifiedName})
         * @return the query builder, limited to a subset of assets in a connection
         */
        public B forPrefix(String qualifiedNamePrefix, String denormalizedAttributeName) {
            String connectionQN = StringUtils.getConnectionQualifiedName(qualifiedNamePrefix);
            if (connectionQN != null) {
                return hierarchy(AssetHierarchy.builder().connectionQualifiedName(connectionQN).connectorName(Connection.getConnectorTypeFromQualifiedName(connectionQN).getValue()).attributeName(denormalizedAttributeName).attributeValue(qualifiedNamePrefix).build());
            } else {
                return hierarchy(AssetHierarchy.builder().build());
            }
        }

        /**
         * Limit assets to those with a particular Atlan tag assigned.
         * @param tagName human-readable name of the Atlan tag
         * @return the query builder, limited to assets with the Atlan tag assigned
         */
        public B withTag(String tagName) {
            return tag(TagFilter.of(client, tagName));
        }

        /**
         * Limit assets to those with a particular source tag assigned, with a particular value.
         * @param tagName human-readable name of the Atlan tag mapped to a source tag
         * @param value of the source tag
         * @return the query builder, limited to assets with the Atlan tag assigned with a particular value
         */
        public B withTagValue(String tagName, String value) {
            return tag(TagFilter.of(client, tagName, value));
        }

        /**
         * Limit assets to those without any owners defined (individuals or groups).
         * @return the query builder, limited to assets without any owners assigned
         */
        public B withoutOwners() {
            return owners(Owners.builder().empty(true).build());
        }

        /**
         * Limit assets to those with any of the specified owners.
         * @param usernames (optional) list of usernames to match as owners
         * @param groups (optional) list of internal group names to match as owners
         * @return the query builder, limited to assets with any of the specified owners assigned
         * @throws AtlanException if there are problems confirming any of the provided owners
         */
        public B withOwners(List usernames, List groups) throws AtlanException {
            if ((usernames == null || usernames.isEmpty()) && (groups == null || groups.isEmpty())) {
                return withoutOwners();
            }
            Owners.OwnersBuilder builder = Owners.builder();
            if (usernames != null) {
                for (String username : usernames) {
                    AtlanUser user = client.getUserCache().getByName(username, true);
                    builder.ownerUser(username).ownerId(user.getId()).selectedOwner(username, OwnerDetails.from(user));
                }
            }
            if (groups != null) {
                for (String alias : groups) {
                    AtlanGroup group = client.getGroupCache().getByName(alias, true);
                    builder.ownerGroup(alias).selectedGroup(alias, group);
                }
            }
            return owners(builder.build());
        }

        /**
         * Limit assets to those with any of the specified terms assigned.
         * @param terms minimal details about the terms, which must include at least GUID, qualifiedName, and name
         * @return the query builder, limited to assets with any of the specified terms assigned
         */
        public B withAnyOf(List terms) {
            return withTerms("equals", terms);
        }

        /**
         * Limit assets to those with all the specified terms assigned.
         * @param terms minimal details about the terms, which must include at least GUID, qualifiedName, and name
         * @return the query builder, limited to assets with all the specified terms assigned
         */
        public B withAll(List terms) {
            return withTerms("AND", terms);
        }

        /**
         * Limit assets to those with none of the specified terms assigned.
         * @param terms minimal details about the terms, which must include at least GUID, qualifiedName, and name
         * @return the query builder, limited to assets with none of the specified terms assigned
         */
        public B withNoneOf(List terms) {
            return withTerms("NAND", terms);
        }

        /**
         * Limit assets to those with no terms assigned.
         * @return the query builder, limited to assets without any terms assigned
         */
        public B withoutTerms() {
            return terms(Terms.builder().operator("isNull").build());
        }

        /**
         * Limit assets to those with any terms assigned.
         * @return the query builder, limited to assets with any terms assigned
         */
        public B withAnyTerm() {
            return terms(Terms.builder().operator("isNotNull").build());
        }

        private B withTerms(String operator, List terms) {
            Terms.TermsBuilder builder = Terms.builder().operator(operator);
            for (GlossaryTerm term : terms) {
                builder.term(TermDetails.builder().guid(term.getGuid()).qualifiedName(term.getQualifiedName()).attributes(Map.of("name", term.getName())).build());
            }
            return terms(builder.build());
        }

        /**
         * Convert this linkable query into an actual link (URL).
         * @return the URL (without tenant domain / hostname) for accessing this limited set of assets
         */
        public String toUrl() {
            return build().getUrl();
        }

        /**
         * Convert this linkable query into an actual link (URL).
         * Note: this will not work if the code is running in the tenant itself (e.g. via a custom package).
         * @return the full URL (including tenant domain) for accessing this limited set of assets in the tenant
         */
        public String toFullUrl() {
            return build().getFullUrl();
        }

        /**
         * @return {@code this}.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B client(final AtlanClient client) {
            this.client = client;
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B certificateStatus(final CertificateStatus certificateStatus) {
            if (this.certificateStatuses == null) this.certificateStatuses = new java.util.ArrayList();
            this.certificateStatuses.add(certificateStatus);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B certificateStatuses(final java.util.Collection certificateStatuses) {
            if (certificateStatuses == null) {
                throw new java.lang.NullPointerException("certificateStatuses cannot be null");
            }
            if (this.certificateStatuses == null) this.certificateStatuses = new java.util.ArrayList();
            this.certificateStatuses.addAll(certificateStatuses);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B clearCertificateStatuses() {
            if (this.certificateStatuses != null) this.certificateStatuses.clear();
            return self();
        }

        /**
         * Asset hierarchy (connector type, connection qualifiedName) to limit assets.
         * @return {@code this}.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B hierarchy(final AssetHierarchy hierarchy) {
            this.hierarchy = hierarchy;
            return self();
        }

        /**
         * Owners by which to limit assets.
         * @return {@code this}.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B owners(final Owners owners) {
            this.owners = owners;
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B property(final DiscoveryFilter property) {
            if (this.properties == null) this.properties = new java.util.ArrayList();
            this.properties.add(property);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B properties(final java.util.Collection properties) {
            if (properties == null) {
                throw new java.lang.NullPointerException("properties cannot be null");
            }
            if (this.properties == null) this.properties = new java.util.ArrayList();
            this.properties.addAll(properties);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B clearProperties() {
            if (this.properties != null) this.properties.clear();
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B tag(final TagFilter tag) {
            if (this.tags == null) this.tags = new java.util.ArrayList();
            this.tags.add(tag);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B tags(final java.util.Collection tags) {
            if (tags == null) {
                throw new java.lang.NullPointerException("tags cannot be null");
            }
            if (this.tags == null) this.tags = new java.util.ArrayList();
            this.tags.addAll(tags);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B clearTags() {
            if (this.tags != null) this.tags.clear();
            return self();
        }

        /**
         * Terms by which to limit assets.
         * @return {@code this}.
         */
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B terms(final Terms terms) {
            this.terms = terms;
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B typeName(final String typeName) {
            if (this.typeNames == null) this.typeNames = new java.util.ArrayList();
            this.typeNames.add(typeName);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B typeNames(final java.util.Collection typeNames) {
            if (typeNames == null) {
                throw new java.lang.NullPointerException("typeNames cannot be null");
            }
            if (this.typeNames == null) this.typeNames = new java.util.ArrayList();
            this.typeNames.addAll(typeNames);
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public B clearTypeNames() {
            if (this.typeNames != null) this.typeNames.clear();
            return self();
        }

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected abstract B self();

        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public abstract C build();

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public java.lang.String toString() {
            return "LinkableQuery.LinkableQueryBuilder(client=" + this.client + ", certificateStatuses=" + this.certificateStatuses + ", hierarchy=" + this.hierarchy + ", owners=" + this.owners + ", properties=" + this.properties + ", tags=" + this.tags + ", terms=" + this.terms + ", typeNames=" + this.typeNames + ")";
        }
    }


    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    private static final class LinkableQueryBuilderImpl extends LinkableQuery.LinkableQueryBuilder {
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        private LinkableQueryBuilderImpl() {
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        protected LinkableQuery.LinkableQueryBuilderImpl self() {
            return this;
        }

        @java.lang.Override
        @java.lang.SuppressWarnings("all")
        @lombok.Generated
        public LinkableQuery build() {
            return new LinkableQuery(this);
        }
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    protected LinkableQuery(final LinkableQuery.LinkableQueryBuilder b) {
        this.client = b.client;
        java.util.List certificateStatuses;
        switch (b.certificateStatuses == null ? 0 : b.certificateStatuses.size()) {
        case 0: 
            certificateStatuses = java.util.Collections.emptyList();
            break;
        case 1: 
            certificateStatuses = java.util.Collections.singletonList(b.certificateStatuses.get(0));
            break;
        default: 
            certificateStatuses = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.certificateStatuses));
        }
        this.certificateStatuses = certificateStatuses;
        this.hierarchy = b.hierarchy;
        this.owners = b.owners;
        java.util.List properties;
        switch (b.properties == null ? 0 : b.properties.size()) {
        case 0: 
            properties = java.util.Collections.emptyList();
            break;
        case 1: 
            properties = java.util.Collections.singletonList(b.properties.get(0));
            break;
        default: 
            properties = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.properties));
        }
        this.properties = properties;
        java.util.List tags;
        switch (b.tags == null ? 0 : b.tags.size()) {
        case 0: 
            tags = java.util.Collections.emptyList();
            break;
        case 1: 
            tags = java.util.Collections.singletonList(b.tags.get(0));
            break;
        default: 
            tags = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.tags));
        }
        this.tags = tags;
        this.terms = b.terms;
        java.util.List typeNames;
        switch (b.typeNames == null ? 0 : b.typeNames.size()) {
        case 0: 
            typeNames = java.util.Collections.emptyList();
            break;
        case 1: 
            typeNames = java.util.Collections.singletonList(b.typeNames.get(0));
            break;
        default: 
            typeNames = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.typeNames));
        }
        this.typeNames = typeNames;
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public static LinkableQuery.LinkableQueryBuilder _internal() {
        return new LinkableQuery.LinkableQueryBuilderImpl();
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (!(o instanceof LinkableQuery)) return false;
        final LinkableQuery other = (LinkableQuery) o;
        if (!other.canEqual((java.lang.Object) this)) return false;
        final java.lang.Object this$client = this.client;
        final java.lang.Object other$client = other.client;
        if (this$client == null ? other$client != null : !this$client.equals(other$client)) return false;
        final java.lang.Object this$certificateStatuses = this.certificateStatuses;
        final java.lang.Object other$certificateStatuses = other.certificateStatuses;
        if (this$certificateStatuses == null ? other$certificateStatuses != null : !this$certificateStatuses.equals(other$certificateStatuses)) return false;
        final java.lang.Object this$hierarchy = this.hierarchy;
        final java.lang.Object other$hierarchy = other.hierarchy;
        if (this$hierarchy == null ? other$hierarchy != null : !this$hierarchy.equals(other$hierarchy)) return false;
        final java.lang.Object this$owners = this.owners;
        final java.lang.Object other$owners = other.owners;
        if (this$owners == null ? other$owners != null : !this$owners.equals(other$owners)) return false;
        final java.lang.Object this$properties = this.properties;
        final java.lang.Object other$properties = other.properties;
        if (this$properties == null ? other$properties != null : !this$properties.equals(other$properties)) return false;
        final java.lang.Object this$tags = this.tags;
        final java.lang.Object other$tags = other.tags;
        if (this$tags == null ? other$tags != null : !this$tags.equals(other$tags)) return false;
        final java.lang.Object this$terms = this.terms;
        final java.lang.Object other$terms = other.terms;
        if (this$terms == null ? other$terms != null : !this$terms.equals(other$terms)) return false;
        final java.lang.Object this$typeNames = this.typeNames;
        final java.lang.Object other$typeNames = other.typeNames;
        if (this$typeNames == null ? other$typeNames != null : !this$typeNames.equals(other$typeNames)) return false;
        return true;
    }

    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    protected boolean canEqual(final java.lang.Object other) {
        return other instanceof LinkableQuery;
    }

    @java.lang.Override
    @java.lang.SuppressWarnings("all")
    @lombok.Generated
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final java.lang.Object $client = this.client;
        result = result * PRIME + ($client == null ? 43 : $client.hashCode());
        final java.lang.Object $certificateStatuses = this.certificateStatuses;
        result = result * PRIME + ($certificateStatuses == null ? 43 : $certificateStatuses.hashCode());
        final java.lang.Object $hierarchy = this.hierarchy;
        result = result * PRIME + ($hierarchy == null ? 43 : $hierarchy.hashCode());
        final java.lang.Object $owners = this.owners;
        result = result * PRIME + ($owners == null ? 43 : $owners.hashCode());
        final java.lang.Object $properties = this.properties;
        result = result * PRIME + ($properties == null ? 43 : $properties.hashCode());
        final java.lang.Object $tags = this.tags;
        result = result * PRIME + ($tags == null ? 43 : $tags.hashCode());
        final java.lang.Object $terms = this.terms;
        result = result * PRIME + ($terms == null ? 43 : $terms.hashCode());
        final java.lang.Object $typeNames = this.typeNames;
        result = result * PRIME + ($typeNames == null ? 43 : $typeNames.hashCode());
        return result;
    }
}