001package gudusoft.gsqlparser.catalog.input.model;
002
003import gudusoft.gsqlparser.catalog.runtime.CatalogObjectKind;
004
005import java.util.ArrayList;
006import java.util.Collections;
007import java.util.EnumSet;
008import java.util.List;
009import java.util.Objects;
010import java.util.Set;
011
012/**
013 * Routine entry (function, procedure, or package) inside a {@link SchemaModel}.
014 *
015 * <p>Plan ยง6. {@link #kind()} is restricted to one of
016 * {@link CatalogObjectKind#FUNCTION FUNCTION},
017 * {@link CatalogObjectKind#PROCEDURE PROCEDURE},
018 * {@link CatalogObjectKind#PACKAGE PACKAGE}, or
019 * {@link CatalogObjectKind#ROUTINE ROUTINE}; other kinds belong on different
020 * model types.</p>
021 */
022public final class RoutineModel {
023
024    private static final Set<CatalogObjectKind> ALLOWED_KINDS = EnumSet.of(
025        CatalogObjectKind.FUNCTION,
026        CatalogObjectKind.PROCEDURE,
027        CatalogObjectKind.PACKAGE,
028        CatalogObjectKind.ROUTINE);
029
030    private final String name;
031    private final CatalogObjectKind kind;
032    private final String returns;
033    private final List<ColumnModel> parameters;
034
035    private RoutineModel(Builder b) {
036        if (b.name == null || b.name.isEmpty()) {
037            throw new IllegalArgumentException("RoutineModel.name is required");
038        }
039        if (b.kind == null) {
040            throw new IllegalArgumentException(
041                "RoutineModel.kind is required (routine '" + b.name + "')");
042        }
043        if (!ALLOWED_KINDS.contains(b.kind)) {
044            throw new IllegalArgumentException(
045                "RoutineModel.kind must be one of FUNCTION/PROCEDURE/PACKAGE/ROUTINE; got " + b.kind);
046        }
047        this.name = b.name;
048        this.kind = b.kind;
049        this.returns = b.returns;
050        this.parameters = Collections.unmodifiableList(new ArrayList<ColumnModel>(b.parameters));
051    }
052
053    public static Builder builder() {
054        return new Builder();
055    }
056
057    public String name() {
058        return name;
059    }
060
061    public CatalogObjectKind kind() {
062        return kind;
063    }
064
065    /** Return-type string for FUNCTION routines; {@code null} for PROCEDURE / PACKAGE. */
066    public String returns() {
067        return returns;
068    }
069
070    public List<ColumnModel> parameters() {
071        return parameters;
072    }
073
074    @Override
075    public boolean equals(Object o) {
076        if (this == o) return true;
077        if (!(o instanceof RoutineModel)) return false;
078        RoutineModel that = (RoutineModel) o;
079        return name.equals(that.name)
080            && kind == that.kind
081            && Objects.equals(returns, that.returns)
082            && parameters.equals(that.parameters);
083    }
084
085    @Override
086    public int hashCode() {
087        return Objects.hash(name, kind, returns, parameters);
088    }
089
090    @Override
091    public String toString() {
092        return "RoutineModel{name=" + name
093            + ", kind=" + kind
094            + ", returns=" + returns
095            + ", params=" + parameters.size() + '}';
096    }
097
098    public static final class Builder {
099
100        private String name;
101        private CatalogObjectKind kind;
102        private String returns;
103        private final List<ColumnModel> parameters = new ArrayList<ColumnModel>();
104
105        private Builder() {
106        }
107
108        public Builder name(String v) {
109            this.name = v;
110            return this;
111        }
112
113        public Builder kind(CatalogObjectKind v) {
114            this.kind = v;
115            return this;
116        }
117
118        public Builder returns(String v) {
119            this.returns = v;
120            return this;
121        }
122
123        public Builder addParameter(ColumnModel v) {
124            if (v == null) {
125                throw new IllegalArgumentException("RoutineModel parameter may not be null");
126            }
127            this.parameters.add(v);
128            return this;
129        }
130
131        public RoutineModel build() {
132            return new RoutineModel(this);
133        }
134    }
135}