001package gudusoft.gsqlparser.dlineage.routine;
002
003import java.util.Collections;
004import java.util.List;
005
006/**
007 * What a routine lookup found: a status, the branch of the match, and the distinct candidate declarations
008 * in declaration order.
009 *
010 * <p>{@link Status#RESOLVED} only for exactly one candidate matched on every named level, with no level
011 * one side names and the other omits. A match that needs caller context to fill an omitted level
012 * ({@code f} against {@code s.f}, {@code db..p} against {@code db.dbo.p}) is {@link Status#REQUIRES_CONTEXT},
013 * and more than one candidate is {@link Status#AMBIGUOUS}: an ambiguous callee binds nothing (the
014 * {@code RoutineCallBinder} contract).</p>
015 */
016public final class RoutineLookupResult {
017
018    public enum Status {
019        RESOLVED, AMBIGUOUS, NOT_FOUND, REQUIRES_CONTEXT
020    }
021
022    public enum Branch {
023        /** Every level equal, and the argument alias. */
024        EXACT,
025        /** A name-only lookup that found declarations of that name keyed with a signature. */
026        NAME_FALLBACK,
027        /** The lookup omits levels the declaration names ({@code f} against {@code s.f}). */
028        LEAF_QUALIFIED,
029        /** The declaration omits levels the lookup names ({@code s.f} against {@code f}). */
030        LEAF_UNQUALIFIED,
031        /** Each side omits a level the other names. */
032        PARTIAL,
033        NONE
034    }
035
036    static final RoutineLookupResult NOT_FOUND = new RoutineLookupResult(Status.NOT_FOUND, Branch.NONE,
037            Collections.<RoutineDeclaration>emptyList());
038
039    private final Status status;
040    private final Branch branch;
041    private final List<RoutineDeclaration> candidates;
042    private final Object legacyWinner;
043
044    RoutineLookupResult(Status status, Branch branch, List<RoutineDeclaration> candidates) {
045        this(status, branch, candidates, null);
046    }
047
048    private RoutineLookupResult(Status status, Branch branch, List<RoutineDeclaration> candidates, Object legacyWinner) {
049        this.status = status;
050        this.branch = branch;
051        this.candidates = Collections.unmodifiableList(candidates);
052        this.legacyWinner = legacyWinner;
053    }
054
055    /** This result with the routine the legacy registry answered at the same lookup (measurement only). */
056    public RoutineLookupResult withLegacyWinner(Object legacy) {
057        return new RoutineLookupResult(status, branch, candidates, legacy);
058    }
059
060    /** What the legacy registry answered at the same lookup, when recorded: compatibility evidence, never a winner. */
061    public Object getLegacyWinner() {
062        return legacyWinner;
063    }
064
065    public Status getStatus() {
066        return status;
067    }
068
069    public Branch getBranch() {
070        return branch;
071    }
072
073    public List<RoutineDeclaration> getCandidates() {
074        return candidates;
075    }
076
077    /** The one declaration found, only when {@link #getStatus()} is RESOLVED. */
078    public RoutineDeclaration getResolved() {
079        return status == Status.RESOLVED ? candidates.get(0) : null;
080    }
081
082    @Override
083    public String toString() {
084        return status + "/" + branch + candidates;
085    }
086}