1use plsql_core::{SchemaName, Span, SymbolId};
15use serde::{Deserialize, Serialize};
16use tracing::instrument;
17
18use crate::DeclId;
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
22pub struct DeclCommon {
23 pub name: SymbolId,
26 pub span: Span,
28 pub schema: Option<SchemaName>,
32 pub parent: Option<DeclId>,
36}
37
38impl DeclCommon {
39 #[must_use]
40 #[instrument(level = "trace")]
41 pub fn new(name: SymbolId, span: Span) -> Self {
42 Self {
43 name,
44 span,
45 schema: None,
46 parent: None,
47 }
48 }
49
50 #[must_use]
51 #[instrument(level = "trace", skip(self))]
52 pub fn with_schema(mut self, schema: SchemaName) -> Self {
53 self.schema = Some(schema);
54 self
55 }
56
57 #[must_use]
58 #[instrument(level = "trace", skip(self))]
59 pub fn with_parent(mut self, parent: DeclId) -> Self {
60 self.parent = Some(parent);
61 self
62 }
63}
64
65#[derive(
67 Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
68)]
69pub enum ParamMode {
70 #[default]
71 In,
72 Out,
73 InOut,
74}
75
76#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
84pub enum TypeRef {
85 Unresolved(String),
87 Anchored(AnchoredType),
90}
91
92#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93pub struct AnchoredType {
94 pub raw: String,
95}
96
97#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
100pub enum DeclKind {
101 Variable,
102 Param,
103 Cursor,
104 Procedure,
105 Function,
106 Package,
107 Type,
108 Table,
109 View,
110 Column,
111 Sequence,
112 Synonym,
113 Index,
114 Trigger,
115}
116
117#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
118pub struct VariableDecl {
119 pub common: DeclCommon,
120 pub ty: Option<TypeRef>,
121 pub default_text: Option<String>,
122 pub constant: bool,
123 pub not_null: bool,
124}
125
126#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
127pub struct ParamDecl {
128 pub common: DeclCommon,
129 pub mode: ParamMode,
130 pub ty: Option<TypeRef>,
131 pub default_text: Option<String>,
132}
133
134#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
135pub struct CursorDecl {
136 pub common: DeclCommon,
137}
138
139#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
140pub struct ProcedureDecl {
141 pub common: DeclCommon,
142 pub params: Vec<DeclId>,
143}
144
145#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
146pub struct FunctionDecl {
147 pub common: DeclCommon,
148 pub params: Vec<DeclId>,
149 pub return_type: Option<TypeRef>,
150}
151
152#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
153pub struct PackageDecl {
154 pub common: DeclCommon,
155 pub members: Vec<DeclId>,
156 pub body: Option<DeclId>,
157}
158
159#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
160pub struct TypeDecl {
161 pub common: DeclCommon,
162}
163
164#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
165pub struct TableDecl {
166 pub common: DeclCommon,
167 pub columns: Vec<DeclId>,
168}
169
170#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
171pub struct ViewDecl {
172 pub common: DeclCommon,
173 pub columns: Vec<DeclId>,
174}
175
176#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
177pub struct ColumnDecl {
178 pub common: DeclCommon,
179 pub ty: Option<TypeRef>,
180 pub not_null: bool,
181}
182
183#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
184pub struct SequenceDecl {
185 pub common: DeclCommon,
186}
187
188#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
189pub struct SynonymDecl {
190 pub common: DeclCommon,
191 pub target: Option<DeclId>,
193 pub public_synonym: bool,
194}
195
196#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
197pub struct IndexDecl {
198 pub common: DeclCommon,
199}
200
201#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
202pub struct TriggerDecl {
203 pub common: DeclCommon,
204}
205
206#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
211pub enum Declaration {
212 Variable(VariableDecl),
213 Param(ParamDecl),
214 Cursor(CursorDecl),
215 Procedure(ProcedureDecl),
216 Function(FunctionDecl),
217 Package(PackageDecl),
218 Type(TypeDecl),
219 Table(TableDecl),
220 View(ViewDecl),
221 Column(ColumnDecl),
222 Sequence(SequenceDecl),
223 Synonym(SynonymDecl),
224 Index(IndexDecl),
225 Trigger(TriggerDecl),
226}
227
228impl Declaration {
229 #[must_use]
230 #[instrument(level = "trace", skip(self))]
231 pub fn common(&self) -> &DeclCommon {
232 match self {
233 Self::Variable(d) => &d.common,
234 Self::Param(d) => &d.common,
235 Self::Cursor(d) => &d.common,
236 Self::Procedure(d) => &d.common,
237 Self::Function(d) => &d.common,
238 Self::Package(d) => &d.common,
239 Self::Type(d) => &d.common,
240 Self::Table(d) => &d.common,
241 Self::View(d) => &d.common,
242 Self::Column(d) => &d.common,
243 Self::Sequence(d) => &d.common,
244 Self::Synonym(d) => &d.common,
245 Self::Index(d) => &d.common,
246 Self::Trigger(d) => &d.common,
247 }
248 }
249
250 #[must_use]
251 #[instrument(level = "trace", skip(self))]
252 pub fn kind(&self) -> DeclKind {
253 match self {
254 Self::Variable(_) => DeclKind::Variable,
255 Self::Param(_) => DeclKind::Param,
256 Self::Cursor(_) => DeclKind::Cursor,
257 Self::Procedure(_) => DeclKind::Procedure,
258 Self::Function(_) => DeclKind::Function,
259 Self::Package(_) => DeclKind::Package,
260 Self::Type(_) => DeclKind::Type,
261 Self::Table(_) => DeclKind::Table,
262 Self::View(_) => DeclKind::View,
263 Self::Column(_) => DeclKind::Column,
264 Self::Sequence(_) => DeclKind::Sequence,
265 Self::Synonym(_) => DeclKind::Synonym,
266 Self::Index(_) => DeclKind::Index,
267 Self::Trigger(_) => DeclKind::Trigger,
268 }
269 }
270
271 #[must_use]
272 #[instrument(level = "trace", skip(self))]
273 pub fn name(&self) -> SymbolId {
274 self.common().name
275 }
276
277 #[must_use]
278 #[instrument(level = "trace", skip(self))]
279 pub fn span(&self) -> Span {
280 self.common().span
281 }
282
283 #[must_use]
284 #[instrument(level = "trace", skip(self))]
285 pub fn is_callable(&self) -> bool {
286 matches!(self, Self::Procedure(_) | Self::Function(_))
287 }
288
289 #[must_use]
290 #[instrument(level = "trace", skip(self))]
291 pub fn is_schema_object(&self) -> bool {
292 matches!(
293 self,
294 Self::Package(_)
295 | Self::Type(_)
296 | Self::Table(_)
297 | Self::View(_)
298 | Self::Sequence(_)
299 | Self::Synonym(_)
300 | Self::Index(_)
301 | Self::Trigger(_)
302 )
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309 use plsql_core::{FileId, Position};
310
311 fn dummy_span() -> Span {
312 Span::new(
313 FileId::new(1),
314 Position::new(1, 1, 0),
315 Position::new(1, 5, 4),
316 )
317 }
318
319 fn common_with_name(raw: u64) -> DeclCommon {
320 DeclCommon::new(SymbolId::new(raw), dummy_span())
321 }
322
323 #[test]
324 fn decl_common_builders_set_optional_fields() {
325 let schema = SchemaName::from(SymbolId::new(10));
326 let common = common_with_name(1)
327 .with_schema(schema)
328 .with_parent(DeclId::new(99));
329 assert_eq!(common.schema, Some(schema));
330 assert_eq!(common.parent, Some(DeclId::new(99)));
331 }
332
333 #[test]
334 fn declaration_kind_matches_variant() {
335 let cases: Vec<(Declaration, DeclKind)> = vec![
336 (
337 Declaration::Variable(VariableDecl {
338 common: common_with_name(1),
339 ty: Some(TypeRef::Unresolved("NUMBER".into())),
340 default_text: None,
341 constant: false,
342 not_null: false,
343 }),
344 DeclKind::Variable,
345 ),
346 (
347 Declaration::Param(ParamDecl {
348 common: common_with_name(2),
349 mode: ParamMode::Out,
350 ty: None,
351 default_text: None,
352 }),
353 DeclKind::Param,
354 ),
355 (
356 Declaration::Cursor(CursorDecl {
357 common: common_with_name(3),
358 }),
359 DeclKind::Cursor,
360 ),
361 (
362 Declaration::Procedure(ProcedureDecl {
363 common: common_with_name(4),
364 params: vec![DeclId::new(2)],
365 }),
366 DeclKind::Procedure,
367 ),
368 (
369 Declaration::Function(FunctionDecl {
370 common: common_with_name(5),
371 params: vec![],
372 return_type: Some(TypeRef::Unresolved("VARCHAR2".into())),
373 }),
374 DeclKind::Function,
375 ),
376 (
377 Declaration::Package(PackageDecl {
378 common: common_with_name(6),
379 members: vec![],
380 body: None,
381 }),
382 DeclKind::Package,
383 ),
384 (
385 Declaration::Type(TypeDecl {
386 common: common_with_name(7),
387 }),
388 DeclKind::Type,
389 ),
390 (
391 Declaration::Table(TableDecl {
392 common: common_with_name(8),
393 columns: vec![],
394 }),
395 DeclKind::Table,
396 ),
397 (
398 Declaration::View(ViewDecl {
399 common: common_with_name(9),
400 columns: vec![],
401 }),
402 DeclKind::View,
403 ),
404 (
405 Declaration::Column(ColumnDecl {
406 common: common_with_name(10),
407 ty: None,
408 not_null: true,
409 }),
410 DeclKind::Column,
411 ),
412 (
413 Declaration::Sequence(SequenceDecl {
414 common: common_with_name(11),
415 }),
416 DeclKind::Sequence,
417 ),
418 (
419 Declaration::Synonym(SynonymDecl {
420 common: common_with_name(12),
421 target: None,
422 public_synonym: true,
423 }),
424 DeclKind::Synonym,
425 ),
426 (
427 Declaration::Index(IndexDecl {
428 common: common_with_name(13),
429 }),
430 DeclKind::Index,
431 ),
432 (
433 Declaration::Trigger(TriggerDecl {
434 common: common_with_name(14),
435 }),
436 DeclKind::Trigger,
437 ),
438 ];
439
440 for (decl, expected_kind) in cases {
441 assert_eq!(decl.kind(), expected_kind);
442 assert_eq!(decl.name(), decl.common().name);
443 assert_eq!(decl.span(), decl.common().span);
444 }
445 }
446
447 #[test]
448 fn is_callable_and_schema_object_partitions_match_intent() {
449 let proc = Declaration::Procedure(ProcedureDecl {
450 common: common_with_name(1),
451 params: vec![],
452 });
453 let func = Declaration::Function(FunctionDecl {
454 common: common_with_name(2),
455 params: vec![],
456 return_type: None,
457 });
458 let var = Declaration::Variable(VariableDecl {
459 common: common_with_name(3),
460 ty: None,
461 default_text: None,
462 constant: false,
463 not_null: false,
464 });
465 let pkg = Declaration::Package(PackageDecl {
466 common: common_with_name(4),
467 members: vec![],
468 body: None,
469 });
470
471 assert!(proc.is_callable());
472 assert!(func.is_callable());
473 assert!(!var.is_callable());
474 assert!(!pkg.is_callable());
475
476 assert!(pkg.is_schema_object());
477 assert!(!proc.is_schema_object());
478 assert!(!var.is_schema_object());
479 }
480
481 #[test]
482 fn synonym_resolution_target_is_optional() {
483 let mut syn = SynonymDecl {
484 common: common_with_name(1),
485 target: None,
486 public_synonym: false,
487 };
488 assert!(syn.target.is_none());
489 syn.target = Some(DeclId::new(42));
490 assert_eq!(syn.target, Some(DeclId::new(42)));
491 }
492}