001package gudusoft.gsqlparser.resolver2.inference;
002
003import gudusoft.gsqlparser.nodes.TParseTreeNode;
004
005/**
006 * Represents a piece of evidence for column inference.
007 *
008 * <p>Evidence is collected from various sources in the SQL statement:
009 * - Column references in WHERE clauses
010 * - JOIN conditions
011 * - SELECT list expressions
012 * - INSERT statements (column lists)
013 * - etc.
014 *
015 * <p>Each piece of evidence has a confidence weight that contributes
016 * to the overall inference confidence.
017 *
018 * <p>Example:
019 * <pre>
020 * SELECT t1.* FROM t1 WHERE t1.id = 100
021 *                              ^^
022 * Evidence: "id" exists in t1 (from WHERE clause, high confidence)
023 * </pre>
024 */
025public class InferenceEvidence {
026
027    /** The inferred column name */
028    private final String columnName;
029
030    /** The table name this evidence relates to */
031    private final String tableName;
032
033    /** Type of evidence */
034    private final EvidenceType evidenceType;
035
036    /** Confidence weight [0.0, 1.0] */
037    private final double confidence;
038
039    /** Source AST node that provides this evidence */
040    private final TParseTreeNode sourceNode;
041
042    /** Description of how this evidence was obtained */
043    private final String description;
044
045    public InferenceEvidence(
046            String columnName,
047            String tableName,
048            EvidenceType evidenceType,
049            double confidence,
050            TParseTreeNode sourceNode,
051            String description) {
052        this.columnName = columnName;
053        this.tableName = tableName;
054        this.evidenceType = evidenceType;
055        this.confidence = Math.max(0.0, Math.min(1.0, confidence));
056        this.sourceNode = sourceNode;
057        this.description = description;
058    }
059
060    public String getColumnName() {
061        return columnName;
062    }
063
064    public String getTableName() {
065        return tableName;
066    }
067
068    public EvidenceType getEvidenceType() {
069        return evidenceType;
070    }
071
072    public double getConfidence() {
073        return confidence;
074    }
075
076    public TParseTreeNode getSourceNode() {
077        return sourceNode;
078    }
079
080    public String getDescription() {
081        return description;
082    }
083
084    /**
085     * Create evidence from a qualified column reference.
086     * Example: WHERE t1.id = 100
087     */
088    public static InferenceEvidence fromQualifiedReference(
089            String columnName,
090            String tableName,
091            TParseTreeNode sourceNode) {
092        return new InferenceEvidence(
093            columnName,
094            tableName,
095            EvidenceType.QUALIFIED_REFERENCE,
096            0.95,  // High confidence - explicit table reference
097            sourceNode,
098            "Qualified column reference: " + tableName + "." + columnName
099        );
100    }
101
102    /**
103     * Create evidence from an unqualified column reference.
104     * Example: WHERE id = 100 (when only one table in scope)
105     */
106    public static InferenceEvidence fromUnqualifiedReference(
107            String columnName,
108            String tableName,
109            TParseTreeNode sourceNode,
110            int tableCount) {
111        double confidence = tableCount == 1 ? 0.8 : 0.5;  // Lower if ambiguous
112        return new InferenceEvidence(
113            columnName,
114            tableName,
115            EvidenceType.UNQUALIFIED_REFERENCE,
116            confidence,
117            sourceNode,
118            "Unqualified column reference: " + columnName + " (tables in scope: " + tableCount + ")"
119        );
120    }
121
122    /**
123     * Create evidence from a JOIN condition.
124     * Example: JOIN t2 ON t1.id = t2.t1_id
125     */
126    public static InferenceEvidence fromJoinCondition(
127            String columnName,
128            String tableName,
129            TParseTreeNode sourceNode) {
130        return new InferenceEvidence(
131            columnName,
132            tableName,
133            EvidenceType.JOIN_CONDITION,
134            0.9,  // Very high confidence - explicit relationship
135            sourceNode,
136            "JOIN condition: " + tableName + "." + columnName
137        );
138    }
139
140    /**
141     * Create evidence from SELECT list.
142     * Example: SELECT t1.name, t1.age FROM t1
143     */
144    public static InferenceEvidence fromSelectList(
145            String columnName,
146            String tableName,
147            TParseTreeNode sourceNode) {
148        return new InferenceEvidence(
149            columnName,
150            tableName,
151            EvidenceType.SELECT_LIST,
152            0.85,
153            sourceNode,
154            "SELECT list column: " + tableName + "." + columnName
155        );
156    }
157
158    /**
159     * Create evidence from INSERT statement column list.
160     * Example: INSERT INTO t1 (id, name) VALUES (...)
161     */
162    public static InferenceEvidence fromInsertColumns(
163            String columnName,
164            String tableName,
165            TParseTreeNode sourceNode) {
166        return new InferenceEvidence(
167            columnName,
168            tableName,
169            EvidenceType.INSERT_COLUMN_LIST,
170            1.0,  // Perfect confidence - explicit column definition
171            sourceNode,
172            "INSERT column list: " + columnName
173        );
174    }
175
176    /**
177     * Create evidence from UPDATE statement.
178     * Example: UPDATE t1 SET name = 'value'
179     */
180    public static InferenceEvidence fromUpdateSet(
181            String columnName,
182            String tableName,
183            TParseTreeNode sourceNode) {
184        return new InferenceEvidence(
185            columnName,
186            tableName,
187            EvidenceType.UPDATE_SET,
188            0.95,
189            sourceNode,
190            "UPDATE SET: " + columnName
191        );
192    }
193
194    @Override
195    public String toString() {
196        return String.format("Evidence[%s.%s, type=%s, conf=%.2f]",
197            tableName, columnName, evidenceType, confidence);
198    }
199
200    @Override
201    public boolean equals(Object obj) {
202        if (this == obj) return true;
203        if (!(obj instanceof InferenceEvidence)) return false;
204        InferenceEvidence other = (InferenceEvidence) obj;
205        return columnName.equals(other.columnName) &&
206               tableName.equals(other.tableName) &&
207               evidenceType == other.evidenceType;
208    }
209
210    @Override
211    public int hashCode() {
212        int result = columnName.hashCode();
213        result = 31 * result + tableName.hashCode();
214        result = 31 * result + evidenceType.hashCode();
215        return result;
216    }
217}