packages feed

postgresql-syntax-0.5.0.0: library-internal/PostgresqlSyntax/Ast/JoinedTable.hs

module PostgresqlSyntax.Ast.JoinedTable where

import PostgresqlSyntax.Ast.JoinMeth
import {-# SOURCE #-} PostgresqlSyntax.Ast.TableRef (TableRef, joinedTableParser, renderJoinedTable)
import qualified PostgresqlSyntax.Helpers.Gens as Gens
import PostgresqlSyntax.IsAst
import PostgresqlSyntax.Prelude
import qualified Test.QuickCheck as Qc

-- |
-- ==== References
-- @
-- | '(' joined_table ')'
-- | table_ref CROSS JOIN table_ref
-- | table_ref join_type JOIN table_ref join_qual
-- | table_ref JOIN table_ref join_qual
-- | table_ref NATURAL join_type JOIN table_ref
-- | table_ref NATURAL JOIN table_ref
--
-- The options are covered by the `JoinMeth` type.
-- @
--
-- See 'PostgresqlSyntax.Ast.JoinMeth' for why this type's own 'IsAst'
-- instance isn't what 'PostgresqlSyntax.Ast.TableRef' actually uses to
-- parse\/render joined tables.
data JoinedTable
  = InParensJoinedTable JoinedTable
  | MethJoinedTable JoinMeth TableRef TableRef
  deriving (Show, Generic, Eq, Ord, Data)

-- |
-- Delegates to 'PostgresqlSyntax.Ast.TableRef.renderJoinedTable'\/
-- 'PostgresqlSyntax.Ast.TableRef.joinedTableParser' rather than combining
-- 'TableRef'\'s and 'JoinMeth'\'s own instances directly: a bare @table_ref@
-- parse is greedy — it absorbs any trailing @CROSS JOIN@\/@JOIN@\/@NATURAL
-- JOIN@ continuation into itself (see 'PostgresqlSyntax.Ast.TableRef'\'s
-- @recur@) — so parsing this type's own @b@ field with the plain exported
-- 'PostgresqlSyntax.Ast.TableRef.parser' would always swallow the @a@\/@c@
-- that's meant to follow it, and 'JoinMeth'\'s own renderer places a
-- 'PostgresqlSyntax.Ast.JoinQual' immediately after the @JOIN@ keyword
-- rather than after @c@ (see its own doc for why). 'TableRef' is the only
-- module with both this type and 'TableRef' in scope non-abstractly at
-- once, so it hosts the one correct, round-trippable implementation.
instance IsAst JoinedTable where
  toTextBuilder = renderJoinedTable
  parser = joinedTableParser

instance Qc.Arbitrary JoinedTable where
  shrink = Qc.genericShrink
  arbitrary =
    Qc.sized $ \n ->
      if n <= 1
        then MethJoinedTable <$> Qc.arbitrary <*> Gens.downscale Qc.arbitrary <*> Gens.downscale Qc.arbitrary
        else
          Qc.oneof
            [ InParensJoinedTable <$> Gens.downscale Qc.arbitrary,
              MethJoinedTable <$> Qc.arbitrary <*> Gens.downscale Qc.arbitrary <*> Gens.downscale Qc.arbitrary
            ]