Fire node hooks for Ident and document their order around typed hooks
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index de925be..a58c9d6 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -402,8 +402,11 @@
 #[cfg(feature = "visitor")]
 impl Visit for Ident {
     fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
+        let node = NodeRef::__new(self, core::any::type_name::<Self>(), None, None, Some(self));
+        visitor.pre_visit_node(node)?;
         visitor.pre_visit_ident(self)?;
-        visitor.post_visit_ident(self)
+        visitor.post_visit_ident(self)?;
+        visitor.post_visit_node(node)
     }
 }
 
diff --git a/src/ast/visitor.rs b/src/ast/visitor.rs
index 55bf5ba..e47d880 100644
--- a/src/ast/visitor.rs
+++ b/src/ast/visitor.rs
@@ -426,8 +426,10 @@
         ControlFlow::Continue(())
     }
 
-    /// Invoked for every AST node before visiting its children, and before
-    /// the node's typed hook such as [`Visitor::pre_visit_expr`].
+    /// Invoked for every AST node before visiting its children. It runs before
+    /// hooks declared on the node's type, such as [`Visitor::pre_visit_expr`],
+    /// and after hooks declared on the field holding it, such as
+    /// [`Visitor::pre_visit_relation`].
     ///
     /// # Example
     /// ```
@@ -458,8 +460,10 @@
         ControlFlow::Continue(())
     }
 
-    /// Invoked for every AST node after visiting its children, and after the
-    /// node's typed hook such as [`Visitor::post_visit_expr`].
+    /// Invoked for every AST node after visiting its children. It runs after
+    /// hooks declared on the node's type, such as [`Visitor::post_visit_expr`],
+    /// and before hooks declared on the field holding it, such as
+    /// [`Visitor::post_visit_relation`].
     fn post_visit_node(&mut self, _node: NodeRef<'_>) -> ControlFlow<Self::Break> {
         ControlFlow::Continue(())
     }
@@ -1435,6 +1439,66 @@
         assert_eq!(visitor.relations, vec!["db1.v", "t"]);
     }
 
+    #[derive(Default)]
+    struct HookOrderVisitor(Vec<String>);
+
+    impl HookOrderVisitor {
+        fn node(&mut self, event: &str, node: NodeRef<'_>) -> ControlFlow<()> {
+            let name = node.type_name().rsplit("::").next().unwrap();
+            if matches!(name, "Expr" | "ObjectName") {
+                self.0.push(format!("{event} node {name}"));
+            }
+            ControlFlow::Continue(())
+        }
+
+        fn typed(&mut self, event: &str) -> ControlFlow<()> {
+            self.0.push(event.to_string());
+            ControlFlow::Continue(())
+        }
+    }
+
+    impl Visitor for HookOrderVisitor {
+        type Break = ();
+
+        fn pre_visit_node(&mut self, node: NodeRef<'_>) -> ControlFlow<()> {
+            self.node("pre", node)
+        }
+        fn post_visit_node(&mut self, node: NodeRef<'_>) -> ControlFlow<()> {
+            self.node("post", node)
+        }
+        fn pre_visit_expr(&mut self, _: &Expr) -> ControlFlow<()> {
+            self.typed("pre expr")
+        }
+        fn post_visit_expr(&mut self, _: &Expr) -> ControlFlow<()> {
+            self.typed("post expr")
+        }
+        fn pre_visit_relation(&mut self, _: &ObjectName) -> ControlFlow<()> {
+            self.typed("pre relation")
+        }
+        fn post_visit_relation(&mut self, _: &ObjectName) -> ControlFlow<()> {
+            self.typed("post relation")
+        }
+    }
+
+    #[test]
+    fn test_visit_node_order_around_typed_hooks() {
+        let mut visitor = HookOrderVisitor::default();
+        do_visit("SELECT a FROM t", &mut visitor);
+        assert_eq!(
+            visitor.0,
+            [
+                "pre node Expr",
+                "pre expr",
+                "post expr",
+                "post node Expr",
+                "pre relation",
+                "pre node ObjectName",
+                "post node ObjectName",
+                "post relation",
+            ]
+        );
+    }
+
     #[derive(Debug, PartialEq)]
     struct Node {
         depth: usize,
@@ -1472,7 +1536,7 @@
     }
 
     #[test]
-    fn test_visit_node_reaches_every_derived_node() {
+    fn test_visit_node_reaches_every_node() {
         let mut visitor = NodeVisitor::default();
         do_visit(
             "SELECT CAST(a AS INT) AS x FROM t JOIN u ON t.id = u.id",
@@ -1492,6 +1556,9 @@
         assert!(item.spanned);
         assert_eq!(item.variant, Some("ExprWithAlias"));
 
+        let alias = &visitor.nodes[find("Ident", "x")];
+        assert_eq!(alias.variant, None);
+
         let data_type = &visitor.nodes[find("DataType", "INT")];
         assert!(!data_type.spanned);
         assert_eq!(data_type.variant, Some("Int"));