mirror of
https://github.com/PostHog/posthog.git
synced 2024-11-24 09:14:46 +01:00
feat(hog): remove semicolons, require "as" for column aliases (#22868)
This commit is contained in:
parent
f324ec6fbc
commit
779b17f46e
File diff suppressed because it is too large
Load Diff
@ -45,8 +45,8 @@ public:
|
||||
|
||||
enum {
|
||||
RuleProgram = 0, RuleDeclaration = 1, RuleExpression = 2, RuleVarDecl = 3,
|
||||
RuleVarAssignment = 4, RuleIdentifierList = 5, RuleStatement = 6, RuleExprStmt = 7,
|
||||
RuleIfStmt = 8, RuleWhileStmt = 9, RuleReturnStmt = 10, RuleFuncStmt = 11,
|
||||
RuleIdentifierList = 4, RuleStatement = 5, RuleReturnStmt = 6, RuleIfStmt = 7,
|
||||
RuleWhileStmt = 8, RuleFuncStmt = 9, RuleVarAssignment = 10, RuleExprStmt = 11,
|
||||
RuleEmptyStmt = 12, RuleBlock = 13, RuleKvPair = 14, RuleKvPairList = 15,
|
||||
RuleSelect = 16, RuleSelectUnionStmt = 17, RuleSelectStmtWithParens = 18,
|
||||
RuleSelectStmt = 19, RuleWithClause = 20, RuleTopClause = 21, RuleFromClause = 22,
|
||||
@ -92,14 +92,14 @@ public:
|
||||
class DeclarationContext;
|
||||
class ExpressionContext;
|
||||
class VarDeclContext;
|
||||
class VarAssignmentContext;
|
||||
class IdentifierListContext;
|
||||
class StatementContext;
|
||||
class ExprStmtContext;
|
||||
class ReturnStmtContext;
|
||||
class IfStmtContext;
|
||||
class WhileStmtContext;
|
||||
class ReturnStmtContext;
|
||||
class FuncStmtContext;
|
||||
class VarAssignmentContext;
|
||||
class ExprStmtContext;
|
||||
class EmptyStmtContext;
|
||||
class BlockContext;
|
||||
class KvPairContext;
|
||||
@ -220,7 +220,6 @@ public:
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *LET();
|
||||
IdentifierContext *identifier();
|
||||
antlr4::tree::TerminalNode *SEMICOLON();
|
||||
antlr4::tree::TerminalNode *COLON();
|
||||
antlr4::tree::TerminalNode *EQ_SINGLE();
|
||||
ExpressionContext *expression();
|
||||
@ -232,23 +231,6 @@ public:
|
||||
|
||||
VarDeclContext* varDecl();
|
||||
|
||||
class VarAssignmentContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
VarAssignmentContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
std::vector<ExpressionContext *> expression();
|
||||
ExpressionContext* expression(size_t i);
|
||||
antlr4::tree::TerminalNode *COLON();
|
||||
antlr4::tree::TerminalNode *EQ_SINGLE();
|
||||
antlr4::tree::TerminalNode *SEMICOLON();
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
VarAssignmentContext* varAssignment();
|
||||
|
||||
class IdentifierListContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
IdentifierListContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
@ -270,12 +252,12 @@ public:
|
||||
StatementContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
ReturnStmtContext *returnStmt();
|
||||
EmptyStmtContext *emptyStmt();
|
||||
ExprStmtContext *exprStmt();
|
||||
IfStmtContext *ifStmt();
|
||||
WhileStmtContext *whileStmt();
|
||||
FuncStmtContext *funcStmt();
|
||||
VarAssignmentContext *varAssignment();
|
||||
ExprStmtContext *exprStmt();
|
||||
EmptyStmtContext *emptyStmt();
|
||||
BlockContext *block();
|
||||
|
||||
|
||||
@ -285,10 +267,11 @@ public:
|
||||
|
||||
StatementContext* statement();
|
||||
|
||||
class ExprStmtContext : public antlr4::ParserRuleContext {
|
||||
class ReturnStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
ExprStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
ReturnStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *RETURN();
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *SEMICOLON();
|
||||
|
||||
@ -297,7 +280,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
ExprStmtContext* exprStmt();
|
||||
ReturnStmtContext* returnStmt();
|
||||
|
||||
class IfStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
@ -327,20 +310,6 @@ public:
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *RPAREN();
|
||||
StatementContext *statement();
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
WhileStmtContext* whileStmt();
|
||||
|
||||
class ReturnStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
ReturnStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
antlr4::tree::TerminalNode *RETURN();
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *SEMICOLON();
|
||||
|
||||
|
||||
@ -348,7 +317,7 @@ public:
|
||||
|
||||
};
|
||||
|
||||
ReturnStmtContext* returnStmt();
|
||||
WhileStmtContext* whileStmt();
|
||||
|
||||
class FuncStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
@ -368,6 +337,36 @@ public:
|
||||
|
||||
FuncStmtContext* funcStmt();
|
||||
|
||||
class VarAssignmentContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
VarAssignmentContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
std::vector<ExpressionContext *> expression();
|
||||
ExpressionContext* expression(size_t i);
|
||||
antlr4::tree::TerminalNode *COLON();
|
||||
antlr4::tree::TerminalNode *EQ_SINGLE();
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
VarAssignmentContext* varAssignment();
|
||||
|
||||
class ExprStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
ExprStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
virtual size_t getRuleIndex() const override;
|
||||
ExpressionContext *expression();
|
||||
antlr4::tree::TerminalNode *SEMICOLON();
|
||||
|
||||
|
||||
virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override;
|
||||
|
||||
};
|
||||
|
||||
ExprStmtContext* exprStmt();
|
||||
|
||||
class EmptyStmtContext : public antlr4::ParserRuleContext {
|
||||
public:
|
||||
EmptyStmtContext(antlr4::ParserRuleContext *parent, size_t invokingState);
|
||||
@ -1246,7 +1245,6 @@ public:
|
||||
ColumnExprAliasContext(ColumnExprContext *ctx);
|
||||
|
||||
ColumnExprContext *columnExpr();
|
||||
AliasContext *alias();
|
||||
antlr4::tree::TerminalNode *AS();
|
||||
IdentifierContext *identifier();
|
||||
antlr4::tree::TerminalNode *STRING_LITERAL();
|
||||
|
File diff suppressed because one or more lines are too long
@ -31,10 +31,6 @@ public:
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitVarAssignment(HogQLParser::VarAssignmentContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitIdentifierList(HogQLParser::IdentifierListContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
@ -43,7 +39,7 @@ public:
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitExprStmt(HogQLParser::ExprStmtContext *ctx) override {
|
||||
virtual std::any visitReturnStmt(HogQLParser::ReturnStmtContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
@ -55,11 +51,15 @@ public:
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitReturnStmt(HogQLParser::ReturnStmtContext *ctx) override {
|
||||
virtual std::any visitFuncStmt(HogQLParser::FuncStmtContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitFuncStmt(HogQLParser::FuncStmtContext *ctx) override {
|
||||
virtual std::any visitVarAssignment(HogQLParser::VarAssignmentContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
virtual std::any visitExprStmt(HogQLParser::ExprStmtContext *ctx) override {
|
||||
return visitChildren(ctx);
|
||||
}
|
||||
|
||||
|
@ -27,22 +27,22 @@ public:
|
||||
|
||||
virtual std::any visitVarDecl(HogQLParser::VarDeclContext *context) = 0;
|
||||
|
||||
virtual std::any visitVarAssignment(HogQLParser::VarAssignmentContext *context) = 0;
|
||||
|
||||
virtual std::any visitIdentifierList(HogQLParser::IdentifierListContext *context) = 0;
|
||||
|
||||
virtual std::any visitStatement(HogQLParser::StatementContext *context) = 0;
|
||||
|
||||
virtual std::any visitExprStmt(HogQLParser::ExprStmtContext *context) = 0;
|
||||
virtual std::any visitReturnStmt(HogQLParser::ReturnStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitIfStmt(HogQLParser::IfStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitWhileStmt(HogQLParser::WhileStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitReturnStmt(HogQLParser::ReturnStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitFuncStmt(HogQLParser::FuncStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitVarAssignment(HogQLParser::VarAssignmentContext *context) = 0;
|
||||
|
||||
virtual std::any visitExprStmt(HogQLParser::ExprStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitEmptyStmt(HogQLParser::EmptyStmtContext *context) = 0;
|
||||
|
||||
virtual std::any visitBlock(HogQLParser::BlockContext *context) = 0;
|
||||
|
@ -1059,9 +1059,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
||||
|
||||
VISIT(ColumnExprAlias) {
|
||||
string alias;
|
||||
if (ctx->alias()) {
|
||||
alias = visitAsString(ctx->alias());
|
||||
} else if (ctx->identifier()) {
|
||||
if (ctx->identifier()) {
|
||||
alias = visitAsString(ctx->identifier());
|
||||
} else if (ctx->STRING_LITERAL()) {
|
||||
alias = parse_string_literal_ctx(ctx->STRING_LITERAL());
|
||||
|
@ -1,10 +1,9 @@
|
||||
["_h", 32, "-- test functions --", 2, "print", 1, 35, 41, "add", 2, 6, 36, 0, 36, 1, 6, 38, 41, "add2", 2, 9, 36, 0, 36,
|
||||
1, 6, 36, 2, 38, 35, 41, "mult", 2, 6, 36, 0, 36, 1, 8, 38, 41, "noArgs", 0, 12, 32, "basdfasdf", 33, 3, 33, 2, 6, 36,
|
||||
1, 38, 35, 35, 41, "empty", 0, 2, 31, 38, 41, "empty2", 0, 4, 29, 35, 31, 38, 41, "empty3", 0, 8, 29, 35, 29, 35, 29,
|
||||
35, 31, 38, 41, "noReturn", 0, 14, 33, 1, 33, 2, 36, 1, 36, 0, 6, 31, 38, 35, 35, 35, 33, 4, 33, 3, 2, "add", 2, 2,
|
||||
"print", 1, 35, 33, 1, 33, 1, 2, "add", 2, 33, 100, 33, 4, 33, 3, 2, "add", 2, 6, 6, 2, "print", 1, 35, 33, -1, 2,
|
||||
"noArgs", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2, "empty", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2,
|
||||
"empty2", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2, "empty3", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2,
|
||||
"noReturn", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, 2, 33, 1, 33, 2, 2, "add", 2, 33, 100, 33, 4, 33, 3, 2, "add", 2,
|
||||
6, 6, 2, "mult", 2, 2, "print", 1, 35, 33, 10, 33, 1, 33, 2, 2, "add2", 2, 33, 100, 33, 4, 33, 3, 2, "add2", 2, 6, 6, 2,
|
||||
"mult", 2, 2, "print", 1, 35]
|
||||
1, 38, 35, 35, 41, "empty", 0, 2, 31, 38, 41, "empty2", 0, 2, 31, 38, 41, "empty3", 0, 2, 31, 38, 41, "noReturn", 0, 14,
|
||||
33, 1, 33, 2, 36, 1, 36, 0, 6, 31, 38, 35, 35, 35, 33, 4, 33, 3, 2, "add", 2, 2, "print", 1, 35, 33, 1, 33, 1, 2, "add",
|
||||
2, 33, 100, 33, 4, 33, 3, 2, "add", 2, 6, 6, 2, "print", 1, 35, 33, -1, 2, "noArgs", 0, 2, "ifNull", 2, 2, "print", 1,
|
||||
35, 33, -1, 2, "empty", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2, "empty2", 0, 2, "ifNull", 2, 2, "print", 1, 35,
|
||||
33, -1, 2, "empty3", 0, 2, "ifNull", 2, 2, "print", 1, 35, 33, -1, 2, "noReturn", 0, 2, "ifNull", 2, 2, "print", 1, 35,
|
||||
33, 2, 33, 1, 33, 2, 2, "add", 2, 33, 100, 33, 4, 33, 3, 2, "add", 2, 6, 6, 2, "mult", 2, 2, "print", 1, 35, 33, 10, 33,
|
||||
1, 33, 2, 2, "add2", 2, 33, 100, 33, 4, 33, 3, 2, "add2", 2, 6, 6, 2, "mult", 2, 2, "print", 1, 35]
|
||||
|
@ -1,12 +1,12 @@
|
||||
print([]);
|
||||
print([1, 2, 3]);
|
||||
print([1, '2', 3]);
|
||||
print([1, [2, 3], 4]);
|
||||
print([1, [2, [3, 4]], 5]);
|
||||
print([])
|
||||
print([1, 2, 3])
|
||||
print([1, '2', 3])
|
||||
print([1, [2, 3], 4])
|
||||
print([1, [2, [3, 4]], 5])
|
||||
|
||||
let a := [1, 2, 3];
|
||||
print(a[1]);
|
||||
print([1, 2, 3][1]);
|
||||
print([1, [2, [3, 4]], 5][1][1][1]);
|
||||
print([1, [2, [3, 4]], 5][1][1][1] + 1);
|
||||
print([1, [2, [3, 4]], 5].1.1.1);
|
||||
let a := [1, 2, 3]
|
||||
print(a[1])
|
||||
print([1, 2, 3][1])
|
||||
print([1, [2, [3, 4]], 5][1][1][1])
|
||||
print([1, [2, [3, 4]], 5][1][1][1] + 1)
|
||||
print([1, [2, [3, 4]], 5].1.1.1)
|
||||
|
@ -1,13 +1,13 @@
|
||||
print({});
|
||||
print({'key': 'value'});
|
||||
print({'key': 'value', 'other': 'thing'});
|
||||
print({'key': {'otherKey': 'value'}});
|
||||
print({key: 'value'});
|
||||
print({})
|
||||
print({'key': 'value'})
|
||||
print({'key': 'value', 'other': 'thing'})
|
||||
print({'key': {'otherKey': 'value'}})
|
||||
print({key: 'value'})
|
||||
|
||||
let key := 3;
|
||||
print({key: 'value'});
|
||||
let key := 3
|
||||
print({key: 'value'})
|
||||
|
||||
print({'key': 'value'}.key);
|
||||
print({'key': 'value'}['key']);
|
||||
print({'key': {'otherKey': 'value'}}.key.otherKey);
|
||||
print({'key': {'otherKey': 'value'}}['key'].otherKey);
|
||||
print({'key': 'value'}.key)
|
||||
print({'key': 'value'}['key'])
|
||||
print({'key': {'otherKey': 'value'}}.key.otherKey)
|
||||
print({'key': {'otherKey': 'value'}}['key'].otherKey)
|
||||
|
@ -1,35 +1,35 @@
|
||||
print('-- test functions --');
|
||||
print('-- test functions --')
|
||||
|
||||
fn add(a, b) {
|
||||
return a + b;
|
||||
return a + b
|
||||
}
|
||||
fn add2(a, b) {
|
||||
let c := a + b;
|
||||
return c;
|
||||
let c := a + b
|
||||
return c
|
||||
}
|
||||
fn mult(a, b) {
|
||||
return a * b;
|
||||
return a * b
|
||||
}
|
||||
fn noArgs() {
|
||||
let url := 'basdfasdf';
|
||||
let second := 2 + 3;
|
||||
return second;
|
||||
let url := 'basdfasdf'
|
||||
let second := 2 + 3
|
||||
return second
|
||||
}
|
||||
fn empty() {}
|
||||
fn empty2() {;}
|
||||
fn empty3() {;;;}
|
||||
fn empty2() {}
|
||||
fn empty3() {}
|
||||
fn noReturn() {
|
||||
let a := 1;
|
||||
let b := 2;
|
||||
let c := a + b;
|
||||
let a := 1
|
||||
let b := 2
|
||||
let c := a + b
|
||||
}
|
||||
|
||||
print(add(3, 4));
|
||||
print(add(3, 4) + 100 + add(1, 1));
|
||||
print(noArgs() ?? -1);
|
||||
print(empty() ?? -1);
|
||||
print(empty2() ?? -1);
|
||||
print(empty3() ?? -1);
|
||||
print(noReturn() ?? -1);
|
||||
print(mult(add(3, 4) + 100 + add(2, 1), 2));
|
||||
print(mult(add2(3, 4) + 100 + add2(2, 1), 10));
|
||||
print(add(3, 4))
|
||||
print(add(3, 4) + 100 + add(1, 1))
|
||||
print(noArgs() ?? -1)
|
||||
print(empty() ?? -1)
|
||||
print(empty2() ?? -1)
|
||||
print(empty3() ?? -1)
|
||||
print(noReturn() ?? -1)
|
||||
print(mult(add(3, 4) + 100 + add(2, 1), 2))
|
||||
print(mult(add2(3, 4) + 100 + add2(2, 1), 10))
|
||||
|
@ -1,15 +1,15 @@
|
||||
print('-- test if else --');
|
||||
print('-- test if else --')
|
||||
{
|
||||
if (true) print(1); else print(2);
|
||||
if (true) print(1); else print(2);
|
||||
if (false) print(1); else print(2);
|
||||
if (true) { print(1); } else { print(2); }
|
||||
if (true) print(1) else print(2)
|
||||
if (true) print(1) else print(2)
|
||||
if (false) print(1) else print(2)
|
||||
if (true) { print(1) } else { print(2) }
|
||||
|
||||
let a := true;
|
||||
let a := true
|
||||
if (a) {
|
||||
let a := 3;
|
||||
print(a + 2);
|
||||
let a := 3
|
||||
print(a + 2)
|
||||
} else {
|
||||
print(2);
|
||||
print(2)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
---- Commented out because python and JS add different spaces to their JSON output
|
||||
-- print(jsonStringify({'$browser': 'Chrome', '$os': 'Windows' }));
|
||||
-- print(jsonStringify({'$browser': 'Chrome', '$os': 'Windows' }, 3));
|
||||
-- print(jsonStringify({'$browser': 'Chrome', '$os': 'Windows' }))
|
||||
-- print(jsonStringify({'$browser': 'Chrome', '$os': 'Windows' }, 3))
|
||||
|
||||
print(jsonParse('[1,2,3]'));
|
||||
print(jsonParse('[1,2,3]'))
|
||||
|
||||
let event := {
|
||||
'event': '$pageview',
|
||||
@ -10,6 +10,6 @@ let event := {
|
||||
'$browser': 'Chrome',
|
||||
'$os': 'Windows'
|
||||
}
|
||||
};
|
||||
let json := jsonStringify(event);
|
||||
print(jsonParse(json));
|
||||
}
|
||||
let json := jsonStringify(event)
|
||||
print(jsonParse(json))
|
||||
|
@ -1,9 +1,9 @@
|
||||
print('-- test while loop --');
|
||||
print('-- test while loop --')
|
||||
{
|
||||
let i := 0;
|
||||
let i := 0
|
||||
while (i < 3) {
|
||||
i := i + 1;
|
||||
print(i);
|
||||
i := i + 1
|
||||
print(i)
|
||||
}
|
||||
print(i);
|
||||
print(i)
|
||||
}
|
||||
|
@ -1,44 +1,44 @@
|
||||
fn mandelbrot(re, im, max_iter) {
|
||||
let z_re := 0.0;
|
||||
let z_im := 0.0;
|
||||
let n := 0;
|
||||
let z_re := 0.0
|
||||
let z_im := 0.0
|
||||
let n := 0
|
||||
while (z_re*z_re + z_im*z_im <= 4 and n < max_iter) {
|
||||
let temp_re := z_re * z_re - z_im * z_im + re;
|
||||
let temp_im := 2 * z_re * z_im + im;
|
||||
z_re := temp_re;
|
||||
z_im := temp_im;
|
||||
n := n + 1;
|
||||
let temp_re := z_re * z_re - z_im * z_im + re
|
||||
let temp_im := 2 * z_re * z_im + im
|
||||
z_re := temp_re
|
||||
z_im := temp_im
|
||||
n := n + 1
|
||||
}
|
||||
if (n == max_iter) {
|
||||
return ' ';
|
||||
return ' '
|
||||
} else {
|
||||
return '#';
|
||||
return '#'
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let width := 80;
|
||||
let height := 24;
|
||||
let xmin := -2.0;
|
||||
let xmax := 1.0;
|
||||
let ymin := -1.0;
|
||||
let ymax := 1.0;
|
||||
let max_iter := 30;
|
||||
let width := 80
|
||||
let height := 24
|
||||
let xmin := -2.0
|
||||
let xmax := 1.0
|
||||
let ymin := -1.0
|
||||
let ymax := 1.0
|
||||
let max_iter := 30
|
||||
|
||||
let y := 0;
|
||||
let y := 0
|
||||
while(y < height) {
|
||||
let row := '';
|
||||
let x := 0;
|
||||
let row := ''
|
||||
let x := 0
|
||||
while (x < width) {
|
||||
let re := x / width * (xmax - xmin) + xmin;
|
||||
let im := y / height * (ymax - ymin) + ymin;
|
||||
let letter := mandelbrot(re, im, max_iter);
|
||||
row := concat(row, letter);
|
||||
x := x + 1;
|
||||
let re := x / width * (xmax - xmin) + xmin
|
||||
let im := y / height * (ymax - ymin) + ymin
|
||||
let letter := mandelbrot(re, im, max_iter)
|
||||
row := concat(row, letter)
|
||||
x := x + 1
|
||||
}
|
||||
print(row);
|
||||
y := y + 1;
|
||||
print(row)
|
||||
y := y + 1
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
main()
|
@ -1,8 +0,0 @@
|
||||
["_h", 41, "mandelbrot", 3, 93, 34, 0.0, 34, 0.0, 33, 0, 36, 0, 36, 5, 15, 33, 4, 36, 4, 36, 4, 8, 36, 3, 36, 3, 8, 6,
|
||||
16, 3, 2, 40, 44, 36, 2, 36, 4, 36, 4, 8, 36, 3, 36, 3, 8, 7, 6, 36, 1, 36, 4, 36, 3, 33, 2, 8, 8, 6, 36, 6, 37, 3, 36,
|
||||
7, 37, 4, 33, 1, 36, 5, 6, 37, 5, 35, 35, 39, -67, 36, 0, 36, 5, 11, 40, 5, 32, " ", 38, 39, 3, 32, "#", 38, 31, 38, 35,
|
||||
35, 35, 41, "main", 0, 119, 33, 80, 33, 24, 34, -2.0, 34, 1.0, 34, -1.0, 34, 1.0, 33, 30, 33, 0, 36, 1, 36, 7, 15, 40,
|
||||
86, 32, "", 33, 0, 36, 0, 36, 9, 15, 40, 58, 36, 2, 36, 2, 36, 3, 7, 36, 0, 36, 9, 9, 8, 6, 36, 4, 36, 4, 36, 5, 7, 36,
|
||||
1, 36, 7, 9, 8, 6, 36, 6, 36, 11, 36, 10, 2, "mandelbrot", 3, 36, 12, 36, 8, 2, "concat", 2, 37, 8, 33, 1, 36, 9, 6, 37,
|
||||
9, 35, 35, 35, 39, -65, 36, 8, 2, "print", 1, 35, 33, 1, 36, 7, 6, 37, 7, 35, 35, 39, -93, 31, 38, 35, 35, 35, 35, 35,
|
||||
35, 35, 35, 2, "main", 0, 35]
|
@ -1,70 +1,70 @@
|
||||
fn test(val) {
|
||||
print(jsonStringify(val));
|
||||
print(jsonStringify(val))
|
||||
}
|
||||
|
||||
print('-- test the most common expressions --');
|
||||
test(1 + 2); -- 3
|
||||
test(1 - 2); -- -1
|
||||
test(3 * 2); -- 6
|
||||
test(3 / 2); -- 1.5
|
||||
test(3 % 2); -- 1
|
||||
test(1 and 2); -- true
|
||||
test(1 or 0); -- true
|
||||
test(1 and 0); -- false
|
||||
test(1 or (0 and 1) or 2); -- true
|
||||
test((1 and 0) and 1); -- false
|
||||
test((1 or 2) and (1 or 2)); -- true
|
||||
test(true); -- true
|
||||
test(not true); -- false
|
||||
test(false); -- false
|
||||
test(null); -- null
|
||||
test(3.14); -- 3.14
|
||||
test(1 = 2); -- false
|
||||
test(1 == 2); -- false
|
||||
test(1 != 2); -- true
|
||||
test(1 < 2); -- true
|
||||
test(1 <= 2); -- true
|
||||
test(1 > 2); -- false
|
||||
test(1 >= 2); -- false
|
||||
test('a' like 'b'); -- false
|
||||
test('baa' like '%a%'); -- true
|
||||
test('baa' like '%x%'); -- false
|
||||
test('baa' ilike '%A%'); -- true
|
||||
test('baa' ilike '%C%'); -- false
|
||||
test('a' ilike 'b'); -- false
|
||||
test('a' not like 'b'); -- true
|
||||
test('a' not ilike 'b'); -- true
|
||||
test('a' in 'car'); -- true
|
||||
test('a' in 'foo'); -- false
|
||||
test('a' not in 'car'); -- false
|
||||
test(properties.bla); -- null
|
||||
test(properties.foo); -- "bar"
|
||||
test(ifNull(properties.foo, false)); -- "bar"
|
||||
test(ifNull(properties.nullValue, false)); -- false
|
||||
test(concat('arg', 'another')); -- 'arganother'
|
||||
test(concat(1, NULL)); -- '1'
|
||||
test(concat(true, false)); -- 'truefalse'
|
||||
test(match('test', 'e.*')); -- true
|
||||
test(match('test', '^e.*')); -- false
|
||||
test(match('test', 'x.*')); -- false
|
||||
test('test' =~ 'e.*'); -- true
|
||||
test('test' !~ 'e.*'); -- false
|
||||
test('test' =~ '^e.*'); -- false
|
||||
test('test' !~ '^e.*'); -- true
|
||||
test('test' =~ 'x.*'); -- false
|
||||
test('test' !~ 'x.*'); -- true
|
||||
test('test' ~* 'EST'); -- true
|
||||
test('test' =~* 'EST'); -- true
|
||||
test('test' !~* 'EST'); -- false
|
||||
test(toString(1)); -- '1'
|
||||
test(toString(1.5)); -- '1.5'
|
||||
test(toString(true)); -- 'true'
|
||||
test(toString(null)); -- 'null'
|
||||
test(toString('string')); -- 'string'
|
||||
test(toInt('1')); -- 1
|
||||
test(toInt('bla')); -- null
|
||||
test(toFloat('1.2')); -- 1.2
|
||||
test(toFloat('bla')); -- null
|
||||
test(toUUID('asd')); -- 'asd'
|
||||
test(1 == null); -- false
|
||||
test(1 != null); -- true
|
||||
print('-- test the most common expressions --')
|
||||
test(1 + 2) -- 3
|
||||
test(1 - 2) -- -1
|
||||
test(3 * 2) -- 6
|
||||
test(3 / 2) -- 1.5
|
||||
test(3 % 2) -- 1
|
||||
test(1 and 2) -- true
|
||||
test(1 or 0) -- true
|
||||
test(1 and 0) -- false
|
||||
test(1 or (0 and 1) or 2) -- true
|
||||
test((1 and 0) and 1) -- false
|
||||
test((1 or 2) and (1 or 2)) -- true
|
||||
test(true) -- true
|
||||
test(not true) -- false
|
||||
test(false) -- false
|
||||
test(null) -- null
|
||||
test(3.14) -- 3.14
|
||||
test(1 = 2) -- false
|
||||
test(1 == 2) -- false
|
||||
test(1 != 2) -- true
|
||||
test(1 < 2) -- true
|
||||
test(1 <= 2) -- true
|
||||
test(1 > 2) -- false
|
||||
test(1 >= 2) -- false
|
||||
test('a' like 'b') -- false
|
||||
test('baa' like '%a%') -- true
|
||||
test('baa' like '%x%') -- false
|
||||
test('baa' ilike '%A%') -- true
|
||||
test('baa' ilike '%C%') -- false
|
||||
test('a' ilike 'b') -- false
|
||||
test('a' not like 'b') -- true
|
||||
test('a' not ilike 'b') -- true
|
||||
test('a' in 'car') -- true
|
||||
test('a' in 'foo') -- false
|
||||
test('a' not in 'car') -- false
|
||||
test(properties.bla) -- null
|
||||
test(properties.foo) -- "bar"
|
||||
test(ifNull(properties.foo, false)) -- "bar"
|
||||
test(ifNull(properties.nullValue, false)) -- false
|
||||
test(concat('arg', 'another')) -- 'arganother'
|
||||
test(concat(1, NULL)) -- '1'
|
||||
test(concat(true, false)) -- 'truefalse'
|
||||
test(match('test', 'e.*')) -- true
|
||||
test(match('test', '^e.*')) -- false
|
||||
test(match('test', 'x.*')) -- false
|
||||
test('test' =~ 'e.*') -- true
|
||||
test('test' !~ 'e.*') -- false
|
||||
test('test' =~ '^e.*') -- false
|
||||
test('test' !~ '^e.*') -- true
|
||||
test('test' =~ 'x.*') -- false
|
||||
test('test' !~ 'x.*') -- true
|
||||
test('test' ~* 'EST') -- true
|
||||
test('test' =~* 'EST') -- true
|
||||
test('test' !~* 'EST') -- false
|
||||
test(toString(1)) -- '1'
|
||||
test(toString(1.5)) -- '1.5'
|
||||
test(toString(true)) -- 'true'
|
||||
test(toString(null)) -- 'null'
|
||||
test(toString('string')) -- 'string'
|
||||
test(toInt('1')) -- 1
|
||||
test(toInt('bla')) -- null
|
||||
test(toFloat('1.2')) -- 1.2
|
||||
test(toFloat('bla')) -- null
|
||||
test(toUUID('asd')) -- 'asd'
|
||||
test(1 == null) -- false
|
||||
test(1 != null) -- true
|
||||
|
@ -1,49 +1,49 @@
|
||||
{
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}];
|
||||
print(r.2.d.1);
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}]
|
||||
print(r.2.d.1)
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}];
|
||||
print(r[2].d[2]);
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}]
|
||||
print(r[2].d[2])
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}];
|
||||
print(r.2['d'][3]);
|
||||
let r := [1, 2, {'d': (1, 3, 42, 6)}]
|
||||
print(r.2['d'][3])
|
||||
}
|
||||
{
|
||||
let r := {'d': (1, 3, 42, 6)};
|
||||
print(r.d.1);
|
||||
let r := {'d': (1, 3, 42, 6)}
|
||||
print(r.d.1)
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
r.2.d.2 := 3;
|
||||
print(r.2.d.2);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
r.2.d.2 := 3
|
||||
print(r.2.d.2)
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
r[2].d[2] := 3;
|
||||
print(r[2].d[2]);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
r[2].d[2] := 3
|
||||
print(r[2].d[2])
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
r[2].c := [666];
|
||||
print(r[2]);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
r[2].c := [666]
|
||||
print(r[2])
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
r[2].d[2] := 3;
|
||||
print(r[2].d);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
r[2].d[2] := 3
|
||||
print(r[2].d)
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
r.2['d'] := ['a', 'b', 'c', 'd'];
|
||||
print(r[2].d[2]);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
r.2['d'] := ['a', 'b', 'c', 'd']
|
||||
print(r[2].d[2])
|
||||
}
|
||||
{
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}];
|
||||
let g := 'd';
|
||||
r.2[g] := ['a', 'b', 'c', 'd'];
|
||||
print(r[2].d[2]);
|
||||
let r := [1, 2, {'d': [1, 3, 42, 3]}]
|
||||
let g := 'd'
|
||||
r.2[g] := ['a', 'b', 'c', 'd']
|
||||
print(r[2].d[2])
|
||||
}
|
||||
{
|
||||
let event := {
|
||||
@ -52,9 +52,9 @@
|
||||
'$browser': 'Chrome',
|
||||
'$os': 'Windows'
|
||||
}
|
||||
};
|
||||
event['properties']['$browser'] := 'Firefox';
|
||||
print(event);
|
||||
}
|
||||
event['properties']['$browser'] := 'Firefox'
|
||||
print(event)
|
||||
}
|
||||
{
|
||||
let event := {
|
||||
@ -63,9 +63,9 @@
|
||||
'$browser': 'Chrome',
|
||||
'$os': 'Windows'
|
||||
}
|
||||
};
|
||||
event.properties.$browser := 'Firefox';
|
||||
print(event);
|
||||
}
|
||||
event.properties.$browser := 'Firefox'
|
||||
print(event)
|
||||
}
|
||||
{
|
||||
let event := {
|
||||
@ -74,7 +74,7 @@
|
||||
'$browser': 'Chrome',
|
||||
'$os': 'Windows'
|
||||
}
|
||||
};
|
||||
let config := {};
|
||||
print(event);
|
||||
}
|
||||
let config := {}
|
||||
print(event)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
print('-- empty, notEmpty, length, lower, upper, reverse --');
|
||||
if (empty('') and notEmpty('234')) print(length('123'));
|
||||
if (lower('Tdd4gh') == 'tdd4gh') print(upper('test'));
|
||||
print(reverse('spinner'));
|
||||
print('-- empty, notEmpty, length, lower, upper, reverse --')
|
||||
if (empty('') and notEmpty('234')) print(length('123'))
|
||||
if (lower('Tdd4gh') == 'tdd4gh') print(upper('test'))
|
||||
print(reverse('spinner'))
|
||||
|
@ -1,9 +1,9 @@
|
||||
print((1, 2, 3));
|
||||
print((1, '2', 3));
|
||||
print((1, (2, 3), 4));
|
||||
print((1, (2, (3, 4)), 5));
|
||||
let a := (1, 2, 3);
|
||||
print(a[1]);
|
||||
print((1, (2, (3, 4)), 5)[1][1][1]);
|
||||
print((1, (2, (3, 4)), 5).1.1.1);
|
||||
print((1, (2, (3, 4)), 5)[1][1][1] + 1);
|
||||
print((1, 2, 3))
|
||||
print((1, '2', 3))
|
||||
print((1, (2, 3), 4))
|
||||
print((1, (2, (3, 4)), 5))
|
||||
let a := (1, 2, 3)
|
||||
print(a[1])
|
||||
print((1, (2, (3, 4)), 5)[1][1][1])
|
||||
print((1, (2, (3, 4)), 5).1.1.1)
|
||||
print((1, (2, (3, 4)), 5)[1][1][1] + 1)
|
||||
|
@ -1,16 +1,16 @@
|
||||
print('-- test variables --');
|
||||
print('-- test variables --')
|
||||
{
|
||||
let a := 1 + 2;
|
||||
print(a);
|
||||
let a := 1 + 2
|
||||
print(a)
|
||||
|
||||
let b := a + 4;
|
||||
print(b);
|
||||
let b := a + 4
|
||||
print(b)
|
||||
}
|
||||
|
||||
print('-- test variable reassignment --');
|
||||
print('-- test variable reassignment --')
|
||||
{
|
||||
let a := 1;
|
||||
a := a + 3;
|
||||
a := a * 2;
|
||||
print(a);
|
||||
let a := 1
|
||||
a := a + 3
|
||||
a := a * 2
|
||||
print(a)
|
||||
}
|
@ -56,6 +56,9 @@ def execute_bytecode(
|
||||
if next_token() != HOGQL_BYTECODE_IDENTIFIER:
|
||||
raise HogVMException(f"Invalid bytecode. Must start with '{HOGQL_BYTECODE_IDENTIFIER}'")
|
||||
|
||||
if len(bytecode) == 1:
|
||||
return BytecodeResult(result=None, stdout=stdout, bytecode=bytecode)
|
||||
|
||||
def check_timeout():
|
||||
if time.time() - start_time > timeout and not debug:
|
||||
raise HogVMException(f"Execution timed out after {timeout} seconds. Performed {ops} ops.")
|
||||
|
@ -30,47 +30,14 @@ posthog/hogql/database/schema/numbers.py:0: error: Incompatible types in assignm
|
||||
posthog/hogql/database/schema/numbers.py:0: note: "Dict" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
|
||||
posthog/hogql/database/schema/numbers.py:0: note: Consider using "Mapping" instead, which is covariant in the value type
|
||||
posthog/hogql/ast.py:0: error: Incompatible return value type (got "bool | None", expected "bool") [return-value]
|
||||
posthog/hogql/visitor.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Type | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Type | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Type | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "RatioExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Constant | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinConstraint | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "OrderExpr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "WindowExpr", variable has type "CTE") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "FieldAliasType", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Incompatible types in assignment (expression has type "Type", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType") [assignment]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "WindowFrameExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "WindowFrameExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "WindowExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Constant | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "RatioExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinConstraint | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "SampleExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "JoinExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument "select" to "SelectQuery" has incompatible type "list[Expr] | None"; expected "list[Expr]" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "Expr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "WindowFrameExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/visitor.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "WindowFrameExpr | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/resolver_utils.py:0: error: Argument 1 to "lookup_field_by_name" has incompatible type "SelectQueryType | SelectUnionQueryType"; expected "SelectQueryType" [arg-type]
|
||||
posthog/hogql/parser.py:0: error: Item "None" of "list[Expr] | None" has no attribute "__iter__" (not iterable) [union-attr]
|
||||
posthog/hogql/parser.py:0: error: "None" has no attribute "text" [attr-defined]
|
||||
@ -198,21 +165,15 @@ posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "select" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "SelectUnionQuery" of "SelectQuery | SelectUnionQuery" has no attribute "group_by" [union-attr]
|
||||
posthog/hogql_queries/insights/trends/aggregation_operations.py:0: error: Item "None" of "list[Expr] | Any | None" has no attribute "append" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 of "visit" is incompatible with supertype "Visitor"; supertype defines the argument type as "AST" [override]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 of "visit" is incompatible with supertype "Visitor"; supertype defines the argument type as "AST | None" [override]
|
||||
posthog/hogql/resolver.py:0: note: This violates the Liskov substitution principle
|
||||
posthog/hogql/resolver.py:0: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
|
||||
posthog/hogql/resolver.py:0: error: List comprehension has incompatible type List[SelectQueryType | None]; expected List[SelectQueryType] [misc]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "JoinExpr | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "JoinExpr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Need type annotation for "columns_with_visible_alias" (hint: "columns_with_visible_alias: dict[<type>, <type>] = ...") [var-annotated]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Type | None", target has type "Type") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Type | None", target has type "Type") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "Expr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "Expr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "Expr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: List comprehension has incompatible type List[Expr]; expected List[OrderExpr] [misc]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "Expr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "Expr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Value expression in dictionary comprehension has incompatible type "Expr"; expected type "WindowExpr" [misc]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Argument 2 to "lookup_cte_by_name" has incompatible type "str | int"; expected "str" [arg-type]
|
||||
@ -229,12 +190,9 @@ posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression
|
||||
posthog/hogql/resolver.py:0: error: Invalid index type "str | int" for "dict[str, BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType]"; expected type "str" [index]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "clone_expr" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "JoinExpr | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "JoinExpr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "JoinExpr | None" has no attribute "join_type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SampleExpr | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "SampleExpr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Visitor" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectViewType" has incompatible type "SelectQueryType | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectUnionQuery | Field | None" has no attribute "type" [union-attr]
|
||||
posthog/hogql/resolver.py:0: error: Argument "select_query_type" to "SelectQueryAliasType" has incompatible type "Type | Any | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
@ -242,9 +200,7 @@ posthog/hogql/resolver.py:0: error: Item "None" of "SelectQuery | SelectUnionQue
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Type | Any | None", variable has type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "append" of "list" has incompatible type "BaseTableType | SelectUnionQueryType | SelectQueryType | SelectQueryAliasType | SelectViewType | None"; expected "SelectQueryType | SelectUnionQueryType" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "JoinExpr | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "JoinExpr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Incompatible types in assignment (expression has type "Expr", variable has type "SampleExpr | None") [assignment]
|
||||
posthog/hogql/resolver.py:0: error: Argument 1 to "visit" of "Resolver" has incompatible type "SampleExpr | None"; expected "Expr" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Argument 2 to "convert_hogqlx_tag" has incompatible type "int | None"; expected "int" [arg-type]
|
||||
posthog/hogql/resolver.py:0: error: Statement is unreachable [unreachable]
|
||||
posthog/hogql/resolver.py:0: error: Item "None" of "Type | None" has no attribute "resolve_constant_type" [union-attr]
|
||||
@ -293,10 +249,6 @@ posthog/hogql/printer.py:0: error: Argument 1 to "len" has incompatible type "li
|
||||
posthog/hogql/printer.py:0: error: Item "None" of "list[Expr] | None" has no attribute "__iter__" (not iterable) [union-attr]
|
||||
posthog/hogql/printer.py:0: error: Right operand of "and" is never evaluated [unreachable]
|
||||
posthog/hogql/printer.py:0: error: Subclass of "TableType" and "LazyTableType" cannot exist: would have incompatible method signatures [unreachable]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "visit" of "_Printer" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "visit" of "_Printer" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "visit" of "_Printer" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "visit" of "_Printer" has incompatible type "SelectQuery | SelectUnionQuery | Field | None"; expected "AST" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "_print_escaped_string" of "_Printer" has incompatible type "int | float | UUID | date | None"; expected "float | int | str | list[Any] | tuple[Any, ...] | datetime | date" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Argument 1 to "join" of "str" has incompatible type "list[str | int]"; expected "Iterable[str]" [arg-type]
|
||||
posthog/hogql/printer.py:0: error: Name "args" already defined on line 0 [no-redef]
|
||||
|
@ -160,7 +160,7 @@ class ClickhouseClientTestCase(TestCase, ClickhouseTestMixin):
|
||||
result = client.get_query_status(self.team.id, query_id)
|
||||
self.assertTrue(result.error)
|
||||
assert result.error_message
|
||||
self.assertRegex(result.error_message, "Unknown table")
|
||||
self.assertRegex(result.error_message, "no viable alternative at input")
|
||||
|
||||
def test_async_query_client_uuid(self):
|
||||
query = build_query("SELECT toUUID('00000000-0000-0000-0000-000000000000')")
|
||||
|
@ -47,7 +47,7 @@ class Statement(Declaration):
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class ExprStatement(Statement):
|
||||
expr: Expr
|
||||
expr: Optional[Expr]
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
|
@ -51,7 +51,7 @@ class GetNodeAtPositionTraverser(TraversingVisitor):
|
||||
self.end = end
|
||||
super().visit(expr)
|
||||
|
||||
def visit(self, node: AST):
|
||||
def visit(self, node: AST | None):
|
||||
if node is not None and node.start is not None and node.end is not None:
|
||||
if self.start >= node.start and self.end <= node.end:
|
||||
self.node = node
|
||||
|
@ -227,6 +227,8 @@ class BytecodeBuilder(Visitor):
|
||||
return response
|
||||
|
||||
def visit_expr_statement(self, node: ast.ExprStatement):
|
||||
if node.expr is None:
|
||||
return []
|
||||
response = self.visit(node.expr)
|
||||
response.append(Operation.POP)
|
||||
return response
|
||||
|
@ -6,32 +6,29 @@ options {
|
||||
|
||||
|
||||
program: declaration* EOF;
|
||||
declaration
|
||||
: varDecl
|
||||
| statement ;
|
||||
|
||||
declaration: varDecl | statement ;
|
||||
|
||||
expression: columnExpr;
|
||||
|
||||
varDecl: LET identifier ( COLON EQ_SINGLE expression )? SEMICOLON ;
|
||||
varAssignment: expression COLON EQ_SINGLE expression SEMICOLON ;
|
||||
varDecl: LET identifier ( COLON EQ_SINGLE expression )? ;
|
||||
identifierList: identifier (COMMA identifier)*;
|
||||
|
||||
statement : returnStmt
|
||||
| emptyStmt
|
||||
| exprStmt
|
||||
| ifStmt
|
||||
| whileStmt
|
||||
| funcStmt
|
||||
| varAssignment
|
||||
| returnStmt
|
||||
| exprStmt
|
||||
| emptyStmt
|
||||
| block ;
|
||||
|
||||
exprStmt : expression SEMICOLON ;
|
||||
ifStmt : IF LPAREN expression RPAREN statement
|
||||
( ELSE statement )? ;
|
||||
whileStmt : WHILE LPAREN expression RPAREN statement;
|
||||
returnStmt : RETURN expression SEMICOLON ;
|
||||
returnStmt : RETURN expression? SEMICOLON?;
|
||||
ifStmt : IF LPAREN expression RPAREN statement ( ELSE statement )? ;
|
||||
whileStmt : WHILE LPAREN expression RPAREN statement SEMICOLON?;
|
||||
funcStmt : FN identifier LPAREN identifierList? RPAREN block;
|
||||
varAssignment : expression COLON EQ_SINGLE expression ;
|
||||
exprStmt : expression SEMICOLON?;
|
||||
emptyStmt : SEMICOLON ;
|
||||
block : LBRACE declaration* RBRACE ;
|
||||
|
||||
@ -184,8 +181,7 @@ columnExpr
|
||||
// TODO(ilezhankin): `BETWEEN a AND b AND c` is parsed in a wrong way: `BETWEEN (a AND b) AND c`
|
||||
| columnExpr NOT? BETWEEN columnExpr AND columnExpr # ColumnExprBetween
|
||||
| <assoc=right> columnExpr QUERY columnExpr COLON columnExpr # ColumnExprTernaryOp
|
||||
// Note: difference with ClickHouse: we also support "AS string" as a shortcut for naming columns
|
||||
| columnExpr (alias | AS identifier | AS STRING_LITERAL) # ColumnExprAlias
|
||||
| columnExpr (AS identifier | AS STRING_LITERAL) # ColumnExprAlias
|
||||
|
||||
| (tableIdentifier DOT)? ASTERISK # ColumnExprAsterisk // single-column only
|
||||
| LPAREN selectUnionStmt RPAREN # ColumnExprSubquery // single-column only
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -29,11 +29,6 @@ class HogQLParserVisitor(ParseTreeVisitor):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#varAssignment.
|
||||
def visitVarAssignment(self, ctx:HogQLParser.VarAssignmentContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#identifierList.
|
||||
def visitIdentifierList(self, ctx:HogQLParser.IdentifierListContext):
|
||||
return self.visitChildren(ctx)
|
||||
@ -44,8 +39,8 @@ class HogQLParserVisitor(ParseTreeVisitor):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#exprStmt.
|
||||
def visitExprStmt(self, ctx:HogQLParser.ExprStmtContext):
|
||||
# Visit a parse tree produced by HogQLParser#returnStmt.
|
||||
def visitReturnStmt(self, ctx:HogQLParser.ReturnStmtContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
@ -59,13 +54,18 @@ class HogQLParserVisitor(ParseTreeVisitor):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#returnStmt.
|
||||
def visitReturnStmt(self, ctx:HogQLParser.ReturnStmtContext):
|
||||
# Visit a parse tree produced by HogQLParser#funcStmt.
|
||||
def visitFuncStmt(self, ctx:HogQLParser.FuncStmtContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#funcStmt.
|
||||
def visitFuncStmt(self, ctx:HogQLParser.FuncStmtContext):
|
||||
# Visit a parse tree produced by HogQLParser#varAssignment.
|
||||
def visitVarAssignment(self, ctx:HogQLParser.VarAssignmentContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
# Visit a parse tree produced by HogQLParser#exprStmt.
|
||||
def visitExprStmt(self, ctx:HogQLParser.ExprStmtContext):
|
||||
return self.visitChildren(ctx)
|
||||
|
||||
|
||||
|
@ -185,7 +185,12 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
raise e
|
||||
|
||||
def visitProgram(self, ctx: HogQLParser.ProgramContext):
|
||||
return ast.Program(declarations=[self.visit(declaration) for declaration in ctx.declaration()])
|
||||
declarations: list[ast.Declaration] = []
|
||||
for declaration in ctx.declaration():
|
||||
if not declaration.statement() or not declaration.statement().emptyStmt():
|
||||
statement = self.visit(declaration)
|
||||
declarations.append(cast(ast.Declaration, statement))
|
||||
return ast.Program(declarations=declarations)
|
||||
|
||||
def visitDeclaration(self, ctx: HogQLParser.DeclarationContext):
|
||||
return self.visitChildren(ctx)
|
||||
@ -245,10 +250,15 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
return [ident.getText() for ident in ctx.identifier()]
|
||||
|
||||
def visitEmptyStmt(self, ctx: HogQLParser.EmptyStmtContext):
|
||||
return ast.ExprStatement(expr=ast.Constant(value=True))
|
||||
return ast.ExprStatement(expr=None)
|
||||
|
||||
def visitBlock(self, ctx: HogQLParser.BlockContext):
|
||||
return ast.Block(declarations=[self.visit(declaration) for declaration in ctx.declaration()])
|
||||
declarations: list[ast.Declaration] = []
|
||||
for declaration in ctx.declaration():
|
||||
if not declaration.statement() or not declaration.statement().emptyStmt():
|
||||
statement = self.visit(declaration)
|
||||
declarations.append(cast(ast.Declaration, statement))
|
||||
return ast.Block(declarations=declarations)
|
||||
|
||||
def visitSelect(self, ctx: HogQLParser.SelectContext):
|
||||
return self.visit(ctx.selectUnionStmt() or ctx.selectStmt() or ctx.hogqlxTagElement())
|
||||
@ -573,9 +583,7 @@ class HogQLParseTreeConverter(ParseTreeVisitor):
|
||||
|
||||
def visitColumnExprAlias(self, ctx: HogQLParser.ColumnExprAliasContext):
|
||||
alias: str
|
||||
if ctx.alias():
|
||||
alias = self.visit(ctx.alias())
|
||||
elif ctx.identifier():
|
||||
if ctx.identifier():
|
||||
alias = self.visit(ctx.identifier())
|
||||
elif ctx.STRING_LITERAL():
|
||||
alias = parse_string_literal_ctx(ctx.STRING_LITERAL())
|
||||
|
@ -173,7 +173,9 @@ class _Printer(Visitor):
|
||||
def indent(self, extra: int = 0):
|
||||
return " " * self.tab_size * (self._indent + extra)
|
||||
|
||||
def visit(self, node: AST):
|
||||
def visit(self, node: AST | None):
|
||||
if node is None:
|
||||
return ""
|
||||
self.stack.append(node)
|
||||
self._indent += 1
|
||||
response = super().visit(node)
|
||||
|
@ -110,7 +110,7 @@ class Resolver(CloningVisitor):
|
||||
self.database = context.database
|
||||
self.cte_counter = 0
|
||||
|
||||
def visit(self, node: ast.Expr) -> ast.Expr:
|
||||
def visit(self, node: ast.Expr | None) -> ast.Expr:
|
||||
if isinstance(node, ast.Expr) and node.type is not None:
|
||||
raise ResolutionError(
|
||||
f"Type already resolved for {type(node).__name__} ({type(node.type).__name__}). Can't run again."
|
||||
|
@ -957,7 +957,7 @@ def parser_test_factory(backend: Literal["python", "cpp"]):
|
||||
|
||||
def test_select_array_join(self):
|
||||
self.assertEqual(
|
||||
self._select("select a from events ARRAY JOIN [1,2,3] a"),
|
||||
self._select("select a from events ARRAY JOIN [1,2,3] as a"),
|
||||
ast.SelectQuery(
|
||||
select=[ast.Field(chain=["a"])],
|
||||
select_from=ast.JoinExpr(table=ast.Field(chain=["events"])),
|
||||
@ -977,7 +977,7 @@ def parser_test_factory(backend: Literal["python", "cpp"]):
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
self._select("select a from events INNER ARRAY JOIN [1,2,3] a"),
|
||||
self._select("select a from events INNER ARRAY JOIN [1,2,3] as a"),
|
||||
ast.SelectQuery(
|
||||
select=[ast.Field(chain=["a"])],
|
||||
select_from=ast.JoinExpr(table=ast.Field(chain=["events"])),
|
||||
@ -997,7 +997,7 @@ def parser_test_factory(backend: Literal["python", "cpp"]):
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
self._select("select 1, b from events LEFT ARRAY JOIN [1,2,3] a, [4,5,6] AS b"),
|
||||
self._select("select 1, b from events LEFT ARRAY JOIN [1,2,3] as a, [4,5,6] AS b"),
|
||||
ast.SelectQuery(
|
||||
select=[ast.Constant(value=1), ast.Field(chain=["b"])],
|
||||
select_from=ast.JoinExpr(table=ast.Field(chain=["events"])),
|
||||
|
@ -243,7 +243,7 @@ class TestPrinter(BaseTest):
|
||||
)
|
||||
self._assert_expr_error(
|
||||
"properties.'no strings'",
|
||||
"no viable alternative at input '.'no strings'",
|
||||
"mismatched input",
|
||||
"hogql",
|
||||
)
|
||||
|
||||
@ -393,10 +393,10 @@ class TestPrinter(BaseTest):
|
||||
self._assert_expr_error("(", "no viable alternative at input '('")
|
||||
self._assert_expr_error("())", "no viable alternative at input '()'")
|
||||
self._assert_expr_error("(3 57", "no viable alternative at input '(3 57'")
|
||||
self._assert_expr_error("select query from events", "mismatched input 'from' expecting <EOF>")
|
||||
self._assert_expr_error("this makes little sense", "Unable to resolve field: this")
|
||||
self._assert_expr_error("select query from events", "mismatched input 'query' expecting <EOF>")
|
||||
self._assert_expr_error("this makes little sense", "mismatched input 'makes' expecting <EOF>")
|
||||
self._assert_expr_error("1;2", "mismatched input ';' expecting <EOF>")
|
||||
self._assert_expr_error("b.a(bla)", "mismatched input '(' expecting '.'")
|
||||
self._assert_expr_error("b.a(bla)", "mismatched input '(' expecting <EOF>")
|
||||
|
||||
def test_logic(self):
|
||||
self.assertEqual(
|
||||
@ -504,11 +504,6 @@ class TestPrinter(BaseTest):
|
||||
self._select("select 1 as `-- select team_id` from events"),
|
||||
f"SELECT 1 AS `-- select team_id` FROM events WHERE equals(events.team_id, {self.team.pk}) LIMIT {MAX_SELECT_RETURNED_ROWS}",
|
||||
)
|
||||
# Some aliases are funny, but that's what the antlr syntax permits, and ClickHouse doesn't complain either
|
||||
self.assertEqual(
|
||||
self._expr("event makes little sense"),
|
||||
"((events.event AS makes) AS little) AS sense",
|
||||
)
|
||||
|
||||
def test_case_when(self):
|
||||
self.assertEqual(self._expr("case when 1 then 2 else 3 end"), "if(1, 2, 3)")
|
||||
|
@ -624,7 +624,7 @@ class TestQuery(ClickhouseTestMixin, APIBaseTest):
|
||||
self._create_random_events()
|
||||
# sample pivot table, testing tuple access
|
||||
query = """
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) r from (
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) as r from (
|
||||
select col_a, groupArray( (col_b, col_c) ) as g from
|
||||
(
|
||||
SELECT properties.index as col_a,
|
||||
@ -894,7 +894,7 @@ class TestQuery(ClickhouseTestMixin, APIBaseTest):
|
||||
group by col_a
|
||||
),
|
||||
PIVOT_FUNCTION_2 AS (
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) r from
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) as r from
|
||||
PIVOT_FUNCTION_1
|
||||
group by col_a
|
||||
)
|
||||
@ -933,7 +933,7 @@ class TestQuery(ClickhouseTestMixin, APIBaseTest):
|
||||
group by col_a
|
||||
),
|
||||
PIVOT_FUNCTION_2 AS (
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) r from
|
||||
select col_a, arrayZip( (sumMap( g.1, g.2 ) as x).1, x.2) as r from
|
||||
PIVOT_FUNCTION_1
|
||||
group by col_a
|
||||
),
|
||||
|
@ -18,9 +18,9 @@ T = TypeVar("T")
|
||||
|
||||
|
||||
class Visitor(Generic[T]):
|
||||
def visit(self, node: AST) -> T:
|
||||
def visit(self, node: AST | None) -> T:
|
||||
if node is None:
|
||||
return node
|
||||
return node # type: ignore
|
||||
|
||||
try:
|
||||
return node.accept(self)
|
||||
@ -509,7 +509,7 @@ class CloningVisitor(Visitor[Any]):
|
||||
type=None if self.clear_types else node.type,
|
||||
ctes={key: self.visit(expr) for key, expr in node.ctes.items()} if node.ctes else None, # to not traverse
|
||||
select_from=self.visit(node.select_from), # keep "select_from" before "select" to resolve tables first
|
||||
select=[self.visit(expr) for expr in node.select] if node.select else None,
|
||||
select=[self.visit(expr) for expr in node.select] if node.select else [],
|
||||
array_join_op=node.array_join_op,
|
||||
array_join_list=[self.visit(expr) for expr in node.array_join_list] if node.array_join_list else None,
|
||||
where=self.visit(node.where),
|
||||
|
@ -645,7 +645,7 @@ class FunnelBase(ABC):
|
||||
exprs: list[ast.Expr] = []
|
||||
|
||||
for i in range(max_steps):
|
||||
exprs.append(parse_expr(f"countIf(steps = {i + 1}) step_{i + 1}"))
|
||||
exprs.append(parse_expr(f"countIf(steps = {i + 1}) as step_{i + 1}"))
|
||||
|
||||
return exprs
|
||||
|
||||
@ -686,7 +686,7 @@ class FunnelBase(ABC):
|
||||
for i in range(0, max_steps):
|
||||
event_fields = ["latest", *self.extra_event_fields_and_properties]
|
||||
event_fields_with_step = ", ".join([f"{field}_{i}" for field in event_fields])
|
||||
event_clause = f"({event_fields_with_step}) as step_{i}_matching_event"
|
||||
event_clause = f"({event_fields_with_step}) AS step_{i}_matching_event"
|
||||
events.append(parse_expr(event_clause))
|
||||
|
||||
return [*events, *self._get_final_matching_event(max_steps)]
|
||||
@ -700,8 +700,8 @@ class FunnelBase(ABC):
|
||||
and self.context.actorsQuery.includeRecordings
|
||||
):
|
||||
for i in range(0, max_steps):
|
||||
exprs.append(parse_expr(f"groupArray(10)(step_{i}_matching_event) as step_{i}_matching_events"))
|
||||
exprs.append(parse_expr(f"groupArray(10)(final_matching_event) as final_matching_events"))
|
||||
exprs.append(parse_expr(f"groupArray(10)(step_{i}_matching_event) AS step_{i}_matching_events"))
|
||||
exprs.append(parse_expr(f"groupArray(10)(final_matching_event) AS final_matching_events"))
|
||||
return exprs
|
||||
|
||||
def _get_step_time_avgs(self, max_steps: int, inner_query: bool = False) -> list[ast.Expr]:
|
||||
@ -709,9 +709,9 @@ class FunnelBase(ABC):
|
||||
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(f"avg(step_{i}_conversion_time) step_{i}_average_conversion_time_inner")
|
||||
parse_expr(f"avg(step_{i}_conversion_time) as step_{i}_average_conversion_time_inner")
|
||||
if inner_query
|
||||
else parse_expr(f"avg(step_{i}_average_conversion_time_inner) step_{i}_average_conversion_time")
|
||||
else parse_expr(f"avg(step_{i}_average_conversion_time_inner) as step_{i}_average_conversion_time")
|
||||
)
|
||||
|
||||
return exprs
|
||||
@ -721,9 +721,9 @@ class FunnelBase(ABC):
|
||||
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(f"median(step_{i}_conversion_time) step_{i}_median_conversion_time_inner")
|
||||
parse_expr(f"median(step_{i}_conversion_time) as step_{i}_median_conversion_time_inner")
|
||||
if inner_query
|
||||
else parse_expr(f"median(step_{i}_median_conversion_time_inner) step_{i}_median_conversion_time")
|
||||
else parse_expr(f"median(step_{i}_median_conversion_time_inner) as step_{i}_median_conversion_time")
|
||||
)
|
||||
|
||||
return exprs
|
||||
@ -732,7 +732,7 @@ class FunnelBase(ABC):
|
||||
exprs: list[ast.Expr] = []
|
||||
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(parse_expr(f"groupArray(step_{i}_conversion_time) step_{i}_conversion_time_array"))
|
||||
exprs.append(parse_expr(f"groupArray(step_{i}_conversion_time) as step_{i}_conversion_time_array"))
|
||||
|
||||
return exprs
|
||||
|
||||
@ -742,7 +742,7 @@ class FunnelBase(ABC):
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"if(isNaN(avgArray(step_{i}_conversion_time_array) as inter_{i}_conversion), NULL, inter_{i}_conversion) step_{i}_average_conversion_time"
|
||||
f"if(isNaN(avgArray(step_{i}_conversion_time_array) as inter_{i}_conversion), NULL, inter_{i}_conversion) as step_{i}_average_conversion_time"
|
||||
)
|
||||
)
|
||||
|
||||
@ -754,7 +754,7 @@ class FunnelBase(ABC):
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"if(isNaN(medianArray(step_{i}_conversion_time_array) as inter_{i}_median), NULL, inter_{i}_median) step_{i}_median_conversion_time"
|
||||
f"if(isNaN(medianArray(step_{i}_conversion_time_array) as inter_{i}_median), NULL, inter_{i}_median) as step_{i}_median_conversion_time"
|
||||
)
|
||||
)
|
||||
|
||||
@ -796,8 +796,8 @@ class FunnelBase(ABC):
|
||||
return (
|
||||
[ast.Field(chain=[f"latest_{target_step}"]), ast.Field(chain=[f"latest_{target_step - 1}"])],
|
||||
[
|
||||
parse_expr(f"argMax(latest_{target_step}, steps) as max_timestamp"),
|
||||
parse_expr(f"argMax(latest_{target_step - 1}, steps) as min_timestamp"),
|
||||
parse_expr(f"argMax(latest_{target_step}, steps) AS max_timestamp"),
|
||||
parse_expr(f"argMax(latest_{target_step - 1}, steps) AS min_timestamp"),
|
||||
],
|
||||
)
|
||||
elif self.context.includeTimestamp:
|
||||
@ -808,9 +808,9 @@ class FunnelBase(ABC):
|
||||
ast.Field(chain=[f"latest_{first_step}"]),
|
||||
],
|
||||
[
|
||||
parse_expr(f"argMax(latest_{target_step}, steps) as timestamp"),
|
||||
parse_expr(f"argMax(latest_{final_step}, steps) as final_timestamp"),
|
||||
parse_expr(f"argMax(latest_{first_step}, steps) as first_timestamp"),
|
||||
parse_expr(f"argMax(latest_{target_step}, steps) AS timestamp"),
|
||||
parse_expr(f"argMax(latest_{final_step}, steps) AS final_timestamp"),
|
||||
parse_expr(f"argMax(latest_{first_step}, steps) AS first_timestamp"),
|
||||
],
|
||||
)
|
||||
else:
|
||||
@ -825,7 +825,7 @@ class FunnelBase(ABC):
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"if(isNotNull(latest_{i}) AND latest_{i} <= toTimeZone(latest_{i-1}, 'UTC') + INTERVAL {windowInterval} {windowIntervalUnit}, dateDiff('second', latest_{i - 1}, latest_{i}), NULL) step_{i}_conversion_time"
|
||||
f"if(isNotNull(latest_{i}) AND latest_{i} <= toTimeZone(latest_{i-1}, 'UTC') + INTERVAL {windowInterval} {windowIntervalUnit}, dateDiff('second', latest_{i - 1}, latest_{i}), NULL) as step_{i}_conversion_time"
|
||||
),
|
||||
)
|
||||
|
||||
@ -859,14 +859,14 @@ class FunnelBase(ABC):
|
||||
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"min(latest_{i}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND {duplicate_event} PRECEDING) latest_{i}"
|
||||
f"min(latest_{i}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND {duplicate_event} PRECEDING) as latest_{i}"
|
||||
)
|
||||
)
|
||||
|
||||
for field in self.extra_event_fields_and_properties:
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f'last_value("{field}_{i}") over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND {duplicate_event} PRECEDING) "{field}_{i}"'
|
||||
f'last_value("{field}_{i}") over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND {duplicate_event} PRECEDING) as "{field}_{i}"'
|
||||
)
|
||||
)
|
||||
|
||||
@ -875,7 +875,7 @@ class FunnelBase(ABC):
|
||||
if cast(int, exclusion.funnelFromStep) + 1 == i:
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"min(exclusion_{exclusion_id}_latest_{exclusion.funnelFromStep}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING) exclusion_{exclusion_id}_latest_{exclusion.funnelFromStep}"
|
||||
f"min(exclusion_{exclusion_id}_latest_{exclusion.funnelFromStep}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN UNBOUNDED PRECEDING AND 0 PRECEDING) as exclusion_{exclusion_id}_latest_{exclusion.funnelFromStep}"
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -81,14 +81,14 @@ class FunnelStrict(FunnelBase):
|
||||
else:
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"min(latest_{i}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN {i} PRECEDING AND {i} PRECEDING) latest_{i}"
|
||||
f"min(latest_{i}) over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN {i} PRECEDING AND {i} PRECEDING) as latest_{i}"
|
||||
)
|
||||
)
|
||||
|
||||
for field in self.extra_event_fields_and_properties:
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f'min("{field}_{i}") over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN {i} PRECEDING AND {i} PRECEDING) "{field}_{i}"'
|
||||
f'min("{field}_{i}") over (PARTITION by aggregation_target {self._get_breakdown_prop()} ORDER BY timestamp DESC ROWS BETWEEN {i} PRECEDING AND {i} PRECEDING) as "{field}_{i}"'
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -132,7 +132,7 @@ class FunnelUnordered(FunnelBase):
|
||||
for i in range(1, max_steps):
|
||||
exprs.append(
|
||||
parse_expr(
|
||||
f"if(isNotNull(conversion_times[{i+1}]) AND conversion_times[{i+1}] <= toTimeZone(conversion_times[{i}], 'UTC') + INTERVAL {windowInterval} {windowIntervalUnit}, dateDiff('second', conversion_times[{i}], conversion_times[{i+1}]), NULL) step_{i}_conversion_time"
|
||||
f"if(isNotNull(conversion_times[{i+1}]) AND conversion_times[{i+1}] <= toTimeZone(conversion_times[{i}], 'UTC') + INTERVAL {windowInterval} {windowIntervalUnit}, dateDiff('second', conversion_times[{i}], conversion_times[{i+1}]), NULL) as step_{i}_conversion_time"
|
||||
)
|
||||
)
|
||||
# array indices in ClickHouse are 1-based :shrug:
|
||||
|
Loading…
Reference in New Issue
Block a user