Repository: typedb/typeql (language: python)

Issue:
Simplify rule pretty printing
## What is the goal of this PR?

We update and simplify the way rules are pretty-printed. Rules now print the `when` inline and produce a more compact output:

```
define
rule a-rule: when {
    $x isa person;
    not {
        $x has name "Alice";
        $x has name "Bob";
    };
    {
        ($x) isa friendship;
    } or {
        ($x) isa employment;
    };
} then {
    $x has is_interesting true;
};
```

## What are the changes implemented in this PR?




Discussion / hints:
### PR Review Checklist

Do not edit the content of this comment. The PR reviewer should simply update this comment by ticking each review item below, as they get completed.

----
[condition]: <> (sufficient)
**Trivial Change**
- [x] This change is trivial and does not require a code or architecture review.

[condition]: <> (necessary)
**Code**
- [ ] Packages, classes, and methods have a single domain of responsibility.
- [ ] Packages, classes, and methods are grouped into cohesive and consistent domain model.
- [ ] The code is canonical and the minimum required to achieve the goal.
- [ ] Modules, libraries, and APIs are easy to use, robust (foolproof and not errorprone), and tested.
- [ ] Logic and naming has clear narrative that communicates the accurate intent and responsibility of each module (e.g. method, class, etc.).
- [ ] The code is algorithmically efficient and scalable for the whole application.

[condition]: <> (necessary)
**Architecture**
- [ ] Any required refactoring is completed, and the architecture does not introduce technical debt incidentally.
- [ ] Any required build and release automations are updated and/or implemented.
- [ ] Any new components follows a consistent style with respect to the pre-existing codebase.
- [ ] The architecture intuitively reflects the application domain, and is easy to understand.
- [ ] The architecture has a well-defined hierarchy of encapsulated components.
- [ ] The architecture is extensible and scalable.



Fix patch:
diff --git a/dependencies/ide/rust/sync.sh b/dependencies/ide/rust/sync.sh
index 946b36fa7..d6849f565 100755
--- a/dependencies/ide/rust/sync.sh
+++ b/dependencies/ide/rust/sync.sh
@@ -16,4 +16,4 @@
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #
 
-bazel run @vaticle_dependencies//ide/rust:sync
+bazel run @vaticle_dependencies//tool/cargo:sync
diff --git a/rust/pattern/negation.rs b/rust/pattern/negation.rs
index 9d2b60337..92218f82d 100644
--- a/rust/pattern/negation.rs
+++ b/rust/pattern/negation.rs
@@ -24,7 +24,7 @@ use core::fmt;
 use std::collections::HashSet;
 
 use crate::{
-    common::{error::TypeQLError, token, validatable::Validatable, Result},
+    common::{error::TypeQLError, string::indent, token, validatable::Validatable, Result},
     pattern::{Conjunction, Disjunction, Normalisable, Pattern, Reference},
 };
 
@@ -83,6 +83,13 @@ impl Normalisable for Negation {
 
 impl fmt::Display for Negation {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{} {{ {}; }}", token::Operator::Not, self.pattern)
+        let pattern_string = self.pattern.to_string();
+        if matches!(*self.pattern, Pattern::Conjunction(_)) {
+            write!(f, "{} {}", token::Operator::Not, pattern_string)
+        } else if pattern_string.lines().count() > 1 {
+            write!(f, "{} {{\n{};\n}}", token::Operator::Not, indent(&pattern_string))
+        } else {
+            write!(f, "{} {{ {}; }}", token::Operator::Not, pattern_string)
+        }
     }
 }
diff --git a/rust/pattern/schema/rule.rs b/rust/pattern/schema/rule.rs
index 40488ede6..2538d94dc 100644
--- a/rust/pattern/schema/rule.rs
+++ b/rust/pattern/schema/rule.rs
@@ -183,16 +183,13 @@ impl fmt::Display for RuleDefinition {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
-            "{} {}:\n{}",
+            "{} {}: {} {} {} {{\n    {};\n}}",
             token::Schema::Rule,
             self.label,
-            indent(&format!(
-                "{} {}\n{} {{\n    {};\n}}",
-                token::Schema::When,
-                self.when,
-                token::Schema::Then,
-                self.then
-            ))
+            token::Schema::When,
+            self.when,
+            token::Schema::Then,
+            self.then
         )
     }
 }


Test patch:
diff --git a/java/parser/test/ParserTest.java b/java/parser/test/ParserTest.java
index 98e15f1bf..b7ce0ab9c 100644
--- a/java/parser/test/ParserTest.java
+++ b/java/parser/test/ParserTest.java
@@ -987,15 +987,29 @@ public void testParsingPattern() {
 
     @Test
     public void testDefineRules() {
-        final String when = "$x isa movie;";
-        final String then = "$x has genre 'drama';";
-        Conjunction<? extends Pattern> whenPattern = and((var("x").isa("movie")));
-        ThingVariable<?> thenPattern = var("x").has("genre", "drama");
+        final String when =
+                "    $x isa person;\n" +
+                "    not {\n" +
+                "        $x has name 'Alice';\n" +
+                "        $x has name 'Bob';\n" +
+                "    };\n" +
+                "    {\n" +
+                "        ($x) isa friendship;\n" +
+                "    } or {\n" +
+                "        ($x) isa employment;\n" +
+                "    };";
+        final String then = "$x has is_interesting true;";
+        Conjunction<? extends Pattern> whenPattern = and(
+                var("x").isa("person"),
+                not(and(var("x").has("name", "Alice"), var("x").has("name", "Bob"))),
+                or(rel(var("x")).isa("friendship"), rel(var("x")).isa("employment"))
+        );
+        ThingVariable<?> thenPattern = var("x").has("is_interesting", true);
 
         TypeQLDefine expected = define(rule("all-movies-are-drama").when(whenPattern).then(thenPattern));
         final String query = "define\n" +
                 "rule all-movies-are-drama: when {\n" +
-                "    " + when + "\n" +
+                when + "\n" +
                 "} then {\n" +
                 "    " + then + "\n" +
                 "};";
diff --git a/rust/parser/test/mod.rs b/rust/parser/test/mod.rs
index d8da360ea..a84c734e9 100644
--- a/rust/parser/test/mod.rs
+++ b/rust/parser/test/mod.rs
@@ -1033,18 +1033,29 @@ fn test_parsing_pattern() {
 #[test]
 fn test_define_rules() {
     let query = r#"define
-rule all-movies-are-drama:
-    when {
-        $x isa movie;
-    }
-    then {
-        $x has genre "drama";
-    };"#;
+rule a-rule: when {
+    $x isa person;
+    not {
+        $x has name "Alice";
+        $x has name "Bob";
+    };
+    {
+        ($x) isa friendship;
+    } or {
+        ($x) isa employment;
+    };
+} then {
+    $x has is_interesting true;
+};"#;
 
     let parsed = parse_query(&query).unwrap().into_define();
-    let expected = typeql_define!(rule("all-movies-are-drama")
-        .when(and!(var("x").isa("movie")))
-        .then(var("x").has(("genre", "drama"))));
+    let expected = typeql_define!(rule("a-rule")
+        .when(and!(
+            var("x").isa("person"),
+            not(and!(var("x").has(("name", "Alice")), var("x").has(("name", "Bob")))),
+            or!(rel(var("x")).isa("friendship"), rel(var("x")).isa("employment"))
+        ))
+        .then(var("x").has(("is_interesting", true))));
 
     assert_valid_eq_repr!(expected, parsed, query);
 }