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}