001package gudusoft.gsqlparser.resolver2.namespace;
002
003import gudusoft.gsqlparser.nodes.TTable;
004import gudusoft.gsqlparser.resolver2.ColumnLevel;
005import gudusoft.gsqlparser.resolver2.model.ColumnSource;
006import gudusoft.gsqlparser.resolver2.model.FieldPath;
007import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
008
009import java.util.List;
010import java.util.Map;
011import java.util.Set;
012
013/**
014 * Represents a namespace that exposes columns.
015 * A namespace can be a table, subquery, CTE, etc.
016 *
017 * Key responsibilities:
018 * 1. Provide column existence checks (hasColumn)
019 * 2. Resolve column names to ColumnSource
020 * 3. Support SELECT * expansion
021 * 4. Track data lineage (getFinalTable)
022 *
023 * Design based on Apache Calcite's SqlValidatorNamespace
024 */
025public interface INamespace {
026
027    /**
028     * Get a display name for this namespace (for debugging/error messages)
029     */
030    String getDisplayName();
031
032    /**
033     * Check if a column exists in this namespace.
034     * Returns a three-level answer: EXISTS, MAYBE, NOT_EXISTS
035     *
036     * @param columnName Column name to check
037     * @return Column existence level
038     */
039    ColumnLevel hasColumn(String columnName);
040
041    /**
042     * Resolve a column name to its source.
043     *
044     * @param columnName Column name to resolve
045     * @return ColumnSource if found, null otherwise
046     */
047    ColumnSource resolveColumn(String columnName);
048
049    /**
050     * Resolve a column path (column.field.subfield...) to its source.
051     *
052     * <p>This method supports deep/record field access patterns like
053     * {@code customer.address.city} where:</p>
054     * <ul>
055     *   <li>path[0] is the base column name (e.g., "customer")</li>
056     *   <li>path[1..n] are field paths (e.g., ["address", "city"])</li>
057     * </ul>
058     *
059     * @param path The column path segments
060     * @return ColumnSource with fieldPath set, or null if base column not found
061     */
062    default ColumnSource resolveColumnPath(List<String> path) {
063        if (path == null || path.isEmpty()) {
064            return null;
065        }
066
067        // Single segment: simple column resolution
068        if (path.size() == 1) {
069            return resolveColumn(path.get(0));
070        }
071
072        // Multiple segments: resolve base column and attach fieldPath
073        String baseColumnName = path.get(0);
074        ColumnSource baseSource = resolveColumn(baseColumnName);
075        if (baseSource == null) {
076            return null;
077        }
078
079        // Attach field path (segments beyond base column)
080        List<String> fieldSegments = path.subList(1, path.size());
081        return baseSource.withFieldPath(FieldPath.of(fieldSegments), "struct_field_access");
082    }
083
084    /**
085     * Get all column sources exposed by this namespace.
086     * Used for SELECT * expansion and smart completion.
087     *
088     * @return Map of column name -> ColumnSource
089     */
090    Map<String, ColumnSource> getAllColumnSources();
091
092    /**
093     * Get the final physical table this namespace represents.
094     * For tables: returns the table itself
095     * For subqueries/CTEs: recursively traces back to physical table(s)
096     *
097     * @return Physical table, or null if not determinable
098     */
099    TTable getFinalTable();
100
101    /**
102     * Get all final physical tables this namespace depends on.
103     * For simple table namespace: returns single table
104     * For subquery/CTE: returns all tables in the query tree
105     *
106     * @return List of all physical tables
107     */
108    List<TTable> getAllFinalTables();
109
110    /**
111     * Check if this namespace is validated/resolved.
112     * Some namespaces require resolution before they can provide column info.
113     *
114     * @return true if validated
115     */
116    boolean isValidated();
117
118    /**
119     * Validate/resolve this namespace.
120     * For subqueries: resolve the SELECT list
121     * For tables: load metadata if needed
122     */
123    void validate();
124
125    /**
126     * Get the associated AST node (TTable, TSelectSqlStatement, etc.)
127     *
128     * @return AST node, or null if not applicable
129     */
130    Object getNode();
131
132    // ========== Star Column Inference Support ==========
133
134    /**
135     * Get the underlying SELECT statement for this namespace.
136     * For CTENamespace: returns the CTE's subquery
137     * For SubqueryNamespace: returns the subquery
138     * For TableNamespace: returns null
139     *
140     * @return the SELECT statement, or null if not applicable
141     */
142    default TSelectSqlStatement getSelectStatement() {
143        return null;
144    }
145
146    /**
147     * Check if this namespace contains a star column (SELECT *).
148     * Used to identify namespaces that may need star column inference.
149     *
150     * @return true if the namespace has SELECT *, false otherwise
151     */
152    default boolean hasStarColumn() {
153        return false;
154    }
155
156    /**
157     * Add an inferred column to this namespace.
158     * Used by star column push-down to add columns discovered from outer queries.
159     *
160     * @param columnName the column name to add
161     * @param confidence the confidence score (0.0 to 1.0)
162     * @param evidence description of why this column was inferred
163     * @return true if the column was added, false if already exists
164     */
165    default boolean addInferredColumn(String columnName, double confidence, String evidence) {
166        // Default implementation does nothing - override in subclasses that support inference
167        return false;
168    }
169
170    /**
171     * Get all columns that were inferred (not from SELECT list directly).
172     * These are columns discovered through star column push-down.
173     *
174     * @return set of inferred column names, empty if none
175     */
176    default Set<String> getInferredColumns() {
177        return java.util.Collections.emptySet();
178    }
179
180    /**
181     * Check if this namespace supports dynamic column inference.
182     * DynamicStarSource and similar namespaces return true.
183     *
184     * @return true if this namespace can have columns added dynamically
185     */
186    default boolean supportsDynamicInference() {
187        return false;
188    }
189
190    /**
191     * Get the star column (SELECT *) from this namespace if one exists.
192     * Used to track the sourceColumn for columns inferred from a star.
193     *
194     * @return The star column TResultColumn, or null if no star column exists
195     */
196    default gudusoft.gsqlparser.nodes.TResultColumn getStarColumn() {
197        return null;
198    }
199
200    // ========== Legacy Compatibility Support ==========
201
202    /**
203     * Get the TTable that this namespace is associated with.
204     * Used for legacy sync to set TObjectName.sourceTable.
205     *
206     * For TableNamespace: returns the table itself
207     * For SubqueryNamespace: returns the TTable wrapping the subquery
208     * For CTENamespace: returns the CTE referencing table
209     * For others: returns null
210     *
211     * @return The source TTable, or null if not applicable
212     */
213    default TTable getSourceTable() {
214        return null;
215    }
216}