001package gudusoft.gsqlparser.lineage2.contract;
002
003/**
004 * Contract {@code Transformation} (lineage2-contract.md §4.2, D-08):
005 * original expression text, normalized form (FINGERPRINT-V1 normalization
006 * family), SHA-256 of the normalized form, and the location of the
007 * <em>original</em> expression in the unit (the normalized form is a
008 * canonical rewrite and intentionally has no coordinates).
009 *
010 * <p>Unlike {@link Endpoint}, the JSON form always carries both the
011 * {@code sourceLocation} and {@code locationNullReason} keys (one of the
012 * two is null) — the gold-fixture-pinned shape.
013 *
014 * <p>Internal API: not part of the public gsqlparser surface.
015 */
016public final class Transformation {
017
018    private final String originalExpression;
019    private final String normalizedExpression;
020    private final String expressionHash;
021    private final SourceLocation sourceLocation;
022    private final LocationNullReason locationNullReason;
023
024    public Transformation(String originalExpression, String normalizedExpression,
025                          String expressionHash, SourceLocation sourceLocation,
026                          LocationNullReason locationNullReason) {
027        if (originalExpression == null || normalizedExpression == null
028                || expressionHash == null) {
029            throw new IllegalArgumentException("originalExpression, "
030                    + "normalizedExpression, and expressionHash must not be null");
031        }
032        this.originalExpression = originalExpression;
033        this.normalizedExpression = normalizedExpression;
034        this.expressionHash = expressionHash;
035        this.sourceLocation = sourceLocation;
036        this.locationNullReason = locationNullReason;
037    }
038
039    /**
040     * Convenience factory: normalizes {@code originalExpression} with the
041     * FINGERPRINT-V1 normalization family and hashes the normalized form.
042     */
043    public static Transformation of(String originalExpression,
044                                    SourceLocation sourceLocation,
045                                    LocationNullReason locationNullReason) {
046        String normalized = FingerprintV1.normalize(originalExpression);
047        return new Transformation(originalExpression, normalized,
048                GuidEncoder.sha256Hex(normalized), sourceLocation,
049                locationNullReason);
050    }
051
052    public String getOriginalExpression() {
053        return originalExpression;
054    }
055
056    public String getNormalizedExpression() {
057        return normalizedExpression;
058    }
059
060    public String getExpressionHash() {
061        return expressionHash;
062    }
063
064    /** Nullable. */
065    public SourceLocation getSourceLocation() {
066        return sourceLocation;
067    }
068
069    /** Nullable — set only when {@code sourceLocation} is null. */
070    public LocationNullReason getLocationNullReason() {
071        return locationNullReason;
072    }
073}