001package gudusoft.gsqlparser.dlineage.dataflow.model; 002 003import gudusoft.gsqlparser.dlineage.util.DlineageUtil; 004 005/** 006 * Matches the star links and model columns of a relation's sources against one star link of its target, the link a 007 * star expansion is publishing. Obtained from {@link Column#starLinkMatcher(int)} once per expansion, it decides the 008 * matches the analyzer used to decide on the target link's folded display, with the same comparisons: a target link 009 * matches a source link or model column under {@link DlineageUtil#sameColumnNormalName}, and is named by a model 010 * column whose folded name equals its own folded display. 011 * 012 * <p>Internal contract of the lineage analyzer. 013 */ 014public final class StarLinkMatcher { 015 016 private final String foldedDisplay; 017 018 private final StarLinkKey key; 019 020 StarLinkMatcher(String foldedDisplay, StarLinkKey key) { 021 this.foldedDisplay = foldedDisplay; 022 this.key = key; 023 } 024 025 /** Whether the star link at {@code ordinal} of {@code source} is this link's column. */ 026 public boolean matches(Column source, int ordinal) { 027 if (StarLinkStore.IDENTITY) { 028 Object other = source.starLinkKey(ordinal); 029 if (other instanceof StarLinkKey && StarLinkStore.identifiers(key, (StarLinkKey) other)) { 030 return decided("matches", key.equals(other), source.starLinkDisplay(ordinal)); 031 } 032 } 033 return DlineageUtil.sameColumnNormalName(foldedDisplay, source.starLinkDisplay(ordinal)); 034 } 035 036 /** Whether {@code model} is this link's column, compared as the analyzer compared a model name. */ 037 public boolean matchesColumn(Column model) { 038 if (StarLinkStore.IDENTITY) { 039 StarLinkKey other = StarLinkStore.modelKey(model); 040 if (StarLinkStore.identifiers(key, other)) { 041 return decided("matchesColumn", key.equals(other), model.getName()); 042 } 043 } 044 return DlineageUtil.sameColumnNormalName(foldedDisplay, StarLinkStore.legacyFold(model.getName())); 045 } 046 047 /** Whether {@code model} carries exactly this link's name. */ 048 public boolean isNamedBy(Column model) { 049 if (StarLinkStore.IDENTITY) { 050 StarLinkKey other = StarLinkStore.modelKey(model); 051 if (StarLinkStore.identifiers(key, other)) { 052 return decided("isNamedBy", key.equals(other), model.getName()); 053 } 054 } 055 return StarLinkStore.legacyFold(model.getName()).equals(foldedDisplay); 056 } 057 058 /** 059 * Whether the star links of {@code source} hold another identity's column under this link's folded display: a 060 * column the grouping by display would take for this link's, and which, grouped by identity, is a different 061 * column (PostgreSQL {@code "Amount"} where this link is {@code amount}). A star that holds it is not inferred to 062 * hold this link's column as well; false while links are grouped by display, and for a label. 063 */ 064 public boolean isDisplacedIn(Column source) { 065 if (!StarLinkStore.IDENTITY || key == null || !key.isIdentifier() || source == null) { 066 return false; 067 } 068 for (int k = 0; k < source.starLinkCount(); k++) { 069 Object other = source.starLinkKey(k); 070 if (other instanceof StarLinkKey && ((StarLinkKey) other).isIdentifier() && !key.equals(other) 071 && DlineageUtil.sameColumnNormalName(foldedDisplay, source.starLinkDisplay(k))) { 072 return true; 073 } 074 } 075 return false; 076 } 077 078 /** 079 * The key this link is remembered by among the target links that already have an explicit source. A source link 080 * is looked up in that set by {@link Column#starLinkKey(int)}. 081 */ 082 public Object key() { 083 return StarLinkStore.IDENTITY && key != null ? key : foldedDisplay; 084 } 085 086 String foldedDisplay() { 087 return foldedDisplay; 088 } 089 090 StarLinkKey identity() { 091 return key; 092 } 093 094 /** Reports an identity answer that the legacy comparison disputes; the legacy comparison runs for the census only. */ 095 private boolean decided(String predicate, boolean identity, String other) { 096 if (StarLinkStore.censusOn()) { 097 boolean answer = "matches".equals(predicate) ? DlineageUtil.sameColumnNormalName(foldedDisplay, other) 098 : "isNamedBy".equals(predicate) ? other != null && foldedDisplay.equals(StarLinkStore.legacyFold(other)) 099 : DlineageUtil.sameColumnNormalName(foldedDisplay, StarLinkStore.legacyFold(other)); 100 if (identity != answer) { 101 StarLinkStore.census("PREDICATE_DIFF " + predicate, foldedDisplay + " ~ " + other); 102 } 103 } 104 return identity; 105 } 106}