001package gudusoft.gsqlparser.ir.builder.common;
002
003import gudusoft.gsqlparser.ir.bound.ERoutineKind;
004
005/**
006 * Standardizes routine ID assembly across dialects.
007 * <p>
008 * Routine ID format: {@code [namespace.]name/KIND(paramCount)}
009 * <p>
010 * Namespace varies by dialect:
011 * <ul>
012 *   <li>Oracle: package name (e.g., MY_PKG.PROC/P(2))</li>
013 *   <li>MSSQL: schema name (e.g., DBO.PROC/P(2))</li>
014 *   <li>PostgreSQL: schema name (e.g., PUBLIC.FUNC/F(1))</li>
015 *   <li>BigQuery: project.dataset (e.g., MYPROJ.DS.FUNC/F(1))</li>
016 *   <li>Snowflake: database.schema (e.g., DB.PUBLIC.PROC/P(0))</li>
017 * </ul>
018 */
019public final class RoutineIdFactory {
020
021    private RoutineIdFactory() {}
022
023    /**
024     * Builds a routine ID from its components.
025     *
026     * @param namespace  package, schema, or qualified namespace (nullable)
027     * @param name       routine name
028     * @param kind       routine kind
029     * @param paramCount parameter count
030     * @return formatted routine ID
031     */
032    public static String build(String namespace, String name, ERoutineKind kind, int paramCount) {
033        StringBuilder sb = new StringBuilder();
034        if (namespace != null && !namespace.isEmpty()) {
035            sb.append(namespace).append('.');
036        }
037        sb.append(name).append('/').append(kindCode(kind))
038                .append('(').append(paramCount).append(')');
039        return sb.toString();
040    }
041
042    /**
043     * Returns the single/two-letter kind code for the given routine kind.
044     */
045    public static String kindCode(ERoutineKind kind) {
046        switch (kind) {
047            case PROCEDURE:         return "P";
048            case FUNCTION:          return "F";
049            case TRIGGER:           return "T";
050            case ANONYMOUS_BLOCK:   return "A";
051            case NESTED_PROCEDURE:  return "NP";
052            case NESTED_FUNCTION:   return "NF";
053            case TYPE_METHOD:       return "TM";
054            case OPAQUE_UDF:        return "OU";
055            case OPAQUE_PROCEDURE:  return "OP";
056            default:                return "P";
057        }
058    }
059
060    /**
061     * Extracts the namespace (package/schema) from a routine ID.
062     * Returns null if there is no namespace prefix.
063     */
064    public static String extractNamespace(String routineId) {
065        if (routineId == null) return null;
066        int slashIdx = routineId.indexOf('/');
067        String nameSection = slashIdx > 0 ? routineId.substring(0, slashIdx) : routineId;
068        int dotIdx = nameSection.lastIndexOf('.');
069        return dotIdx > 0 ? nameSection.substring(0, dotIdx) : null;
070    }
071
072    /**
073     * Extracts the simple routine name from a routine ID.
074     */
075    public static String extractName(String routineId) {
076        if (routineId == null) return null;
077        int slashIdx = routineId.indexOf('/');
078        String nameSection = slashIdx > 0 ? routineId.substring(0, slashIdx) : routineId;
079        int dotIdx = nameSection.lastIndexOf('.');
080        return dotIdx >= 0 ? nameSection.substring(dotIdx + 1) : nameSection;
081    }
082}