surql_parser/
schema_lookup.rs1use crate::{collect_surql_files, extract_definitions, read_surql_file};
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct FunctionParam {
6 pub name: String,
7 pub kind: String,
8}
9
10pub fn find_function_params(
32 fn_name: &str,
33 schema_dir: &std::path::Path,
34) -> anyhow::Result<Option<Vec<FunctionParam>>> {
35 let stripped = fn_name
36 .strip_prefix("fn::")
37 .ok_or_else(|| anyhow::anyhow!("function name must start with fn::"))?;
38
39 let mut files = Vec::new();
40 collect_surql_files(schema_dir, &mut files);
41 files.sort();
42
43 for path in &files {
44 let content = match read_surql_file(path) {
45 Ok(c) => c,
46 Err(e) => {
47 tracing::warn!("Skipping {}: {e}", path.display());
48 continue;
49 }
50 };
51 let defs = match extract_definitions(&content) {
52 Ok(d) => d,
53 Err(e) => {
54 tracing::warn!("Skipping {}: {e}", path.display());
55 continue;
56 }
57 };
58 for func in &defs.functions {
59 if func.name == stripped {
60 use surrealdb_types::{SqlFormat, ToSql};
61 let params = func
62 .args
63 .iter()
64 .map(|(name, kind)| {
65 let mut kind_str = String::new();
66 kind.fmt_sql(&mut kind_str, SqlFormat::SingleLine);
67 let clean_name = name.strip_prefix('$').unwrap_or(name).to_string();
68 FunctionParam {
69 name: clean_name,
70 kind: kind_str,
71 }
72 })
73 .collect();
74 return Ok(Some(params));
75 }
76 }
77 }
78
79 Ok(None)
80}
81
82#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct FieldType {
85 pub table: String,
86 pub field: String,
87 pub kind: String,
88}
89
90pub fn find_field_type(
108 table: &str,
109 field: &str,
110 schema_dir: &std::path::Path,
111) -> anyhow::Result<Option<String>> {
112 let mut files = Vec::new();
113 collect_surql_files(schema_dir, &mut files);
114 files.sort();
115
116 for path in &files {
117 let content = match read_surql_file(path) {
118 Ok(c) => c,
119 Err(e) => {
120 tracing::warn!("Skipping {}: {e}", path.display());
121 continue;
122 }
123 };
124 let defs = match extract_definitions(&content) {
125 Ok(d) => d,
126 Err(e) => {
127 tracing::warn!("Skipping {}: {e}", path.display());
128 continue;
129 }
130 };
131 for f in &defs.fields {
132 use surrealdb_types::{SqlFormat, ToSql};
133 let mut tbl_name = String::new();
134 f.what.fmt_sql(&mut tbl_name, SqlFormat::SingleLine);
135 let mut fld_name = String::new();
136 f.name.fmt_sql(&mut fld_name, SqlFormat::SingleLine);
137
138 if tbl_name == table && fld_name == field {
139 if let Some(ref kind) = f.field_kind {
140 let mut kind_str = String::new();
141 kind.fmt_sql(&mut kind_str, SqlFormat::SingleLine);
142 return Ok(Some(kind_str));
143 }
144 return Ok(None);
145 }
146 }
147 }
148
149 Ok(None)
150}
151
152pub fn collect_field_types(schema_dir: &std::path::Path) -> anyhow::Result<Vec<FieldType>> {
157 let mut files = Vec::new();
158 collect_surql_files(schema_dir, &mut files);
159 files.sort();
160
161 let mut result = Vec::new();
162
163 for path in &files {
164 let content = match read_surql_file(path) {
165 Ok(c) => c,
166 Err(e) => {
167 tracing::warn!("Skipping {}: {e}", path.display());
168 continue;
169 }
170 };
171 let defs = match extract_definitions(&content) {
172 Ok(d) => d,
173 Err(e) => {
174 tracing::warn!("Skipping {}: {e}", path.display());
175 continue;
176 }
177 };
178 for f in &defs.fields {
179 use surrealdb_types::{SqlFormat, ToSql};
180 let mut tbl_name = String::new();
181 f.what.fmt_sql(&mut tbl_name, SqlFormat::SingleLine);
182 let mut fld_name = String::new();
183 f.name.fmt_sql(&mut fld_name, SqlFormat::SingleLine);
184
185 if let Some(ref kind) = f.field_kind {
186 let mut kind_str = String::new();
187 kind.fmt_sql(&mut kind_str, SqlFormat::SingleLine);
188 result.push(FieldType {
189 table: tbl_name,
190 field: fld_name,
191 kind: kind_str,
192 });
193 }
194 }
195 }
196
197 Ok(result)
198}