diff --git a/src/SqlSquared.purs b/src/SqlSquared.purs index 70bc0b7..cc6722a 100644 --- a/src/SqlSquared.purs +++ b/src/SqlSquared.purs @@ -3,8 +3,11 @@ module SqlSquared , SqlQuery , SqlModule , print + , printPretty , printQuery + , printQueryPretty , printModule + , printModulePretty , genSql , genSqlQuery , genSqlModule @@ -25,7 +28,7 @@ import Matryoshka (cata, anaM) import SqlSquared.Constructors (array, as, as', binop, bool, buildSelect, groupBy, having, hugeNum, ident, ident', int, invokeFunction, invokeFunction', let', let_, map_, match, match', null, num, parens, projection, select, select', set, splice, string, switch, switch', then_, unop, var, when) as Constructors import SqlSquared.Lenses (_ArrayLiteral, _Binop, _BoolLiteral, _Case, _DecimalLiteral, _ExprRelation, _GroupBy, _Identifier, _IntLiteral, _InvokeFunction, _JoinRelation, _Let, _Literal, _MapLiteral, _Match, _NullLiteral, _OrderBy, _Parens, _Projection, _Select, _SetLiteral, _Splice, _StringLiteral, _Switch, _TableRelation, _Unop, _Var, _VarRelation, _alias, _aliasName, _args, _bindTo, _cases, _clause, _cond, _else, _expr, _filter, _groupBy, _having, _ident, _in, _isDistinct, _joinType, _keys, _left, _lhs, _name, _op, _orderBy, _projections, _relations, _rhs, _right, _tablePath) as Lenses import SqlSquared.Parser (Literal(..), PositionedToken, parse, parseModule, parseQuery, prettyParse) as Parser -import SqlSquared.Signature (type (×), BinaryOperator(..), BinopR, Case(..), ExprRelR, FunctionDeclR, GroupBy(..), Ident(..), InvokeFunctionR, JoinRelR, JoinType(..), LetR, MatchR, OrderBy(..), OrderType(..), Projection(..), Relation(..), SelectR, SqlDeclF(..), SqlF(..), SqlModuleF(..), SqlQueryF(..), SwitchR, TableRelR, UnaryOperator(..), UnopR, VarRelR, binopFromString, binopToString, genBinaryOperator, genCase, genGroupBy, genJoinType, genOrderBy, genOrderType, genProjection, genRelation, genSqlDeclF, genSqlF, genSqlModuleF, genSqlQueryF, genUnaryOperator, joinTypeFromString, orderTypeFromString, printBinaryOperator, printCase, printGroupBy, printIdent, printJoinType, printOrderBy, printOrderType, printProjection, printRelation, printSqlDeclF, printSqlF, printSqlModuleF, printSqlQueryF, printUnaryOperator, unopFromString, unopToString, (×), (∘), (⋙)) as Sig +import SqlSquared.Signature (type (×), BinaryOperator(..), BinopR, Case(..), ExprRelR, FunctionDeclR, GroupBy(..), Ident(..), InvokeFunctionR, JoinRelR, JoinType(..), LetR, MatchR, OrderBy(..), OrderType(..), Projection(..), Relation(..), SelectR, SqlDeclF(..), SqlF(..), SqlModuleF(..), SqlQueryF(..), SwitchR, TableRelR, UnaryOperator(..), UnopR, VarRelR, binopFromString, binopToString, genBinaryOperator, genCase, genGroupBy, genJoinType, genOrderBy, genOrderType, genProjection, genRelation, genSqlDeclF, genSqlF, genSqlModuleF, genSqlQueryF, genUnaryOperator, joinTypeFromString, orderTypeFromString, printBinaryOperator, printCase, printGroupBy, printIdent, printJoinType, printOrderBy, printOrderType, printProjection, printRelation, printSqlDeclF, printSqlF, printSqlFPretty, printSqlModuleF, printSqlQueryF, printUnaryOperator, unopFromString, unopToString, (×), (∘), (⋙)) as Sig type Sql = Mu (Sig.SqlF EJ.EJsonF) @@ -42,6 +45,15 @@ printQuery = Sig.printSqlQueryF <<< map print printModule ∷ SqlModule → String printModule = Sig.printSqlModuleF <<< map print +printPretty ∷ Sql → String +printPretty = cata $ Sig.printSqlFPretty EJ.renderEJsonF + +printQueryPretty ∷ SqlQuery → String +printQueryPretty = Sig.printSqlQueryF <<< map printPretty + +printModulePretty ∷ SqlModule → String +printModulePretty = Sig.printSqlModuleF <<< map printPretty + genSql ∷ ∀ m. Gen.MonadGen m ⇒ MonadRec m ⇒ m Sql genSql = Gen.sized $ anaM (Sig.genSqlF EJ.arbitraryEJsonF) diff --git a/src/SqlSquared/Signature.purs b/src/SqlSquared/Signature.purs index f88f0ba..cafba17 100644 --- a/src/SqlSquared/Signature.purs +++ b/src/SqlSquared/Signature.purs @@ -12,6 +12,7 @@ module SqlSquared.Signature , SqlQueryF(..) , SqlModuleF(..) , printSqlF + , printSqlFPretty , printSqlDeclF , printSqlQueryF , printSqlModuleF @@ -47,11 +48,12 @@ import Data.Maybe (Maybe(..)) import Data.Newtype (class Newtype) import Data.NonEmpty ((:|)) import Data.Ord (class Ord1) +import Data.String as String import Data.String.Gen as GenS import Data.Traversable as T import Matryoshka (Algebra, CoalgebraM, class Corecursive, embed) import SqlSquared.Path as Pt -import SqlSquared.Signature.BinaryOperator (BinaryOperator(..), binopFromString, binopToString, genBinaryOperator, printBinaryOperator) as BO +import SqlSquared.Signature.BinaryOperator (BinaryOperator(..), binopFromString, binopToString, genBinaryOperator, printBinaryOperator, printBinaryOperatorPretty) as BO import SqlSquared.Signature.Case (Case(..), genCase, printCase) as CS import SqlSquared.Signature.GroupBy (GroupBy(..), genGroupBy, printGroupBy) as GB import SqlSquared.Signature.Ident (Ident(..), genIdent, printIdent) as ID @@ -361,6 +363,25 @@ printSqlF printLiteralF = case _ of Parens t → "(" <> t <> ")" +printSqlFPretty ∷ ∀ l. Algebra l String → Algebra (SqlF l) String +printSqlFPretty printLiteralF = case _ of + Binop {lhs, rhs, op} → + BO.printBinaryOperatorPretty lhs rhs op + Select { isDistinct, projections, relations, filter, groupBy, orderBy } → + "SELECT " + <> (if isDistinct then "DISTINCT " else "") + <> "\n " + <> (F.intercalate ", \n " $ map (reindent ∘ PR.printProjection) projections) + <> (relations # F.foldMap \rs → "\nFROM\n " <> reindent (RL.printRelation rs)) + <> (filter # F.foldMap \f → "\nWHERE\n " <> f) + <> (groupBy # F.foldMap \gb → "\nGROUP BY\n " <> reindent (GB.printGroupBy gb)) + <> (orderBy # F.foldMap \ob → "\nORDER BY\n " <> reindent (OB.printOrderBy ob)) + other → + printSqlF printLiteralF other + +reindent ∷ String → String +reindent = String.replaceAll (String.Pattern "\n") (String.Replacement "\n ") + printSqlDeclF ∷ Algebra SqlDeclF String printSqlDeclF = case _ of FunctionDecl { ident, args, body } → diff --git a/src/SqlSquared/Signature/BinaryOperator.purs b/src/SqlSquared/Signature/BinaryOperator.purs index 49585d7..ef49c31 100644 --- a/src/SqlSquared/Signature/BinaryOperator.purs +++ b/src/SqlSquared/Signature/BinaryOperator.purs @@ -147,3 +147,8 @@ printBinaryOperator lhs rhs = case _ of IntersectAll → lhs <> " INTERSECT ALL " <> rhs Except → lhs <> " EXCEPT " <> rhs UnshiftMap → "{" <> lhs <> ": " <> rhs <> "...}" + +printBinaryOperatorPretty ∷ String → String → BinaryOperator → String +printBinaryOperatorPretty lhs rhs = case _ of + UnionAll → lhs <> "\nUNION ALL\n" <> rhs + other → printBinaryOperator lhs rhs other diff --git a/src/SqlSquared/Signature/Relation.purs b/src/SqlSquared/Signature/Relation.purs index 3127092..542f8d7 100644 --- a/src/SqlSquared/Signature/Relation.purs +++ b/src/SqlSquared/Signature/Relation.purs @@ -9,6 +9,7 @@ import Data.Either (Either(..), either) import Data.Foldable as F import Data.Maybe (Maybe) import Data.NonEmpty ((:|)) +import Data.String as String import Data.String.Gen as GenS import Data.Traversable as T import Matryoshka (Algebra, CoalgebraM) @@ -83,7 +84,10 @@ instance traversableRelation ∷ T.Traversable Relation where printRelation ∷ Algebra Relation String printRelation = case _ of ExprRelation { expr, alias } → - "(" <> expr <> ") AS " <> ID.printIdent alias + let + indented = String.contains (String.Pattern "\n") expr + in + "(" <> expr <> (if indented then "\n" else "") <> ") AS " <> ID.printIdent alias VarRelation { var, alias } → ":" <> ID.printIdent var <> F.foldMap (\a → " AS " <> ID.printIdent a) alias TableRelation { path, alias } →