1use crate::HoverKind;
2
3pub const CREATE_PROCEDURE_DOCS: &str =
4 "https://docs.snowflake.com/en/sql-reference/sql/create-procedure";
5pub const CREATE_TASK_DOCS: &str = "https://docs.snowflake.com/en/sql-reference/sql/create-task";
6pub const DATA_TYPES_DOCS: &str = "https://docs.snowflake.com/en/sql-reference/data-types";
7
8pub(crate) const ROUTINE_OPTION_STOPS: &[&str] = &[
9 "AS",
10 "ARTIFACT_REPOSITORY",
11 "CALLED",
12 "COMMENT",
13 "COPY",
14 "EXECUTE",
15 "EXTERNAL_ACCESS_INTEGRATIONS",
16 "HANDLER",
17 "IMMUTABLE",
18 "IMPORTS",
19 "LANGUAGE",
20 "MEMOIZABLE",
21 "NULL",
22 "PACKAGES",
23 "RETURNS",
24 "RUNTIME_VERSION",
25 "SECRETS",
26 "SECURE",
27 "STRICT",
28 "TARGET_PATH",
29 "VOLATILE",
30];
31
32#[derive(Clone, Copy)]
33pub(crate) struct StaticHover {
34 pub(crate) kind: HoverKind,
35 pub(crate) title: &'static str,
36 pub(crate) body: &'static str,
37 pub(crate) docs_url: Option<&'static str>,
38}
39
40pub(crate) fn type_info(text: &str) -> Option<(&'static str, &'static str)> {
41 let item = [
42 (
43 &["NUMBER", "DECIMAL", "NUMERIC", "INT", "INTEGER", "BIGINT"][..],
44 "NUMBER",
45 "Exact fixed-point numeric type. Use precision and scale for stable financial or identifier-like values.",
46 ),
47 (
48 &["FLOAT", "DOUBLE", "REAL"][..],
49 "FLOAT",
50 "Approximate floating-point numeric type. Prefer NUMBER when exact decimal behavior matters.",
51 ),
52 (
53 &["VARCHAR", "STRING", "TEXT", "CHAR"][..],
54 "VARCHAR",
55 "Variable-length character data. STRING and TEXT are Snowflake aliases for VARCHAR.",
56 ),
57 (&["BOOLEAN"][..], "BOOLEAN", "TRUE/FALSE logical value."),
58 (
59 &["VARIANT"][..],
60 "VARIANT",
61 "Semi-structured value that can hold JSON-like OBJECT, ARRAY, scalar, or SQL NULL distinctions.",
62 ),
63 (
64 &["OBJECT"][..],
65 "OBJECT",
66 "Semi-structured key/value object. Common with JSON ingestion and colon path access.",
67 ),
68 (
69 &["ARRAY"][..],
70 "ARRAY",
71 "Semi-structured ordered collection. Use bracket indexing and FLATTEN/TABLE for traversal.",
72 ),
73 (
74 &["MAP"][..],
75 "MAP",
76 "Structured key/value collection type. Useful when key and value types are part of the schema.",
77 ),
78 (
79 &["VECTOR"][..],
80 "VECTOR",
81 "Vector type for embeddings and similarity workloads; keep element type and dimension explicit.",
82 ),
83 (
84 &["DATE"][..],
85 "DATE",
86 "Calendar date without time of day.",
87 ),
88 (
89 &["TIME"][..],
90 "TIME",
91 "Time of day without date.",
92 ),
93 (
94 &["TIMESTAMP", "TIMESTAMP_NTZ", "TIMESTAMP_LTZ", "TIMESTAMP_TZ"][..],
95 "TIMESTAMP",
96 "Timestamp family. NTZ has no time zone, LTZ uses the session time zone, and TZ stores an explicit offset.",
97 ),
98 (&["BINARY"][..], "BINARY", "Variable-length binary data."),
99 (
100 &["GEOGRAPHY", "GEOMETRY"][..],
101 "GEOSPATIAL",
102 "Geospatial data for spherical geography or planar geometry operations.",
103 ),
104 ]
105 .into_iter()
106 .find(|(aliases, _, _)| aliases.iter().any(|alias| text.eq_ignore_ascii_case(alias)))?;
107
108 Some((item.1, item.2))
109}
110
111pub(crate) fn language_template(text: &str) -> Option<StaticHover> {
112 if text.eq_ignore_ascii_case("JAVASCRIPT") {
113 Some(StaticHover {
114 kind: HoverKind::Language,
115 title: "LANGUAGE JAVASCRIPT",
116 body: "JavaScript stored procedure body. The handler is the body itself; SQL argument names can need careful case handling inside JavaScript.",
117 docs_url: Some(CREATE_PROCEDURE_DOCS),
118 })
119 } else if text.eq_ignore_ascii_case("PYTHON") {
120 Some(StaticHover {
121 kind: HoverKind::Language,
122 title: "LANGUAGE PYTHON",
123 body: "Snowpark Python stored procedure. HANDLER names the Python function; RUNTIME_VERSION pins Python; PACKAGES, IMPORTS, EXTERNAL_ACCESS_INTEGRATIONS, and SECRETS describe the runtime environment.",
124 docs_url: Some(CREATE_PROCEDURE_DOCS),
125 })
126 } else if text.eq_ignore_ascii_case("JAVA") {
127 Some(StaticHover {
128 kind: HoverKind::Language,
129 title: "LANGUAGE JAVA",
130 body: "Java stored procedure. HANDLER names a class and method; RUNTIME_VERSION, PACKAGES, IMPORTS, and TARGET_PATH describe the JVM runtime and staged artifact.",
131 docs_url: Some(CREATE_PROCEDURE_DOCS),
132 })
133 } else if text.eq_ignore_ascii_case("SCALA") {
134 Some(StaticHover {
135 kind: HoverKind::Language,
136 title: "LANGUAGE SCALA",
137 body: "Snowpark Scala stored procedure. HANDLER names the Scala entry point; RUNTIME_VERSION, PACKAGES, IMPORTS, and TARGET_PATH describe the JVM runtime and staged artifact.",
138 docs_url: Some(CREATE_PROCEDURE_DOCS),
139 })
140 } else if text.eq_ignore_ascii_case("SQL") {
141 Some(StaticHover {
142 kind: HoverKind::Language,
143 title: "LANGUAGE SQL",
144 body: "Snowflake Scripting stored procedure body. Use SQL procedural constructs such as DECLARE, BEGIN, RETURN, loops, and EXCEPTION handlers.",
145 docs_url: Some(CREATE_PROCEDURE_DOCS),
146 })
147 } else {
148 None
149 }
150}
151
152pub(crate) fn property_template(text: &str) -> Option<StaticHover> {
153 PROPERTIES
154 .iter()
155 .copied()
156 .find(|property| text.eq_ignore_ascii_case(property.title))
157}
158
159pub(crate) fn keyword_template(text: &str) -> Option<StaticHover> {
160 if text.eq_ignore_ascii_case("PROCEDURE") {
161 Some(StaticHover {
162 kind: HoverKind::Procedure,
163 title: "Stored procedure",
164 body: "Schema object that can be called with CALL. Procedures support SQL, JavaScript, Python, Java, and Scala handlers.",
165 docs_url: Some(CREATE_PROCEDURE_DOCS),
166 })
167 } else if text.eq_ignore_ascii_case("TASK") {
168 Some(StaticHover {
169 kind: HoverKind::Task,
170 title: "Task",
171 body: "Schema object that executes SQL on a schedule or as part of a task graph. Newly created tasks start suspended.",
172 docs_url: Some(CREATE_TASK_DOCS),
173 })
174 } else {
175 None
176 }
177}
178
179const PROPERTIES: &[StaticHover] = &[
180 StaticHover {
181 kind: HoverKind::Property,
182 title: "RETURNS",
183 body: "Declares a procedure result type. It can be a scalar type or RETURNS TABLE(...), depending on the procedure language and support level.",
184 docs_url: Some(CREATE_PROCEDURE_DOCS),
185 },
186 StaticHover {
187 kind: HoverKind::Property,
188 title: "LANGUAGE",
189 body: "Selects the stored procedure handler language: SQL, JAVASCRIPT, PYTHON, JAVA, or SCALA.",
190 docs_url: Some(CREATE_PROCEDURE_DOCS),
191 },
192 StaticHover {
193 kind: HoverKind::Property,
194 title: "HANDLER",
195 body: "Names the external-language entry point, such as a Python function or JVM method.",
196 docs_url: Some(CREATE_PROCEDURE_DOCS),
197 },
198 StaticHover {
199 kind: HoverKind::Property,
200 title: "PACKAGES",
201 body: "Declares runtime packages available to Snowpark Java, Scala, or Python procedure handlers.",
202 docs_url: Some(CREATE_PROCEDURE_DOCS),
203 },
204 StaticHover {
205 kind: HoverKind::Property,
206 title: "IMPORTS",
207 body: "Adds staged files that the stored procedure handler can read at runtime.",
208 docs_url: Some(CREATE_PROCEDURE_DOCS),
209 },
210 StaticHover {
211 kind: HoverKind::Property,
212 title: "RUNTIME_VERSION",
213 body: "Pins the language runtime version for Java, Python, or Scala procedure handlers.",
214 docs_url: Some(CREATE_PROCEDURE_DOCS),
215 },
216 StaticHover {
217 kind: HoverKind::Property,
218 title: "TARGET_PATH",
219 body: "Stage path for the compiled Java or Scala procedure artifact. Use it when Snowflake should write the generated handler artifact to a stage.",
220 docs_url: Some(CREATE_PROCEDURE_DOCS),
221 },
222 StaticHover {
223 kind: HoverKind::Property,
224 title: "ARTIFACT_REPOSITORY",
225 body: "Selects an artifact repository for resolving supported external-language dependencies.",
226 docs_url: Some(CREATE_PROCEDURE_DOCS),
227 },
228 StaticHover {
229 kind: HoverKind::Property,
230 title: "EXTERNAL_ACCESS_INTEGRATIONS",
231 body: "Allows an external-language procedure to use one or more external access integrations for outbound network access.",
232 docs_url: Some(CREATE_PROCEDURE_DOCS),
233 },
234 StaticHover {
235 kind: HoverKind::Property,
236 title: "SECRETS",
237 body: "Maps Snowflake secrets to names the external-language handler can use at runtime.",
238 docs_url: Some(CREATE_PROCEDURE_DOCS),
239 },
240 StaticHover {
241 kind: HoverKind::Property,
242 title: "STRICT",
243 body: "Alias for RETURNS NULL ON NULL INPUT: Snowflake does not call the handler when any input argument is NULL.",
244 docs_url: Some(CREATE_PROCEDURE_DOCS),
245 },
246 StaticHover {
247 kind: HoverKind::Property,
248 title: "CALLED",
249 body: "Part of CALLED ON NULL INPUT: Snowflake calls the procedure even when an input argument is NULL.",
250 docs_url: Some(CREATE_PROCEDURE_DOCS),
251 },
252 StaticHover {
253 kind: HoverKind::Property,
254 title: "IMMUTABLE",
255 body: "Declares that the result depends only on inputs and not on database state or side effects.",
256 docs_url: Some(CREATE_PROCEDURE_DOCS),
257 },
258 StaticHover {
259 kind: HoverKind::Property,
260 title: "VOLATILE",
261 body: "Declares that the procedure can depend on state or side effects; this is the conservative behavior for procedural code.",
262 docs_url: Some(CREATE_PROCEDURE_DOCS),
263 },
264 StaticHover {
265 kind: HoverKind::Property,
266 title: "EXECUTE",
267 body: "Controls whether a procedure or task runs with owner, caller, restricted caller, or user execution context.",
268 docs_url: Some(CREATE_PROCEDURE_DOCS),
269 },
270 StaticHover {
271 kind: HoverKind::Property,
272 title: "WAREHOUSE",
273 body: "Virtual warehouse that supplies compute for a task run. Omit it only when using serverless task sizing.",
274 docs_url: Some(CREATE_TASK_DOCS),
275 },
276 StaticHover {
277 kind: HoverKind::Property,
278 title: "USER_TASK_MANAGED_INITIAL_WAREHOUSE_SIZE",
279 body: "Initial serverless task size. Snowflake can manage task compute after enough run history exists.",
280 docs_url: Some(CREATE_TASK_DOCS),
281 },
282 StaticHover {
283 kind: HoverKind::Property,
284 title: "SCHEDULE",
285 body: "Task schedule. Snowflake accepts interval strings or USING CRON expressions with a time zone.",
286 docs_url: Some(CREATE_TASK_DOCS),
287 },
288 StaticHover {
289 kind: HoverKind::Property,
290 title: "AFTER",
291 body: "Creates a task graph dependency; this task runs after one or more predecessor tasks.",
292 docs_url: Some(CREATE_TASK_DOCS),
293 },
294 StaticHover {
295 kind: HoverKind::Property,
296 title: "WHEN",
297 body: "Boolean task condition evaluated before the task body runs. Common with stream checks such as SYSTEM$STREAM_HAS_DATA.",
298 docs_url: Some(CREATE_TASK_DOCS),
299 },
300 StaticHover {
301 kind: HoverKind::Property,
302 title: "FINALIZE",
303 body: "Marks a task as a finalizer for a task graph root.",
304 docs_url: Some(CREATE_TASK_DOCS),
305 },
306 StaticHover {
307 kind: HoverKind::Property,
308 title: "TASK_AUTO_RETRY_ATTEMPTS",
309 body: "Configures automatic retries for failed task graph runs.",
310 docs_url: Some(CREATE_TASK_DOCS),
311 },
312];