001package gudusoft.gsqlparser.catalog.runtime; 002 003import java.util.Collections; 004import java.util.EnumSet; 005import java.util.Set; 006 007/** 008 * What is known about a child object's PARENT kind before resolution (stage S0R of 009 * docs/refactor/identifier_identity_display_separation_plan.md). 010 * 011 * <h3>Why a constraint and not a kind</h3> 012 * A resolved identity always knows its parent's exact kind. A LOOKUP often does not: parsing 013 * {@code schema.relation.column} establishes that the parent is a relation, but not whether the 014 * object it resolves to will be a table, a view or a materialized view. An API that demanded the 015 * exact kind would force the caller to invent {@code TABLE} to get past it — which is the 016 * arity-style guess in a new costume, and it would then reject the perfectly correct answer when the 017 * name turned out to be a view. 018 * 019 * <p>So a lookup carries a family; only {@link CatalogObjectKey} carries an exact kind. 020 */ 021public final class CatalogParentConstraint { 022 023 /** Relations own columns. */ 024 public static final CatalogParentConstraint RELATION = new CatalogParentConstraint( 025 "RELATION", EnumSet.of(CatalogObjectKind.TABLE, CatalogObjectKind.VIEW, 026 CatalogObjectKind.MATERIALIZED_VIEW)); 027 028 /** Containers that own routines. */ 029 public static final CatalogParentConstraint ROUTINE_CONTAINER = new CatalogParentConstraint( 030 "ROUTINE_CONTAINER", EnumSet.of(CatalogObjectKind.PACKAGE)); 031 032 private final String name; 033 private final Set<CatalogObjectKind> allowed; 034 035 private CatalogParentConstraint(String name, Set<CatalogObjectKind> allowed) { 036 this.name = name; 037 this.allowed = Collections.unmodifiableSet(allowed); 038 } 039 040 /** Exactly one kind — for a caller whose metadata genuinely states it. */ 041 public static CatalogParentConstraint exactly(CatalogObjectKind kind) { 042 if (kind == null) { 043 throw new IllegalArgumentException("an exact parent constraint needs a kind"); 044 } 045 return new CatalogParentConstraint("EXACT(" + kind + ")", EnumSet.of(kind)); 046 } 047 048 public boolean admits(CatalogObjectKind kind) { 049 return kind != null && allowed.contains(kind); 050 } 051 052 /** The single kind, when this constraint names exactly one; null for a family. */ 053 public CatalogObjectKind exactKind() { 054 return allowed.size() == 1 ? allowed.iterator().next() : null; 055 } 056 057 public Set<CatalogObjectKind> allowedKinds() { 058 return allowed; 059 } 060 061 @Override 062 public boolean equals(Object o) { 063 if (this == o) { 064 return true; 065 } 066 if (o == null || getClass() != o.getClass()) { 067 return false; 068 } 069 return allowed.equals(((CatalogParentConstraint) o).allowed); 070 } 071 072 @Override 073 public int hashCode() { 074 return allowed.hashCode(); 075 } 076 077 @Override 078 public String toString() { 079 return name; 080 } 081}