Skip to content

Commit

Permalink
Introduce unformatted toString (#239)
Browse files Browse the repository at this point in the history
## What is the goal of this PR?

We introduce an unformatted `toString` method which will not introduce
any indentation or newlines.

This fixes a bug where a user's strings with newlines in them receive
indentation in the middle of the attribute. Now, to avoid this visual or
downstream effect the API exists to disable newlines and indentation.

## What are the changes implemented in this PR?

* introduce `toString(boolean pretty)` which allows enabling or
disabling pretty-printing. This API is available on `Defineable`,
`TypeQLQuery`, and `Pattern`, but not `Constraint` since these are very
short and don't do any pretty printing themselves.
* the default `toString()` on all objects does do pretty printing when
the option is available
  • Loading branch information
flyingsilverfin authored Oct 21, 2022
1 parent b18f598 commit 4230aea
Show file tree
Hide file tree
Showing 16 changed files with 162 additions and 75 deletions.
22 changes: 15 additions & 7 deletions java/pattern/Conjunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,26 @@ public Disjunction<Conjunction<Conjunctable>> normalise() {
@Override
public Conjunction<?> asConjunction() { return this; }

public String toString(boolean isMultiline) {
TypeQLToken.Char whitespace = isMultiline ? NEW_LINE : SPACE;
String body = patterns.stream().map(Objects::toString).collect(SEMICOLON_NEW_LINE.joiner()) + SEMICOLON;
if (isMultiline) body = indent(body);
return CURLY_OPEN.toString() + whitespace + body + whitespace + CURLY_CLOSE;
}

@Override
public String toString() {
return toString(patterns.size() > 1 || patterns.get(0).toString().lines().count() > 1);
}

@Override
public String toString(boolean pretty) {
if (pretty) {
TypeQLToken.Char whitespace = NEW_LINE;
String body = patterns.stream().map(p -> p.toString(pretty)).collect(SEMICOLON_NEW_LINE.joiner()) + SEMICOLON;
body = indent(body);
return CURLY_OPEN.toString() + whitespace + body + whitespace + CURLY_CLOSE;
} else {
TypeQLToken.Char whitespace = SPACE;
String body = patterns.stream().map(p -> p.toString(pretty)).collect(SEMICOLON.joiner()) + SEMICOLON;
return CURLY_OPEN.toString() + whitespace + body + whitespace + CURLY_CLOSE;
}
}


@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
2 changes: 2 additions & 0 deletions java/pattern/Definable.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ default Rule asRule() {
default TypeVariable asTypeVariable() {
throw TypeQLException.of(INVALID_CASTING.message(className(this.getClass()), className(TypeVariable.class)));
}

String toString(boolean pretty);
}
29 changes: 23 additions & 6 deletions java/pattern/Disjunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
package com.vaticle.typeql.lang.pattern;

import com.vaticle.typeql.lang.pattern.variable.UnboundVariable;

import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;

import static com.vaticle.typedb.common.collection.Collections.list;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.CURLY_CLOSE;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.CURLY_OPEN;
Expand Down Expand Up @@ -75,22 +77,37 @@ else if (p.isNegation())
}

@Override
public boolean isDisjunction() { return true; }
public boolean isDisjunction() {
return true;
}

@Override
public Disjunction<?> asDisjunction() { return this; }
public Disjunction<?> asDisjunction() {
return this;
}

@Override
public String toString() {
return toString(true);
}

@Override
public String toString(boolean pretty) {
StringBuilder disjunction = new StringBuilder();
Iterator<T> patternIter = patterns.iterator();
while (patternIter.hasNext()) {
Pattern pattern = patternIter.next();
if (pattern.isConjunction()) disjunction.append(pattern.asConjunction().toString(true));
if (pattern.isConjunction()) disjunction.append(pattern.asConjunction().toString(pretty));
else {
disjunction.append(CURLY_OPEN).append(NEW_LINE);
disjunction.append(indent(pattern.toString() + SEMICOLON));
disjunction.append(NEW_LINE).append(CURLY_CLOSE);
disjunction.append(CURLY_OPEN);
if (pretty) {
disjunction.append(NEW_LINE);
disjunction.append(indent(pattern.toString(pretty) + SEMICOLON));
disjunction.append(NEW_LINE);
} else {
disjunction.append(pattern.toString(pretty)).append(SEMICOLON);
}
disjunction.append(CURLY_CLOSE);
}
if (patternIter.hasNext()) disjunction.append(SPACE).append(OR).append(SPACE);
}
Expand Down
28 changes: 19 additions & 9 deletions java/pattern/Negation.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public Negation(T pattern) {
this.pattern = pattern;
}

public T pattern() { return pattern; }
public T pattern() {
return pattern;
}

@Override
public List<? extends Pattern> patterns() {
Expand Down Expand Up @@ -86,22 +88,30 @@ public Negation<Disjunction<Conjunction<Conjunctable>>> normalise() {
}

@Override
public boolean isNegation() { return true; }
public boolean isNegation() {
return true;
}

@Override
public Negation<?> asNegation() { return this; }
public Negation<?> asNegation() {
return this;
}

@Override
public String toString() {
public String toString(boolean pretty) {
StringBuilder negation = new StringBuilder();
negation.append(TypeQLToken.Operator.NOT).append(SPACE);

if (pattern.isConjunction()) {
negation.append(pattern);
} else if (pattern.toString().lines().count() > 1) {
negation.append(CURLY_OPEN).append(NEW_LINE);
negation.append(indent(pattern.toString() + SEMICOLON));
negation.append(NEW_LINE).append(CURLY_CLOSE);
negation.append(pattern.toString(pretty));
} else if (pattern.toString(pretty).lines().count() > 1) {
negation.append(CURLY_OPEN);
if (pretty) {
negation.append(NEW_LINE).append(indent(pattern.toString(pretty) + SEMICOLON)).append(NEW_LINE);
} else {
negation.append(pattern.toString(pretty)).append(SEMICOLON);
}
negation.append(CURLY_CLOSE);
} else {
negation.append(CURLY_OPEN).append(SPACE);
negation.append(pattern).append(SEMICOLON);
Expand Down
2 changes: 2 additions & 0 deletions java/pattern/Pattern.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@ default Conjunctable asConjunctable() {

@Override
String toString();

String toString(boolean pretty);
}
26 changes: 19 additions & 7 deletions java/pattern/schema/Rule.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,27 @@ private static void validateThen(String label, @Nullable Conjunction<? extends P

@Override
public String toString() {
return toString(true);
}

@Override
public String toString(boolean pretty) {
StringBuilder rule = new StringBuilder("" + RULE + SPACE + label);
if (when != null) {
rule.append(COLON).append(NEW_LINE);
StringBuilder body = new StringBuilder();
body.append(WHEN).append(SPACE).append(when.toString(true)).append(NEW_LINE);
body.append(THEN).append(SPACE).append(CURLY_OPEN).append(NEW_LINE);
body.append(indent(then)).append(SEMICOLON);
body.append(NEW_LINE).append(CURLY_CLOSE);
rule.append(indent(body));
if (pretty) {
rule.append(COLON).append(NEW_LINE);
StringBuilder body = new StringBuilder();
body.append(WHEN).append(SPACE).append(when.toString(pretty)).append(NEW_LINE);
body.append(THEN).append(SPACE).append(CURLY_OPEN).append(NEW_LINE);
body.append(indent(then)).append(SEMICOLON);
body.append(NEW_LINE).append(CURLY_CLOSE);
rule.append(indent(body));
} else {
rule.append(COLON);
String content = String.valueOf(WHEN) + SPACE + when.toString(pretty) + THEN + SPACE + CURLY_OPEN +
then.toString(true) + SEMICOLON + CURLY_CLOSE;
rule.append(content);
}
}
return rule.toString();
}
Expand Down
2 changes: 1 addition & 1 deletion java/pattern/variable/ConceptVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public Optional<ConceptConstraint.Is> is() {
}

@Override
public String toString() {
public String toString(boolean pretty) {
if (isConstraint == null) return reference.toString();
return reference.toString() + SPACE + isConstraint;
}
Expand Down
45 changes: 29 additions & 16 deletions java/pattern/variable/ThingVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.Optional;
import java.util.stream.Stream;

import static com.vaticle.typeql.lang.common.TypeQLToken.Char.COMMA;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.COMMA_NEW_LINE;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.SPACE;
import static com.vaticle.typeql.lang.common.exception.ErrorMessage.ILLEGAL_CONSTRAINT_REPETITION;
Expand Down Expand Up @@ -120,9 +121,6 @@ String hasSyntax() {
return has().stream().map(ThingConstraint.Has::toString).collect(COMMA_NEW_LINE.joiner());
}

@Override
public abstract String toString();

@Override
public final boolean equals(Object o) {
if (this == o) return true;
Expand Down Expand Up @@ -162,19 +160,23 @@ private String thingSyntax() {
}

@Override
public String toString() {
public String toString(boolean pretty) {
StringBuilder thing = new StringBuilder();
if (isVisible()) thing.append(reference.syntax());
String constraints = Stream.of(thingSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
String constraints;
if (pretty) {
constraints = Stream.of(thingSyntax(), hasSyntax()).filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
} else {
constraints = Stream.of(thingSyntax(), hasSyntax()).filter(s -> !s.isEmpty()).collect(COMMA.joiner());
}
if (!constraints.isEmpty()) thing.append(SPACE).append(constraints);
return thing.toString();
}
}

public static class Relation extends ThingVariable<Relation> implements ThingVariableBuilder.Relation,
ThingVariableBuilder.Common<Relation> {
ThingVariableBuilder.Common<Relation> {

Relation(Reference reference, ThingConstraint.Relation relationConstraint) {
super(reference);
Expand All @@ -194,14 +196,19 @@ public ThingVariable.Relation constrain(ThingConstraint.Relation.RolePlayer role
}

@Override
public String toString() {
public String toString(boolean pretty) {
assert relation().isPresent();
StringBuilder relation = new StringBuilder();
if (isVisible()) relation.append(reference.syntax()).append(SPACE);
relation.append(relation().get());
String constraints = Stream.of(isaSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
String constraints;
if (pretty) {
constraints = Stream.of(isaSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
} else {
constraints = Stream.of(isaSyntax(), hasSyntax()).filter(s -> !s.isEmpty()).collect(COMMA.joiner());
}
if (!constraints.isEmpty()) relation.append(SPACE).append(constraints);
return relation.toString();
}
Expand All @@ -221,14 +228,20 @@ ThingVariable.Attribute getThis() {
}

@Override
public String toString() {
public String toString(boolean pretty) {
assert value().isPresent();
StringBuilder attribute = new StringBuilder();
if (isVisible()) attribute.append(reference.syntax()).append(SPACE);
attribute.append(value().get());
String constraints = Stream.of(isaSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
String constraints;
if (pretty) {
constraints = Stream.of(isaSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA_NEW_LINE.joiner());
constraints = indent(constraints).trim();
} else {
constraints = Stream.of(isaSyntax(), hasSyntax())
.filter(s -> !s.isEmpty()).collect(COMMA.joiner());
}
if (!constraints.isEmpty()) attribute.append(SPACE).append(constraints);
return attribute.toString();
}
Expand Down
14 changes: 11 additions & 3 deletions java/pattern/variable/TypeVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.stream.Stream;

import static com.vaticle.typedb.common.collection.Collections.set;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.COMMA;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.COMMA_NEW_LINE;
import static com.vaticle.typeql.lang.common.TypeQLToken.Char.SPACE;
import static com.vaticle.typeql.lang.common.exception.ErrorMessage.ILLEGAL_CONSTRAINT_REPETITION;
Expand Down Expand Up @@ -185,12 +186,17 @@ public List<TypeConstraint.Relates> relates() {
}

@Override
public String toString() {
public String toString(boolean pretty) {
StringBuilder syntax = new StringBuilder();
if (isVisible() || label().isPresent()) {
syntax.append(isVisible() ? reference.syntax() : label().get().scopedLabel());
Stream<TypeConstraint> consStream = isVisible() ? constraints.stream() : constraints.stream().skip(1);
String consStr = indent(consStream.map(Constraint::toString).collect(COMMA_NEW_LINE.joiner())).trim();
String consStr;
if (pretty) {
consStr = indent(consStream.map(Constraint::toString).collect(COMMA_NEW_LINE.joiner())).trim();
} else {
consStr = consStream.map(Constraint::toString).collect(COMMA.joiner());
}
if (!consStr.isEmpty()) syntax.append(SPACE).append(consStr);
} else {
// This should only be called by debuggers trying to print nested variables
Expand Down Expand Up @@ -219,5 +225,7 @@ public boolean isTypeVariable() {
}

@Override
public TypeVariable asTypeVariable() { return this; }
public TypeVariable asTypeVariable() {
return this;
}
}
2 changes: 1 addition & 1 deletion java/pattern/variable/UnboundVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public ThingVariable.Relation constrain(ThingConstraint.Relation constraint) {
}

@Override
public String toString() {
public String toString(boolean pretty) {
return reference.syntax();
}

Expand Down
6 changes: 5 additions & 1 deletion java/pattern/variable/Variable.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ public boolean isVisible() {
}

@Override
public abstract String toString();
public String toString() {
return toString(true);
}

public abstract String toString(boolean pretty);

@Override
public abstract boolean equals(Object o);
Expand Down
4 changes: 2 additions & 2 deletions java/query/TypeQLDefinable.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ public final List<Rule> rules() {
}

@Override
public final String toString() {
public String toString(boolean pretty) {
StringBuilder query = new StringBuilder();
appendSubQuery(query, command, definables);
appendSubQuery(query, command, definables.stream().map(d -> d.toString(pretty)), pretty);
return query.toString();
}

Expand Down
Loading

0 comments on commit 4230aea

Please sign in to comment.