module Main.Gen where
import qualified Data.HashSet as HashSet
import qualified Data.List as List
import qualified Data.Text as Text
import Hedgehog (Gen, MonadGen)
import Hedgehog.Gen
import qualified Hedgehog.Range as Range
import PostgresqlSyntax.Ast
import qualified PostgresqlSyntax.KeywordSet as KeywordSet
import qualified PostgresqlSyntax.Validation as Validation
import Prelude hiding (bit, bool, filter, fromList, maybe, sortBy)
-- * Generic
inSet _set = filter (flip HashSet.member _set)
notInSet _set = filter (not . flip HashSet.member _set)
-- * Statements
preparableStmt =
choice
[ SelectPreparableStmt <$> selectStmt,
InsertPreparableStmt <$> insertStmt,
UpdatePreparableStmt <$> updateStmt,
DeletePreparableStmt <$> deleteStmt,
CallPreparableStmt <$> callStmt
]
-- * Call
callStmt = CallStmt <$> funcApplication
-- * Insert
insertStmt = InsertStmt <$> maybe withClause <*> insertTarget <*> insertRest <*> maybe onConflict <*> maybe returningClause
insertTarget = InsertTarget <$> qualifiedName <*> maybe colId
insertRest =
choice
[ SelectInsertRest <$> maybe insertColumnList <*> maybe overrideKind <*> selectStmt,
pure DefaultValuesInsertRest
]
overrideKind = enumBounded
insertColumnList = nonEmpty (Range.exponential 1 7) insertColumnItem
insertColumnItem = InsertColumnItem <$> colId <*> maybe indirection
onConflict = OnConflict <$> maybe confExpr <*> onConflictDo
onConflictDo =
choice
[ UpdateOnConflictDo <$> setClauseList <*> maybe whereClause,
pure NothingOnConflictDo
]
confExpr =
choice
[ WhereConfExpr <$> indexParams <*> maybe whereClause,
ConstraintConfExpr <$> name
]
returningClause = targetList
-- * Update
updateStmt = UpdateStmt <$> maybe withClause <*> relationExprOptAlias <*> setClauseList <*> maybe fromClause <*> maybe whereOrCurrentClause <*> maybe returningClause
setClauseList = nonEmpty (Range.exponential 1 10) setClause
setClause =
choice
[ TargetSetClause <$> setTarget <*> aExpr,
TargetListSetClause <$> setTargetList <*> aExpr
]
setTarget = SetTarget <$> colId <*> maybe indirection
setTargetList = nonEmpty (Range.exponential 1 10) setTarget
-- * Delete
deleteStmt = DeleteStmt <$> maybe withClause <*> relationExprOptAlias <*> maybe usingClause <*> maybe whereOrCurrentClause <*> maybe returningClause
usingClause = fromList
-- * Select
selectStmt = Left <$> selectNoParens
-- ** selectNoParens
selectNoParens =
frequency
[ (90, SelectNoParens <$> maybe withClause <*> (Left <$> simpleSelect) <*> maybe sortClause <*> maybe selectLimit <*> maybe forLockingClause),
(10, SelectNoParens <$> fmap Just withClause <*> selectClause <*> fmap Just sortClause <*> fmap Just selectLimit <*> fmap Just forLockingClause)
]
terminalSelectNoParens =
SelectNoParens <$> pure Nothing <*> (Left <$> terminalSimpleSelect) <*> pure Nothing <*> pure Nothing <*> pure Nothing
-- ** selectWithParens
selectWithParens = sized $ \_size ->
if _size <= 1
then discard
else
frequency
[ (95, NoParensSelectWithParens <$> selectNoParens),
(5, WithParensSelectWithParens <$> selectWithParens)
]
terminalSelectWithParens = NoParensSelectWithParens <$> terminalSelectNoParens
-- ** selectClause
selectClause =
choice
[ Left <$> simpleSelect,
Right <$> small selectWithParens
]
nonTrailingSelectClause = Left <$> nonTrailingSimpleSelect
-- ** simpleSelect
simpleSelect =
choice
[ normalSimpleSelect,
tableSimpleSelect,
valuesSimpleSelect,
small nonTrailingSelectClause >>= binSimpleSelect
]
nonTrailingSimpleSelect = choice [normalSimpleSelect, valuesSimpleSelect, tableSimpleSelect]
normalSimpleSelect = NormalSimpleSelect <$> maybe targeting <*> maybe intoClause <*> maybe fromClause <*> maybe whereClause <*> maybe groupClause <*> maybe havingClause <*> maybe windowClause
tableSimpleSelect = TableSimpleSelect <$> relationExpr
valuesSimpleSelect = ValuesSimpleSelect <$> valuesClause
binSimpleSelect _leftSelect =
BinSimpleSelect <$> selectBinOp <*> pure _leftSelect <*> maybe allOrDistinct <*> small selectClause
terminalSimpleSelect = pure (NormalSimpleSelect Nothing Nothing Nothing Nothing Nothing Nothing Nothing)
-- * Targeting
targeting =
choice
[ NormalTargeting <$> targetList,
AllTargeting <$> maybe targetList,
DistinctTargeting <$> maybe (nonEmpty (Range.exponential 1 8) aExpr) <*> targetList
]
targetList = nonEmpty (Range.exponential 1 8) targetEl
targetEl =
choice
[ pure AsteriskTargetEl,
AliasedExprTargetEl <$> aExpr <*> colLabel,
ImplicitlyAliasedExprTargetEl <$> prefixAExpr <*> ident,
ExprTargetEl <$> aExpr
]
-- * BinSimpleSelect
selectBinOp = element [UnionSelectBinOp, IntersectSelectBinOp, ExceptSelectBinOp]
-- * With Clause
withClause = WithClause <$> bool <*> nonEmpty (Range.exponential 1 7) commonTableExpr
commonTableExpr = CommonTableExpr <$> name <*> maybe (nonEmpty (Range.exponential 1 8) name) <*> maybe bool <*> small preparableStmt
-- * Into Clause
intoClause = optTempTableName
optTempTableName =
choice
[ TemporaryOptTempTableName <$> bool <*> qualifiedName,
TempOptTempTableName <$> bool <*> qualifiedName,
LocalTemporaryOptTempTableName <$> bool <*> qualifiedName,
LocalTempOptTempTableName <$> bool <*> qualifiedName,
GlobalTemporaryOptTempTableName <$> bool <*> qualifiedName,
GlobalTempOptTempTableName <$> bool <*> qualifiedName,
UnloggedOptTempTableName <$> bool <*> qualifiedName,
TableOptTempTableName <$> qualifiedName,
QualifedOptTempTableName <$> qualifiedName
]
-- * From Clause
fromList = nonEmpty (Range.exponential 1 8) tableRef
fromClause = fromList
tableRef = choice [relationExprTableRef, selectTableRef, joinTableRef]
relationExprTableRef = RelationExprTableRef <$> relationExpr <*> maybe aliasClause <*> maybe tablesampleClause
funcTableRef = FuncTableRef <$> bool <*> funcTable <*> maybe funcAliasClause
selectTableRef = SelectTableRef <$> bool <*> small selectWithParens <*> maybe aliasClause
joinTableRef = JoinTableRef <$> joinedTable <*> maybe aliasClause
relationExpr =
choice
[ SimpleRelationExpr <$> qualifiedName <*> bool,
OnlyRelationExpr <$> qualifiedName <*> bool
]
relationExprOptAlias = RelationExprOptAlias <$> relationExpr <*> maybe ((,) <$> bool <*> colId)
tablesampleClause = TablesampleClause <$> funcName <*> exprList <*> maybe repeatableClause
repeatableClause = aExpr
funcTable =
choice
[ FuncExprFuncTable <$> funcExprWindowless <*> optOrdinality,
RowsFromFuncTable <$> rowsfromList <*> optOrdinality
]
rowsfromItem = RowsfromItem <$> funcExprWindowless <*> maybe colDefList
rowsfromList = nonEmpty (Range.exponential 1 8) rowsfromItem
colDefList = tableFuncElementList
optOrdinality = bool
tableFuncElementList = nonEmpty (Range.exponential 1 7) tableFuncElement
tableFuncElement = TableFuncElement <$> colId <*> typename <*> maybe collateClause
collateClause = anyName
aliasClause = AliasClause <$> bool <*> name <*> maybe (nonEmpty (Range.exponential 1 8) name)
funcAliasClause =
choice
[ AliasFuncAliasClause <$> aliasClause,
AsFuncAliasClause <$> tableFuncElementList,
AsColIdFuncAliasClause <$> colId <*> tableFuncElementList,
ColIdFuncAliasClause <$> colId <*> tableFuncElementList
]
joinedTable =
frequency
[ (5,) $ InParensJoinedTable <$> joinedTable,
(95,) $ MethJoinedTable <$> joinMeth <*> tableRef <*> choice [relationExprTableRef, selectTableRef, funcTableRef]
]
joinMeth =
choice
[ pure CrossJoinMeth,
QualJoinMeth <$> maybe joinType <*> joinQual,
NaturalJoinMeth <$> maybe joinType
]
joinType =
choice
[ FullJoinType <$> bool,
LeftJoinType <$> bool,
RightJoinType <$> bool,
pure InnerJoinType
]
joinQual =
choice
[ UsingJoinQual <$> nonEmpty (Range.exponential 1 8) name,
OnJoinQual <$> aExpr
]
-- * Group Clause
groupClause = nonEmpty (Range.exponential 1 8) groupByItem
groupByItem =
choice
[ ExprGroupByItem <$> aExpr,
pure EmptyGroupingSetGroupByItem,
RollupGroupByItem <$> nonEmpty (Range.exponential 1 8) aExpr,
CubeGroupByItem <$> nonEmpty (Range.exponential 1 8) aExpr,
GroupingSetsGroupByItem <$> nonEmpty (Range.exponential 1 3) groupByItem
]
-- * Having Clause
havingClause = aExpr
-- * Where Clause
whereClause = aExpr
whereOrCurrentClause =
choice
[ ExprWhereOrCurrentClause <$> aExpr,
CursorWhereOrCurrentClause <$> cursorName
]
-- * Window Clause
windowClause = nonEmpty (Range.exponential 1 8) windowDefinition
windowDefinition = WindowDefinition <$> name <*> windowSpecification
windowSpecification = WindowSpecification <$> maybe name <*> maybe (nonEmpty (Range.exponential 1 8) nonSuffixOpAExpr) <*> maybe sortClause <*> maybe frameClause
frameClause = FrameClause <$> frameClauseMode <*> frameExtent <*> maybe windowExclusionClause
frameClauseMode = element [RangeFrameClauseMode, RowsFrameClauseMode, GroupsFrameClauseMode]
frameExtent =
choice
[ SingularFrameExtent <$> frameBound,
BetweenFrameExtent <$> frameBound <*> frameBound
]
frameBound =
choice
[ pure UnboundedPrecedingFrameBound,
pure UnboundedFollowingFrameBound,
pure CurrentRowFrameBound,
PrecedingFrameBound <$> prefixAExpr,
FollowingFrameBound <$> prefixAExpr
]
windowExclusionClause = element [CurrentRowWindowExclusionClause, GroupWindowExclusionClause, TiesWindowExclusionClause, NoOthersWindowExclusionClause]
-- * Values Clause
valuesClause = nonEmpty (Range.exponential 1 8) (nonEmpty (Range.exponential 1 8) aExpr)
-- * Sort Clause
sortClause = nonEmpty (Range.exponential 1 8) sortBy
sortBy =
choice
[ UsingSortBy <$> nonSuffixOpAExpr <*> qualAllOp <*> maybe nullsOrder,
AscDescSortBy <$> nonSuffixOpAExpr <*> maybe ascDesc <*> maybe nullsOrder
]
-- * All or distinct
allOrDistinct = bool
-- * Limit
selectLimit =
choice
[ LimitOffsetSelectLimit <$> limitClause <*> offsetClause,
OffsetLimitSelectLimit <$> offsetClause <*> limitClause,
LimitSelectLimit <$> limitClause,
OffsetSelectLimit <$> offsetClause
]
limitClause =
choice
[ LimitLimitClause <$> selectLimitValue <*> maybe aExpr,
FetchOnlyLimitClause <$> bool <*> maybe selectFetchFirstValue <*> bool
]
selectFetchFirstValue =
choice
[ ExprSelectFetchFirstValue <$> cExpr,
NumSelectFetchFirstValue <$> bool <*> iconstOrFconst
]
selectLimitValue =
choice
[ ExprSelectLimitValue <$> aExpr,
pure AllSelectLimitValue
]
offsetClause =
choice
[ ExprOffsetClause <$> aExpr,
FetchFirstOffsetClause <$> selectFetchFirstValue <*> bool
]
-- * For Locking
forLockingClause =
choice
[ ItemsForLockingClause <$> nonEmpty (Range.exponential 1 8) forLockingItem,
pure ReadOnlyForLockingClause
]
forLockingItem = ForLockingItem <$> forLockingStrength <*> maybe (nonEmpty (Range.exponential 1 8) qualifiedName) <*> maybe bool
forLockingStrength =
element
[ UpdateForLockingStrength,
NoKeyUpdateForLockingStrength,
ShareForLockingStrength,
KeyForLockingStrength
]
-- * Expressions
exprList = nonEmpty (Range.exponential 1 7) aExpr
aExpr =
recursive
choice
[ CExprAExpr <$> cExpr,
pure DefaultAExpr
]
[ TypecastAExpr <$> prefixAExpr <*> typename,
CollateAExpr <$> prefixAExpr <*> anyName,
AtTimeZoneAExpr <$> prefixAExpr <*> aExpr,
PlusAExpr <$> aExpr,
MinusAExpr <$> aExpr,
SymbolicBinOpAExpr <$> prefixAExpr <*> symbolicExprBinOp <*> aExpr,
PrefixQualOpAExpr <$> qualOp <*> aExpr,
SuffixQualOpAExpr <$> prefixAExpr <*> qualOp,
AndAExpr <$> prefixAExpr <*> aExpr,
OrAExpr <$> prefixAExpr <*> aExpr,
NotAExpr <$> aExpr,
VerbalExprBinOpAExpr <$> prefixAExpr <*> bool <*> verbalExprBinOp <*> prefixAExpr <*> maybe aExpr,
ReversableOpAExpr <$> prefixAExpr <*> bool <*> aExprReversableOp,
IsnullAExpr <$> prefixAExpr,
NotnullAExpr <$> prefixAExpr,
OverlapsAExpr <$> row <*> row,
SubqueryAExpr <$> prefixAExpr <*> subqueryOp <*> subType <*> choice [Left <$> selectWithParens, Right <$> nonSelectAExpr],
UniqueAExpr <$> selectWithParens
]
prefixAExpr =
choice
[ CExprAExpr <$> cExpr,
pure DefaultAExpr,
UniqueAExpr <$> selectWithParens
]
nonSuffixOpAExpr =
recursive
choice
[ CExprAExpr <$> cExpr,
pure DefaultAExpr
]
[ TypecastAExpr <$> prefixAExpr <*> typename,
CollateAExpr <$> prefixAExpr <*> anyName,
AtTimeZoneAExpr <$> prefixAExpr <*> nonSuffixOpAExpr,
PlusAExpr <$> nonSuffixOpAExpr,
MinusAExpr <$> nonSuffixOpAExpr,
SymbolicBinOpAExpr <$> prefixAExpr <*> symbolicExprBinOp <*> nonSuffixOpAExpr,
PrefixQualOpAExpr <$> qualOp <*> nonSuffixOpAExpr,
AndAExpr <$> prefixAExpr <*> nonSuffixOpAExpr,
OrAExpr <$> prefixAExpr <*> nonSuffixOpAExpr,
NotAExpr <$> nonSuffixOpAExpr,
VerbalExprBinOpAExpr <$> prefixAExpr <*> bool <*> verbalExprBinOp <*> prefixAExpr <*> maybe nonSuffixOpAExpr,
IsnullAExpr <$> prefixAExpr,
NotnullAExpr <$> prefixAExpr,
UniqueAExpr <$> selectWithParens
]
nonSelectAExpr =
choice
[ TypecastAExpr <$> prefixAExpr <*> typename,
CollateAExpr <$> prefixAExpr <*> anyName,
AtTimeZoneAExpr <$> prefixAExpr <*> aExpr,
PlusAExpr <$> aExpr,
MinusAExpr <$> aExpr,
SymbolicBinOpAExpr <$> prefixAExpr <*> symbolicExprBinOp <*> aExpr,
PrefixQualOpAExpr <$> qualOp <*> aExpr,
SuffixQualOpAExpr <$> prefixAExpr <*> qualOp,
AndAExpr <$> prefixAExpr <*> aExpr,
OrAExpr <$> prefixAExpr <*> aExpr,
NotAExpr <$> aExpr,
VerbalExprBinOpAExpr <$> prefixAExpr <*> bool <*> verbalExprBinOp <*> prefixAExpr <*> maybe aExpr,
ReversableOpAExpr <$> prefixAExpr <*> bool <*> aExprReversableOp,
IsnullAExpr <$> prefixAExpr,
NotnullAExpr <$> prefixAExpr,
OverlapsAExpr <$> row <*> row,
SubqueryAExpr <$> prefixAExpr <*> subqueryOp <*> subType <*> choice [Left <$> selectWithParens, Right <$> nonSelectAExpr],
UniqueAExpr <$> selectWithParens
]
bExpr =
recursive
choice
[ CExprBExpr <$> cExpr
]
[ TypecastBExpr <$> prefixBExpr <*> typename,
PlusBExpr <$> bExpr,
MinusBExpr <$> bExpr,
SymbolicBinOpBExpr <$> prefixBExpr <*> symbolicExprBinOp <*> bExpr,
QualOpBExpr <$> qualOp <*> bExpr,
IsOpBExpr <$> prefixBExpr <*> bool <*> bExprIsOp
]
prefixBExpr =
choice
[ CExprBExpr <$> cExpr
]
cExpr =
recursive
choice
[ ColumnrefCExpr <$> columnref
]
[ AexprConstCExpr <$> aexprConst,
ParamCExpr <$> integral (Range.linear 1 19) <*> maybe indirection,
InParensCExpr <$> nonSelectAExpr <*> maybe indirection,
CaseCExpr <$> caseExpr,
FuncCExpr <$> funcExpr,
SelectWithParensCExpr <$> selectWithParens <*> maybe indirection,
ExistsCExpr <$> selectWithParens,
ArrayCExpr <$> choice [Left <$> selectWithParens, Right <$> arrayExpr],
ExplicitRowCExpr <$> explicitRow,
ImplicitRowCExpr <$> implicitRow,
GroupingCExpr <$> exprList
]
-- **
caseExpr = CaseExpr <$> maybe aExpr <*> whenClauseList <*> maybe aExpr
whenClauseList = nonEmpty (Range.exponential 1 7) whenClause
whenClause = WhenClause <$> small aExpr <*> small aExpr
inExpr =
choice
[ SelectInExpr <$> NoParensSelectWithParens <$> selectNoParens,
ExprListInExpr <$> exprList
]
arrayExpr =
small $
choice
[ ExprListArrayExpr <$> exprList,
ArrayExprListArrayExpr <$> arrayExprList,
pure EmptyArrayExpr
]
arrayExprList = nonEmpty (Range.exponential 1 4) arrayExpr
row =
choice
[ ExplicitRowRow <$> explicitRow,
ImplicitRowRow <$> implicitRow
]
explicitRow = maybe exprList
implicitRow = ImplicitRow <$> exprList <*> aExpr
-- ** FuncExpr
funcExpr =
choice
[ ApplicationFuncExpr <$> funcApplication <*> maybe withinGroupClause <*> maybe filterClause <*> maybe overClause,
SubexprFuncExpr <$> funcExprCommonSubexpr
]
funcExprWindowless =
choice
[ ApplicationFuncExprWindowless <$> funcApplication,
CommonSubexprFuncExprWindowless <$> funcExprCommonSubexpr
]
funcApplication = FuncApplication <$> funcName <*> maybe funcApplicationParams
funcApplicationParams =
choice
[ NormalFuncApplicationParams <$> maybe allOrDistinct <*> nonEmpty (Range.exponential 1 8) funcArgExpr <*> maybe sortClause,
VariadicFuncApplicationParams <$> maybe (nonEmpty (Range.exponential 1 8) funcArgExpr) <*> funcArgExpr <*> maybe sortClause,
pure StarFuncApplicationParams
]
funcArgExpr =
choice
[ ExprFuncArgExpr <$> small aExpr,
ColonEqualsFuncArgExpr <$> name <*> small aExpr,
EqualsGreaterFuncArgExpr <$> name <*> small aExpr
]
withinGroupClause = sortClause
filterClause = aExpr
overClause = choice [WindowOverClause <$> windowSpecification, ColIdOverClause <$> colId]
funcExprCommonSubexpr =
choice
[ CollationForFuncExprCommonSubexpr <$> aExpr,
pure CurrentDateFuncExprCommonSubexpr,
CurrentTimeFuncExprCommonSubexpr <$> maybe iconst,
CurrentTimestampFuncExprCommonSubexpr <$> maybe iconst,
LocalTimeFuncExprCommonSubexpr <$> maybe iconst,
LocalTimestampFuncExprCommonSubexpr <$> maybe iconst,
pure CurrentRoleFuncExprCommonSubexpr,
pure CurrentUserFuncExprCommonSubexpr,
pure SessionUserFuncExprCommonSubexpr,
pure UserFuncExprCommonSubexpr,
pure CurrentCatalogFuncExprCommonSubexpr,
pure CurrentSchemaFuncExprCommonSubexpr,
CastFuncExprCommonSubexpr <$> aExpr <*> typename,
ExtractFuncExprCommonSubexpr <$> maybe extractList,
OverlayFuncExprCommonSubexpr <$> overlayList,
PositionFuncExprCommonSubexpr <$> maybe positionList,
SubstringFuncExprCommonSubexpr <$> maybe substrList,
TreatFuncExprCommonSubexpr <$> aExpr <*> typename,
TrimFuncExprCommonSubexpr <$> maybe trimModifier <*> trimList,
NullIfFuncExprCommonSubexpr <$> aExpr <*> aExpr,
CoalesceFuncExprCommonSubexpr <$> exprList,
GreatestFuncExprCommonSubexpr <$> exprList,
LeastFuncExprCommonSubexpr <$> exprList
]
extractList = ExtractList <$> extractArg <*> aExpr
extractArg =
choice
[ IdentExtractArg <$> ident,
pure YearExtractArg,
pure MonthExtractArg,
pure DayExtractArg,
pure HourExtractArg,
pure MinuteExtractArg,
pure SecondExtractArg,
SconstExtractArg <$> sconst
]
overlayList = OverlayList <$> aExpr <*> overlayPlacing <*> substrFrom <*> maybe substrFor
overlayPlacing = aExpr
positionList = PositionList <$> bExpr <*> bExpr
substrList =
choice
[ ExprSubstrList <$> aExpr <*> substrListFromFor,
ExprListSubstrList <$> exprList
]
substrListFromFor =
choice
[ FromForSubstrListFromFor <$> substrFrom <*> substrFor,
ForFromSubstrListFromFor <$> substrFor <*> substrFrom,
FromSubstrListFromFor <$> substrFrom,
ForSubstrListFromFor <$> substrFor
]
substrFrom = aExpr
substrFor = aExpr
trimModifier = enumBounded
trimList =
choice
[ ExprFromExprListTrimList <$> aExpr <*> exprList,
FromExprListTrimList <$> exprList,
ExprListTrimList <$> exprList
]
-- * Operators
qualOp = choice [OpQualOp <$> op, OperatorQualOp <$> anyOperator]
qualAllOp =
choice
[ AllQualAllOp <$> allOp,
AnyQualAllOp <$> anyOperator
]
op = do
a <- text (Range.exponential 1 7) (element "+-*/<>=~!@#%^&|`?")
case Validation.op a of
Nothing -> return a
_ -> discard
anyOperator =
recursive
choice
[ AllOpAnyOperator <$> allOp
]
[ QualifiedAnyOperator <$> colId <*> anyOperator
]
allOp = choice [OpAllOp <$> op, MathAllOp <$> mathOp]
mathOp = enumBounded
symbolicExprBinOp =
choice
[ MathSymbolicExprBinOp <$> mathOp,
QualSymbolicExprBinOp <$> qualOp
]
binOp = element (toList KeywordSet.symbolicBinOp <> ["AND", "OR", "IS DISTINCT FROM", "IS NOT DISTINCT FROM"])
verbalExprBinOp = enumBounded
aExprReversableOp =
choice
[ pure NullAExprReversableOp,
pure TrueAExprReversableOp,
pure FalseAExprReversableOp,
pure UnknownAExprReversableOp,
DistinctFromAExprReversableOp <$> aExpr,
OfAExprReversableOp <$> typeList,
BetweenAExprReversableOp <$> bool <*> bExpr <*> aExpr,
BetweenSymmetricAExprReversableOp <$> bExpr <*> aExpr,
InAExprReversableOp <$> inExpr,
pure DocumentAExprReversableOp
]
bExprIsOp =
choice
[ DistinctFromBExprIsOp <$> bExpr,
OfBExprIsOp <$> typeList,
pure DocumentBExprIsOp
]
subqueryOp =
choice
[ AllSubqueryOp <$> allOp,
AnySubqueryOp <$> anyOperator,
LikeSubqueryOp <$> bool,
IlikeSubqueryOp <$> bool
]
-- * Constants
aexprConst =
choice
[ IAexprConst <$> iconst,
FAexprConst <$> fconst,
SAexprConst <$> sconst,
BAexprConst <$> text (Range.exponential 1 100) (element "01"),
XAexprConst <$> text (Range.exponential 1 100) (element "0123456789abcdefABCDEF"),
FuncAexprConst <$> funcName <*> maybe funcConstArgs <*> sconst,
ConstTypenameAexprConst <$> constTypename <*> sconst,
StringIntervalAexprConst <$> sconst <*> maybe interval,
IntIntervalAexprConst <$> integral (Range.exponential 0 2309482309483029) <*> sconst,
BoolAexprConst <$> bool,
pure NullAexprConst
]
funcConstArgs = FuncConstArgs <$> nonEmpty (Range.exponential 1 7) funcArgExpr <*> maybe sortClause
constTypename =
choice
[ NumericConstTypename <$> numeric,
ConstBitConstTypename <$> constBit,
ConstCharacterConstTypename <$> constCharacter,
ConstDatetimeConstTypename <$> constDatetime
]
numeric =
choice
[ pure IntNumeric,
pure IntegerNumeric,
pure SmallintNumeric,
pure BigintNumeric,
pure RealNumeric,
FloatNumeric <$> maybe iconst,
pure DoublePrecisionNumeric,
DecimalNumeric <$> maybe (nonEmpty (Range.exponential 1 7) (small aExpr)),
DecNumeric <$> maybe (nonEmpty (Range.exponential 1 7) (small aExpr)),
NumericNumeric <$> maybe (nonEmpty (Range.exponential 1 7) (small aExpr)),
pure BooleanNumeric
]
bit = Bit <$> bool <*> maybe (nonEmpty (Range.exponential 1 7) (small aExpr))
constBit = bit
constCharacter = ConstCharacter <$> character <*> maybe iconst
character =
choice
[ CharacterCharacter <$> bool,
CharCharacter <$> bool,
pure VarcharCharacter,
NationalCharacterCharacter <$> bool,
NationalCharCharacter <$> bool,
NcharCharacter <$> bool
]
constDatetime =
choice
[ TimestampConstDatetime <$> maybe iconst <*> maybe bool,
TimeConstDatetime <$> maybe iconst <*> maybe bool
]
interval =
choice
[ pure YearInterval,
pure MonthInterval,
pure DayInterval,
pure HourInterval,
pure MinuteInterval,
SecondInterval <$> intervalSecond,
pure YearToMonthInterval,
pure DayToHourInterval,
pure DayToMinuteInterval,
DayToSecondInterval <$> intervalSecond,
pure HourToMinuteInterval,
HourToSecondInterval <$> intervalSecond,
MinuteToSecondInterval <$> intervalSecond
]
intervalSecond = maybe iconst
sconst = text (Range.exponential 0 1000) unicode
iconstOrFconst = choice [Left <$> iconst <|> Right <$> fconst]
fconst =
filter (\a -> fromIntegral (round a) /= a) $
realFrac_ (Range.exponentialFloat 0 309457394857984375983475943)
iconst = integral (Range.exponential 0 maxBound)
-- * Types
nullable = pure False
arrayDimensionsAmount = int (Range.exponential 0 4)
-- ** Typename
typename = Typename <$> bool <*> simpleTypename <*> pure False <*> maybe ((,) <$> typenameArrayDimensions <*> pure False)
typenameArrayDimensions =
choice
[ BoundsTypenameArrayDimensions <$> arrayBounds,
ExplicitTypenameArrayDimensions <$> maybe iconst
]
arrayBounds = nonEmpty (Range.exponential 1 4) (maybe iconst)
simpleTypename =
choice
[ GenericTypeSimpleTypename <$> genericType,
NumericSimpleTypename <$> numeric,
BitSimpleTypename <$> bit,
CharacterSimpleTypename <$> character,
ConstDatetimeSimpleTypename <$> constDatetime,
ConstIntervalSimpleTypename <$> choice [Left <$> maybe interval, Right <$> iconst]
]
genericType = GenericType <$> typeFunctionName <*> maybe attrs <*> maybe typeModifiers
attrs = nonEmpty (Range.exponential 1 10) attrName
typeModifiers = exprList
typeList = nonEmpty (Range.exponential 1 7) typename
subType = enumBounded
-- * Names
columnref = Columnref <$> colId <*> maybe indirection
keywordNotInSet = \set -> notInSet set $ do
a <- element startList
b <- text (Range.linear 1 29) (element contList)
return (Text.cons a b)
where
startList = "abcdefghijklmnopqrstuvwxyz_" <> List.filter isLower (enumFromTo '\200' '\377')
contList = startList <> "0123456789$"
ident = identWithSet mempty
typeName = identWithSet KeywordSet.typeFunctionName
name = identWithSet KeywordSet.colId
cursorName = name
identWithSet set =
frequency
[ (95,) $ UnquotedIdent <$> (keywordNotInSet . HashSet.difference KeywordSet.keyword) set,
(5,) $ QuotedIdent <$> text (Range.linear 1 30) quotedChar
]
qualifiedName =
choice
[ SimpleQualifiedName <$> name,
IndirectedQualifiedName <$> name <*> indirection
]
indirection = nonEmpty (Range.linear 1 3) indirectionEl
indirectionEl =
choice
[ AttrNameIndirectionEl <$> name,
pure AllIndirectionEl,
ExprIndirectionEl <$> (small aExpr),
SliceIndirectionEl <$> maybe (small aExpr) <*> maybe (small aExpr)
]
quotedChar = filter (not . isControl) unicode
colId = name
colLabel = name
attrName = colLabel
typeFunctionName = name
funcName =
choice
[ TypeFuncName <$> typeFunctionName,
IndirectedFuncName <$> colId <*> indirection
]
anyName = AnyName <$> colId <*> maybe attrs
-- * Indexes
indexParams = nonEmpty (Range.exponential 1 5) indexElem
indexElem = IndexElem <$> indexElemDef <*> maybe collate <*> maybe class_ <*> maybe ascDesc <*> maybe nullsOrder
indexElemDef =
choice
[ IdIndexElemDef <$> colId,
FuncIndexElemDef <$> funcExprWindowless,
ExprIndexElemDef <$> aExpr
]
collate = anyName
class_ = anyName
ascDesc = enumBounded
nullsOrder = enumBounded