packages feed

project-m36 1.0.0 → 1.0.1

raw patch · 42 files changed

+285/−137 lines, 42 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- ProjectM36.SQL.Convert: aggregateFunctions :: [(FuncName, FunctionName)]
+ ProjectM36.AtomFunctionError: AtomFunctionAttributeNameNotFoundError :: Text -> AtomFunctionError
+ ProjectM36.AtomFunctionError: RelationAtomExpectedError :: Text -> AtomFunctionError
+ ProjectM36.AtomType: anyRelationAtomType :: AtomType
+ ProjectM36.Base: SubrelationAttributeAtomExpr :: AttributeName -> AttributeName -> AtomExprBase a
+ ProjectM36.Base: SubrelationFoldAtom :: !Relation -> !AttributeName -> Atom
+ ProjectM36.Base: SubrelationFoldAtomType :: AtomType -> AtomType
+ ProjectM36.Base: type AggAtomFuncExprInfo = (AttributeName, AttributeName)
+ ProjectM36.Client: SubrelationAttributeAtomExpr :: AttributeName -> AttributeName -> AtomExprBase a
+ ProjectM36.Client: SubrelationFoldAtom :: !Relation -> !AttributeName -> Atom
+ ProjectM36.Client: SubrelationFoldAtomType :: AtomType -> AtomType
+ ProjectM36.Client.Simple: SubrelationFoldAtom :: !Relation -> !AttributeName -> Atom
+ ProjectM36.Client.Simple: SubrelationFoldAtomType :: AtomType -> AtomType
+ ProjectM36.SQL.Convert: aggregateFunctionsMap :: [(FuncName, FunctionName)]
+ ProjectM36.SQL.Convert: func :: FunctionName -> [AtomExpr] -> AtomExpr
+ ProjectM36.Transaction.Persist: aggregateFunctionsPath :: FilePath -> FilePath
- ProjectM36.AtomFunctions.Primitive: relationMax :: Relation -> Either AtomFunctionError Atom
+ ProjectM36.AtomFunctions.Primitive: relationMax :: Relation -> AttributeName -> Either AtomFunctionError Atom
- ProjectM36.AtomFunctions.Primitive: relationMean :: Relation -> Either AtomFunctionError Atom
+ ProjectM36.AtomFunctions.Primitive: relationMean :: Relation -> AttributeName -> Either AtomFunctionError Atom
- ProjectM36.AtomFunctions.Primitive: relationMin :: Relation -> Either AtomFunctionError Atom
+ ProjectM36.AtomFunctions.Primitive: relationMin :: Relation -> AttributeName -> Either AtomFunctionError Atom
- ProjectM36.AtomFunctions.Primitive: relationSum :: Relation -> Either AtomFunctionError Atom
+ ProjectM36.AtomFunctions.Primitive: relationSum :: Relation -> AttributeName -> Either AtomFunctionError Atom
- ProjectM36.Base: AttributeAtomExpr :: !AttributeName -> AtomExprBase a
+ ProjectM36.Base: AttributeAtomExpr :: AttributeName -> AtomExprBase a
- ProjectM36.Base: DifferenceF :: r_aEOp -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: DifferenceF :: r_aFkX -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: EqualsF :: r_aEOp -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: EqualsF :: r_aFkX -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: ExistingRelationF :: Relation -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: ExistingRelationF :: Relation -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: ExtendF :: ExtendTupleExprBase a_asQw -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: ExtendF :: ExtendTupleExprBase a_atbU -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: FunctionAtomExpr :: FunctionName -> [AtomExprBase a] -> a -> AtomExprBase a
+ ProjectM36.Base: FunctionAtomExpr :: !FunctionName -> [AtomExprBase a] -> a -> AtomExprBase a
- ProjectM36.Base: GroupF :: AttributeNamesBase a_asQw -> Text -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: GroupF :: AttributeNamesBase a_atbU -> Text -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: JoinF :: r_aEOp -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: JoinF :: r_aFkX -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: MakeRelationFromExprsF :: Maybe [AttributeExprBase a_asQw] -> TupleExprsBase a_asQw -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: MakeRelationFromExprsF :: Maybe [AttributeExprBase a_atbU] -> TupleExprsBase a_atbU -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: MakeStaticRelationF :: Attributes -> RelationTupleSet -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: MakeStaticRelationF :: Attributes -> RelationTupleSet -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: NotEqualsF :: r_aEOp -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: NotEqualsF :: r_aFkX -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: ProjectF :: AttributeNamesBase a_asQw -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: ProjectF :: AttributeNamesBase a_atbU -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: RelationValuedAttributeF :: Text -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: RelationValuedAttributeF :: Text -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: RelationVariableF :: Text -> a_asQw -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: RelationVariableF :: Text -> a_atbU -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: RenameF :: Set (Text, Text) -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: RenameF :: Set (Text, Text) -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: RestrictF :: RestrictionPredicateExprBase a_asQw -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: RestrictF :: RestrictionPredicateExprBase a_atbU -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: UngroupF :: Text -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: UngroupF :: Text -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: UnionF :: r_aEOp -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: UnionF :: r_aFkX -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: WithF :: [(WithNameExprBase a_asQw, r_aEOp)] -> r_aEOp -> RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: WithF :: [(WithNameExprBase a_atbU, r_aFkX)] -> r_aFkX -> RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Base: data RelationalExprBaseF (a_asQw :: Type) r_aEOp
+ ProjectM36.Base: data RelationalExprBaseF (a_atbU :: Type) r_aFkX
- ProjectM36.Client: AttributeAtomExpr :: !AttributeName -> AtomExprBase a
+ ProjectM36.Client: AttributeAtomExpr :: AttributeName -> AtomExprBase a
- ProjectM36.Client: FunctionAtomExpr :: FunctionName -> [AtomExprBase a] -> a -> AtomExprBase a
+ ProjectM36.Client: FunctionAtomExpr :: !FunctionName -> [AtomExprBase a] -> a -> AtomExprBase a
- ProjectM36.SQL.Select: BetweenOperatorF :: r_a1HOQ -> r_a1HOQ -> r_a1HOQ -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: BetweenOperatorF :: r_a1JfP -> r_a1JfP -> r_a1JfP -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: BinaryOperatorF :: r_a1HOQ -> OperatorName -> r_a1HOQ -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: BinaryOperatorF :: r_a1JfP -> OperatorName -> r_a1JfP -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: BooleanLiteralF :: Bool -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: BooleanLiteralF :: Bool -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: BooleanOperatorExprF :: r_a1HOQ -> BoolOp -> r_a1HOQ -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: BooleanOperatorExprF :: r_a1JfP -> BoolOp -> r_a1JfP -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: CaseExprF :: [(r_a1HOQ, r_a1HOQ)] -> Maybe r_a1HOQ -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: CaseExprF :: [(r_a1JfP, r_a1JfP)] -> Maybe r_a1JfP -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: DoubleLiteralF :: Double -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: DoubleLiteralF :: Double -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: ExistsExprF :: Select -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: ExistsExprF :: Select -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: FunctionApplicationF :: FuncName -> [r_a1HOQ] -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: FunctionApplicationF :: FuncName -> [r_a1JfP] -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: IdentifierF :: n_a1xRE -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: IdentifierF :: n_a1ziD -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: InExprF :: InFlag -> r_a1HOQ -> InPredicateValue -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: InExprF :: InFlag -> r_a1JfP -> InPredicateValue -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: IntegerLiteralF :: Integer -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: IntegerLiteralF :: Integer -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: NullLiteralF :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: NullLiteralF :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: PostfixOperatorF :: r_a1HOQ -> OperatorName -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: PostfixOperatorF :: r_a1JfP -> OperatorName -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: PrefixOperatorF :: OperatorName -> r_a1HOQ -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: PrefixOperatorF :: OperatorName -> r_a1JfP -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: QuantifiedComparisonF :: r_a1HOQ -> ComparisonOperator -> QuantifiedComparisonPredicate -> Select -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: QuantifiedComparisonF :: r_a1JfP -> ComparisonOperator -> QuantifiedComparisonPredicate -> Select -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: StringLiteralF :: Text -> ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: StringLiteralF :: Text -> ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP
- ProjectM36.SQL.Select: [caseElseF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> Maybe r_a1HOQ
+ ProjectM36.SQL.Select: [caseElseF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> Maybe r_a1JfP
- ProjectM36.SQL.Select: [caseWhensF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> [(r_a1HOQ, r_a1HOQ)]
+ ProjectM36.SQL.Select: [caseWhensF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> [(r_a1JfP, r_a1JfP)]
- ProjectM36.SQL.Select: [qcExprF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> r_a1HOQ
+ ProjectM36.SQL.Select: [qcExprF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> r_a1JfP
- ProjectM36.SQL.Select: [qcOperatorF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> ComparisonOperator
+ ProjectM36.SQL.Select: [qcOperatorF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> ComparisonOperator
- ProjectM36.SQL.Select: [qcPredicateF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> QuantifiedComparisonPredicate
+ ProjectM36.SQL.Select: [qcPredicateF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> QuantifiedComparisonPredicate
- ProjectM36.SQL.Select: [qcQueryF] :: ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ -> Select
+ ProjectM36.SQL.Select: [qcQueryF] :: ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP -> Select
- ProjectM36.SQL.Select: data ScalarExprBaseF (n_a1xRE :: Type) r_a1HOQ
+ ProjectM36.SQL.Select: data ScalarExprBaseF (n_a1ziD :: Type) r_a1JfP

Files

Changelog.markdown view
@@ -1,3 +1,7 @@+# 2024-07-15 (v1.0.1)++* add support for aggregate functions using sub-relation attributes+ # 2024-06-06 (v1.0.0)  * add support for relational expression evaluation against sub-relations
project-m36.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: 2.2 Name: project-m36-Version: 1.0.0+Version: 1.0.1 License: MIT --note that this license specification is erroneous and only labeled MIT to appease hackage which does not recognize public domain packages in cabal >2.2- Project:M36 is dedicated to the public domain Build-Type: Simple
src/bin/TutorialD/Interpreter/Base.hs view
@@ -69,10 +69,12 @@   istart <- letterChar <|> char '_'   identifierRemainder istart +identifierP :: Parser Text+identifierP = identifier <* spaceConsumer+ identifierRemainder :: Char -> Parser Text identifierRemainder c = do   rest <- many (alphaNumChar <|> char '_' <|> char '#')-  spaceConsumer   pure (pack (c:rest))  symbol :: ParseStr -> Parser Text
src/bin/TutorialD/Interpreter/DatabaseContextExpr.hs view
@@ -98,7 +98,7 @@ addConstraintP :: Parser DatabaseContextExpr addConstraintP = do   reservedOp "constraint" <|> reservedOp "foreign key"-  constraintName <- identifier+  constraintName <- identifierP   subset <- relExprP   op <- (reservedOp "in" $> SubsetOp) <|> (reservedOp "equals" $> EqualityOp)   superset <- relExprP@@ -112,13 +112,13 @@ deleteConstraintP :: Parser DatabaseContextExpr   deleteConstraintP = do   reserved "deleteconstraint"-  RemoveInclusionDependency <$> identifier+  RemoveInclusionDependency <$> identifierP    -- key <constraint name> {<uniqueness attributes>} <uniqueness relexpr> keyP :: Parser DatabaseContextExpr   keyP = do   reserved "key"-  keyName <- identifier+  keyName <- identifierP   uniquenessAttrNames <- braces attributeListP   uniquenessExpr <- relExprP   let newIncDep = inclusionDependencyForKey uniquenessAttrNames uniquenessExpr@@ -127,7 +127,7 @@ funcDepP :: Parser DatabaseContextExpr   funcDepP = do   reserved "funcdep"-  keyName <- identifier+  keyName <- identifierP   source <- parens attributeListP   reserved "->"   dependents <- parens attributeListP@@ -141,7 +141,7 @@    attributeAssignmentP :: Parser (AttributeName, AtomExpr) attributeAssignmentP = do-  attrName <- identifier+  attrName <- identifierP   reservedOp ":="   atomExpr <- atomExprP   pure (attrName, atomExpr)@@ -149,7 +149,7 @@ addNotificationP :: Parser DatabaseContextExpr addNotificationP = do   reserved "notify"-  notName <- identifier+  notName <- identifierP   triggerExpr <- relExprP    resultOldExpr <- relExprP   AddNotification notName triggerExpr resultOldExpr <$> relExprP@@ -157,7 +157,7 @@ removeNotificationP :: Parser DatabaseContextExpr   removeNotificationP = do   reserved "unnotify"-  RemoveNotification <$> identifier+  RemoveNotification <$> identifierP  -- | data Hair = Bald | Color Text addTypeConstructorP :: Parser DatabaseContextExpr
src/bin/TutorialD/Interpreter/DatabaseContextIOOperator.hs view
@@ -15,7 +15,7 @@ createArbitraryRelationP :: Parser DatabaseContextIOExpr createArbitraryRelationP = do   reserved "createarbitraryrelation"-  relVarName <- identifier+  relVarName <- identifierP   attrExprs <- makeAttributeExprsP :: Parser [AttributeExpr]   min' <- fromInteger <$> integer   _ <- symbol "-"
src/bin/TutorialD/Interpreter/Import/BasicExamples.hs view
@@ -20,7 +20,7 @@ importBasicExampleOperatorP :: Parser ImportBasicExampleOperator importBasicExampleOperatorP = do    reservedOp ":importexample"-  example <- identifier+  example <- identifierP   if example == "cjdate" then     pure ImportBasicDateExampleOperator     else
src/bin/TutorialD/Interpreter/Import/CSV.hs view
@@ -25,6 +25,6 @@   reserved ":importcsv"   path <- quotedString   spaceConsumer-  relVarName <- identifier+  relVarName <- identifierP   return $ RelVarDataImportOperator relVarName (T.unpack path) importCSVRelation   
src/bin/TutorialD/Interpreter/RODatabaseContextOperator.hs view
@@ -73,7 +73,7 @@ showConstraintsP :: Parser RODatabaseContextOperator showConstraintsP = do   colonOp ":constraints"-  ShowConstraints <$> option "" identifier+  ShowConstraints <$> option "" identifierP    plotRelExprP :: Parser RODatabaseContextOperator   plotRelExprP = do@@ -227,7 +227,7 @@ attrOrdersExprP = reserved "orderby" *> braces (sepBy attrOrderExprP comma)  attrOrderExprP :: Parser DF.AttributeOrderExpr-attrOrderExprP = DF.AttributeOrderExpr <$> identifier <*> orderP+attrOrderExprP = DF.AttributeOrderExpr <$> identifierP <*> orderP  orderP :: Parser DF.Order orderP = try (reservedOp "ascending" >> pure DF.AscendingOrder) <|> try (reservedOp "descending" >> pure DF.DescendingOrder) <|> pure DF.AscendingOrder
src/bin/TutorialD/Interpreter/RelationalExpr.hs view
@@ -15,6 +15,7 @@ import qualified Data.Map as M import Data.List (sort) import ProjectM36.MiscUtils+import Control.Monad (void)  --used in projection attributeListP :: RelationalMarkerExpr a => Parser (AttributeNamesBase a)@@ -207,14 +208,16 @@ atomExprP = consumeAtomExprP True  consumeAtomExprP :: RelationalMarkerExpr a => Bool -> Parser (AtomExprBase a)-consumeAtomExprP consume = try functionAtomExprP <|>-            ifThenAtomExprP <|>  -            boolAtomExprP <|> -- we do this before the constructed atom parser to consume True and False -            try (parens (constructedAtomExprP True)) <|>-            constructedAtomExprP consume <|>-            relationalAtomExprP <|>-            attributeAtomExprP <|>-            try nakedAtomExprP+consumeAtomExprP consume =+  try functionAtomExprP <|>+  ifThenAtomExprP <|>  +  boolAtomExprP <|> -- we do this before the constructed atom parser to consume True and False +  try (parens (constructedAtomExprP True)) <|>+  constructedAtomExprP consume <|>+  try subrelationAttributeExprP <|>  +  relationalAtomExprP <|>+  attributeAtomExprP <|>+  try nakedAtomExprP  attributeAtomExprP :: Parser (AtomExprBase a) attributeAtomExprP = do@@ -247,6 +250,26 @@   reserved "else"   IfThenAtomExpr ifE thenE <$> atomExprP ++-- "@relattr.subrelattr"+subrelationAttributeNameP :: Parser (AttributeName, AttributeName)+subrelationAttributeNameP = do+  void $ single '@'+  relAttr <- uncapitalizedOrQuotedIdentifier+  void $ single '.'+  subrelAttr <- uncapitalizedOrQuotedIdentifier+  spaceConsumer+  pure (relAttr, subrelAttr)++subrelationAttributeExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a)+subrelationAttributeExprP = do+  void $ single '@'+  relAttr <- uncapitalizedOrQuotedIdentifier+  void $ single '.'+  subrelAttr <- uncapitalizedOrQuotedIdentifier+  spaceConsumer+  pure (SubrelationAttributeAtomExpr relAttr subrelAttr)+ functionAtomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a) functionAtomExprP =   FunctionAtomExpr <$> functionNameP <*> parens (sepBy atomExprP comma) <*> parseMarkerP@@ -291,7 +314,7 @@  createMacroP :: RelationalMarkerExpr a => Parser (WithNameExprBase a, RelationalExprBase a) createMacroP = do -  name <- identifier+  name <- identifierP   reservedOp "as"   expr <- relExprP   marker <- parseMarkerP
src/bin/TutorialD/Interpreter/SchemaOperator.hs view
@@ -19,7 +19,7 @@ setCurrentSchemaP :: Parser SchemaOperator setCurrentSchemaP = do   reserved ":setschema"-  SetCurrentSchema <$> identifier+  SetCurrentSchema <$> identifierP    schemaExprP :: Parser SchemaExpr schemaExprP = addSubschemaP <|>@@ -28,7 +28,7 @@ addSubschemaP :: Parser SchemaExpr addSubschemaP = do   reserved ":addschema"-  AddSubschema <$> identifier <*> parens (sepBy schemaIsomorphP comma)+  AddSubschema <$> identifierP <*> parens (sepBy schemaIsomorphP comma)    schemaIsomorphP :: Parser SchemaIsomorph   schemaIsomorphP = isoRestrictP <|> isoUnionP <|> isoRenameP <|> isoPassthrough
src/bin/TutorialD/Interpreter/TransGraphRelationalOperator.hs view
@@ -20,7 +20,7 @@  transactionIdLookupP :: Parser TransactionIdLookup transactionIdLookupP =  (TransactionIdLookup <$> uuidP) <|>-                        (TransactionIdHeadNameLookup <$> identifier <*> many transactionIdHeadBacktrackP)+                        (TransactionIdHeadNameLookup <$> identifierP <*> many transactionIdHeadBacktrackP)                          transactionIdHeadBacktrackP :: Parser TransactionIdHeadBacktrack                         transactionIdHeadBacktrackP = (string "~" *> (TransactionIdHeadParentBacktrack <$> backtrackP)) <|>
src/bin/TutorialD/Interpreter/TransactionGraphOperator.hs view
@@ -17,12 +17,12 @@ autoMergeToHeadP :: Parser ConvenienceTransactionGraphOperator autoMergeToHeadP = do   reserved ":automergetohead"-  AutoMergeToHead <$> mergeTransactionStrategyP <*> identifier+  AutoMergeToHead <$> mergeTransactionStrategyP <*> identifierP  jumpToHeadP :: Parser TransactionGraphOperator jumpToHeadP = do   reservedOp ":jumphead"-  JumpToHead <$> identifier+  JumpToHead <$> identifierP  jumpToTransactionP :: Parser TransactionGraphOperator jumpToTransactionP = do@@ -37,12 +37,12 @@ branchTransactionP :: Parser TransactionGraphOperator branchTransactionP = do   reservedOp ":branch"-  Branch <$> identifier+  Branch <$> identifierP  deleteBranchP :: Parser TransactionGraphOperator deleteBranchP = do   reserved ":deletebranch"-  DeleteBranch <$> identifier+  DeleteBranch <$> identifierP  commitTransactionP :: Parser TransactionGraphOperator commitTransactionP = do@@ -63,15 +63,15 @@ mergeTransactionStrategyP = (reserved "union" $> UnionMergeStrategy) <|>                             (do                                 reserved "selectedbranch"-                                SelectedBranchMergeStrategy <$> identifier) <|>+                                SelectedBranchMergeStrategy <$> identifierP) <|>                             (do                                 reserved "unionpreferbranch"-                                UnionPreferMergeStrategy <$> identifier)+                                UnionPreferMergeStrategy <$> identifierP)    mergeTransactionsP :: Parser TransactionGraphOperator mergeTransactionsP = do   reservedOp ":mergetrans"-  MergeTransactions <$> mergeTransactionStrategyP <*> identifier <*> identifier+  MergeTransactions <$> mergeTransactionStrategyP <*> identifierP <*> identifierP  validateMerkleHashesP :: Parser ROTransactionGraphOperator validateMerkleHashesP = reservedOp ":validatemerklehashes" $> ValidateMerkleHashes
src/bin/TutorialD/Interpreter/Types.hs view
@@ -13,20 +13,25 @@   parseMarkerP = pure ()  typeConstructorNameP :: Parser TypeConstructorName-typeConstructorNameP = capitalizedIdentifier+typeConstructorNameP = capitalizedIdentifier <* spaceConsumer  dataConstructorNameP :: Parser DataConstructorName dataConstructorNameP = try $ do-  ident <- capitalizedIdentifier+  ident <- capitalizedIdentifier <* spaceConsumer   when (ident `elem` ["True", "False"]) $ failure Nothing mempty --don't parse True or False as ConstructedAtoms (use NakedAtoms instead)   pure ident  attributeNameP :: Parser AttributeName-attributeNameP = try uncapitalizedIdentifier <|> quotedIdentifier+attributeNameP = uncapitalizedOrQuotedIdentifier <* spaceConsumer  functionNameP :: Parser FunctionName-functionNameP = try uncapitalizedIdentifier <|> quotedIdentifier+functionNameP = uncapitalizedOrQuotedIdentifier <* spaceConsumer +-- does not consumer following spaces+uncapitalizedOrQuotedIdentifier :: Parser StringType+uncapitalizedOrQuotedIdentifier =+  try uncapitalizedIdentifier <|> quotedIdentifier+ -- | Upper case names are type names while lower case names are polymorphic typeconstructor arguments. -- data *Either a b* = Left a | Right b typeConstructorDefP :: Parser TypeConstructorDef@@ -58,10 +63,10 @@ attributeAndTypeNameP = AttributeAndTypeNameExpr <$> attributeNameP <*> typeConstructorP <*> parseMarkerP  typeIdentifierP :: Parser TypeConstructorName-typeIdentifierP = capitalizedIdentifier+typeIdentifierP = capitalizedIdentifier <* spaceConsumer  typeVariableIdentifierP :: Parser TypeVarName-typeVariableIdentifierP = uncapitalizedIdentifier+typeVariableIdentifierP = uncapitalizedIdentifier <* spaceConsumer                              -- *Either Int Text*, *Int* typeConstructorP :: Parser TypeConstructor                  @@ -75,4 +80,4 @@                      relVarNameP :: Parser RelVarName-relVarNameP = try uncapitalizedIdentifier <|> quotedIdentifier+relVarNameP = uncapitalizedOrQuotedIdentifier <* spaceConsumer
src/bin/TutorialD/Printer.hs view
@@ -40,10 +40,12 @@   pretty (UUIDAtom u) = pretty u   pretty (RelationAtom x) = pretty x   pretty (RelationalExprAtom re) = pretty re+  pretty (SubrelationFoldAtom _rel _subAttr) = "SubrelationFoldAtom" -- this is only used as an argument to aggregate functions, so users should never be able to construct it directly   pretty (ConstructedAtom n _ as) = pretty n <+> prettyList as  instance Pretty AtomExpr where-  pretty (AttributeAtomExpr attrName) = prettyAttributeName ("@" <> attrName)+  pretty (AttributeAtomExpr attrName) = "@" <> prettyAttributeName attrName+  pretty (SubrelationAttributeAtomExpr relAttr subAttr) = "@" <> prettyAttributeName relAttr <> "." <> prettyAttributeName subAttr   pretty (NakedAtomExpr atom)         = pretty atom   pretty (FunctionAtomExpr atomFuncName' atomExprs _) = pretty atomFuncName' <> prettyAtomExprsAsArguments atomExprs   pretty (RelationAtomExpr relExpr) = pretty relExpr@@ -154,6 +156,7 @@   pretty BoolAtomType = "Bool"   pretty UUIDAtomType = "UUID"   pretty (RelationAtomType attrs) = "relation " <+> prettyBracesList (A.toList attrs)+  pretty (SubrelationFoldAtomType typ) = "SubRelationFoldAtomType" <+> pretty typ   pretty (ConstructedAtomType tcName tvMap) = pretty tcName <+> hsep (map pretty (M.toList tvMap)) --order matters   pretty RelationalExprAtomType = "RelationalExpr"   pretty (TypeVariableType x) = pretty x
src/lib/ProjectM36/Arbitrary.hs view
@@ -3,6 +3,7 @@  module ProjectM36.Arbitrary where import ProjectM36.Base+import qualified ProjectM36.Attribute as A import ProjectM36.Error import ProjectM36.AtomFunctionError import ProjectM36.AtomType@@ -28,11 +29,20 @@   Right . ScientificAtom <$> lift (arbitrary :: Gen Scientific)  arbitrary' (RelationAtomType attrs)  = do-  tcMap <-ask+  tcMap <- ask   maybeRel <- lift $ runReaderT (arbitraryRelation attrs (0,5)) tcMap   case maybeRel of     Left err -> pure $ Left err     Right rel -> pure $ Right $ RelationAtom rel++arbitrary' (SubrelationFoldAtomType typ) = do+  tcMap <- ask+  maybeRel <- lift $ runReaderT (arbitraryRelation (A.attributesFromList [Attribute "a" typ]) (0,5)) tcMap+  case maybeRel of+    Left err -> pure $ Left err+    Right rel -> do+      anAttr <- lift $ elements (A.attributeNamesList (attributes rel))+      pure (Right (SubrelationFoldAtom rel anAttr))  arbitrary' IntAtomType =    Right . IntAtom <$> lift (arbitrary :: Gen Int)
src/lib/ProjectM36/Atom.hs view
@@ -23,7 +23,7 @@ atomToText (BoolAtom i) = (T.pack . show) i atomToText (UUIDAtom u) = (T.pack . show) u atomToText (RelationalExprAtom re) = (T.pack . show) re-+atomToText (SubrelationFoldAtom rel attrName) = (T.pack . show) rel <> " @" <> attrName atomToText (RelationAtom i) = (T.pack . show) i atomToText (ConstructedAtom dConsName typ atoms)    | isIntervalAtomType typ = case atoms of --special handling for printing intervals
src/lib/ProjectM36/AtomFunction.hs view
@@ -13,7 +13,9 @@  foldAtomFuncType :: AtomType -> AtomType -> [AtomType] --the underscore in the attribute name means that any attributes are acceptable-foldAtomFuncType foldType returnType = [RelationAtomType (A.attributesFromList [Attribute "_" foldType]), returnType]+foldAtomFuncType foldType returnType =+  [SubrelationFoldAtomType foldType,+   returnType]  atomFunctionForName :: FunctionName -> AtomFunctions -> Either RelationalError AtomFunction atomFunctionForName funcName' funcSet = if HS.null foundFunc then
src/lib/ProjectM36/AtomFunctionError.hs view
@@ -9,11 +9,13 @@                          AtomFunctionParseError String |                          InvalidIntervalOrderingError |                          InvalidIntervalBoundariesError |+                         AtomFunctionAttributeNameNotFoundError Text |                          InvalidIntBoundError |                          InvalidUUIDString Text |+                         RelationAtomExpectedError Text |                          AtomFunctionEmptyRelationError |                          AtomTypeDoesNotSupportOrderingError Text |                          AtomTypeDoesNotSupportIntervalError Text |                          AtomFunctionBytesDecodingError String-                       deriving(Generic, Eq, Show, NFData)+                       deriving (Generic, Eq, Show, NFData) 
src/lib/ProjectM36/AtomFunctions/Primitive.hs view
@@ -4,8 +4,8 @@ import ProjectM36.Tuple import ProjectM36.AtomFunctionError import ProjectM36.AtomFunction+import ProjectM36.AtomType import qualified Data.HashSet as HS-import qualified Data.Vector as V import Control.Monad import qualified Data.UUID as U import qualified Data.Text as T@@ -35,23 +35,24 @@                                )},     Function { funcName = "sum",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body $ relationAtomFunc relationSum+               funcBody = body $ relationFoldFunc relationSum              },     Function { funcName = "count",-               funcType = foldAtomFuncType (TypeVariableType "a") IntegerAtomType,+               funcType = [anyRelationAtomType,+                           IntegerAtomType],                funcBody = body $ relationAtomFunc relationCount              },     Function { funcName = "max",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body $ relationAtomFunc relationMax +               funcBody = body $ relationFoldFunc relationMax               },     Function { funcName = "min",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body $ relationAtomFunc relationMin+               funcBody = body $ relationFoldFunc relationMin              },     Function { funcName = "mean",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body $ relationAtomFunc relationMean+               funcBody = body $ relationFoldFunc relationMean              },     Function { funcName = "eq",                funcType = [TypeVariableType "a", TypeVariableType "a", BoolAtomType],@@ -117,13 +118,21 @@                  [BoolAtom b1, BoolAtom b2] ->                    Right $ BoolAtom (b1 || b2)                  _ -> Left AtomFunctionTypeMismatchError                   +             },+    Function { funcName = "increment",+               funcType = [IntegerAtomType, IntegerAtomType],+               funcBody = body $ \case+                 [IntegerAtom i] -> pure (IntegerAtom (i+1))+                 _ -> Left AtomFunctionTypeMismatchError              }        ] <> scientificAtomFunctions   where     body = FunctionBuiltInBody-    relationAtomFunc f [RelationAtom x] = f x+    relationAtomFunc f [RelationAtom rel] = f rel     relationAtomFunc _ _ = Left AtomFunctionTypeMismatchError+    relationFoldFunc f [SubrelationFoldAtom rel subAttr] = f rel subAttr+    relationFoldFunc _ _ = Left AtomFunctionTypeMismatchError                           integerAtomFuncLessThan :: Bool -> [Atom] -> Either AtomFunctionError Atom integerAtomFuncLessThan equality (IntegerAtom i1:IntegerAtom i2:_) = pure (BoolAtom (i1 `op` i2))@@ -136,35 +145,48 @@ boolAtomNot _ = error "boolAtomNot called on non-Bool atom"  --used by sum atom function-relationSum :: Relation -> Either AtomFunctionError Atom-relationSum relIn = pure (IntegerAtom (relFold (\tupIn acc -> acc + newVal tupIn) 0 relIn))+relationSum :: Relation -> AttributeName -> Either AtomFunctionError Atom+relationSum relIn subAttr = pure (IntegerAtom (relFold (\tupIn acc -> acc + newVal tupIn) 0 relIn))   where     --extract Integer from Atom-    newVal tupIn = castInteger (tupleAtoms tupIn V.! 0)+    newVal tupIn =+      case atomForAttributeName subAttr tupIn of+        Left err -> error (show err)+        Right atom -> castInteger atom      relationCount :: Relation -> Either AtomFunctionError Atom relationCount relIn = pure (IntegerAtom (relFold (\_ acc -> acc + 1) (0::Integer) relIn)) -relationMax :: Relation -> Either AtomFunctionError Atom-relationMax relIn = case oneTuple relIn of+relationMax :: Relation -> AttributeName -> Either AtomFunctionError Atom+relationMax relIn subAttr = case oneTuple relIn of     Nothing -> Left AtomFunctionEmptyRelationError     Just oneTup -> pure (IntegerAtom (relFold (\tupIn acc -> max acc (newVal tupIn)) (newVal oneTup) relIn))   where-    newVal tupIn = castInteger (tupleAtoms tupIn V.! 0)+    newVal tupIn =+      case atomForAttributeName subAttr tupIn of+        Left err -> error (show err)+        Right atom -> castInteger atom -relationMin :: Relation -> Either AtomFunctionError Atom-relationMin relIn = case oneTuple relIn of +relationMin :: Relation -> AttributeName -> Either AtomFunctionError Atom+relationMin relIn subAttr = case oneTuple relIn of    Nothing -> Left AtomFunctionEmptyRelationError   Just oneTup -> pure (IntegerAtom (relFold (\tupIn acc -> min acc (newVal tupIn)) (newVal oneTup) relIn))   where-    newVal tupIn = castInteger (tupleAtoms tupIn V.! 0)+    newVal tupIn =+      case atomForAttributeName subAttr tupIn of+        Left err -> error (show err)+        Right atom -> castInteger atom -relationMean :: Relation -> Either AtomFunctionError Atom-relationMean relIn = case oneTuple relIn of++relationMean :: Relation -> AttributeName -> Either AtomFunctionError Atom+relationMean relIn subAttr = case oneTuple relIn of   Nothing -> Left AtomFunctionEmptyRelationError   Just _oneTup -> do     let (sum'', count') = relFold (\tupIn (sum', count) -> (sum' + newVal tupIn, count + 1)) (0, 0) relIn-        newVal tupIn = castInteger (tupleAtoms tupIn V.! 0)+        newVal tupIn =+          case atomForAttributeName subAttr tupIn of+            Left err -> error (show err)+            Right atom -> castInteger atom     pure (IntegerAtom (sum'' `div` count'))      @@ -174,7 +196,7 @@  castInteger :: Atom -> Integer castInteger (IntegerAtom i) = i -castInteger _ = error "attempted to cast non-IntegerAtom to Int"+castInteger _ = error "attempted to cast non-IntegerAtom to Integer"   scientificAtomFunctions :: AtomFunctions
src/lib/ProjectM36/AtomType.hs view
@@ -358,6 +358,9 @@                                else                                  atomTypeVerify (A.atomType attr1) (A.atomType attr2)) $ V.toList (V.zip (attributesVec attrs1) (attributesVec attrs2))   return x+atomTypeVerify (SubrelationFoldAtomType typ1) (SubrelationFoldAtomType typ2) = do+  resTyp <- atomTypeVerify typ1 typ2+  pure (SubrelationFoldAtomType resTyp) atomTypeVerify x y = if x == y then                        Right x                      else@@ -448,6 +451,7 @@     RelationalExprAtomType -> True     RelationAtomType attrs -> isResolvedAttributes attrs     ConstructedAtomType _ tvMap -> all isResolvedType (M.elems tvMap)+    SubrelationFoldAtomType typ' -> isResolvedType typ'     TypeVariableType _ -> False  isResolvedAttributes :: Attributes -> Bool@@ -456,4 +460,5 @@ isResolvedAttribute :: Attribute -> Bool isResolvedAttribute = isResolvedType . A.atomType ---given two AtomTypes x,y+anyRelationAtomType :: AtomType+anyRelationAtomType = RelationAtomType (A.attributesFromList [Attribute "_" (TypeVariableType "a")])
src/lib/ProjectM36/Atomable.hs view
@@ -256,6 +256,8 @@   = RelationAtomTypeConstructor $ map attrToAttrExpr $ V.toList (attributesVec attrs)   where     attrToAttrExpr (Attribute n t) = AttributeAndTypeNameExpr n (typeToTypeConstructor t) ()+typeToTypeConstructor (SubrelationFoldAtomType _typ) =+  error "typeToTypeConstructor for SubrelationFoldAtomType is nonsense" typeToTypeConstructor (ConstructedAtomType tcName tvMap)   = ADTypeConstructor tcName $ map typeToTypeConstructor (M.elems tvMap) typeToTypeConstructor (TypeVariableType tvName) = TypeVariable tvName
src/lib/ProjectM36/Base.hs view
@@ -67,6 +67,7 @@             UUIDAtom !UUID |             RelationAtom !Relation |             RelationalExprAtom !RelationalExpr | --used for returning inc deps+            SubrelationFoldAtom !Relation !AttributeName |             ConstructedAtom !DataConstructorName !AtomType [Atom]             deriving (Eq, Show, Typeable, NFData, Generic, Read)                      @@ -85,6 +86,7 @@   hashWithSalt salt (UUIDAtom u) = salt `hashWithSalt` u   hashWithSalt salt (RelationAtom r) = salt `hashWithSalt` r   hashWithSalt salt (RelationalExprAtom re) = salt `hashWithSalt` re+  hashWithSalt salt (SubrelationFoldAtom rel attrName) = salt `hashWithSalt` rel `hashWithSalt` attrName  -- I suspect the definition of ConstructedAtomType with its name alone is insufficient to disambiguate the cases; for example, one could create a type named X, remove a type named X, and re-add it using different constructors. However, as long as requests are served from only one DatabaseContext at-a-time, the type name is unambiguous. This will become a problem for time-travel, however. -- | The AtomType uniquely identifies the type of a atom.@@ -99,6 +101,7 @@                 BoolAtomType |                 UUIDAtomType |                 RelationAtomType Attributes |+                SubrelationFoldAtomType AtomType |                 ConstructedAtomType TypeConstructorName TypeVarMap |                 RelationalExprAtomType |                 TypeVariableType TypeVarName@@ -233,9 +236,9 @@   --relational variables should also be able to be explicitly-typed like in Haskell   --- | Reference a relation variable by its name.   RelationVariable RelVarName a |   -  --- | Create a projection over attribute names. (Note that the 'AttributeNames' structure allows for the names to be inverted.)+  -- | Extract a relation from an `Atom` that is a nested relation (a relation within a relation).     RelationValuedAttribute AttributeName |-  -- | Extract a relation from an `Atom` that is a nested relation (a relation within a relation).+  --- | Create a projection over attribute names. (Note that the 'AttributeNames' structure allows for the names to be inverted.)     Project (AttributeNamesBase a) (RelationalExprBase a) |   --- | Create a union of two relational expressions. The expressions should have identical attributes.   Union (RelationalExprBase a) (RelationalExprBase a) |@@ -504,10 +507,14 @@  type GraphRefAtomExpr = AtomExprBase GraphRefTransactionMarker +type AggAtomFuncExprInfo = (AttributeName, AttributeName) -- (relvar attribute name, subrel attribute name)+ -- | An atom expression represents an action to take when extending a relation or when statically defining a relation or a new tuple.-data AtomExprBase a = AttributeAtomExpr !AttributeName |+data AtomExprBase a = AttributeAtomExpr AttributeName |+                      SubrelationAttributeAtomExpr AttributeName AttributeName |                       NakedAtomExpr !Atom |-                      FunctionAtomExpr FunctionName [AtomExprBase a] a |+                      FunctionAtomExpr !FunctionName [AtomExprBase a] a |+                      -- as a simple, first aggregation case, we can only apply an aggregation to a RelationAtom while "selecting" one attribute                       RelationAtomExpr (RelationalExprBase a) |                       IfThenAtomExpr (AtomExprBase a) (AtomExprBase a) (AtomExprBase a) | -- if, then, else                       ConstructedAtomExpr DataConstructorName [AtomExprBase a] a@@ -653,6 +660,7 @@   BoolAtomType -> S.empty   UUIDAtomType -> S.empty   RelationalExprAtomType -> S.empty+  SubrelationFoldAtomType{} -> S.empty   (RelationAtomType attrs) -> S.unions (map attrTypeVars (V.toList (attributesVec attrs)))   (ConstructedAtomType _ tvMap) -> M.keysSet tvMap   (TypeVariableType nam) -> S.singleton nam@@ -679,6 +687,7 @@ atomTypeVars BoolAtomType = S.empty atomTypeVars UUIDAtomType = S.empty atomTypeVars RelationalExprAtomType = S.empty+atomTypeVars SubrelationFoldAtomType{} = S.empty atomTypeVars (RelationAtomType attrs) = S.unions (map attrTypeVars (V.toList (attributesVec attrs))) atomTypeVars (ConstructedAtomType _ tvMap) = M.keysSet tvMap atomTypeVars (TypeVariableType nam) = S.singleton nam
src/lib/ProjectM36/DataTypes/Interval.hs view
@@ -40,6 +40,7 @@   RelationAtomType _ -> False   ConstructedAtomType _ _ -> False --once we support an interval-style typeclass, we might enable this   RelationalExprAtomType -> False+  SubrelationFoldAtomType{} -> False   TypeVariableType _ -> False    supportsOrdering :: AtomType -> Bool  @@ -56,6 +57,7 @@   UUIDAtomType -> False   RelationAtomType _ -> False   RelationalExprAtomType -> False+  SubrelationFoldAtomType{} -> False   ConstructedAtomType _ _ -> False --once we support an interval-style typeclass, we might enable this   TypeVariableType _ -> False   
src/lib/ProjectM36/DataTypes/Primitive.hs view
@@ -51,3 +51,4 @@ atomTypeForAtom (RelationAtom (Relation attrs _)) = RelationAtomType attrs atomTypeForAtom (ConstructedAtom _ aType _) = aType atomTypeForAtom (RelationalExprAtom _) = RelationalExprAtomType+atomTypeForAtom (SubrelationFoldAtom _ _) = SubrelationFoldAtomType (TypeVariableType "a")
src/lib/ProjectM36/DataTypes/SQL/Null.hs view
@@ -4,7 +4,6 @@ import qualified Data.Map as M import qualified Data.HashSet as HS import ProjectM36.DataTypes.Primitive-import qualified Data.Vector as V import ProjectM36.AtomFunction import ProjectM36.Tuple import ProjectM36.Relation@@ -264,7 +263,7 @@ sqlSum = sqlIntegerAgg (+)  sqlIntegerAgg :: (Integer -> Integer -> Integer) -> [Atom] -> Either AtomFunctionError Atom-sqlIntegerAgg op [RelationAtom relIn] =+sqlIntegerAgg op [SubrelationFoldAtom relIn subAttr] =   case oneTuple relIn of     Nothing -> pure $ nullAtom IntegerAtomType Nothing -- SQL max/min of empty table is NULL     Just oneTup ->@@ -273,7 +272,10 @@         else         pure $ relFold (\tupIn acc -> nullMax acc (newVal tupIn)) (newVal oneTup) relIn  where-   newVal tupIn = tupleAtoms tupIn V.! 0+   newVal tupIn =+      case atomForAttributeName subAttr tupIn of+        Left err -> error (show err)+        Right atom -> atom    nullMax acc nextVal =      let mNextVal = sqlNullableIntegerToMaybe nextVal          mOldVal = sqlNullableIntegerToMaybe acc
src/lib/ProjectM36/DataTypes/Sorting.hs view
@@ -30,6 +30,8 @@   UUIDAtomType -> False   RelationalExprAtomType -> False   RelationAtomType _ -> False+  SubrelationFoldAtomType{} -> False   ConstructedAtomType _ _ -> False   TypeVariableType _ -> False+     
src/lib/ProjectM36/FunctionalDependency.hs view
src/lib/ProjectM36/HashSecurely.hs view
@@ -50,6 +50,7 @@       UUIDAtom u -> up ("UUIDAtom" <> BL.toStrict (UUID.toByteString u))       RelationAtom r -> hashBytesL ctx "RelationAtom" [SHash r]       RelationalExprAtom e -> hashBytesL ctx "RelationalExprAtom" [SHash e]+      SubrelationFoldAtom rel subAttr -> hashBytesL ctx "SubrelationFoldAtom" [SHash rel, SHash subAttr]       ConstructedAtom d typ args ->           hashBytesL ctx "ConstructedAtom" ([SHash d, SHash typ] <> map SHash args)       where@@ -138,6 +139,7 @@   hashBytes atomExpr ctx =     case atomExpr of       (AttributeAtomExpr a) -> hashBytesL ctx "AttributeAtomExpr" [SHash a]+      (SubrelationAttributeAtomExpr relAttr subAttr) -> hashBytesL ctx "SubrelationAttributeAtomExpr" [SHash relAttr, SHash subAttr]       (NakedAtomExpr a) -> hashBytesL ctx "NakedAtomExpr" [SHash a]       (FunctionAtomExpr fname args marker) ->         hashBytesL ctx "FunctionAtomExpr" $ [SHash fname, SHash marker] <> map SHash args@@ -165,6 +167,7 @@       RelationAtomType attrs -> hashBytesL ctx "RelationAtomType" (V.map SHash (attributesVec attrs))       ConstructedAtomType tConsName tvarMap -> hashBytesL ctx "ConstructedAtomType" (SHash tConsName : map SHash (M.toAscList tvarMap))       RelationalExprAtomType -> hashb "RelationalExprAtomType"+      SubrelationFoldAtomType typ' -> hashBytesL ctx "SubrelationFoldAtomType" [SHash typ']       TypeVariableType tvn -> hashBytesL ctx "TypeVariableType" [SHash tvn]     where       hashb = SHA256.update ctx
src/lib/ProjectM36/NormalizeExpr.hs view
@@ -112,6 +112,7 @@  processAtomExpr :: AtomExpr -> ProcessExprM GraphRefAtomExpr processAtomExpr (AttributeAtomExpr nam) = pure $ AttributeAtomExpr nam+processAtomExpr (SubrelationAttributeAtomExpr relAttr subAttr) = pure (SubrelationAttributeAtomExpr relAttr subAttr) processAtomExpr (NakedAtomExpr atom) = pure $ NakedAtomExpr atom processAtomExpr (FunctionAtomExpr fName atomExprs ()) =   FunctionAtomExpr fName <$> mapM processAtomExpr atomExprs  <*> askMarker
src/lib/ProjectM36/ReferencedTransactionIds.hs view
@@ -96,6 +96,7 @@     case expr of       AttributeAtomExpr{} -> mempty       NakedAtomExpr{} -> mempty+      SubrelationAttributeAtomExpr{} -> mempty       FunctionAtomExpr _ args marker ->         S.unions (referencedTransactionIds marker : (referencedTransactionIds <$> args))       RelationAtomExpr rExpr ->
src/lib/ProjectM36/Relation/Parse/CSV.hs view
@@ -134,7 +134,10 @@             case lefts atomArgs of               [] -> pure (Right (ConstructedAtom dConsName typ (rights atomArgs)))               errs -> pure (Left (someErrors errs))-parseCSVAtomP attrName _ (RelationAtomType _) _ = pure (Left (RelationValuedAttributesNotSupportedError [attrName]))+parseCSVAtomP attrName _ (RelationAtomType _) _ =+  pure (Left (RelationValuedAttributesNotSupportedError [attrName]))+parseCSVAtomP attrName _ (SubrelationFoldAtomType _) _ =+  pure (Left (RelationValuedAttributesNotSupportedError [attrName])) parseCSVAtomP _ _ (TypeVariableType x) _ = pure (Left (TypeConstructorTypeVarMissing x))        capitalizedIdentifier :: APT.Parser T.Text
src/lib/ProjectM36/RelationalExpression.hs view
@@ -51,8 +51,6 @@ import GHC.Paths #endif ---import Debug.Trace- data DatabaseContextExprDetails = CountUpdatedTuples  databaseContextExprDetailsFunc :: DatabaseContextExprDetails -> ResultAccumFunc@@ -855,18 +853,22 @@                Right (tupleAtomExtend newAttrName atom tup)                ) +  + evalGraphRefAtomExpr :: RelationTuple -> GraphRefAtomExpr -> GraphRefRelationalExprM Atom evalGraphRefAtomExpr tupIn (AttributeAtomExpr attrName) =   case atomForAttributeName attrName tupIn of-    Right atom -> pure atom-    Left err@(NoSuchAttributeNamesError _) -> do-      env <- askEnv-      case gre_extra env of-        Nothing -> throwError err-        Just (Left ctxtup) -> lift $ except $ atomForAttributeName attrName ctxtup-        Just (Right _) -> throwError err-    Left err -> throwError err+      Right atom -> pure atom+      Left err@(NoSuchAttributeNamesError _) -> do+        env <- askEnv+        case gre_extra env of+          Nothing -> throwError err+          Just (Left ctxtup) -> lift $ except $ atomForAttributeName attrName ctxtup+          Just (Right _) -> throwError err+      Left err -> throwError err+   evalGraphRefAtomExpr _ (NakedAtomExpr atom) = pure atom+-- first argumentr is starting value, second argument is relationatom evalGraphRefAtomExpr tupIn (FunctionAtomExpr funcName' arguments tid) = do   argTypes <- mapM (typeForGraphRefAtomExpr (tupleAttributes tupIn)) arguments   context <- gfDatabaseContextForMarker tid@@ -895,6 +897,12 @@   let gfEnv = mergeTuplesIntoGraphRefRelationalExprEnv tupIn env   relAtom <- lift $ except $ runGraphRefRelationalExprM gfEnv (evalGraphRefRelationalExpr relExpr)   pure (RelationAtom relAtom)+evalGraphRefAtomExpr tupIn (SubrelationAttributeAtomExpr relAttr subAttr) = do+  atom <- evalGraphRefAtomExpr tupIn (AttributeAtomExpr relAttr)+  case atom of+    RelationAtom rel ->+      pure (SubrelationFoldAtom rel subAttr)+    _ -> throwError (AttributeIsNotRelationValuedError relAttr) evalGraphRefAtomExpr tupIn (IfThenAtomExpr ifExpr thenExpr elseExpr) = do   conditional <- evalGraphRefAtomExpr tupIn ifExpr   case conditional of@@ -909,7 +917,7 @@   aType <- local mergeEnv (typeForGraphRefAtomExpr (tupleAttributes tupIn) cons)   argAtoms <- local mergeEnv $     mapM (evalGraphRefAtomExpr tupIn) dConsArgs-  pure (ConstructedAtom dConsName aType argAtoms)+  pure (ConstructedAtom dConsName aType argAtoms)   typeForGraphRefAtomExpr :: Attributes -> GraphRefAtomExpr -> GraphRefRelationalExprM AtomType typeForGraphRefAtomExpr attrs (AttributeAtomExpr attrName) = do@@ -923,10 +931,17 @@         Right attr -> pure (A.atomType attr)         Left _ -> case atomForAttributeName attrName envTup of           Right atom -> pure (atomTypeForAtom atom)-          Left _ -> --throwError (traceStack (show ("typeForGRAtomExpr", attrs, envTup)) err)+          Left _ ->              throwError err     Left err -> throwError err-+typeForGraphRefAtomExpr attrs (SubrelationAttributeAtomExpr relAttr subAttr) = do+  relType <- typeForGraphRefAtomExpr attrs (AttributeAtomExpr relAttr)+  case relType of+    RelationAtomType relAttrs -> +      case A.atomTypeForAttributeName subAttr relAttrs of+        Left err -> throwError err+        Right attrType -> pure (SubrelationFoldAtomType attrType)+    _ -> throwError (AttributeIsNotRelationValuedError relAttr) typeForGraphRefAtomExpr _ (NakedAtomExpr atom) = pure (atomTypeForAtom atom) typeForGraphRefAtomExpr attrs (FunctionAtomExpr funcName' atomArgs transId) = do   funcs <- atomFunctions <$> gfDatabaseContextForMarker transId@@ -941,7 +956,8 @@       argTypes <- mapM (typeForGraphRefAtomExpr attrs) atomArgs       mapM_ (\(fArg,arg,argCount) -> do                 let handler :: RelationalError -> GraphRefRelationalExprM AtomType-                    handler (AtomTypeMismatchError expSubType actSubType) = throwError (AtomFunctionTypeError funcName' argCount expSubType actSubType)+                    handler (AtomTypeMismatchError expSubType actSubType) = do+                      throwError (AtomFunctionTypeError funcName' argCount expSubType actSubType)                     handler err = throwError err                 lift (except $ atomTypeVerify fArg arg) `catchError` handler             ) (zip3 funcArgTypes argTypes [1..])@@ -989,6 +1005,11 @@  verifyGraphRefAtomExprTypes _ (NakedAtomExpr atom) expectedType =   lift $ except $ atomTypeVerify expectedType (atomTypeForAtom atom)+verifyGraphRefAtomExprTypes relIn (SubrelationAttributeAtomExpr relAttr subAttr) expectedType = do+    let mergedAttrsEnv = mergeAttributesIntoGraphRefRelationalExprEnv (attributes relIn)+    (Relation relAttrs _) <- R.local mergedAttrsEnv (typeForGraphRefRelationalExpr (RelationValuedAttribute relAttr))+    subAttrType <- lift $ except $ A.atomTypeForAttributeName subAttr relAttrs+    lift $ except $ atomTypeVerify expectedType (SubrelationFoldAtomType subAttrType) verifyGraphRefAtomExprTypes relIn (FunctionAtomExpr funcName' funcArgExprs tid) expectedType = do   context <- gfDatabaseContextForMarker tid   let functions = atomFunctions context@@ -996,7 +1017,8 @@   let expectedArgTypes = funcType func       funcArgVerifier (atomExpr, expectedType2, argCount) = do         let handler :: RelationalError -> GraphRefRelationalExprM AtomType-            handler (AtomTypeMismatchError expSubType actSubType) = throwError (AtomFunctionTypeError funcName' argCount expSubType actSubType)+            handler (AtomTypeMismatchError expSubType actSubType) = do+              throwError (AtomFunctionTypeError funcName' argCount expSubType actSubType)             handler err = throwError err         verifyGraphRefAtomExprTypes relIn atomExpr expectedType2 `catchError` handler      funcArgTypes <- mapM funcArgVerifier $ zip3 funcArgExprs expectedArgTypes [1..]@@ -1237,7 +1259,6 @@           case typ of             RelationAtomType relAttrs -> pure $ emptyRelationWithAttrs relAttrs             other -> throwError (AtomTypeMismatchError (RelationAtomType A.emptyAttributes) other)-         typeForGraphRefRelationalExpr (Project attrNames expr) = do   exprType' <- typeForGraphRefRelationalExpr expr   projectionAttrs <- evalGraphRefAttributeNames attrNames expr@@ -1462,6 +1483,7 @@  instance ResolveGraphRefTransactionMarker GraphRefAtomExpr where   resolve orig@AttributeAtomExpr{} = pure orig+  resolve orig@SubrelationAttributeAtomExpr{} = pure orig   resolve orig@NakedAtomExpr{} = pure orig   resolve (FunctionAtomExpr nam atomExprs marker) =     FunctionAtomExpr nam <$> mapM resolve atomExprs <*> pure marker
src/lib/ProjectM36/SQL/Convert.hs view
@@ -555,7 +555,7 @@                               (S.fromList (map fst (nonAggregates groupInfo)))) "_sql_aggregate"               else                 pure id-    let coalesceBoolF expr = FunctionAtomExpr "sql_coalesce_bool" [expr] ()                +    let coalesceBoolF expr = func "sql_coalesce_bool" [expr]     fGroupHavingExtend <-        case havingRestriction groupInfo of         Nothing -> pure id@@ -632,11 +632,14 @@                                  limit = limitClause tExpr }     pure (dfExpr, columnMap) +func :: FunctionName -> [AtomExpr] -> AtomExpr+func fname args = FunctionAtomExpr fname args ()+ convertWhereClause :: TypeForRelExprF -> RestrictionExpr -> ConvertM RestrictionPredicateExpr convertWhereClause typeF (RestrictionExpr rexpr) = do     let wrongType t = throwSQLE $ TypeMismatchError t BoolAtomType --must be boolean expression-        coalesceBoolF expr = FunctionAtomExpr "sql_coalesce_bool" [expr] ()-        sqlEq l = FunctionAtomExpr "sql_equals" l ()+        coalesceBoolF expr = func "sql_coalesce_bool" [expr]+        sqlEq = func "sql_equals"     case rexpr of       IntegerLiteral{} -> wrongType IntegerAtomType       DoubleLiteral{} -> wrongType DoubleAtomType@@ -650,7 +653,7 @@       BinaryOperator (Identifier colName) (OperatorName ["="]) exprMatch -> do --we don't know here if this results in a boolean expression, so we pass it down         attrName <- attributeNameForColumnName colName         expr' <- convertScalarExpr typeF exprMatch-        pure (AtomExprPredicate (coalesceBoolF (FunctionAtomExpr "sql_equals" [AttributeAtomExpr attrName, expr'] ())))+        pure (AtomExprPredicate (coalesceBoolF (func "sql_equals" [AttributeAtomExpr attrName, expr'])))       BinaryOperator exprA op exprB -> do         a <- convertScalarExpr typeF exprA         b <- convertScalarExpr typeF exprB@@ -658,7 +661,7 @@         pure (AtomExprPredicate (coalesceBoolF (f [a,b])))       PostfixOperator expr (OperatorName ops) -> do         expr' <- convertScalarExpr typeF expr-        let isnull = AtomExprPredicate (coalesceBoolF (FunctionAtomExpr "sql_isnull" [expr'] ()))+        let isnull = AtomExprPredicate (coalesceBoolF (func "sql_isnull" [expr']))         case ops of           ["is", "null"] ->              pure isnull@@ -673,7 +676,7 @@            let predExpr' = sqlEq [eqExpr, firstItem]                folder predExpr'' sexprItem = do                  item <- convertScalarExpr typeF sexprItem-                 pure $ FunctionAtomExpr "sql_or" [sqlEq [eqExpr,item], predExpr''] ()+                 pure $ func "sql_or" [sqlEq [eqExpr,item], predExpr'']            res <- AtomExprPredicate . coalesceBoolF <$> foldM folder predExpr' matches             case inOrNotIn of              In -> pure res@@ -708,9 +711,9 @@         f <- lookupOperator False op         pure $ f [a,b]       FunctionApplication funcName' fargs -> do-        func <- lookupFunc funcName'+        func' <- lookupFunc funcName'         fargs' <- mapM (convertScalarExpr typeF) fargs-        pure (func fargs')+        pure (func' fargs')       other -> throwSQLE $ NotSupportedError ("scalar expr: " <> T.pack (show other))  -- SQL conflates projection and extension so we use the SQL context name here@@ -736,19 +739,19 @@         f <- lookupOperator False op         pure $ f [a,b]       FunctionApplication fname fargs -> do-        func <- lookupFunc fname+        func' <- lookupFunc fname         -- as a special case, count(*) is valid, if non-sensical SQL, so handle it here         fargs' <- if fname == FuncName ["count"] && fargs == [Identifier (ColumnProjectionName [Asterisk])] then                    pure [AttributeAtomExpr "_sql_aggregate"]                  else                     mapM (convertProjectionScalarExpr typeF) fargs-        pure (func fargs')+        pure (func' fargs')       PrefixOperator op sexpr -> do-        func <- lookupOperator True op+        func' <- lookupOperator True op         arg <- convertProjectionScalarExpr typeF sexpr-        pure (func [arg])+        pure (func' [arg])       CaseExpr conditionals mElse -> do-        let coalesceBoolF expr' = FunctionAtomExpr "sql_coalesce_bool" [expr'] ()+        let coalesceBoolF expr' = func "sql_coalesce_bool" [expr']         conditionals' <- mapM (\(ifExpr, thenExpr) -> do                                   ifE <- coalesceBoolF <$> convertProjectionScalarExpr typeF ifExpr                                   thenE <- convertProjectionScalarExpr typeF thenExpr@@ -932,7 +935,7 @@                     else                     new_name                 joinName = firstAvailableName (1::Int) allAttrs-                extender = AttributeExtendTupleExpr joinName (FunctionAtomExpr "sql_coalesce_bool" [joinRe] ())+                extender = AttributeExtendTupleExpr joinName (func "sql_coalesce_bool" [joinRe])                 --joinMatchRestriction = Restrict (AttributeEqualityPredicate joinName (ConstructedAtomExpr "True" [] ()))                 joinMatchRestriction = Restrict (AttributeEqualityPredicate joinName (NakedAtomExpr (BoolAtom True)))                 projectAwayJoinMatch = Project (InvertedAttributeNames (S.fromList [joinName]))@@ -942,7 +945,7 @@ lookupOperator :: Bool -> OperatorName -> ConvertM ([AtomExpr] -> AtomExpr) lookupOperator isPrefix op@(OperatorName nam)   | isPrefix = do-      let f n args = FunctionAtomExpr n args ()+      let f = func       case nam of         ["-"] -> pure $ f "sql_negate"         _ -> throwSQLE $ NoSuchSQLOperatorError op@@ -960,7 +963,7 @@         Just match -> pure match     other -> throwSQLE $ NotSupportedError ("function name: " <> T.pack (show other))   where-    f n args = FunctionAtomExpr n args ()+    f = func     aggMapper (FuncName [nam], nam') = (nam, f nam')     aggMapper (FuncName other,_) = error ("unexpected multi-component SQL aggregate function: " <> show other)     sqlFuncs = [(">",f "sql_gt"),@@ -974,7 +977,7 @@                  ("and", f "sql_and"),                  ("or", f "sql_or"),                  ("abs", f "sql_abs")-               ] <> map aggMapper aggregateFunctions+               ] <> map aggMapper aggregateFunctionsMap   -- | Used in join condition detection necessary for renames to enable natural joins.@@ -1082,6 +1085,7 @@       case expr of         x@AttributeAtomExpr{} -> x --potential rename         x@NakedAtomExpr{} -> x+        x@SubrelationAttributeAtomExpr{} -> x          FunctionAtomExpr fname args () -> FunctionAtomExpr fname (pushAtom <$> args) ()         RelationAtomExpr e -> RelationAtomExpr (push e)         IfThenAtomExpr ifE thenE elseE -> IfThenAtomExpr (pushAtom ifE) (pushAtom thenE) (pushAtom elseE)@@ -1300,7 +1304,7 @@   where     incDep = inclusionDependencyForKey (AttributeNames (S.singleton attrName)) (Restrict notNull (RelationVariable rvname ()))     incDepName = rvname <> "_" <> attrName <> "_unique"-    notNull = NotPredicate (AtomExprPredicate (FunctionAtomExpr "sql_isnull" [AttributeAtomExpr attrName] ()))+    notNull = NotPredicate (AtomExprPredicate (func "sql_isnull" [AttributeAtomExpr attrName] ))                                     {-@@ -1389,14 +1393,14 @@ emptyGroupByInfo :: GroupByInfo emptyGroupByInfo = GroupByInfo { aggregates = [], nonAggregates = [], havingRestriction = Nothing } -aggregateFunctions :: [(FuncName, FunctionName)]-aggregateFunctions = [(FuncName ["max"], "sql_max"),+aggregateFunctionsMap :: [(FuncName, FunctionName)]+aggregateFunctionsMap = [(FuncName ["max"], "sql_max"),                        (FuncName ["min"], "sql_min"),                        (FuncName ["sum"], "sql_sum"),                        (FuncName ["count"], "sql_count")]  isAggregateFunction :: FuncName -> Bool-isAggregateFunction fname = fname `elem` map fst aggregateFunctions+isAggregateFunction fname = fname `elem` map fst aggregateFunctionsMap  containsAggregate :: ProjectionScalarExpr -> Bool containsAggregate expr =@@ -1479,21 +1483,20 @@   case expr of     AttributeAtomExpr{} -> expr     NakedAtomExpr{} -> expr+    SubrelationAttributeAtomExpr{} -> expr     FunctionAtomExpr fname [AttributeAtomExpr attrName] ()       | fname == "sql_count" && -- count(*) counts the number of rows         attrName == "_sql_aggregate" -> expr       | fname == "sql_count" -> -- count(city) counts the number city elements that are not null-        callF fname [RelationAtomExpr+        func fname [RelationAtomExpr                      (Restrict                        (NotPredicate                         (AtomExprPredicate-                         (callF "sql_isnull" [AttributeAtomExpr attrName]))) (RelationValuedAttribute "_sql_aggregate"))]-      | fname `elem` map snd aggregateFunctions ->-          FunctionAtomExpr fname-            [RelationAtomExpr (Project (AttributeNames (S.singleton attrName)) (RelationValuedAttribute "_sql_aggregate"))] ()+                         (func "sql_isnull" [AttributeAtomExpr attrName]))) (RelationValuedAttribute "_sql_aggregate"))]+      | fname `elem` map snd aggregateFunctionsMap ->+          func fname+            [SubrelationAttributeAtomExpr "_sql_aggregate" attrName]     FunctionAtomExpr fname args () -> FunctionAtomExpr fname (map processSQLAggregateFunctions args) ()     RelationAtomExpr{} -> expr --not supported in SQL     IfThenAtomExpr ifE thenE elseE -> IfThenAtomExpr (processSQLAggregateFunctions ifE) (processSQLAggregateFunctions thenE) (processSQLAggregateFunctions elseE)     ConstructedAtomExpr{} -> expr --not supported in SQL-  where-    callF fname args = FunctionAtomExpr fname args ()
src/lib/ProjectM36/StaticOptimizer.hs view
@@ -437,6 +437,7 @@  isStaticAtomExpr :: AtomExpr -> Bool isStaticAtomExpr NakedAtomExpr{} = True+isStaticAtomExpr SubrelationAttributeAtomExpr{} = False isStaticAtomExpr ConstructedAtomExpr{} = True isStaticAtomExpr AttributeAtomExpr{} = False isStaticAtomExpr FunctionAtomExpr{} = False
src/lib/ProjectM36/TransGraphRelationalExpression.hs view
@@ -122,6 +122,7 @@    processTransGraphAtomExpr :: TransGraphAtomExpr -> TransGraphEvalMonad GraphRefAtomExpr processTransGraphAtomExpr (AttributeAtomExpr aname) = pure $ AttributeAtomExpr aname+processTransGraphAtomExpr (SubrelationAttributeAtomExpr relAttr subAttr) = pure $ SubrelationAttributeAtomExpr relAttr subAttr processTransGraphAtomExpr (NakedAtomExpr atom) = pure $ NakedAtomExpr atom processTransGraphAtomExpr (FunctionAtomExpr funcName' args tLookup) =   FunctionAtomExpr funcName' <$> mapM processTransGraphAtomExpr args <*> findTransId tLookup
src/lib/ProjectM36/Transaction/Persist.hs view
@@ -69,6 +69,9 @@ registeredQueriesPath :: FilePath -> FilePath registeredQueriesPath transdir = transdir </> "registered_queries" +aggregateFunctionsPath :: FilePath -> FilePath+aggregateFunctionsPath transdir = transdir </> "aggregateFunctions"+ -- | where compiled modules are stored within the database directory objectFilesPath :: FilePath -> FilePath objectFilesPath transdir = transdir </> ".." </> "compiled_modules"@@ -93,7 +96,7 @@                                        relationVariables = relvars,                                        typeConstructorMapping = typeCons,                                        notifications = notifs,-                                       atomFunctions = atomFuncs, +                                       atomFunctions = atomFuncs,                                        dbcFunctions = dbcFuncs,                                        registeredQueries = registeredQs }         newSchemas = Schemas newContext sschemas
src/lib/ProjectM36/TransactionGraph.hs view
@@ -517,7 +517,7 @@   let newContext = DatabaseContext {         inclusionDependencies = incDeps,          relationVariables = relVars, -        atomFunctions = atomFuncs, +        atomFunctions = atomFuncs,         dbcFunctions = dbcFuncs,         notifications = notifs,         typeConstructorMapping = types,
src/lib/ProjectM36/TransactionGraph/Merge.hs view
@@ -62,7 +62,7 @@   PreferFirst -> pure $ HS.union funcsA funcsB   PreferSecond -> pure $ HS.union funcsB funcsA   PreferNeither -> pure $ HS.union funcsA funcsB-  + unionMergeTypeConstructorMapping :: MergePreference -> TypeConstructorMapping -> TypeConstructorMapping -> Either MergeError TypeConstructorMapping   unionMergeTypeConstructorMapping prefer typesA typesB = do   let allFuncNames = S.fromList $ map (\(tc,_) -> TCD.name tc) (typesA ++ typesB)
src/lib/ProjectM36/Tuple.hs view
@@ -61,7 +61,6 @@     unknownAttrNames = V.filter (`V.notElem` attributeNames attrs) attrNameVec     mapper attrName = fromMaybe (error "logic failure in vectorIndicesForAttributeNames") (V.elemIndex attrName (attributeNames attrs)) - relationForAttributeName :: AttributeName -> RelationTuple -> Either RelationalError Relation relationForAttributeName attrName tuple = do   aType <- atomTypeForAttributeName attrName (tupleAttributes tuple)@@ -222,3 +221,6 @@   RelationTuple newAttrs (V.drop index vals)   where     newAttrs = A.drop index attrs+  +  +  
src/lib/ProjectM36/WithNameExpr.hs view
@@ -84,6 +84,7 @@ substituteWithNameMacrosAtomExpr macros atomExpr =   case atomExpr of     e@AttributeAtomExpr{} -> e+    e@SubrelationAttributeAtomExpr{} -> e     e@NakedAtomExpr{} -> e     FunctionAtomExpr fname atomExprs tid ->       FunctionAtomExpr fname (map (substituteWithNameMacrosAtomExpr macros) atomExprs) tid
test/SQL/InterpreterTest.hs view
@@ -24,6 +24,7 @@ import Text.Megaparsec import qualified Data.Text as T import qualified Data.Map as M+import TutorialD.Printer  main :: IO () main = do@@ -59,7 +60,7 @@   (tgraph,transId) <- freshTransactionGraph sqlDBContext   (sess, conn) <- dateExamplesConnection emptyNotificationCallback   -  let readTests = [+  let readTests = [{-         -- simple relvar         ("SELECT * FROM s", "(s)", "(s)"),         -- simple projection@@ -163,24 +164,24 @@         ("SELECT abs(-4)",          "((relation{}{tuple{}}:{attr_1:=sql_abs(sql_negate(4))}){attr_1})",          "(relation{tuple{attr_1 SQLJust 4}})"-         ),+         ),-}         -- where not exists         -- group by with max aggregate         ("SELECT city,max(status) FROM s GROUP BY city",-         "((s group ({all but city} as `_sql_aggregate`) : {attr_2:=sql_max(@`_sql_aggregate`{status})}){city,attr_2})",+         "((s group ({all but city} as `_sql_aggregate`) : {attr_2:=sql_max(@`_sql_aggregate`.status)}){city,attr_2})",          "(relation{city Text, attr_2 SQLNullable Integer}{tuple{city \"London\", attr_2 SQLJust 20}, tuple{city \"Paris\", attr_2 SQLJust 30}, tuple{city \"Athens\", attr_2 SQLJust 30}})"-         ),+         ){-,         -- group by with aggregate max column alias         ("SELECT city,max(status) as status FROM s GROUP BY city",-         "((s group ({all but city} as `_sql_aggregate`) : {status:=sql_max(@`_sql_aggregate`{status})}){city,status})",+         "((s group ({all but city} as `_sql_aggregate`) : {status:=sql_max(@`_sql_aggregate`.status)}){city,status})",          "(relation{city Text, status SQLNullable Integer}{tuple{city \"London\", status SQLJust 20}, tuple{city \"Paris\", status SQLJust 30}, tuple{city \"Athens\", status SQLJust 30}})"),         -- aggregate max without grouping         ("SELECT max(status) as status FROM s",-         "(((s group ({all but } as `_sql_aggregate`)):{status:=sql_max( (@`_sql_aggregate`){ status } )}){ status })",+         "(((s group ({all but } as `_sql_aggregate`)):{status:=sql_max( (@`_sql_aggregate`.status)}){ status })",          "(relation{status SQLNullable Integer}{tuple{status SQLJust 30}})"),         -- group by having max         ("select city,max(status) as status from s group by city having max(status)=30",-         "((((s group ({all but city} as `_sql_aggregate`)):{status:=sql_max( (@`_sql_aggregate`){ status } ), `_sql_having`:=sql_coalesce_bool( sql_equals( sql_max( (@`_sql_aggregate`){ status } ), 30 ) )}){ city, status }) where `_sql_having`=True)",+         "((((s group ({all but city} as `_sql_aggregate`)):{status:=sql_max( (@`_sql_aggregate`.status), `_sql_having`:=sql_coalesce_bool( sql_equals( sql_max( (@`_sql_aggregate`.status), 30 ) )}){ city, status }) where `_sql_having`=True)",          "(relation{city Text,status SQLNullable Integer}{tuple{city \"Athens\",status SQLJust 30},tuple{city \"Paris\",status SQLJust 30}})"),         -- count(*) aggregate         ("select count(*) as c from s",@@ -282,7 +283,7 @@          "(relation{attr_1 SQLNullable Bool}{tuple{attr_1 SQLNull}})"),         ("SELECT NULL OR TRUE",          "((relation{}{tuple{}}:{attr_1:=sql_or(SQLNullOfUnknownType,True)}){attr_1})",-         "(relation{attr_1 SQLNullable Bool}{tuple{attr_1 SQLJust True}})")+         "(relation{attr_1 SQLNullable Bool}{tuple{attr_1 SQLJust True}})")-}         ]       gfEnv = GraphRefRelationalExprEnv {         gre_context = Just sqlDBContext,@@ -315,7 +316,7 @@          --print ("selectAsRelExpr"::String, queryAsRelExpr)         --print ("expected: "::String, pretty tutdAsDFExpr)-        --print ("actual  : "::String, pretty queryAsDFExpr)+        print ("actual  : "::String, renderPretty queryAsDFExpr)         assertEqual (T.unpack sql) tutdAsDFExpr queryAsDFExpr         --check that the expression can actually be executed         eEvald <- executeDataFrameExpr sess conn tutdAsDFExpr
test/TutorialD/InterpreterTest.hs view
@@ -95,7 +95,8 @@       testShowDDL,       testRegisteredQueries,       testCrossJoin,-      testIfThenExpr+      testIfThenExpr,+      testSubrelationAttributeAtomExpr       ]  simpleRelTests :: Test@@ -184,14 +185,14 @@                            --relatom function tests                            ("x:=((s group ({city} as y)):{z:=count(@y)}){z}", mkRelation groupCountAttrs (RelationTupleSet [mkRelationTuple groupCountAttrs (V.singleton $ IntegerAtom 1)])),                            ("x:=(sp group ({s#} as y)) ungroup y", Right supplierProductsRel),-                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=max(@x)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 400), ("S2", 400), ("S3", 200), ("S4", 400)])),-                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=min(@x)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 100), ("S2", 300), ("S3", 200), ("S4", 200)])),-                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=sum(@x)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 1000), ("S2", 700), ("S3", 200), ("S4", 900)])),+                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=max(@x.qty)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 400), ("S2", 400), ("S3", 200), ("S4", 400)])),+                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=min(@x.qty)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 100), ("S2", 300), ("S3", 200), ("S4", 200)])),+                           ("x:=((sp{s#,qty}) group ({qty} as x):{z:=sum(@x.qty)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 1000), ("S2", 700), ("S3", 200), ("S4", 900)])),                            --boolean function restriction                            ("x:=s where lt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),                            ("x:=s where gt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S3", TextAtom "Blake", IntegerAtom 30, TextAtom "Paris"],                                                                                                        [TextAtom "S5", TextAtom "Adams", IntegerAtom 30, TextAtom "Athens"]]),-                           ("x:=s where sum(@status)", Left $ AtomFunctionTypeError "sum" 1 (RelationAtomType (attributesFromList [Attribute "_" IntegerAtomType])) IntegerAtomType),+                           ("x:=s where sum(@status)", Left $ AtomFunctionTypeError "sum" 1 (SubrelationFoldAtomType IntegerAtomType) IntegerAtomType),                            ("x:=s where not(gte(@status,20))", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),                            --test "all but" attribute inversion syntax                            ("x:=s{all but s#} = s{city,sname,status}", Right relationTrue),@@ -805,7 +806,7 @@   Right hash2 <- getDDLHash sessionId dbconn     assertBool "add relvar" (hash1 /= hash2)   -- the test should break if the hash is calculated differently-  assertEqual "static hash check" "ds0uvEvV8CvivyYyxJ75S0CeAnNzKAAH5AdOv74+ydM=" (B64.encode (_unSecureHash hash1))+  assertEqual "static hash check" "3aNi/azK9QNSXQQQ0QOuGcqAPlRh0d7zX0bNwjowPDA=" (B64.encode (_unSecureHash hash1))   -- remove an rv   executeTutorialD sessionId dbconn "undefine x"   Right hash3 <- getDDLHash sessionId dbconn@@ -876,3 +877,12 @@   executeTutorialD session dbconn "x:=(s:{islondon:=if eq(@city,\"London\") then True else False}){city,islondon} = relation{tuple{city \"London\", islondon True},tuple{city \"Paris\",islondon False},tuple{city \"Athens\", islondon False}}"   eEqRel <- executeRelationalExpr session dbconn (RelationVariable "x" ())   assertEqual "if-then" (Right relationTrue) eEqRel++testSubrelationAttributeAtomExpr :: Test+testSubrelationAttributeAtomExpr = TestCase $ do+  (session, dbconn) <- dateExamplesConnection emptyNotificationCallback+  executeTutorialD session dbconn "x:=(s group ({all from s} as sub):{l:=sum(@sub.status)}){l}"+  executeTutorialD session dbconn "y:=relation{tuple{l 110}}"+  executeTutorialD session dbconn "z:= x = y"+  res <- executeRelationalExpr session dbconn (RelationVariable "z" ())+  assertEqual "sum" (Right relationTrue) res