Skip to content

Commit e75ff26

Browse files
committed
feat(diagnostics): database object location
1 parent 9952744 commit e75ff26

File tree

5 files changed

+52
-0
lines changed

5 files changed

+52
-0
lines changed

crates/pgls_diagnostics/src/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ mod internal {
458458
resource: match loc.resource {
459459
Some(Resource::Argv) => Some(Resource::Argv),
460460
Some(Resource::Memory) => Some(Resource::Memory),
461+
Some(Resource::Database) => Some(Resource::Database),
461462
Some(Resource::File(file)) => {
462463
if let Some(Resource::File(path)) = &self.path {
463464
Some(Resource::File(path.as_ref()))
@@ -468,6 +469,7 @@ mod internal {
468469
None => self.path.as_ref().map(Resource::as_deref),
469470
},
470471
span: loc.span,
472+
database_object: loc.database_object,
471473
source_code: loc.source_code,
472474
}
473475
}
@@ -523,6 +525,7 @@ mod internal {
523525
Location {
524526
resource: loc.resource,
525527
span: self.span.or(loc.span),
528+
database_object: loc.database_object,
526529
source_code: loc.source_code,
527530
}
528531
}

crates/pgls_diagnostics/src/display.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ mod tests {
790790
visitor.record_frame(Location {
791791
resource: Some(Resource::File("other_path")),
792792
span: Some(TextRange::new(TextSize::from(8), TextSize::from(16))),
793+
database_object: None,
793794
source_code: Some(SourceCode {
794795
text: "context location context",
795796
line_starts: None,

crates/pgls_diagnostics/src/location.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub struct Location<'a> {
1212
/// An optional range of text within the resource associated with the
1313
/// diagnostic.
1414
pub span: Option<TextRange>,
15+
/// An optional tuple identifying a database object
16+
pub database_object: Option<(Option<&'a str>, &'a str)>,
1517
/// The optional source code of the resource.
1618
pub source_code: Option<BorrowedSourceCode<'a>>,
1719
}
@@ -23,6 +25,7 @@ impl<'a> Location<'a> {
2325
resource: None,
2426
span: None,
2527
source_code: None,
28+
database_object: None,
2629
}
2730
}
2831
}
@@ -42,6 +45,8 @@ impl Eq for Location<'_> {}
4245
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
4346
#[serde(rename_all = "camelCase")]
4447
pub enum Resource<Path> {
48+
/// The diagnostic is related to the database and its schema.
49+
Database,
4550
/// The diagnostic is related to the content of the command line arguments.
4651
Argv,
4752
/// The diagnostic is related to the content of a memory buffer.
@@ -70,6 +75,7 @@ impl<P> Resource<P> {
7075
P: Deref,
7176
{
7277
match self {
78+
Resource::Database => Resource::Database,
7379
Resource::Argv => Resource::Argv,
7480
Resource::Memory => Resource::Memory,
7581
Resource::File(file) => Resource::File(file),
@@ -81,6 +87,7 @@ impl Resource<&'_ str> {
8187
/// Converts a `Path<&str>` to `Path<String>`.
8288
pub fn to_owned(self) -> Resource<String> {
8389
match self {
90+
Resource::Database => Resource::Database,
8491
Resource::Argv => Resource::Argv,
8592
Resource::Memory => Resource::Memory,
8693
Resource::File(file) => Resource::File(file.to_owned()),
@@ -194,6 +201,7 @@ pub struct LocationBuilder<'a> {
194201
resource: Option<Resource<&'a str>>,
195202
span: Option<TextRange>,
196203
source_code: Option<BorrowedSourceCode<'a>>,
204+
database_object: Option<(Option<&'a str>, &'a str)>,
197205
}
198206

199207
impl<'a> LocationBuilder<'a> {
@@ -212,11 +220,17 @@ impl<'a> LocationBuilder<'a> {
212220
self
213221
}
214222

223+
pub fn database_object<D: AsDatabaseObject>(mut self, database_object: &'a D) -> Self {
224+
self.database_object = database_object.as_database_object();
225+
self
226+
}
227+
215228
pub fn build(self) -> Location<'a> {
216229
Location {
217230
resource: self.resource,
218231
span: self.span,
219232
source_code: self.source_code,
233+
database_object: self.database_object,
220234
}
221235
}
222236
}
@@ -342,6 +356,35 @@ impl AsSourceCode for String {
342356
}
343357
}
344358

359+
/// Utility trait for types that can be converted into a database object reference
360+
pub trait AsDatabaseObject {
361+
fn as_database_object(&self) -> Option<(Option<&'_ str>, &'_ str)>;
362+
}
363+
364+
impl<T: AsDatabaseObject> AsDatabaseObject for Option<T> {
365+
fn as_database_object(&self) -> Option<(Option<&'_ str>, &'_ str)> {
366+
self.as_ref().and_then(T::as_database_object)
367+
}
368+
}
369+
370+
impl<T: AsDatabaseObject + ?Sized> AsDatabaseObject for &'_ T {
371+
fn as_database_object(&self) -> Option<(Option<&'_ str>, &'_ str)> {
372+
T::as_database_object(*self)
373+
}
374+
}
375+
376+
impl AsDatabaseObject for (Option<&str>, &str) {
377+
fn as_database_object(&self) -> Option<(Option<&'_ str>, &'_ str)> {
378+
Some((self.0, self.1))
379+
}
380+
}
381+
382+
impl AsDatabaseObject for (Option<String>, String) {
383+
fn as_database_object(&self) -> Option<(Option<&'_ str>, &'_ str)> {
384+
Some((self.0.as_deref(), self.1.as_str()))
385+
}
386+
}
387+
345388
#[cfg(test)]
346389
mod tests {
347390
use pgls_text_size::TextSize;

crates/pgls_diagnostics/src/serde.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ impl super::Advices for Advice {
274274
Advice::Frame(location) => visitor.record_frame(super::Location {
275275
resource: location.path.as_ref().map(super::Resource::as_deref),
276276
span: location.span,
277+
database_object: None,
277278
source_code: location.source_code.as_deref().map(|text| SourceCode {
278279
text,
279280
line_starts: None,

crates/pgls_diagnostics_macros/src/parse.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ pub(crate) enum LocationField {
436436
Resource(Ident),
437437
Span(Ident),
438438
SourceCode(Ident),
439+
DatabaseObject(Ident),
439440
}
440441

441442
impl Parse for LocationAttr {
@@ -450,6 +451,8 @@ impl Parse for LocationAttr {
450451
LocationField::Span(ident)
451452
} else if ident == "source_code" {
452453
LocationField::SourceCode(ident)
454+
} else if ident == "database_object" {
455+
LocationField::DatabaseObject(ident)
453456
} else {
454457
return Err(Error::new_spanned(ident, "unknown location field"));
455458
};
@@ -467,6 +470,7 @@ impl ToTokens for LocationField {
467470
LocationField::Resource(ident) => ident.to_tokens(tokens),
468471
LocationField::Span(ident) => ident.to_tokens(tokens),
469472
LocationField::SourceCode(ident) => ident.to_tokens(tokens),
473+
LocationField::DatabaseObject(ident) => ident.to_tokens(tokens),
470474
}
471475
}
472476
}

0 commit comments

Comments
 (0)