001package gudusoft.gsqlparser.dlineage.dataflow.model.xml;
002
003import java.util.Comparator;
004import java.util.LinkedHashSet;
005import java.util.Set;
006
007import javax.xml.bind.annotation.XmlAttribute;
008import javax.xml.bind.annotation.XmlElement;
009import javax.xml.bind.annotation.XmlElementWrapper;
010import javax.xml.bind.annotation.XmlTransient;
011import javax.xml.bind.annotation.XmlType;
012
013import gudusoft.gsqlparser.TSourceToken;
014import gudusoft.gsqlparser.dlineage.dataflow.model.ModelBindingManager;
015import gudusoft.gsqlparser.dlineage.dataflow.model.Transform;
016import gudusoft.gsqlparser.dlineage.util.DlineageUtil;
017import gudusoft.gsqlparser.dlineage.util.Pair3;
018import gudusoft.gsqlparser.util.SQLUtil;
019
020@XmlType(propOrder = { "id", "name", "column", "value", "source_id", "source_name", "column_type", "parent_id", "parent_name", "parent_alias",
021                "coordinate", "clauseType", "source", "type", "transforms", "candidateParents"})
022public class sourceColumn {
023
024        private String id;
025
026        private String name;
027        
028        private String column;
029
030        private String value;
031
032        private String source_id;
033
034        private String source_name;
035
036        private String column_type;
037
038        private String parent_id;
039
040        private String parent_name;
041        
042        private String parent_alias;
043
044        private String coordinate;
045
046        private String clauseType;
047
048        private String source;
049        
050        private String type;
051        
052        private Set<transform> transforms;
053        
054        private Set<candidateTable> candidateParents;
055        
056        @XmlTransient
057        private Boolean struct;
058
059        private String dedupCoordinate;
060
061        @XmlElementWrapper(name="candidateTables") 
062        @XmlElement(name="candidateTable", required = false)
063        public Set<candidateTable> getCandidateParents() {
064                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) {
065                        return null;
066                }
067                return candidateParents;
068        }
069        
070        public void setCandidateParents(Set<candidateTable> candidateParents) {
071                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) {
072                        return;
073                }
074                this.candidateParents = candidateParents;
075        }
076        
077        public void addCandidateParent(candidateTable candidateParent) {
078                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isShowCandidateTable()) {
079                        return;
080                }
081                if(candidateParent == null)
082                        return;
083                if(candidateParents == null) {
084                        candidateParents = new LinkedHashSet<candidateTable>();
085                }
086                candidateParents.add(candidateParent);
087        }
088        
089        @XmlElementWrapper(name="transforms") 
090        @XmlElement(name="transform", required = false)
091        public Set<transform> getTransforms() {
092                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) {
093                        return null;
094                }
095                return transforms;
096        }
097        
098        public void setTransforms(Set<transform> transforms) {
099                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) {
100                        return;
101                }
102                this.transforms = transforms;
103        }
104        
105        public void addTransform(Transform transform) {
106                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) {
107                        return;
108                }
109                if(transform == null)
110                        return;
111                if(transforms == null) {
112                        transforms = new LinkedHashSet<transform>();
113                }
114                
115                transform t = new transform();
116                if (transform.getCode() != null) {
117                        if (ModelBindingManager.getGlobalOption().isTransformCoordinate()) {
118                                TSourceToken startToken = transform.getCode().getStartToken();
119                                TSourceToken endToken = transform.getCode().getEndToken();
120                                Pair3<Long, Long, String> startPosition = new Pair3<Long, Long, String>(startToken.lineNo,
121                                                startToken.columnNo, ModelBindingManager.getGlobalHash());
122                                Pair3<Long, Long, String> endPosition = new Pair3<Long, Long, String>(endToken.lineNo,
123                                                endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash());
124                                t.setCoordinate(convertCoordinate(startPosition) + "," + convertCoordinate(endPosition));
125                        }
126                        t.setCode(transform.getCode().toString());
127                } else if (!SQLUtil.isEmpty(transform.getCodeString())) {
128                        if (ModelBindingManager.getGlobalOption().isTransformCoordinate()) {
129                                TSourceToken startToken = transform.getStartToken();
130                                TSourceToken endToken = transform.getEndToken();
131                                Pair3<Long, Long, String> startPosition = new Pair3<Long, Long, String>(startToken.lineNo,
132                                                startToken.columnNo, ModelBindingManager.getGlobalHash());
133                                Pair3<Long, Long, String> endPosition = new Pair3<Long, Long, String>(endToken.lineNo,
134                                                endToken.columnNo + SQLUtil.endTrim(endToken.getAstext()).length(), ModelBindingManager.getGlobalHash());
135                                t.setCoordinate(convertCoordinate(startPosition) + "," + convertCoordinate(endPosition));
136                        }
137                        t.setCode(transform.getCodeString());
138                }
139                t.setType(transform.getType());
140                transforms.add(t);
141        }
142        
143        public void addTransform(transform transform) {
144                if (ModelBindingManager.getGlobalOption()!=null && !ModelBindingManager.getGlobalOption().isTransform()) {
145                        return;
146                }
147                if(transform == null)
148                        return;
149                if(transforms == null) {
150                        transforms = new LinkedHashSet<transform>();
151                }
152                transforms.add(transform);
153        }
154        
155        private Pair3<Long, Long, Integer> convertCoordinate(Pair3<Long, Long, String> position) {
156                return new Pair3<Long, Long, Integer>(position.first, position.second,
157                                ModelBindingManager.getGlobalSqlInfo().getIndexOf(position.third));
158        }
159        
160        @XmlAttribute(required = false)
161        public String getCoordinate() {
162//              if (ModelBindingManager.getGlobalOption()!=null && ModelBindingManager.getGlobalOption().isIgnoreCoordinate()) {
163//                      return null;
164//              }
165                return coordinate;
166        }
167
168        public void setCoordinate(String coordinate) {
169//              if (ModelBindingManager.getGlobalOption()!=null && ModelBindingManager.getGlobalOption().isIgnoreCoordinate()) {
170//                      return;
171//              }
172                this.coordinate = coordinate;
173        }
174
175        @XmlAttribute(required = false)
176        public String getColumn() {
177                return column;
178        }
179
180        public void setColumn(String column) {
181                this.column = column;
182        }
183
184        @XmlAttribute(required = false)
185        public String getId() {
186                return id;
187        }
188
189        public void setId(String id) {
190                this.id = id;
191        }
192
193        @XmlAttribute(name = "parent_id", required = false)
194        public String getParent_id() {
195                return parent_id;
196        }
197
198        public void setParent_id(String parent_id) {
199                this.parent_id = parent_id;
200        }
201
202        @XmlAttribute(name = "parent_name", required = false)
203        public String getParent_name() {
204                return parent_name;
205        }
206
207        public void setParent_name(String parent_name) {
208                this.parent_name = parent_name;
209        }
210        
211        @XmlAttribute(name = "parent_alias", required = false)
212        public String getParent_alias() {
213                return parent_alias;
214        }
215
216        public void setParent_alias(String parent_alias) {
217                this.parent_alias = parent_alias;
218        }
219
220        @XmlAttribute(required = false)
221        public String getValue() {
222                return value;
223        }
224
225        public void setValue(String value) {
226                this.value = value;
227        }
228
229        @XmlAttribute(name = "source_name", required = false)
230        public String getSource_name() {
231                return source_name;
232        }
233
234        public void setSource_name(String source_name) {
235                this.source_name = source_name;
236        }
237
238        @XmlAttribute(name = "source_id", required = false)
239        public String getSource_id() {
240                return source_id;
241        }
242
243        public void setSource_id(String source_id) {
244                this.source_id = source_id;
245        }
246
247        @XmlAttribute(required = false)
248        public String getClauseType() {
249                return clauseType;
250        }
251
252        public void setClauseType(String clauseType) {
253                this.clauseType = clauseType;
254        }
255
256        @XmlAttribute(name = "column_type", required = false)
257        public String getColumn_type() {
258                return column_type;
259        }
260
261        public void setColumn_type(String column_type) {
262                this.column_type = column_type;
263        }
264
265        @XmlAttribute(required = false)
266        public String getSource() {
267                return source;
268        }
269
270        public void setSource(String source) {
271                this.source = source;
272        }
273        
274        @XmlAttribute(required = false)
275        public String getType() {
276                return type;
277        }
278
279        public void setType(String type) {
280                this.type = type;
281        }
282
283        @Override
284        public int hashCode() {
285                final int prime = 31;
286                int result = 1;
287                String columnName = getColumnName(this);
288                result = prime * result + ((columnName == null) ? 0 : columnName.hashCode());
289                result = prime * result + ((coordinate == null) ? 0 : coordinate.hashCode());
290                result = prime * result + ((parent_id == null) ? 0 : parent_id.hashCode());
291                return result;
292        }
293
294        private String getColumnName(sourceColumn column) {
295                if ("constant".equals(column.getColumn_type())) {
296                        return column.column;
297                }
298                if (ModelBindingManager.getGlobalVendor() != null) {
299                        return DlineageUtil.getIdentifierNormalColumnName(column.column);
300                }
301                return column.column;
302        }
303
304        @Override
305        public boolean equals(Object obj) {
306                if (this == obj)
307                        return true;
308                if (obj == null)
309                        return false;
310                if (getClass() != obj.getClass())
311                        return false;
312                sourceColumn other = (sourceColumn) obj;
313                if (column == null) {
314                        if (other.column != null)
315                                return false;
316                } else if (!getColumnName(this).equals(getColumnName(other)))
317                        return false;
318                if (coordinate == null) {
319                        if (other.coordinate != null)
320                                return false;
321                } else if (coordinate.hashCode() != other.coordinate.hashCode())
322                        return false;
323                if (parent_id == null) {
324                        if (other.parent_id != null)
325                                return false;
326                } else if (!parent_id.equals(other.parent_id))
327                        return false;
328                return true;
329        }
330
331        @XmlAttribute(required = false)
332        public String getName() {
333                return name;
334        }
335
336        public void setName(String name) {
337                this.name = name;
338        }
339
340        @XmlTransient
341        public Boolean isStruct() {
342                return struct;
343        }
344
345        public void setStruct(Boolean struct) {
346                this.struct = struct;
347        }
348
349        public String toDedupKey() {
350                StringBuilder sb = new StringBuilder(128);
351                appendDedupKey(sb);
352                return sb.toString();
353        }
354
355        public long toDedupHash() {
356                StringBuilder sb = new StringBuilder(128);
357                appendDedupKey(sb);
358                return SQLUtil.hash64(sb);
359        }
360
361        /**
362         * The coordinate this source would have carried before reference-site
363         * publishing — the column model's definition span. The table-merge pass
364         * stamps it in for its dedup steps (equals/hashCode and toDedupHash include
365         * the coordinate), so sources and relations keep collapsing exactly as they
366         * did when every reference was rendered with the model span, then restores
367         * the published reference-site coordinate on the survivors. Never
368         * serialized.
369         */
370        @XmlTransient
371        public String getDedupCoordinate() {
372                return dedupCoordinate;
373        }
374
375        public void setDedupCoordinate(String dedupCoordinate) {
376                this.dedupCoordinate = dedupCoordinate;
377        }
378
379        void appendDedupKey(StringBuilder sb) {
380                if (name != null) { sb.append("name=").append(name).append('|'); }
381                if (column != null) { sb.append("column=").append(column).append('|'); }
382                if (parent_id != null) { sb.append("parent_id=").append(parent_id).append('|'); }
383                if (source_id != null) { sb.append("source_id=").append(source_id).append('|'); }
384                if (value != null) { sb.append("value=").append(value).append('|'); }
385                if (source_name != null) { sb.append("source_name=").append(source_name).append('|'); }
386                if (column_type != null) { sb.append("column_type=").append(column_type).append('|'); }
387                if (parent_name != null) { sb.append("parent_name=").append(parent_name).append('|'); }
388                if (parent_alias != null) { sb.append("parent_alias=").append(parent_alias).append('|'); }
389                if (coordinate != null) { sb.append("coordinate=").append(coordinate).append('|'); }
390                if (clauseType != null) { sb.append("clauseType=").append(clauseType).append('|'); }
391                if (source != null) { sb.append("source=").append(source).append('|'); }
392                if (type != null) { sb.append("type=").append(type).append('|'); }
393                if (transforms != null && !transforms.isEmpty()) {
394                        sb.append("transforms=[");
395                        transforms.stream().sorted(Comparator.comparing(transform::getType, Comparator.nullsFirst(Comparator.<String>naturalOrder())))
396                                        .forEach(t -> { sb.append('{'); t.appendDedupKey(sb); sb.append("},"); });
397                        sb.setLength(sb.length() - 1);
398                        sb.append("]|");
399                }
400                if (candidateParents != null && !candidateParents.isEmpty()) {
401                        sb.append("candidateParents=[");
402                        candidateParents.stream().sorted(Comparator.comparing(candidateTable::getId, Comparator.nullsFirst(Comparator.<String>naturalOrder())))
403                                        .forEach(c -> { sb.append('{'); c.appendDedupKey(sb); sb.append("},"); });
404                        sb.setLength(sb.length() - 1);
405                        sb.append("]|");
406                }
407        }
408}