001package gudusoft.gsqlparser.resolver2.model;
002
003/**
004 * A side-channel annotation for deep struct field access (3+ part names without alias).
005 *
006 * <p>Unlike {@link ColumnSource} (which is part of the main resolution result and
007 * triggers sourceTable binding), this hint is purely informational. It provides
008 * struct field path information to downstream consumers (e.g., DataFlowAnalyzer)
009 * without altering the resolution path or lineage topology.</p>
010 *
011 * <p>This solves the problem where 3-part no-alias struct access like
012 * {@code customer.address.city FROM orders} cannot use the main EXACT_MATCH
013 * resolution path because doing so changes sourceTable binding and breaks
014 * existing lineage chains (see plan document Section 10).</p>
015 *
016 * <p>Example:</p>
017 * <pre>
018 * -- SQL: SELECT customer.address.city FROM orders
019 * -- StructFieldHint:
020 * --   baseColumn = "customer"
021 * --   fieldPath = ["address", "city"]
022 * --   evidence = "struct_field_hint_no_alias"
023 * --   confidence = 0.7
024 * </pre>
025 *
026 * @see FieldPath
027 */
028public class StructFieldHint {
029
030    private final String baseColumn;
031    private final FieldPath fieldPath;
032    private final String evidence;
033    private final double confidence;
034
035    public StructFieldHint(String baseColumn, FieldPath fieldPath, String evidence, double confidence) {
036        this.baseColumn = baseColumn;
037        this.fieldPath = fieldPath;
038        this.evidence = evidence;
039        this.confidence = Math.max(0.0, Math.min(1.0, confidence));
040    }
041
042    public String getBaseColumn() {
043        return baseColumn;
044    }
045
046    public FieldPath getFieldPath() {
047        return fieldPath;
048    }
049
050    public String getEvidence() {
051        return evidence;
052    }
053
054    public double getConfidence() {
055        return confidence;
056    }
057
058    /**
059     * Get the full dotted reference (e.g., "customer.address.city").
060     */
061    public String toFullReference() {
062        if (fieldPath == null || fieldPath.isEmpty()) {
063            return baseColumn != null ? baseColumn : "";
064        }
065        return fieldPath.toFullReference(baseColumn);
066    }
067
068    @Override
069    public String toString() {
070        return "StructFieldHint{base=" + baseColumn +
071            ", path=" + fieldPath +
072            ", evidence=" + evidence +
073            ", confidence=" + confidence + "}";
074    }
075}